Skip to content

Commit 354ea47

Browse files
committed
fix: validate transform data before storage
During testing I accidentally managed to submit `NaN` as a pan coordinate. This had the unfortunate side effect of bricking the editor. Given the serverity of an accidental `NaN` and that `NaN`s are not impossible considering the amount of math involved in mouse move operations, this commit introduces a simple validation step. The new validation step should additionally be able to unstuck anyone who have happened into this state by accident already.
1 parent cdecf7c commit 354ea47

File tree

2 files changed

+36
-7
lines changed

2 files changed

+36
-7
lines changed

src/components/EditorCanvas/Canvas.jsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ export default function Canvas() {
139139
const rect = canvas.current.getBoundingClientRect();
140140
setLinkingLine({
141141
...linkingLine,
142-
endX: (e.clientX - rect.left - transform.pan?.x) / transform.zoom,
143-
endY: (e.clientY - rect.top - transform.pan?.y) / transform.zoom,
142+
endX: (e.clientX - rect.left - transform.pan.x) / transform.zoom,
143+
endY: (e.clientY - rect.top - transform.pan.y) / transform.zoom,
144144
});
145145
} else if (
146146
panning.isPanning &&
@@ -154,7 +154,7 @@ export default function Canvas() {
154154
const dy = e.clientY - panning.dy;
155155
setTransform((prev) => ({
156156
...prev,
157-
pan: { x: prev.pan?.x + dx, y: prev.pan?.y + dy },
157+
pan: { x: prev.pan.x + dx, y: prev.pan.y + dy },
158158
}));
159159
setPanning((prev) => ({ ...prev, dx: e.clientX, dy: e.clientY }));
160160
} else if (dragging.element === ObjectType.TABLE && dragging.id >= 0) {
@@ -258,7 +258,7 @@ export default function Canvas() {
258258
};
259259

260260
const didPan = () =>
261-
!(transform.pan?.x === panning.x && transform.pan?.y === panning.y);
261+
!(transform.pan.x === panning.x && transform.pan.y === panning.y);
262262

263263
const getMovedElementDetails = () => {
264264
switch (dragging.element) {
@@ -477,7 +477,7 @@ export default function Canvas() {
477477
)}
478478
<g
479479
style={{
480-
transform: `translate(${transform.pan?.x}px, ${transform.pan?.y}px) scale(${transform.zoom})`,
480+
transform: `translate(${transform.pan.x}px, ${transform.pan.y}px) scale(${transform.zoom})`,
481481
transformOrigin: "top left",
482482
}}
483483
id="diagram"

src/context/TransformContext.jsx

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,42 @@
1-
import { createContext, useState } from "react";
1+
import { createContext, useCallback, useState } from "react";
22

33
export const TransformContext = createContext(null);
44

55
export default function TransformContextProvider({ children }) {
6-
const [transform, setTransform] = useState({
6+
const [transform, setTransformInternal] = useState({
77
zoom: 1,
88
pan: { x: 0, y: 0 },
99
});
1010

11+
/**
12+
* @type {typeof setTransformInternal}
13+
*/
14+
const setTransform = useCallback(
15+
(actionOrValue) => {
16+
const findFirstNumber = (...values) =>
17+
values.find((value) => typeof value === "number" && !isNaN(value));
18+
19+
setTransformInternal((prev) => {
20+
if (typeof actionOrValue === "function") {
21+
actionOrValue = actionOrValue(prev);
22+
}
23+
24+
return {
25+
zoom: clamp(
26+
findFirstNumber(actionOrValue.zoom, prev.zoom, 1),
27+
0.02,
28+
5,
29+
),
30+
pan: {
31+
x: findFirstNumber(actionOrValue.pan?.x, prev.pan?.x, 0),
32+
y: findFirstNumber(actionOrValue.pan?.y, prev.pan?.y, 0),
33+
},
34+
};
35+
});
36+
},
37+
[setTransformInternal],
38+
);
39+
1140
return (
1241
<TransformContext.Provider value={{ transform, setTransform }}>
1342
{children}

0 commit comments

Comments
 (0)