@mhamz.01/easyflow-whiteboard 2.19.0 → 2.20.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.
@@ -20,6 +20,6 @@ interface UseMouseHandlersProps {
20
20
  handleEraserUp: () => boolean;
21
21
  };
22
22
  }
23
- export declare const useMouseHandlers: ({ fabricCanvas, activeTool, toolOptions, drawingHandlers, eraserHandlers, }: UseMouseHandlersProps) => void;
23
+ export declare const useMouseHandlers: ({ fabricCanvas, activeTool, drawingHandlers, eraserHandlers, }: UseMouseHandlersProps) => void;
24
24
  export {};
25
25
  //# sourceMappingURL=useMouseHandlers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMouseHandlers.d.ts","sourceRoot":"","sources":["../../src/hooks/useMouseHandlers.ts"],"names":[],"mappings":"AACA,OAAc,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,qBAAqB;IAC7B,YAAY,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,GAAG,CAAC;IACjB,eAAe,EAAE;QACf,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;QACpC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;QACpC,aAAa,EAAE,MAAM,IAAI,CAAC;KAC3B,CAAC;IACF,cAAc,EAAE;QACd,eAAe,EAAE,MAAM,IAAI,CAAC;QAC5B,cAAc,EAAE,MAAM,IAAI,CAAC;QAC3B,gBAAgB,EAAE,MAAM,OAAO,CAAC;QAChC,gBAAgB,EAAE,CAAC,OAAO,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,IAAI,CAAC;QAC9D,cAAc,EAAE,MAAM,OAAO,CAAC;KAC/B,CAAC;CACH;AAED,eAAO,MAAM,gBAAgB,GAAI,6EAM9B,qBAAqB,SA8CvB,CAAC"}
1
+ {"version":3,"file":"useMouseHandlers.d.ts","sourceRoot":"","sources":["../../src/hooks/useMouseHandlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,UAAU,qBAAqB;IAC7B,YAAY,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,UAAU,EAAI,MAAM,CAAC;IACrB,WAAW,EAAG,GAAG,CAAC;IAClB,eAAe,EAAE;QACf,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;QACpC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;QACpC,aAAa,EAAI,MAAM,IAAI,CAAC;KAC7B,CAAC;IACF,cAAc,EAAE;QACd,eAAe,EAAG,MAAM,IAAI,CAAC;QAC7B,cAAc,EAAI,MAAM,IAAI,CAAC;QAC7B,gBAAgB,EAAE,MAAM,OAAO,CAAC;QAChC,gBAAgB,EAAE,CAAC,OAAO,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,IAAI,CAAC;QAC9D,cAAc,EAAI,MAAM,OAAO,CAAC;KACjC,CAAC;CACH;AAED,eAAO,MAAM,gBAAgB,GAAI,gEAK9B,qBAAqB,SAqFvB,CAAC"}
@@ -1,44 +1,81 @@
1
- import { useEffect } from "react";
2
- export const useMouseHandlers = ({ fabricCanvas, activeTool, toolOptions, drawingHandlers, eraserHandlers, }) => {
1
+ import { useEffect, useRef } from "react";
2
+ export const useMouseHandlers = ({ fabricCanvas, activeTool, drawingHandlers, eraserHandlers, }) => {
3
+ // ── PERF FIX 1: All props in refs — effect registers ONCE ────────────────
4
+ // Old deps: [activeTool, toolOptions, drawingHandlers, eraserHandlers]
5
+ // drawingHandlers and eraserHandlers are plain objects recreated every render
6
+ // → all 5 canvas listeners re-registered on every single render.
7
+ // With refs, the effect is stable for the full lifetime of the canvas.
8
+ const activeToolRef = useRef(activeTool);
9
+ const drawingRef = useRef(drawingHandlers);
10
+ const eraserRef = useRef(eraserHandlers);
11
+ // These update every render synchronously — handlers always see latest values
12
+ activeToolRef.current = activeTool;
13
+ drawingRef.current = drawingHandlers;
14
+ eraserRef.current = eraserHandlers;
3
15
  useEffect(() => {
4
16
  const canvas = fabricCanvas.current;
5
17
  if (!canvas)
6
18
  return;
19
+ // ── PERF FIX 2: rAF throttle on mouse:move ───────────────────────────
20
+ // mouse:move fires at raw pointer rate — up to 200-1000 events/sec on
21
+ // high-DPI displays. Without throttling, getScenePoint + handler logic
22
+ // runs far more often than the screen can paint (60-120fps).
23
+ let rafId = null;
24
+ let lastMoveOpt = null;
7
25
  const handleMouseDown = (opt) => {
8
- // Eraser
9
- if (eraserHandlers.handleEraserDown())
26
+ if (eraserRef.current.handleEraserDown())
10
27
  return;
11
- // Drawing
12
- drawingHandlers.handleMouseDown(opt);
28
+ drawingRef.current.handleMouseDown(opt);
13
29
  };
14
30
  const handleMouseMove = (opt) => {
15
- const pointer = canvas.getScenePoint(opt.e);
16
- // Eraser
17
- if (activeTool === "eraser") {
18
- eraserHandlers.handleEraserMove(pointer);
19
- return;
20
- }
21
- // Drawing
22
- drawingHandlers.handleMouseMove(opt);
31
+ // Store latest event — rAF will consume it
32
+ lastMoveOpt = opt;
33
+ if (rafId !== null)
34
+ return; // frame already queued
35
+ rafId = requestAnimationFrame(() => {
36
+ rafId = null;
37
+ if (!lastMoveOpt)
38
+ return;
39
+ const currentOpt = lastMoveOpt;
40
+ lastMoveOpt = null;
41
+ const tool = activeToolRef.current;
42
+ if (tool === "eraser") {
43
+ // ── PERF FIX 3: Only call getScenePoint for tools that need it ────
44
+ const canvas = fabricCanvas.current;
45
+ if (!canvas)
46
+ return;
47
+ const pointer = canvas.getScenePoint(currentOpt.e);
48
+ eraserRef.current.handleEraserMove(pointer);
49
+ return;
50
+ }
51
+ drawingRef.current.handleMouseMove(currentOpt);
52
+ });
23
53
  };
24
54
  const handleMouseUp = () => {
25
- // Eraser
26
- if (eraserHandlers.handleEraserUp())
55
+ // Cancel any pending move frame on mouse up
56
+ if (rafId !== null) {
57
+ cancelAnimationFrame(rafId);
58
+ rafId = null;
59
+ lastMoveOpt = null;
60
+ }
61
+ if (eraserRef.current.handleEraserUp())
27
62
  return;
28
- // Drawing
29
- drawingHandlers.handleMouseUp();
63
+ drawingRef.current.handleMouseUp();
30
64
  };
31
- canvas.on("mouse:over", eraserHandlers.handleMouseOver);
32
- canvas.on("mouse:out", eraserHandlers.handleMouseOut);
65
+ canvas.on("mouse:over", () => eraserRef.current.handleMouseOver());
66
+ canvas.on("mouse:out", () => eraserRef.current.handleMouseOut());
33
67
  canvas.on("mouse:down", handleMouseDown);
34
68
  canvas.on("mouse:move", handleMouseMove);
35
69
  canvas.on("mouse:up", handleMouseUp);
36
70
  return () => {
37
- canvas.off("mouse:over", eraserHandlers.handleMouseOver);
38
- canvas.off("mouse:out", eraserHandlers.handleMouseOut);
71
+ canvas.off("mouse:over", () => eraserRef.current.handleMouseOver());
72
+ canvas.off("mouse:out", () => eraserRef.current.handleMouseOut());
39
73
  canvas.off("mouse:down", handleMouseDown);
40
74
  canvas.off("mouse:move", handleMouseMove);
41
75
  canvas.off("mouse:up", handleMouseUp);
76
+ if (rafId !== null)
77
+ cancelAnimationFrame(rafId);
42
78
  };
43
- }, [activeTool, toolOptions, fabricCanvas, drawingHandlers, eraserHandlers]);
79
+ // ── PERF FIX 4: Stable — everything read via refs ─────────────────────────
80
+ }, [fabricCanvas]);
44
81
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "description": "A feature-rich whiteboard component built with Fabric.js and React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",