diff --git a/package-lock.json b/package-lock.json index 381cecb..2679c49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 7c72169..e222e8d 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/canvas.jsx b/src/components/canvas.jsx index e9f482b..3735cf4 100644 --- a/src/components/canvas.jsx +++ b/src/components/canvas.jsx @@ -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, diff --git a/src/components/control_panel.jsx b/src/components/control_panel.jsx index 56d96c6..738e7ec 100644 --- a/src/components/control_panel.jsx +++ b/src/components/control_panel.jsx @@ -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]); } }; diff --git a/src/components/note.jsx b/src/components/note.jsx index b63b8ee..785986c 100644 --- a/src/components/note.jsx +++ b/src/components/note.jsx @@ -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 (
- +
diff --git a/src/components/table_overview.jsx b/src/components/table_overview.jsx index 67b8350..98d1e3c 100644 --- a/src/components/table_overview.jsx +++ b/src/components/table_overview.jsx @@ -102,13 +102,7 @@ export default function TableOverview(props) { /> - diff --git a/src/data/data.js b/src/data/data.js index d0a1726..5fba11a 100644 --- a/src/data/data.js +++ b/src/data/data.js @@ -80,6 +80,8 @@ const Action = { ADD: 0, MOVE: 1, DELETE: 2, + EDIT: 3, + PAN: 4, }; export { diff --git a/src/pages/editor.jsx b/src/pages/editor.jsx index 9bd063e..7a5a236 100644 --- a/src/pages/editor.jsx +++ b/src/pages/editor.jsx @@ -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 }} >