mirror of
https://github.com/drawdb-io/drawdb.git
synced 2025-07-18 10:11:24 +00:00
Panning with middle click, persistent bulk selection (#498)
* panning with middle click, persistant bulk selection * remove unused variables
This commit is contained in:
@@ -5,8 +5,6 @@ import {
|
|||||||
Constraint,
|
Constraint,
|
||||||
darkBgTheme,
|
darkBgTheme,
|
||||||
ObjectType,
|
ObjectType,
|
||||||
tableFieldHeight,
|
|
||||||
tableHeaderHeight,
|
|
||||||
gridSize,
|
gridSize,
|
||||||
gridCircleRadius,
|
gridCircleRadius,
|
||||||
} from "../../data/constants";
|
} from "../../data/constants";
|
||||||
@@ -29,7 +27,7 @@ import {
|
|||||||
} from "../../hooks";
|
} from "../../hooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEventListener } from "usehooks-ts";
|
import { useEventListener } from "usehooks-ts";
|
||||||
import { areFieldsCompatible } from "../../utils/utils";
|
import { areFieldsCompatible, getTableHeight } from "../../utils/utils";
|
||||||
import { getRectFromEndpoints, isInsideRect } from "../../utils/rect";
|
import { getRectFromEndpoints, isInsideRect } from "../../utils/rect";
|
||||||
import { noteWidth, State } from "../../data/constants";
|
import { noteWidth, State } from "../../data/constants";
|
||||||
|
|
||||||
@@ -117,8 +115,7 @@ export default function Canvas() {
|
|||||||
x: table.x,
|
x: table.x,
|
||||||
y: table.y,
|
y: table.y,
|
||||||
width: settings.tableWidth,
|
width: settings.tableWidth,
|
||||||
height:
|
height: getTableHeight(table),
|
||||||
table.fields.length * tableFieldHeight + tableHeaderHeight + 7,
|
|
||||||
},
|
},
|
||||||
rect,
|
rect,
|
||||||
)
|
)
|
||||||
@@ -230,14 +227,7 @@ export default function Canvas() {
|
|||||||
prevCoords = { prevX: note.x, prevY: note.y };
|
prevCoords = { prevX: note.x, prevY: note.y };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locked) {
|
if (!locked) {
|
||||||
setPanning({
|
|
||||||
isPanning: true,
|
|
||||||
panStart: transform.pan,
|
|
||||||
cursorStart: pointer.spaces.screen,
|
|
||||||
});
|
|
||||||
pointer.setStyle("grabbing");
|
|
||||||
} else {
|
|
||||||
setDragging((prev) => ({
|
setDragging((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
id,
|
id,
|
||||||
@@ -274,6 +264,21 @@ export default function Canvas() {
|
|||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
|
if (panning.isPanning) {
|
||||||
|
setTransform((prev) => ({
|
||||||
|
...prev,
|
||||||
|
pan: {
|
||||||
|
x:
|
||||||
|
panning.panStart.x +
|
||||||
|
(panning.cursorStart.x - pointer.spaces.screen.x) / transform.zoom,
|
||||||
|
y:
|
||||||
|
panning.panStart.y +
|
||||||
|
(panning.cursorStart.y - pointer.spaces.screen.y) / transform.zoom,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isDragging =
|
const isDragging =
|
||||||
dragging.element !== ObjectType.NONE && dragging.id !== null;
|
dragging.element !== ObjectType.NONE && dragging.id !== null;
|
||||||
|
|
||||||
@@ -300,26 +305,38 @@ export default function Canvas() {
|
|||||||
} else if (
|
} else if (
|
||||||
dragging.element !== ObjectType.NONE &&
|
dragging.element !== ObjectType.NONE &&
|
||||||
dragging.id !== null &&
|
dragging.id !== null &&
|
||||||
bulkSelectedElements.length
|
bulkSelectedElements.length &&
|
||||||
|
bulkSelectedElements.some(
|
||||||
|
(element) =>
|
||||||
|
element.id === dragging.id && element.type === dragging.element,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
for (const element of bulkSelectedElements) {
|
for (const element of bulkSelectedElements) {
|
||||||
if (element.type === ObjectType.TABLE) {
|
if (element.type === ObjectType.TABLE) {
|
||||||
const { x, y } = tables.find((e) => e.id === element.id);
|
const table = tables.find((e) => e.id === element.id);
|
||||||
|
if (table.locked) continue;
|
||||||
|
const { x, y } = table;
|
||||||
updateTable(element.id, {
|
updateTable(element.id, {
|
||||||
x: x + deltaX,
|
x: x + deltaX,
|
||||||
y: y + deltaY,
|
y: y + deltaY,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (element.type === ObjectType.AREA) {
|
if (element.type === ObjectType.AREA) {
|
||||||
|
const area = areas[element.id];
|
||||||
|
if (area.locked) continue;
|
||||||
|
const { x, y } = area;
|
||||||
updateArea(element.id, {
|
updateArea(element.id, {
|
||||||
x: areas[element.id].x + deltaX,
|
x: x + deltaX,
|
||||||
y: areas[element.id].y + deltaY,
|
y: y + deltaY,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (element.type === ObjectType.NOTE) {
|
if (element.type === ObjectType.NOTE) {
|
||||||
|
const note = notes[element.id];
|
||||||
|
if (note.locked) continue;
|
||||||
|
const { x, y } = note;
|
||||||
updateNote(element.id, {
|
updateNote(element.id, {
|
||||||
x: notes[element.id].x + deltaX,
|
x: x + deltaX,
|
||||||
y: notes[element.id].y + deltaY,
|
y: y + deltaY,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,25 +346,6 @@ export default function Canvas() {
|
|||||||
prevX: finalX,
|
prevX: finalX,
|
||||||
prevY: finalY,
|
prevY: finalY,
|
||||||
}));
|
}));
|
||||||
} else if (
|
|
||||||
panning.isPanning &&
|
|
||||||
dragging.element === ObjectType.NONE &&
|
|
||||||
areaResize.id === -1
|
|
||||||
) {
|
|
||||||
if (!settings.panning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setTransform((prev) => ({
|
|
||||||
...prev,
|
|
||||||
pan: {
|
|
||||||
x:
|
|
||||||
panning.panStart.x +
|
|
||||||
(panning.cursorStart.x - pointer.spaces.screen.x) / transform.zoom,
|
|
||||||
y:
|
|
||||||
panning.panStart.y +
|
|
||||||
(panning.cursorStart.y - pointer.spaces.screen.y) / transform.zoom,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
} else if (dragging.element === ObjectType.TABLE && dragging.id !== null) {
|
} else if (dragging.element === ObjectType.TABLE && dragging.id !== null) {
|
||||||
const table = tables.find((t) => t.id === dragging.id);
|
const table = tables.find((t) => t.id === dragging.id);
|
||||||
if (table.locked) return;
|
if (table.locked) return;
|
||||||
@@ -430,7 +428,10 @@ export default function Canvas() {
|
|||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!settings.panning) {
|
const isMouseLeftButton = e.button === 0;
|
||||||
|
const isMouseMiddleButton = e.button === 1;
|
||||||
|
|
||||||
|
if (isMouseLeftButton) {
|
||||||
setBulkSelectRectPts({
|
setBulkSelectRectPts({
|
||||||
x1: pointer.spaces.diagram.x,
|
x1: pointer.spaces.diagram.x,
|
||||||
y1: pointer.spaces.diagram.y,
|
y1: pointer.spaces.diagram.y,
|
||||||
@@ -439,7 +440,7 @@ export default function Canvas() {
|
|||||||
show: true,
|
show: true,
|
||||||
});
|
});
|
||||||
pointer.setStyle("crosshair");
|
pointer.setStyle("crosshair");
|
||||||
} else {
|
} else if (isMouseMiddleButton) {
|
||||||
setPanning({
|
setPanning({
|
||||||
isPanning: true,
|
isPanning: true,
|
||||||
panStart: transform.pan,
|
panStart: transform.pan,
|
||||||
@@ -488,6 +489,8 @@ export default function Canvas() {
|
|||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
|
let bulkMoved = false;
|
||||||
|
|
||||||
if (coordsDidUpdate({ id: dragging.id, type: dragging.element })) {
|
if (coordsDidUpdate({ id: dragging.id, type: dragging.element })) {
|
||||||
if (bulkSelectedElements.length) {
|
if (bulkSelectedElements.length) {
|
||||||
setUndoStack((prev) => [
|
setUndoStack((prev) => [
|
||||||
@@ -505,12 +508,7 @@ export default function Canvas() {
|
|||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
setSelectedElement((prev) => ({
|
bulkMoved = true;
|
||||||
...prev,
|
|
||||||
element: ObjectType.NONE,
|
|
||||||
id: -1,
|
|
||||||
open: false,
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
const element = getElement({
|
const element = getElement({
|
||||||
id: dragging.id,
|
id: dragging.id,
|
||||||
@@ -553,18 +551,13 @@ export default function Canvas() {
|
|||||||
y2: pointer.spaces.diagram.y,
|
y2: pointer.spaces.diagram.y,
|
||||||
show: false,
|
show: false,
|
||||||
}));
|
}));
|
||||||
collectSelectedElements();
|
if (!bulkMoved) {
|
||||||
|
collectSelectedElements();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panning.isPanning && didPan()) {
|
if (panning.isPanning && didPan()) {
|
||||||
setSaveState(State.SAVING);
|
setSaveState(State.SAVING);
|
||||||
setSelectedElement((prev) => ({
|
|
||||||
...prev,
|
|
||||||
element: ObjectType.NONE,
|
|
||||||
id: -1,
|
|
||||||
open: false,
|
|
||||||
}));
|
|
||||||
setBulkSelectedElements([]);
|
|
||||||
}
|
}
|
||||||
setPanning((old) => ({ ...old, isPanning: false }));
|
setPanning((old) => ({ ...old, isPanning: false }));
|
||||||
pointer.setStyle("default");
|
pointer.setStyle("default");
|
||||||
|
@@ -1396,15 +1396,6 @@ export default function ControlPanel({
|
|||||||
function: () =>
|
function: () =>
|
||||||
setSettings((prev) => ({ ...prev, autosave: !prev.autosave })),
|
setSettings((prev) => ({ ...prev, autosave: !prev.autosave })),
|
||||||
},
|
},
|
||||||
panning: {
|
|
||||||
state: settings.panning ? (
|
|
||||||
<i className="bi bi-toggle-on" />
|
|
||||||
) : (
|
|
||||||
<i className="bi bi-toggle-off" />
|
|
||||||
),
|
|
||||||
function: () =>
|
|
||||||
setSettings((prev) => ({ ...prev, panning: !prev.panning })),
|
|
||||||
},
|
|
||||||
table_width: {
|
table_width: {
|
||||||
function: () => setModal(MODAL.TABLE_WIDTH),
|
function: () => setModal(MODAL.TABLE_WIDTH),
|
||||||
},
|
},
|
||||||
@@ -1603,23 +1594,6 @@ export default function ControlPanel({
|
|||||||
<i className="fa-solid fa-magnifying-glass-minus" />
|
<i className="fa-solid fa-magnifying-glass-minus" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
|
||||||
content={settings.panning ? t("multiselect") : t("panning")}
|
|
||||||
position="bottom"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="py-1 px-2 hover-2 rounded-sm text-lg w-10"
|
|
||||||
onClick={() =>
|
|
||||||
setSettings((prev) => ({ ...prev, panning: !prev.panning }))
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{settings.panning ? (
|
|
||||||
<i className="fa-solid fa-expand" />
|
|
||||||
) : (
|
|
||||||
<i className="fa-regular fa-hand"></i>
|
|
||||||
)}
|
|
||||||
</button>
|
|
||||||
</Tooltip>
|
|
||||||
<Divider layout="vertical" margin="8px" />
|
<Divider layout="vertical" margin="8px" />
|
||||||
<Tooltip content={t("undo")} position="bottom">
|
<Tooltip content={t("undo")} position="bottom">
|
||||||
<button
|
<button
|
||||||
|
@@ -9,7 +9,6 @@ const defaultSettings = {
|
|||||||
showDataTypes: true,
|
showDataTypes: true,
|
||||||
mode: "light",
|
mode: "light",
|
||||||
autosave: true,
|
autosave: true,
|
||||||
panning: true,
|
|
||||||
showCardinality: true,
|
showCardinality: true,
|
||||||
showRelationshipLabels: true,
|
showRelationshipLabels: true,
|
||||||
tableWidth: tableWidth,
|
tableWidth: tableWidth,
|
||||||
|
Reference in New Issue
Block a user