more undo redo for resize and panning
This commit is contained in:
parent
be66cf6e84
commit
16bc0edd36
1
package-lock.json
generated
1
package-lock.json
generated
@ -22,6 +22,7 @@
|
||||
"html-to-image": "^1.11.11",
|
||||
"jsonschema": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"node-sql-parser": "^4.7.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
|
@ -17,6 +17,7 @@
|
||||
"html-to-image": "^1.11.11",
|
||||
"jsonschema": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
"node-sql-parser": "^4.7.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
|
@ -46,9 +46,12 @@ export default function Canvas(props) {
|
||||
tableId: -1,
|
||||
field: -2,
|
||||
});
|
||||
const [panning, setPanning] = useState(false);
|
||||
const [panning, setPanning] = useState({ state: false, x: 0, y: 0 });
|
||||
const [panOffset, setPanOffset] = useState({ x: 0, y: 0 });
|
||||
const [areaResize, setAreaResize] = useState({ id: -1, dir: "none" });
|
||||
const [areaResize, setAreaResize] = useState({
|
||||
id: -1,
|
||||
dir: "none",
|
||||
});
|
||||
const [initCoords, setInitCoords] = useState({
|
||||
x: 0,
|
||||
y: 0,
|
||||
@ -114,7 +117,7 @@ export default function Canvas(props) {
|
||||
endY: (e.clientY - offsetY) / settings.zoom - settings.pan.y,
|
||||
});
|
||||
} else if (
|
||||
panning &&
|
||||
panning.state &&
|
||||
dragging.element === ObjectType.NONE &&
|
||||
areaResize.id === -1
|
||||
) {
|
||||
@ -150,7 +153,7 @@ export default function Canvas(props) {
|
||||
let newHeight = initCoords.height;
|
||||
const mouseX = e.clientX / settings.zoom;
|
||||
const mouseY = e.clientY / settings.zoom;
|
||||
setPanning(false);
|
||||
setPanning({ state: false, x: 0, y: 0 });
|
||||
if (areaResize.dir === "br") {
|
||||
newWidth = initCoords.width + (mouseX - initCoords.mouseX);
|
||||
newHeight = initCoords.height + (mouseY - initCoords.mouseY);
|
||||
@ -187,7 +190,7 @@ export default function Canvas(props) {
|
||||
};
|
||||
|
||||
const handleMouseDown = (e) => {
|
||||
setPanning(true);
|
||||
setPanning({ state: true, ...settings.pan });
|
||||
setPanOffset({ x: e.clientX, y: e.clientY });
|
||||
setCursor("grabbing");
|
||||
};
|
||||
@ -214,6 +217,18 @@ export default function Canvas(props) {
|
||||
}
|
||||
};
|
||||
|
||||
const didResize = (id) => {
|
||||
return !(
|
||||
areas[id].x === initCoords.x &&
|
||||
areas[id].y === initCoords.y &&
|
||||
areas[id].width === initCoords.width &&
|
||||
areas[id].height === initCoords.height
|
||||
);
|
||||
};
|
||||
|
||||
const didPan = () =>
|
||||
!(settings.pan.x === panning.x && settings.pan.y === panning.y);
|
||||
|
||||
const handleMouseUp = (e) => {
|
||||
if (coordsDidUpdate(dragging.element)) {
|
||||
setUndoStack((prev) => [
|
||||
@ -229,10 +244,44 @@ export default function Canvas(props) {
|
||||
setRedoStack([]);
|
||||
}
|
||||
setDragging({ element: ObjectType.NONE, id: -1, prevX: 0, prevY: 0 });
|
||||
setPanning(false);
|
||||
// NOTE: consider just saving the offset to sub and add in undo redo
|
||||
if (panning.state && didPan()) {
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.PAN,
|
||||
data: {
|
||||
undo: { x: panning.x, y: panning.y },
|
||||
redo: settings.pan,
|
||||
},
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
}
|
||||
setPanning({ state: false, x: 0, y: 0 });
|
||||
setCursor("default");
|
||||
if (linking) handleLinking();
|
||||
setLinking(false);
|
||||
if (areaResize.id !== -1 && didResize(areaResize.id)) {
|
||||
setUndoStack((prev) => [
|
||||
...prev,
|
||||
{
|
||||
action: Action.EDIT,
|
||||
element: ObjectType.AREA,
|
||||
data: {
|
||||
undo: {
|
||||
...areas[areaResize.id],
|
||||
x: initCoords.x,
|
||||
y: initCoords.y,
|
||||
width: initCoords.width,
|
||||
height: initCoords.height,
|
||||
},
|
||||
redo: areas[areaResize.id],
|
||||
},
|
||||
},
|
||||
]);
|
||||
setRedoStack([]);
|
||||
}
|
||||
setAreaResize({ id: -1, dir: "none" });
|
||||
setInitCoords({
|
||||
x: 0,
|
||||
|
@ -158,6 +158,25 @@ export default function ControlPanel(props) {
|
||||
addArea(false, a.data);
|
||||
}
|
||||
setRedoStack((prev) => [...prev, a]);
|
||||
} else if (a.action === Action.EDIT) {
|
||||
if (a.element === ObjectType.AREA) {
|
||||
setAreas((prev) =>
|
||||
prev.map((n) => {
|
||||
if (n.id === a.data.undo.id) {
|
||||
return a.data.undo;
|
||||
}
|
||||
return n;
|
||||
})
|
||||
);
|
||||
}
|
||||
setRedoStack((prev) => [...prev, a]);
|
||||
} else if (a.action === Action.PAN) {
|
||||
console.log(a)
|
||||
setSettings((prev) => ({
|
||||
...prev,
|
||||
pan: a.data.undo
|
||||
}));
|
||||
setRedoStack((prev) => [...prev, a]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -206,6 +225,24 @@ export default function ControlPanel(props) {
|
||||
deleteArea(a.data.id, false);
|
||||
}
|
||||
setUndoStack((prev) => [...prev, a]);
|
||||
} else if (a.action === Action.EDIT) {
|
||||
if (a.element === ObjectType.AREA) {
|
||||
setAreas((prev) =>
|
||||
prev.map((n) => {
|
||||
if (n.id === a.data.redo.id) {
|
||||
return a.data.redo;
|
||||
}
|
||||
return n;
|
||||
})
|
||||
);
|
||||
}
|
||||
setUndoStack((prev) => [...prev, a]);
|
||||
} else if (a.action === Action.PAN) {
|
||||
setSettings((prev) => ({
|
||||
...prev,
|
||||
pan: a.data.redo
|
||||
}));
|
||||
setUndoStack((prev) => [...prev, a]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -11,7 +11,7 @@ export default function Note(props) {
|
||||
const textarea = document.getElementById(`note_${props.data.id}`);
|
||||
textarea.style.height = "0";
|
||||
textarea.style.height = textarea.scrollHeight + "px";
|
||||
const newHeight = textarea.scrollHeight + 16 + 20 + 4;
|
||||
const newHeight = textarea.scrollHeight + 41;
|
||||
setNotes((prev) =>
|
||||
prev.map((n) => {
|
||||
if (n.id === props.data.id) {
|
||||
@ -25,17 +25,17 @@ export default function Note(props) {
|
||||
return (
|
||||
<g>
|
||||
<path
|
||||
d={`M${props.data.x + fold} ${props.data.y} L${
|
||||
d={`M${props.data.x + fold} ${props.data.y} L${props.data.x + w - r} ${
|
||||
props.data.y
|
||||
} A${r} ${r} 0 0 1 ${props.data.x + w} ${props.data.y + r} L${
|
||||
props.data.x + w
|
||||
} ${props.data.y + props.data.height - r} A${r} ${r} 0 0 1 ${
|
||||
props.data.x + w - r
|
||||
} ${props.data.y} A${r} ${r} 0 0 1 ${props.data.x + w} ${
|
||||
props.data.y + r
|
||||
} L${props.data.x + w} ${
|
||||
props.data.y + props.data.height - r
|
||||
} A${r} ${r} 0 0 1 ${props.data.x + w - r} ${
|
||||
} ${props.data.y + props.data.height} L${props.data.x + r} ${
|
||||
props.data.y + props.data.height
|
||||
} L${props.data.x + r} ${props.data.y + props.data.height} A${r} ${r} 0 0 1 ${
|
||||
props.data.x
|
||||
} ${props.data.y + props.data.height - r} L${props.data.x} ${props.data.y + fold}`}
|
||||
} A${r} ${r} 0 0 1 ${props.data.x} ${
|
||||
props.data.y + props.data.height - r
|
||||
} L${props.data.x} ${props.data.y + fold}`}
|
||||
fill={props.data.color}
|
||||
stroke="#665b25"
|
||||
strokeLinejoin="round"
|
||||
@ -62,13 +62,15 @@ export default function Note(props) {
|
||||
onMouseDown={props.onMouseDown}
|
||||
>
|
||||
<div className="text-gray-900 select-none w-full h-full cursor-move px-3 py-2">
|
||||
<label htmlFor={`note_${props.data.id}`} className="ms-5">{props.data.title}</label>
|
||||
<label htmlFor={`note_${props.data.id}`} className="ms-5">
|
||||
{props.data.title}
|
||||
</label>
|
||||
<textarea
|
||||
id={`note_${props.data.id}`}
|
||||
value={props.data.content}
|
||||
onInput={handleChange}
|
||||
className="mt-1 w-full resize-none outline-none overflow-y-hidden border-none select-none"
|
||||
style={{backgroundColor: props.data.color}}
|
||||
onChange={handleChange}
|
||||
className="w-full resize-none outline-none overflow-y-hidden border-none select-none"
|
||||
style={{ backgroundColor: props.data.color }}
|
||||
></textarea>
|
||||
</div>
|
||||
</foreignObject>
|
||||
|
@ -102,13 +102,7 @@ export default function TableOverview(props) {
|
||||
/>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Button
|
||||
icon={<IconPlus />}
|
||||
block
|
||||
onClick={() => {
|
||||
addTable(true);
|
||||
}}
|
||||
>
|
||||
<Button icon={<IconPlus />} block onClick={() => addTable(true)}>
|
||||
Add table
|
||||
</Button>
|
||||
</Col>
|
||||
|
@ -80,6 +80,8 @@ const Action = {
|
||||
ADD: 0,
|
||||
MOVE: 1,
|
||||
DELETE: 2,
|
||||
EDIT: 3,
|
||||
PAN: 4,
|
||||
};
|
||||
|
||||
export {
|
||||
|
@ -325,6 +325,20 @@ export default function Editor(props) {
|
||||
);
|
||||
};
|
||||
|
||||
const editNote = (id, values, addToHistory=true) => {
|
||||
setNotes((prev) =>
|
||||
prev.map((t) => {
|
||||
if (t.id === id) {
|
||||
return {
|
||||
...t,
|
||||
...values,
|
||||
};
|
||||
}
|
||||
return t;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Editor - drawDB";
|
||||
}, []);
|
||||
@ -348,7 +362,7 @@ export default function Editor(props) {
|
||||
value={{ areas, setAreas, moveArea, addArea, deleteArea }}
|
||||
>
|
||||
<NoteContext.Provider
|
||||
value={{ notes, setNotes, moveNote, addNote, deleteNote }}
|
||||
value={{ notes, setNotes, moveNote, addNote, deleteNote, editNote }}
|
||||
>
|
||||
<TabContext.Provider value={{ tab, setTab }}>
|
||||
<SettingsContext.Provider value={{ settings, setSettings }}>
|
||||
|
Loading…
Reference in New Issue
Block a user