@mhamz.01/easyflow-whiteboard 2.39.0 → 2.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePan.d.ts","sourceRoot":"","sources":["../../src/hooks/usePan.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usePan.d.ts","sourceRoot":"","sources":["../../src/hooks/usePan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,WAAW;IACnB,YAAY,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,iBAAiB,EAAE,CAAC,QAAQ,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACjE;AAED,eAAO,MAAM,MAAM,GAAI,8DAKpB,WAAW,SA8Gb,CAAC"}
|
package/dist/hooks/usePan.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
2
|
export const usePan = ({ fabricCanvas, activeTool, handleZoom, setCanvasViewport, }) => {
|
|
3
|
+
// Refs so the effect registers ONCE but always reads latest values.
|
|
4
|
+
// Avoids tearing down/reattaching mouse:down/move/up on every tool change.
|
|
5
|
+
const activeToolRef = useRef(activeTool);
|
|
6
|
+
const handleZoomRef = useRef(handleZoom);
|
|
7
|
+
const setCanvasViewportRef = useRef(setCanvasViewport);
|
|
8
|
+
// Assigned synchronously in render — always fresh before any event fires
|
|
9
|
+
activeToolRef.current = activeTool;
|
|
10
|
+
handleZoomRef.current = handleZoom;
|
|
11
|
+
setCanvasViewportRef.current = setCanvasViewport;
|
|
3
12
|
useEffect(() => {
|
|
4
13
|
const canvas = fabricCanvas.current;
|
|
5
14
|
if (!canvas)
|
|
@@ -11,16 +20,14 @@ export const usePan = ({ fabricCanvas, activeTool, handleZoom, setCanvasViewport
|
|
|
11
20
|
let lastY = 0;
|
|
12
21
|
let lastTouchDistance = 0;
|
|
13
22
|
const onDown = (opt) => {
|
|
14
|
-
if (
|
|
23
|
+
if (activeToolRef.current !== "pan")
|
|
15
24
|
return;
|
|
16
25
|
const e = opt.e;
|
|
17
|
-
// Pinch initialization
|
|
18
26
|
if (e.touches && e.touches.length === 2) {
|
|
19
27
|
isPanning = false;
|
|
20
28
|
lastTouchDistance = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
|
|
21
29
|
return;
|
|
22
30
|
}
|
|
23
|
-
// Pan initialization
|
|
24
31
|
const pointer = e.touches ? e.touches[0] : e;
|
|
25
32
|
isPanning = true;
|
|
26
33
|
lastX = pointer.clientX;
|
|
@@ -28,45 +35,50 @@ export const usePan = ({ fabricCanvas, activeTool, handleZoom, setCanvasViewport
|
|
|
28
35
|
canvas.setCursor("grabbing");
|
|
29
36
|
};
|
|
30
37
|
const onMove = (opt) => {
|
|
31
|
-
if (
|
|
38
|
+
if (activeToolRef.current !== "pan")
|
|
32
39
|
return;
|
|
33
40
|
const e = opt.e;
|
|
34
|
-
// Handle pinch zoom (two fingers)
|
|
35
41
|
if (e.touches && e.touches.length === 2) {
|
|
36
42
|
const currentDistance = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
|
|
37
43
|
if (lastTouchDistance > 0) {
|
|
38
44
|
const zoom = canvas.getZoom();
|
|
39
45
|
const delta = (currentDistance - lastTouchDistance) * 0.01;
|
|
40
|
-
const newZoom = zoom + delta;
|
|
41
46
|
const midX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
|
|
42
47
|
const midY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
|
|
43
48
|
const rect = canvasEl.getBoundingClientRect();
|
|
44
|
-
|
|
49
|
+
handleZoomRef.current(zoom + delta, {
|
|
50
|
+
x: midX - rect.left,
|
|
51
|
+
y: midY - rect.top,
|
|
52
|
+
});
|
|
45
53
|
}
|
|
46
54
|
lastTouchDistance = currentDistance;
|
|
47
55
|
return;
|
|
48
56
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
if (!isPanning)
|
|
58
|
+
return; // early exit — avoids any work on non-pan moves
|
|
59
|
+
const pointer = e.touches ? e.touches[0] : e;
|
|
60
|
+
const vpt = canvas.viewportTransform;
|
|
61
|
+
if (!vpt)
|
|
62
|
+
return;
|
|
63
|
+
// VPT mutation is synchronous — NO rAF here intentionally.
|
|
64
|
+
// rAF delays the mutation by one frame which makes pan feel like 20fps.
|
|
65
|
+
vpt[4] += pointer.clientX - lastX;
|
|
66
|
+
vpt[5] += pointer.clientY - lastY;
|
|
67
|
+
canvas.requestRenderAll();
|
|
68
|
+
lastX = pointer.clientX;
|
|
69
|
+
lastY = pointer.clientY;
|
|
61
70
|
};
|
|
62
71
|
const onUp = () => {
|
|
72
|
+
if (!isPanning && lastTouchDistance === 0)
|
|
73
|
+
return; // nothing to clean up
|
|
63
74
|
const vpt = canvas.viewportTransform;
|
|
64
75
|
if (vpt) {
|
|
65
|
-
|
|
76
|
+
// React state update only on mouse:up — not per-frame during pan
|
|
77
|
+
setCanvasViewportRef.current({ x: vpt[4], y: vpt[5] });
|
|
66
78
|
}
|
|
67
79
|
isPanning = false;
|
|
68
80
|
lastTouchDistance = 0;
|
|
69
|
-
canvas.setCursor(
|
|
81
|
+
canvas.setCursor(activeToolRef.current === "pan" ? "grab" : "default");
|
|
70
82
|
};
|
|
71
83
|
canvas.on("mouse:down", onDown);
|
|
72
84
|
canvas.on("mouse:move", onMove);
|
|
@@ -76,5 +88,5 @@ export const usePan = ({ fabricCanvas, activeTool, handleZoom, setCanvasViewport
|
|
|
76
88
|
canvas.off("mouse:move", onMove);
|
|
77
89
|
canvas.off("mouse:up", onUp);
|
|
78
90
|
};
|
|
79
|
-
}, [
|
|
91
|
+
}, [fabricCanvas]); // registered once per canvas mount
|
|
80
92
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePersistance.d.ts","sourceRoot":"","sources":["../../src/hooks/usePersistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,mBAAmB;IAC3B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACzC,kBAAkB,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;CAC9C;AAKD,eAAO,MAAM,cAAc,GAAI,sFAO5B,mBAAmB,
|
|
1
|
+
{"version":3,"file":"usePersistance.d.ts","sourceRoot":"","sources":["../../src/hooks/usePersistance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,mBAAmB;IAC3B,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACzC,kBAAkB,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;CAC9C;AAKD,eAAO,MAAM,cAAc,GAAI,sFAO5B,mBAAmB,SAkFrB,CAAC"}
|
|
@@ -12,6 +12,7 @@ export const usePersistence = ({ fabricCanvas, tasks, documents, pushHistory, is
|
|
|
12
12
|
const json = JSON.stringify(canvas.toJSON());
|
|
13
13
|
localStorage.setItem(CANVAS_KEY, json);
|
|
14
14
|
pushHistory(json);
|
|
15
|
+
console.log("💾 Canvas content saving to storage is: " + json);
|
|
15
16
|
console.log("💾 Canvas saved via requestIdleCallback");
|
|
16
17
|
}
|
|
17
18
|
catch (err) {
|
|
@@ -34,6 +35,7 @@ export const usePersistence = ({ fabricCanvas, tasks, documents, pushHistory, is
|
|
|
34
35
|
try {
|
|
35
36
|
const nodesData = { tasks, documents };
|
|
36
37
|
localStorage.setItem(NODES_KEY, JSON.stringify(nodesData));
|
|
38
|
+
console.log("💾 Nodes saving to storage is: " + JSON.stringify(nodesData));
|
|
37
39
|
console.log("💾 Custom nodes saved");
|
|
38
40
|
}
|
|
39
41
|
catch (err) {
|