mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-07-18 10:11:24 +00:00
Refactor dragging logic (#523)
* refactor dragging logic * Remove unnecessary undefined in TableInfo.jsx
This commit is contained in:
@@ -9,7 +9,6 @@ import {
|
|||||||
} from "@douyinfe/semi-icons";
|
} from "@douyinfe/semi-icons";
|
||||||
import { Tab, Action, ObjectType, State } from "../../data/constants";
|
import { Tab, Action, ObjectType, State } from "../../data/constants";
|
||||||
import {
|
import {
|
||||||
useCanvas,
|
|
||||||
useLayout,
|
useLayout,
|
||||||
useSettings,
|
useSettings,
|
||||||
useUndoRedo,
|
useUndoRedo,
|
||||||
@@ -24,15 +23,10 @@ export default function Area({
|
|||||||
data,
|
data,
|
||||||
onPointerDown,
|
onPointerDown,
|
||||||
setResize,
|
setResize,
|
||||||
setInitCoords,
|
setInitDimensions,
|
||||||
}) {
|
}) {
|
||||||
const ref = useRef(null);
|
const ref = useRef(null);
|
||||||
const isHovered = useHover(ref);
|
const isHovered = useHover(ref);
|
||||||
const {
|
|
||||||
pointer: {
|
|
||||||
spaces: { diagram: pointer },
|
|
||||||
},
|
|
||||||
} = useCanvas();
|
|
||||||
const { layout } = useLayout();
|
const { layout } = useLayout();
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
const { setSaveState } = useSaveState();
|
const { setSaveState } = useSaveState();
|
||||||
@@ -46,13 +40,11 @@ export default function Area({
|
|||||||
|
|
||||||
const handleResize = (e, dir) => {
|
const handleResize = (e, dir) => {
|
||||||
setResize({ id: data.id, dir: dir });
|
setResize({ id: data.id, dir: dir });
|
||||||
setInitCoords({
|
setInitDimensions({
|
||||||
x: data.x,
|
x: data.x,
|
||||||
y: data.y,
|
y: data.y,
|
||||||
width: data.width,
|
width: data.width,
|
||||||
height: data.height,
|
height: data.height,
|
||||||
pointerX: pointer.x,
|
|
||||||
pointerY: pointer.y,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -57,11 +57,9 @@ export default function Canvas() {
|
|||||||
setBulkSelectedElements,
|
setBulkSelectedElements,
|
||||||
} = useSelect();
|
} = useSelect();
|
||||||
const notDragging = {
|
const notDragging = {
|
||||||
element: ObjectType.NONE,
|
id: -1,
|
||||||
id: null,
|
type: ObjectType.NONE,
|
||||||
prevX: 0,
|
grabOffset: { x: 0, y: 0 },
|
||||||
prevY: 0,
|
|
||||||
initialPositions: [],
|
|
||||||
};
|
};
|
||||||
const [dragging, setDragging] = useState(notDragging);
|
const [dragging, setDragging] = useState(notDragging);
|
||||||
const [linking, setLinking] = useState(false);
|
const [linking, setLinking] = useState(false);
|
||||||
@@ -75,7 +73,6 @@ export default function Canvas() {
|
|||||||
endX: 0,
|
endX: 0,
|
||||||
endY: 0,
|
endY: 0,
|
||||||
});
|
});
|
||||||
const [grabOffset, setGrabOffset] = useState({ x: 0, y: 0 });
|
|
||||||
const [hoveredTable, setHoveredTable] = useState({
|
const [hoveredTable, setHoveredTable] = useState({
|
||||||
tableId: null,
|
tableId: null,
|
||||||
fieldId: null,
|
fieldId: null,
|
||||||
@@ -86,13 +83,11 @@ export default function Canvas() {
|
|||||||
cursorStart: { x: 0, y: 0 },
|
cursorStart: { x: 0, y: 0 },
|
||||||
});
|
});
|
||||||
const [areaResize, setAreaResize] = useState({ id: -1, dir: "none" });
|
const [areaResize, setAreaResize] = useState({ id: -1, dir: "none" });
|
||||||
const [initCoords, setInitCoords] = useState({
|
const [areaInitDimensions, setAreaInitDimensions] = useState({
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
pointerX: 0,
|
|
||||||
pointerY: 0,
|
|
||||||
});
|
});
|
||||||
const [bulkSelectRectPts, setBulkSelectRectPts] = useState({
|
const [bulkSelectRectPts, setBulkSelectRectPts] = useState({
|
||||||
x1: 0,
|
x1: 0,
|
||||||
@@ -124,6 +119,8 @@ export default function Canvas() {
|
|||||||
elements.push({
|
elements.push({
|
||||||
id: table.id,
|
id: table.id,
|
||||||
type: ObjectType.TABLE,
|
type: ObjectType.TABLE,
|
||||||
|
currentCoords: { x: table.x, y: table.y },
|
||||||
|
initialCoords: { x: table.x, y: table.y },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -145,6 +142,8 @@ export default function Canvas() {
|
|||||||
elements.push({
|
elements.push({
|
||||||
id: area.id,
|
id: area.id,
|
||||||
type: ObjectType.AREA,
|
type: ObjectType.AREA,
|
||||||
|
currentCoords: { x: area.x, y: area.y },
|
||||||
|
initialCoords: { x: area.x, y: area.y },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -166,6 +165,8 @@ export default function Canvas() {
|
|||||||
elements.push({
|
elements.push({
|
||||||
id: note.id,
|
id: note.id,
|
||||||
type: ObjectType.NOTE,
|
type: ObjectType.NOTE,
|
||||||
|
currentCoords: { x: note.x, y: note.y },
|
||||||
|
initialCoords: { x: note.x, y: note.y },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -210,31 +211,41 @@ export default function Canvas() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let prevCoords = { prevX: element.x, prevY: element.y };
|
|
||||||
setGrabOffset({
|
|
||||||
x: element.x - pointer.spaces.diagram.x,
|
|
||||||
y: element.y - pointer.spaces.diagram.y,
|
|
||||||
});
|
|
||||||
|
|
||||||
let newBulkSelectedElements;
|
let newBulkSelectedElements;
|
||||||
if (bulkSelectedElements.some((el) => el.id === id && el.type === type)) {
|
if (bulkSelectedElements.some((el) => el.id === id && el.type === type)) {
|
||||||
newBulkSelectedElements = bulkSelectedElements;
|
newBulkSelectedElements = bulkSelectedElements;
|
||||||
} else {
|
} else {
|
||||||
newBulkSelectedElements = [{ id, type }];
|
newBulkSelectedElements = [
|
||||||
|
{
|
||||||
|
id,
|
||||||
|
type,
|
||||||
|
currentCoords: { x: element.x, y: element.y },
|
||||||
|
initialCoords: { x: element.x, y: element.y },
|
||||||
|
},
|
||||||
|
];
|
||||||
setBulkSelectedElements(newBulkSelectedElements);
|
setBulkSelectedElements(newBulkSelectedElements);
|
||||||
}
|
}
|
||||||
|
|
||||||
setDragging((prev) => ({
|
setDragging({
|
||||||
...prev,
|
|
||||||
id,
|
id,
|
||||||
element: type,
|
type,
|
||||||
...prevCoords,
|
grabOffset: {
|
||||||
initialPositions: newBulkSelectedElements.map((el) => {
|
x: pointer.spaces.diagram.x - element.x,
|
||||||
const { x, y } = getElement(el);
|
y: pointer.spaces.diagram.y - element.y,
|
||||||
return { ...el, undo: { x, y } };
|
},
|
||||||
}),
|
});
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const coordinatesAfterSnappingToGrid = ({ x, y }) => {
|
||||||
|
if (settings.snapToGrid) {
|
||||||
|
return {
|
||||||
|
x: Math.round(x / gridSize) * gridSize,
|
||||||
|
y: Math.round(y / gridSize) * gridSize,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { x, y };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {PointerEvent} e
|
* @param {PointerEvent} e
|
||||||
*/
|
*/
|
||||||
@@ -258,23 +269,6 @@ export default function Canvas() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDragging =
|
|
||||||
dragging.element !== ObjectType.NONE && dragging.id !== null;
|
|
||||||
|
|
||||||
const currentX = pointer.spaces.diagram.x + (isDragging ? grabOffset.x : 0);
|
|
||||||
const currentY = pointer.spaces.diagram.y + (isDragging ? grabOffset.y : 0);
|
|
||||||
|
|
||||||
let finalX = currentX;
|
|
||||||
let finalY = currentY;
|
|
||||||
|
|
||||||
if (settings.snapToGrid) {
|
|
||||||
finalX = Math.round(currentX / gridSize) * gridSize;
|
|
||||||
finalY = Math.round(currentY / gridSize) * gridSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
const deltaX = finalX - dragging.prevX;
|
|
||||||
const deltaY = finalY - dragging.prevY;
|
|
||||||
|
|
||||||
if (linking) {
|
if (linking) {
|
||||||
setLinkingLine({
|
setLinkingLine({
|
||||||
...linkingLine,
|
...linkingLine,
|
||||||
@@ -284,68 +278,73 @@ export default function Canvas() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDragging) {
|
if (isDragging()) {
|
||||||
for (const el of bulkSelectedElements) {
|
const { x: mainElementFinalX, y: mainElementFinalY } =
|
||||||
const element = getElement(el);
|
coordinatesAfterSnappingToGrid({
|
||||||
const { type } = el;
|
x: pointer.spaces.diagram.x - dragging.grabOffset.x,
|
||||||
if (element.locked) continue;
|
y: pointer.spaces.diagram.y - dragging.grabOffset.y,
|
||||||
const { x, y } = element;
|
});
|
||||||
|
|
||||||
if (type === ObjectType.TABLE) {
|
const { currentCoords } = bulkSelectedElements.find(
|
||||||
updateTable(el.id, {
|
(el) => el.id === dragging.id && el.type === dragging.type,
|
||||||
x: x + deltaX,
|
);
|
||||||
y: y + deltaY,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (type === ObjectType.AREA) {
|
|
||||||
updateArea(el.id, {
|
|
||||||
x: x + deltaX,
|
|
||||||
y: y + deltaY,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (type === ObjectType.NOTE) {
|
|
||||||
updateNote(el.id, {
|
|
||||||
x: x + deltaX,
|
|
||||||
y: y + deltaY,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setDragging((prev) => ({
|
const deltaX = mainElementFinalX - currentCoords.x;
|
||||||
...prev,
|
const deltaY = mainElementFinalY - currentCoords.y;
|
||||||
prevX: finalX,
|
|
||||||
prevY: finalY,
|
const newBulkSelectedElements = [];
|
||||||
}));
|
bulkSelectedElements.forEach((el) => {
|
||||||
|
const elementFinalCoords = {
|
||||||
|
x: el.currentCoords.x + deltaX,
|
||||||
|
y: el.currentCoords.y + deltaY,
|
||||||
|
};
|
||||||
|
if (el.type === ObjectType.TABLE) {
|
||||||
|
updateTable(el.id, { ...elementFinalCoords });
|
||||||
|
}
|
||||||
|
if (el.type === ObjectType.AREA) {
|
||||||
|
updateArea(el.id, { ...elementFinalCoords });
|
||||||
|
}
|
||||||
|
if (el.type === ObjectType.NOTE) {
|
||||||
|
updateNote(el.id, { ...elementFinalCoords });
|
||||||
|
}
|
||||||
|
newBulkSelectedElements.push({
|
||||||
|
...el,
|
||||||
|
currentCoords: elementFinalCoords,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setBulkSelectedElements(newBulkSelectedElements);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (areaResize.id !== -1) {
|
if (areaResize.id !== -1) {
|
||||||
if (areaResize.dir === "none") return;
|
if (areaResize.dir === "none") return;
|
||||||
let newDims = { ...initCoords };
|
let newDims = { ...areaInitDimensions };
|
||||||
delete newDims.pointerX;
|
|
||||||
delete newDims.pointerY;
|
|
||||||
setPanning((old) => ({ ...old, isPanning: false }));
|
setPanning((old) => ({ ...old, isPanning: false }));
|
||||||
|
const { x, y } = coordinatesAfterSnappingToGrid(pointer.spaces.diagram);
|
||||||
|
|
||||||
switch (areaResize.dir) {
|
switch (areaResize.dir) {
|
||||||
case "br":
|
case "br":
|
||||||
newDims.width = finalX - initCoords.x;
|
newDims.width = x - areaInitDimensions.x;
|
||||||
newDims.height = finalY - initCoords.y;
|
newDims.height = y - areaInitDimensions.y;
|
||||||
break;
|
break;
|
||||||
case "tl":
|
case "tl":
|
||||||
newDims.x = finalX;
|
newDims.x = x;
|
||||||
newDims.y = finalY;
|
newDims.y = y;
|
||||||
newDims.width = initCoords.width - (finalX - initCoords.x);
|
newDims.width = areaInitDimensions.width - (x - areaInitDimensions.x);
|
||||||
newDims.height = initCoords.height - (finalY - initCoords.y);
|
newDims.height =
|
||||||
|
areaInitDimensions.height - (y - areaInitDimensions.y);
|
||||||
break;
|
break;
|
||||||
case "tr":
|
case "tr":
|
||||||
newDims.y = finalY;
|
newDims.y = y;
|
||||||
newDims.width = finalX - initCoords.x;
|
newDims.width = x - areaInitDimensions.x;
|
||||||
newDims.height = initCoords.height - (finalY - initCoords.y);
|
newDims.height =
|
||||||
|
areaInitDimensions.height - (y - areaInitDimensions.y);
|
||||||
break;
|
break;
|
||||||
case "bl":
|
case "bl":
|
||||||
newDims.x = finalX;
|
newDims.x = x;
|
||||||
newDims.width = initCoords.width - (finalX - initCoords.x);
|
newDims.width = areaInitDimensions.width - (x - areaInitDimensions.x);
|
||||||
newDims.height = finalY - initCoords.y;
|
newDims.height = y - areaInitDimensions.y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,8 +355,8 @@ export default function Canvas() {
|
|||||||
if (bulkSelectRectPts.show) {
|
if (bulkSelectRectPts.show) {
|
||||||
setBulkSelectRectPts((prev) => ({
|
setBulkSelectRectPts((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
x2: finalX,
|
x2: pointer.spaces.diagram.x,
|
||||||
y2: finalY,
|
y2: pointer.spaces.diagram.y,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -400,27 +399,25 @@ export default function Canvas() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const coordsDidUpdate = () => {
|
const isDragging = () => {
|
||||||
const element = { id: dragging.id, type: dragging.element };
|
return dragging.type !== ObjectType.NONE && dragging.id !== -1;
|
||||||
const elementData = getElement(element);
|
};
|
||||||
const updated = !(
|
|
||||||
dragging.prevX === elementData.x && dragging.prevY === elementData.y
|
|
||||||
);
|
|
||||||
|
|
||||||
|
const didDrag = () => {
|
||||||
|
if (!isDragging()) return false;
|
||||||
|
// checking any element is sufficient
|
||||||
|
const { currentCoords, initialCoords } = bulkSelectedElements[0];
|
||||||
return (
|
return (
|
||||||
updated ||
|
currentCoords.x !== initialCoords.x || currentCoords.y !== initialCoords.y
|
||||||
dragging.initialPositions.some(
|
|
||||||
(el) => !(el.undo.x === elementData.x && el.undo.y === elementData.y),
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const didResize = (id) => {
|
const didResize = (id) => {
|
||||||
return !(
|
return !(
|
||||||
areas[id].x === initCoords.x &&
|
areas[id].x === areaInitDimensions.x &&
|
||||||
areas[id].y === initCoords.y &&
|
areas[id].y === areaInitDimensions.y &&
|
||||||
areas[id].width === initCoords.width &&
|
areas[id].width === areaInitDimensions.width &&
|
||||||
areas[id].height === initCoords.height
|
areas[id].height === areaInitDimensions.height
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -438,24 +435,29 @@ export default function Canvas() {
|
|||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
const coordinatesDidUpdate = coordsDidUpdate();
|
if (didDrag()) {
|
||||||
|
|
||||||
if (coordinatesDidUpdate) {
|
|
||||||
setUndoStack((prev) => [
|
setUndoStack((prev) => [
|
||||||
...prev,
|
...prev,
|
||||||
{
|
{
|
||||||
action: Action.MOVE,
|
action: Action.MOVE,
|
||||||
bulk: true,
|
bulk: true,
|
||||||
message: t("bulk_update"),
|
message: t("bulk_update"),
|
||||||
elements: dragging.initialPositions.map((element) => {
|
elements: bulkSelectedElements.map((el) => ({
|
||||||
const { x, y } = getElement(element);
|
id: el.id,
|
||||||
return { ...element, redo: { x, y } };
|
type: el.type,
|
||||||
}),
|
undo: el.initialCoords,
|
||||||
|
redo: el.currentCoords,
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
setRedoStack([]);
|
setRedoStack([]);
|
||||||
|
setBulkSelectedElements((prev) =>
|
||||||
|
prev.map((el) => ({
|
||||||
|
...el,
|
||||||
|
initialCoords: { ...el.currentCoords },
|
||||||
|
})),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
setDragging(notDragging);
|
|
||||||
|
|
||||||
if (bulkSelectRectPts.show) {
|
if (bulkSelectRectPts.show) {
|
||||||
setBulkSelectRectPts((prev) => ({
|
setBulkSelectRectPts((prev) => ({
|
||||||
@@ -464,10 +466,11 @@ export default function Canvas() {
|
|||||||
y2: pointer.spaces.diagram.y,
|
y2: pointer.spaces.diagram.y,
|
||||||
show: false,
|
show: false,
|
||||||
}));
|
}));
|
||||||
if (!coordinatesDidUpdate) {
|
if (!isDragging()) {
|
||||||
collectSelectedElements();
|
collectSelectedElements();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setDragging(notDragging);
|
||||||
|
|
||||||
if (panning.isPanning && didPan()) {
|
if (panning.isPanning && didPan()) {
|
||||||
setSaveState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
@@ -487,10 +490,10 @@ export default function Canvas() {
|
|||||||
aid: areaResize.id,
|
aid: areaResize.id,
|
||||||
undo: {
|
undo: {
|
||||||
...areas[areaResize.id],
|
...areas[areaResize.id],
|
||||||
x: initCoords.x,
|
x: areaInitDimensions.x,
|
||||||
y: initCoords.y,
|
y: areaInitDimensions.y,
|
||||||
width: initCoords.width,
|
width: areaInitDimensions.width,
|
||||||
height: initCoords.height,
|
height: areaInitDimensions.height,
|
||||||
},
|
},
|
||||||
redo: areas[areaResize.id],
|
redo: areas[areaResize.id],
|
||||||
message: t("edit_area", {
|
message: t("edit_area", {
|
||||||
@@ -502,13 +505,11 @@ export default function Canvas() {
|
|||||||
setRedoStack([]);
|
setRedoStack([]);
|
||||||
}
|
}
|
||||||
setAreaResize({ id: -1, dir: "none" });
|
setAreaResize({ id: -1, dir: "none" });
|
||||||
setInitCoords({
|
setAreaInitDimensions({
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
pointerX: 0,
|
|
||||||
pointerY: 0,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -664,7 +665,7 @@ export default function Canvas() {
|
|||||||
handlePointerDownOnElement(e, a.id, ObjectType.AREA)
|
handlePointerDownOnElement(e, a.id, ObjectType.AREA)
|
||||||
}
|
}
|
||||||
setResize={setAreaResize}
|
setResize={setAreaResize}
|
||||||
setInitCoords={setInitCoords}
|
setInitDimensions={setAreaInitDimensions}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{relationships.map((e, i) => (
|
{relationships.map((e, i) => (
|
||||||
|
@@ -62,7 +62,6 @@ export default function TableInfo({ data }) {
|
|||||||
});
|
});
|
||||||
setRedoStack([]);
|
setRedoStack([]);
|
||||||
};
|
};
|
||||||
undefined;
|
|
||||||
|
|
||||||
const inheritedFieldNames =
|
const inheritedFieldNames =
|
||||||
Array.isArray(data.inherits) && data.inherits.length > 0
|
Array.isArray(data.inherits) && data.inherits.length > 0
|
||||||
|
Reference in New Issue
Block a user