@bwp-web/canvas 0.4.1 → 0.4.3
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.
- package/dist/Canvas/Canvas.d.ts +11 -1
- package/dist/Canvas/Canvas.d.ts.map +1 -1
- package/dist/background.d.ts +15 -3
- package/dist/background.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/shared.d.ts +3 -2
- package/dist/hooks/shared.d.ts.map +1 -1
- package/dist/hooks/useCanvasClick.d.ts +27 -0
- package/dist/hooks/useCanvasClick.d.ts.map +1 -0
- package/dist/hooks/useCanvasEvents.d.ts +35 -0
- package/dist/hooks/useCanvasEvents.d.ts.map +1 -0
- package/dist/hooks/useCanvasTooltip.d.ts +45 -0
- package/dist/hooks/useCanvasTooltip.d.ts.map +1 -0
- package/dist/hooks/useEditCanvas.d.ts +18 -1
- package/dist/hooks/useEditCanvas.d.ts.map +1 -1
- package/dist/hooks/useObjectOverlay.d.ts +49 -0
- package/dist/hooks/useObjectOverlay.d.ts.map +1 -0
- package/dist/hooks/useViewCanvas.d.ts +3 -1
- package/dist/hooks/useViewCanvas.d.ts.map +1 -1
- package/dist/index.cjs +471 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +399 -32
- package/dist/index.js.map +1 -1
- package/dist/interactions/dragToCreate.d.ts +2 -0
- package/dist/interactions/dragToCreate.d.ts.map +1 -1
- package/dist/interactions/drawToCreate.d.ts +7 -1
- package/dist/interactions/drawToCreate.d.ts.map +1 -1
- package/dist/serialization.d.ts +12 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/viewport.d.ts +12 -1
- package/dist/viewport.d.ts.map +1 -1
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,14 @@ export { useEditCanvas } from './hooks';
|
|
|
5
5
|
export type { UseEditCanvasOptions } from './hooks';
|
|
6
6
|
export { useViewCanvas } from './hooks';
|
|
7
7
|
export type { UseViewCanvasOptions, ViewObjectStyle } from './hooks';
|
|
8
|
+
export { useCanvasEvents } from './hooks';
|
|
9
|
+
export type { CanvasEventHandlers } from './hooks';
|
|
10
|
+
export { useCanvasTooltip } from './hooks';
|
|
11
|
+
export type { UseCanvasTooltipOptions, CanvasTooltipState } from './hooks';
|
|
12
|
+
export { useCanvasClick } from './hooks';
|
|
13
|
+
export type { UseCanvasClickOptions } from './hooks';
|
|
14
|
+
export { useObjectOverlay } from './hooks';
|
|
15
|
+
export type { UseObjectOverlayOptions } from './hooks';
|
|
8
16
|
export type { Point2D, ShapeStyleOptions, SnappingOptions, InteractionModeOptions, SnappableInteractionOptions, DragBounds, ModeSetup, } from './types';
|
|
9
17
|
export { createRectangle, createRectangleAtPoint, editRectangle, } from './shapes';
|
|
10
18
|
export type { RectangleOptions, RectangleAtPointOptions } from './shapes';
|
|
@@ -20,7 +28,7 @@ export type { DrawToCreateOptions } from './interactions';
|
|
|
20
28
|
export { enableVertexEdit } from './interactions';
|
|
21
29
|
export type { VertexEditOptions } from './interactions';
|
|
22
30
|
export { enablePanAndZoom, resetViewport } from './viewport';
|
|
23
|
-
export type { ViewportController, ViewportMode, PanAndZoomOptions, } from './viewport';
|
|
31
|
+
export type { ViewportController, ViewportMode, PanAndZoomOptions, PanToObjectOptions, } from './viewport';
|
|
24
32
|
export { getSnapPoints, registerSnapPointExtractor } from './alignment';
|
|
25
33
|
export type { SnapPointExtractor } from './alignment';
|
|
26
34
|
export { enableObjectAlignment } from './alignment';
|
|
@@ -31,8 +39,9 @@ export { snapCursorPoint } from './alignment';
|
|
|
31
39
|
export type { CursorSnapResult, CursorSnapOptions, GuidelineStyle, } from './alignment';
|
|
32
40
|
export { deleteObjects, enableKeyboardShortcuts } from './keyboard';
|
|
33
41
|
export { enableScaledStrokes, serializeCanvas, loadCanvas, getBaseStrokeWidth, } from './serialization';
|
|
34
|
-
export type { SerializeOptions } from './serialization';
|
|
35
|
-
export { fitViewportToBackground, setBackgroundOpacity, getBackgroundOpacity, setBackgroundInverted, getBackgroundInverted, resizeImageUrl, setBackgroundImage, } from './background';
|
|
36
|
-
export type { FitViewportOptions, ResizeResult, ResizeImageOptions, } from './background';
|
|
42
|
+
export type { SerializeOptions, LoadCanvasOptions } from './serialization';
|
|
43
|
+
export { fitViewportToBackground, getBackgroundSrc, setBackgroundOpacity, getBackgroundOpacity, setBackgroundInverted, getBackgroundInverted, resizeImageUrl, setBackgroundImage, } from './background';
|
|
44
|
+
export type { FitViewportOptions, ResizeResult, ResizeImageOptions, SetBackgroundImageOptions, } from './background';
|
|
37
45
|
export { DEFAULT_CONTROL_STYLE, DEFAULT_SHAPE_STYLE, DEFAULT_CIRCLE_STYLE, DEFAULT_DRAG_SHAPE_STYLE, DEFAULT_GUIDELINE_SHAPE_STYLE, DEFAULT_ALIGNMENT_STYLE, } from './styles';
|
|
46
|
+
export { Canvas as FabricCanvas, FabricObject, FabricImage, Rect, Polygon, Point, util, } from 'fabric';
|
|
38
47
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,YAAY,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/fabricAugmentation.ts
|
|
2
|
+
import "fabric";
|
|
3
|
+
|
|
1
4
|
// src/Canvas/Canvas.tsx
|
|
2
5
|
import { Canvas as FabricCanvas } from "fabric";
|
|
3
6
|
import { useEffect, useRef } from "react";
|
|
@@ -26,27 +29,56 @@ function enableKeyboardShortcuts(canvas) {
|
|
|
26
29
|
// src/Canvas/Canvas.tsx
|
|
27
30
|
import { jsx } from "react/jsx-runtime";
|
|
28
31
|
function Canvas({
|
|
29
|
-
width
|
|
30
|
-
height
|
|
32
|
+
width,
|
|
33
|
+
height,
|
|
31
34
|
className,
|
|
32
35
|
style,
|
|
33
36
|
onReady
|
|
34
37
|
}) {
|
|
35
38
|
const canvasRef = useRef(null);
|
|
39
|
+
const wrapperRef = useRef(null);
|
|
40
|
+
const isFixedSize = width !== void 0 && height !== void 0;
|
|
36
41
|
useEffect(() => {
|
|
37
42
|
const el = canvasRef.current;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
43
|
+
const wrapper = wrapperRef.current;
|
|
44
|
+
if (!el || !wrapper) return;
|
|
45
|
+
const initialWidth = isFixedSize ? width : wrapper.clientWidth || 800;
|
|
46
|
+
const initialHeight = isFixedSize ? height : wrapper.clientHeight || 600;
|
|
47
|
+
const fabricCanvas = new FabricCanvas(el, {
|
|
48
|
+
width: initialWidth,
|
|
49
|
+
height: initialHeight
|
|
50
|
+
});
|
|
42
51
|
onReady?.(fabricCanvas);
|
|
43
52
|
const cleanupShortcuts = enableKeyboardShortcuts(fabricCanvas);
|
|
53
|
+
let observer;
|
|
54
|
+
let rafId = 0;
|
|
55
|
+
if (!isFixedSize) {
|
|
56
|
+
let currentWidth = initialWidth;
|
|
57
|
+
let currentHeight = initialHeight;
|
|
58
|
+
observer = new ResizeObserver((entries) => {
|
|
59
|
+
cancelAnimationFrame(rafId);
|
|
60
|
+
rafId = requestAnimationFrame(() => {
|
|
61
|
+
const entry = entries[0];
|
|
62
|
+
if (!entry) return;
|
|
63
|
+
const { width: newWidth, height: newHeight } = entry.contentRect;
|
|
64
|
+
if (newWidth > 0 && newHeight > 0 && (newWidth !== currentWidth || newHeight !== currentHeight)) {
|
|
65
|
+
currentWidth = newWidth;
|
|
66
|
+
currentHeight = newHeight;
|
|
67
|
+
fabricCanvas.setDimensions({ width: newWidth, height: newHeight });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
observer.observe(wrapper);
|
|
72
|
+
}
|
|
44
73
|
return () => {
|
|
74
|
+
cancelAnimationFrame(rafId);
|
|
75
|
+
observer?.disconnect();
|
|
45
76
|
cleanupShortcuts();
|
|
46
77
|
fabricCanvas.dispose();
|
|
47
78
|
};
|
|
48
79
|
}, []);
|
|
49
|
-
|
|
80
|
+
const wrapperStyle = isFixedSize ? { ...style } : { width: "100%", height: "100%", ...style };
|
|
81
|
+
return /* @__PURE__ */ jsx("div", { ref: wrapperRef, className, style: wrapperStyle, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef }) });
|
|
50
82
|
}
|
|
51
83
|
|
|
52
84
|
// src/hooks/useEditCanvas.ts
|
|
@@ -54,7 +86,9 @@ import { useCallback, useEffect as useEffect2, useRef as useRef2, useState } fro
|
|
|
54
86
|
import { Polygon as Polygon4 } from "fabric";
|
|
55
87
|
|
|
56
88
|
// src/viewport.ts
|
|
57
|
-
import {
|
|
89
|
+
import {
|
|
90
|
+
Point
|
|
91
|
+
} from "fabric";
|
|
58
92
|
|
|
59
93
|
// src/constants.ts
|
|
60
94
|
var DEFAULT_MIN_ZOOM = 0.2;
|
|
@@ -256,6 +290,54 @@ function enablePanAndZoom(canvas, options) {
|
|
|
256
290
|
z
|
|
257
291
|
);
|
|
258
292
|
},
|
|
293
|
+
panToObject(object, panOpts) {
|
|
294
|
+
const zoom = canvas.getZoom();
|
|
295
|
+
const objectCenter = object.getCenterPoint();
|
|
296
|
+
const canvasCenterX = canvas.getWidth() / 2;
|
|
297
|
+
const canvasCenterY = canvas.getHeight() / 2;
|
|
298
|
+
const targetX = canvasCenterX - objectCenter.x * zoom;
|
|
299
|
+
const targetY = canvasCenterY - objectCenter.y * zoom;
|
|
300
|
+
if (!panOpts?.animate) {
|
|
301
|
+
const vt2 = canvas.viewportTransform;
|
|
302
|
+
if (!vt2) return;
|
|
303
|
+
canvas.setViewportTransform([
|
|
304
|
+
vt2[0],
|
|
305
|
+
vt2[1],
|
|
306
|
+
vt2[2],
|
|
307
|
+
vt2[3],
|
|
308
|
+
targetX,
|
|
309
|
+
targetY
|
|
310
|
+
]);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const duration = panOpts.duration ?? 300;
|
|
314
|
+
const vt = canvas.viewportTransform;
|
|
315
|
+
if (!vt) return;
|
|
316
|
+
const startX = vt[4];
|
|
317
|
+
const startY = vt[5];
|
|
318
|
+
const startTime = performance.now();
|
|
319
|
+
function step(now) {
|
|
320
|
+
const elapsed = now - startTime;
|
|
321
|
+
const t = Math.min(elapsed / duration, 1);
|
|
322
|
+
const eased = 1 - Math.pow(1 - t, 3);
|
|
323
|
+
const currentX = startX + (targetX - startX) * eased;
|
|
324
|
+
const currentY = startY + (targetY - startY) * eased;
|
|
325
|
+
const currentVt = canvas.viewportTransform;
|
|
326
|
+
if (!currentVt) return;
|
|
327
|
+
canvas.setViewportTransform([
|
|
328
|
+
currentVt[0],
|
|
329
|
+
currentVt[1],
|
|
330
|
+
currentVt[2],
|
|
331
|
+
currentVt[3],
|
|
332
|
+
currentX,
|
|
333
|
+
currentY
|
|
334
|
+
]);
|
|
335
|
+
if (t < 1) {
|
|
336
|
+
requestAnimationFrame(step);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
requestAnimationFrame(step);
|
|
340
|
+
},
|
|
259
341
|
cleanup() {
|
|
260
342
|
canvas.off("mouse:wheel", handleWheel);
|
|
261
343
|
canvas.off("mouse:down", panHandlers.handleMouseDown);
|
|
@@ -274,6 +356,11 @@ import { FabricImage, filters } from "fabric";
|
|
|
274
356
|
function getBackgroundImage(canvas) {
|
|
275
357
|
return canvas.backgroundImage;
|
|
276
358
|
}
|
|
359
|
+
function getBackgroundSrc(canvas) {
|
|
360
|
+
const bg = getBackgroundImage(canvas);
|
|
361
|
+
if (!bg) return null;
|
|
362
|
+
return bg.getSrc() || null;
|
|
363
|
+
}
|
|
277
364
|
function fitViewportToBackground(canvas, options) {
|
|
278
365
|
const bg = getBackgroundImage(canvas);
|
|
279
366
|
if (!bg) return;
|
|
@@ -369,14 +456,18 @@ function resizeImageUrl(url, options) {
|
|
|
369
456
|
img.src = url;
|
|
370
457
|
});
|
|
371
458
|
}
|
|
372
|
-
async function setBackgroundImage(canvas, url,
|
|
459
|
+
async function setBackgroundImage(canvas, url, options) {
|
|
460
|
+
const prevOpacity = options?.preserveOpacity ? getBackgroundOpacity(canvas) : void 0;
|
|
373
461
|
let imageUrl = url;
|
|
374
|
-
if (
|
|
375
|
-
const result = await resizeImageUrl(url,
|
|
462
|
+
if (options !== void 0) {
|
|
463
|
+
const result = await resizeImageUrl(url, options);
|
|
376
464
|
imageUrl = result.url;
|
|
377
465
|
}
|
|
378
466
|
const img = await FabricImage.fromURL(imageUrl, { crossOrigin: "anonymous" });
|
|
379
467
|
canvas.backgroundImage = img;
|
|
468
|
+
if (prevOpacity !== void 0 && prevOpacity !== 1) {
|
|
469
|
+
img.set("opacity", prevOpacity);
|
|
470
|
+
}
|
|
380
471
|
canvas.requestRenderAll();
|
|
381
472
|
return img;
|
|
382
473
|
}
|
|
@@ -405,7 +496,10 @@ function createViewportActions(canvasRef, viewportRef, setZoom) {
|
|
|
405
496
|
viewportRef.current?.zoomOut(step);
|
|
406
497
|
syncZoom(canvasRef, setZoom);
|
|
407
498
|
};
|
|
408
|
-
|
|
499
|
+
const panToObject = (object, panOpts) => {
|
|
500
|
+
viewportRef.current?.panToObject(object, panOpts);
|
|
501
|
+
};
|
|
502
|
+
return { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject };
|
|
409
503
|
}
|
|
410
504
|
function resolveAlignmentEnabled(enableAlignment, alignmentProp) {
|
|
411
505
|
if (enableAlignment !== void 0) return enableAlignment;
|
|
@@ -1301,21 +1395,39 @@ function enableDragToCreate(canvas, factory, options) {
|
|
|
1301
1395
|
options?.onCreated?.(obj);
|
|
1302
1396
|
previewRect = null;
|
|
1303
1397
|
};
|
|
1398
|
+
const handleKeyDown = (e) => {
|
|
1399
|
+
if (e.key === "Escape") {
|
|
1400
|
+
e.stopImmediatePropagation();
|
|
1401
|
+
e.preventDefault();
|
|
1402
|
+
cleanup("cancel");
|
|
1403
|
+
}
|
|
1404
|
+
};
|
|
1304
1405
|
canvas.on("mouse:down", handleMouseDown);
|
|
1305
1406
|
canvas.on("mouse:move", handleMouseMove);
|
|
1306
1407
|
canvas.on("mouse:up", handleMouseUp);
|
|
1307
|
-
|
|
1408
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
1409
|
+
let exited = false;
|
|
1410
|
+
function cleanup(reason) {
|
|
1411
|
+
if (exited) return;
|
|
1412
|
+
exited = true;
|
|
1308
1413
|
canvas.off("mouse:down", handleMouseDown);
|
|
1309
1414
|
canvas.off("mouse:move", handleMouseMove);
|
|
1310
1415
|
canvas.off("mouse:up", handleMouseUp);
|
|
1416
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
1311
1417
|
shiftTracker.cleanup();
|
|
1312
1418
|
snapping.cleanup();
|
|
1313
1419
|
if (isDrawing && previewRect) {
|
|
1420
|
+
snapping.excludeSet.delete(previewRect);
|
|
1314
1421
|
canvas.remove(previewRect);
|
|
1422
|
+
canvas.selection = previousSelection;
|
|
1315
1423
|
canvas.requestRenderAll();
|
|
1316
1424
|
}
|
|
1317
1425
|
restoreViewport(options?.viewport);
|
|
1318
|
-
|
|
1426
|
+
if (reason === "cancel") {
|
|
1427
|
+
options?.onCancel?.();
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
return () => cleanup();
|
|
1319
1431
|
}
|
|
1320
1432
|
|
|
1321
1433
|
// src/interactions/drawToCreate.ts
|
|
@@ -1595,6 +1707,9 @@ function enableDrawToCreate(canvas, options) {
|
|
|
1595
1707
|
removePreviewElements();
|
|
1596
1708
|
snapping.clearSnapResult();
|
|
1597
1709
|
const polygon = createPolygonFromVertices(canvas, points, options?.style);
|
|
1710
|
+
if (options?.data) {
|
|
1711
|
+
polygon.data = options.data;
|
|
1712
|
+
}
|
|
1598
1713
|
canvas.selection = previousSelection;
|
|
1599
1714
|
canvas.requestRenderAll();
|
|
1600
1715
|
restoreViewport(options?.viewport);
|
|
@@ -1973,8 +2088,15 @@ function serializeCanvas(canvas, options) {
|
|
|
1973
2088
|
});
|
|
1974
2089
|
return json;
|
|
1975
2090
|
}
|
|
1976
|
-
async function loadCanvas(canvas, json) {
|
|
2091
|
+
async function loadCanvas(canvas, json, options) {
|
|
1977
2092
|
await canvas.loadFromJSON(json);
|
|
2093
|
+
if (options?.filter) {
|
|
2094
|
+
const toRemove = [];
|
|
2095
|
+
canvas.forEachObject((obj) => {
|
|
2096
|
+
if (!options.filter(obj)) toRemove.push(obj);
|
|
2097
|
+
});
|
|
2098
|
+
for (const obj of toRemove) canvas.remove(obj);
|
|
2099
|
+
}
|
|
1978
2100
|
canvas.forEachObject((obj) => {
|
|
1979
2101
|
obj.set(DEFAULT_CONTROL_STYLE);
|
|
1980
2102
|
if (obj.shapeType === "circle" && obj instanceof Rect5) {
|
|
@@ -1982,6 +2104,7 @@ async function loadCanvas(canvas, json) {
|
|
|
1982
2104
|
}
|
|
1983
2105
|
});
|
|
1984
2106
|
canvas.requestRenderAll();
|
|
2107
|
+
return canvas.getObjects();
|
|
1985
2108
|
}
|
|
1986
2109
|
|
|
1987
2110
|
// src/hooks/useEditCanvas.ts
|
|
@@ -1997,6 +2120,7 @@ function useEditCanvas(options) {
|
|
|
1997
2120
|
const [selected, setSelected] = useState([]);
|
|
1998
2121
|
const [viewportMode, setViewportModeState] = useState("select");
|
|
1999
2122
|
const [isEditingVertices, setIsEditingVertices] = useState(false);
|
|
2123
|
+
const [isDirty, setIsDirty] = useState(false);
|
|
2000
2124
|
const setMode = useCallback((setup) => {
|
|
2001
2125
|
vertexEditCleanupRef.current?.();
|
|
2002
2126
|
vertexEditCleanupRef.current = null;
|
|
@@ -2067,6 +2191,11 @@ function useEditCanvas(options) {
|
|
|
2067
2191
|
canvas.on("selection:cleared", () => {
|
|
2068
2192
|
setSelected([]);
|
|
2069
2193
|
});
|
|
2194
|
+
if (options?.trackChanges) {
|
|
2195
|
+
canvas.on("object:added", () => setIsDirty(true));
|
|
2196
|
+
canvas.on("object:removed", () => setIsDirty(true));
|
|
2197
|
+
canvas.on("object:modified", () => setIsDirty(true));
|
|
2198
|
+
}
|
|
2070
2199
|
if (options?.vertexEdit !== false) {
|
|
2071
2200
|
const vertexOpts = typeof options?.vertexEdit === "object" ? options.vertexEdit : void 0;
|
|
2072
2201
|
canvas.on("mouse:dblclick", (e) => {
|
|
@@ -2121,22 +2250,26 @@ function useEditCanvas(options) {
|
|
|
2121
2250
|
viewportRef.current?.setMode(mode);
|
|
2122
2251
|
setViewportModeState(mode);
|
|
2123
2252
|
}, []);
|
|
2124
|
-
const { resetViewport: resetViewport2, zoomIn, zoomOut } = createViewportActions(
|
|
2253
|
+
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject } = createViewportActions(
|
|
2125
2254
|
canvasRef,
|
|
2126
2255
|
viewportRef,
|
|
2127
2256
|
setZoom
|
|
2128
2257
|
);
|
|
2129
|
-
const setBackground = useCallback(
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2258
|
+
const setBackground = useCallback(
|
|
2259
|
+
async (url, bgOpts) => {
|
|
2260
|
+
const canvas = canvasRef.current;
|
|
2261
|
+
if (!canvas) throw new Error("Canvas not ready");
|
|
2262
|
+
const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveOpacity ? { preserveOpacity: true } : void 0;
|
|
2263
|
+
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2264
|
+
if (options?.autoFitToBackground !== false) {
|
|
2265
|
+
fitViewportToBackground(canvas);
|
|
2266
|
+
syncZoom(canvasRef, setZoom);
|
|
2267
|
+
}
|
|
2268
|
+
return img;
|
|
2269
|
+
},
|
|
2270
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2271
|
+
[]
|
|
2272
|
+
);
|
|
2140
2273
|
return {
|
|
2141
2274
|
/** Pass this to `<Canvas onReady={...} />` */
|
|
2142
2275
|
onReady,
|
|
@@ -2157,7 +2290,9 @@ function useEditCanvas(options) {
|
|
|
2157
2290
|
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2158
2291
|
zoomIn,
|
|
2159
2292
|
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2160
|
-
zoomOut
|
|
2293
|
+
zoomOut,
|
|
2294
|
+
/** Pan the viewport to center on a specific object. */
|
|
2295
|
+
panToObject
|
|
2161
2296
|
},
|
|
2162
2297
|
/** Whether vertex edit mode is currently active (reactive). */
|
|
2163
2298
|
isEditingVertices,
|
|
@@ -2181,8 +2316,15 @@ function useEditCanvas(options) {
|
|
|
2181
2316
|
* Set a background image from a URL. Automatically resizes if the image
|
|
2182
2317
|
* exceeds the configured limits (opt out via `backgroundResize: false`),
|
|
2183
2318
|
* and fits the viewport after setting if `autoFitToBackground` is enabled.
|
|
2319
|
+
*
|
|
2320
|
+
* Pass `{ preserveOpacity: true }` to keep the current background opacity
|
|
2321
|
+
* when replacing the image.
|
|
2184
2322
|
*/
|
|
2185
|
-
setBackground
|
|
2323
|
+
setBackground,
|
|
2324
|
+
/** Whether the canvas has been modified since the last `resetDirty()` call. Requires `trackChanges: true`. */
|
|
2325
|
+
isDirty,
|
|
2326
|
+
/** Reset the dirty flag (e.g., after a successful save). */
|
|
2327
|
+
resetDirty: useCallback(() => setIsDirty(false), [])
|
|
2186
2328
|
};
|
|
2187
2329
|
}
|
|
2188
2330
|
|
|
@@ -2240,7 +2382,7 @@ function useViewCanvas(options) {
|
|
|
2240
2382
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2241
2383
|
[]
|
|
2242
2384
|
);
|
|
2243
|
-
const { resetViewport: resetViewport2, zoomIn, zoomOut } = createViewportActions(
|
|
2385
|
+
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject } = createViewportActions(
|
|
2244
2386
|
canvasRef,
|
|
2245
2387
|
viewportRef,
|
|
2246
2388
|
setZoom
|
|
@@ -2306,7 +2448,9 @@ function useViewCanvas(options) {
|
|
|
2306
2448
|
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2307
2449
|
zoomIn,
|
|
2308
2450
|
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2309
|
-
zoomOut
|
|
2451
|
+
zoomOut,
|
|
2452
|
+
/** Pan the viewport to center on a specific object. */
|
|
2453
|
+
panToObject
|
|
2310
2454
|
},
|
|
2311
2455
|
/** Update a single object's visual style by its `data.id`. */
|
|
2312
2456
|
setObjectStyle,
|
|
@@ -2316,6 +2460,217 @@ function useViewCanvas(options) {
|
|
|
2316
2460
|
setObjectStyleByType
|
|
2317
2461
|
};
|
|
2318
2462
|
}
|
|
2463
|
+
|
|
2464
|
+
// src/hooks/useCanvasEvents.ts
|
|
2465
|
+
import { useEffect as useEffect3, useRef as useRef4 } from "react";
|
|
2466
|
+
function useCanvasEvents(canvasRef, events) {
|
|
2467
|
+
const eventsRef = useRef4(events);
|
|
2468
|
+
eventsRef.current = events;
|
|
2469
|
+
useEffect3(() => {
|
|
2470
|
+
const canvas = canvasRef.current;
|
|
2471
|
+
if (!canvas) return;
|
|
2472
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
2473
|
+
for (const key of Object.keys(eventsRef.current)) {
|
|
2474
|
+
if (!eventsRef.current[key]) continue;
|
|
2475
|
+
const wrapped = (options) => {
|
|
2476
|
+
eventsRef.current[key]?.(options);
|
|
2477
|
+
};
|
|
2478
|
+
canvas.on(key, wrapped);
|
|
2479
|
+
wrappers.set(key, wrapped);
|
|
2480
|
+
}
|
|
2481
|
+
return () => {
|
|
2482
|
+
wrappers.forEach((handler, name) => {
|
|
2483
|
+
canvas.off(name, handler);
|
|
2484
|
+
});
|
|
2485
|
+
};
|
|
2486
|
+
}, [canvasRef]);
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
// src/hooks/useCanvasTooltip.ts
|
|
2490
|
+
import { useEffect as useEffect4, useRef as useRef5, useState as useState3 } from "react";
|
|
2491
|
+
function useCanvasTooltip(canvasRef, options) {
|
|
2492
|
+
const [state, setState] = useState3({
|
|
2493
|
+
visible: false,
|
|
2494
|
+
content: null,
|
|
2495
|
+
position: { x: 0, y: 0 }
|
|
2496
|
+
});
|
|
2497
|
+
const hoveredObjectRef = useRef5(null);
|
|
2498
|
+
const optionsRef = useRef5(options);
|
|
2499
|
+
optionsRef.current = options;
|
|
2500
|
+
useEffect4(() => {
|
|
2501
|
+
const canvas = canvasRef.current;
|
|
2502
|
+
if (!canvas) return;
|
|
2503
|
+
function calculatePosition(target) {
|
|
2504
|
+
const bounds = target.getBoundingRect();
|
|
2505
|
+
const zoom = canvas.getZoom();
|
|
2506
|
+
const vt = canvas.viewportTransform;
|
|
2507
|
+
if (!vt) return null;
|
|
2508
|
+
return {
|
|
2509
|
+
x: (bounds.left + bounds.width / 2) * zoom + vt[4],
|
|
2510
|
+
y: bounds.top * zoom + vt[5] - 10
|
|
2511
|
+
};
|
|
2512
|
+
}
|
|
2513
|
+
const handleMouseOver = (e) => {
|
|
2514
|
+
const target = e.target;
|
|
2515
|
+
if (!target) return;
|
|
2516
|
+
const content = optionsRef.current.getContent(target);
|
|
2517
|
+
if (content === null) return;
|
|
2518
|
+
if (hoveredObjectRef.current !== target) {
|
|
2519
|
+
hoveredObjectRef.current = target;
|
|
2520
|
+
const position = calculatePosition(target);
|
|
2521
|
+
if (position) {
|
|
2522
|
+
setState({ visible: true, content, position });
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
const handleMouseOut = (e) => {
|
|
2527
|
+
if (e.target && hoveredObjectRef.current === e.target) {
|
|
2528
|
+
setState((prev) => ({ ...prev, visible: false }));
|
|
2529
|
+
hoveredObjectRef.current = null;
|
|
2530
|
+
}
|
|
2531
|
+
};
|
|
2532
|
+
const updatePosition = () => {
|
|
2533
|
+
if (!hoveredObjectRef.current) return;
|
|
2534
|
+
const position = calculatePosition(hoveredObjectRef.current);
|
|
2535
|
+
if (position) {
|
|
2536
|
+
setState((prev) => prev.visible ? { ...prev, position } : prev);
|
|
2537
|
+
}
|
|
2538
|
+
};
|
|
2539
|
+
canvas.on("mouse:over", handleMouseOver);
|
|
2540
|
+
canvas.on("mouse:out", handleMouseOut);
|
|
2541
|
+
canvas.on("after:render", updatePosition);
|
|
2542
|
+
canvas.on("mouse:wheel", updatePosition);
|
|
2543
|
+
return () => {
|
|
2544
|
+
canvas.off("mouse:over", handleMouseOver);
|
|
2545
|
+
canvas.off("mouse:out", handleMouseOut);
|
|
2546
|
+
canvas.off("after:render", updatePosition);
|
|
2547
|
+
canvas.off("mouse:wheel", updatePosition);
|
|
2548
|
+
};
|
|
2549
|
+
}, [canvasRef]);
|
|
2550
|
+
return state;
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
// src/hooks/useCanvasClick.ts
|
|
2554
|
+
import { useEffect as useEffect5, useRef as useRef6 } from "react";
|
|
2555
|
+
function useCanvasClick(canvasRef, onClick, options) {
|
|
2556
|
+
const onClickRef = useRef6(onClick);
|
|
2557
|
+
onClickRef.current = onClick;
|
|
2558
|
+
const optionsRef = useRef6(options);
|
|
2559
|
+
optionsRef.current = options;
|
|
2560
|
+
useEffect5(() => {
|
|
2561
|
+
const canvas = canvasRef.current;
|
|
2562
|
+
if (!canvas) return;
|
|
2563
|
+
let mouseDown = null;
|
|
2564
|
+
let isPanning = false;
|
|
2565
|
+
const handleMouseDown = (e) => {
|
|
2566
|
+
const native = e.e instanceof TouchEvent ? e.e.touches[0] : e.e;
|
|
2567
|
+
if (native) {
|
|
2568
|
+
mouseDown = { x: native.clientX, y: native.clientY, time: Date.now() };
|
|
2569
|
+
isPanning = false;
|
|
2570
|
+
}
|
|
2571
|
+
};
|
|
2572
|
+
const handleMouseMove = (e) => {
|
|
2573
|
+
if (!mouseDown) return;
|
|
2574
|
+
const native = e.e instanceof TouchEvent ? e.e.touches[0] : e.e;
|
|
2575
|
+
if (!native) return;
|
|
2576
|
+
const threshold = optionsRef.current?.threshold ?? 5;
|
|
2577
|
+
const deltaX = Math.abs(native.clientX - mouseDown.x);
|
|
2578
|
+
const deltaY = Math.abs(native.clientY - mouseDown.y);
|
|
2579
|
+
if (deltaX > threshold || deltaY > threshold) {
|
|
2580
|
+
isPanning = true;
|
|
2581
|
+
}
|
|
2582
|
+
};
|
|
2583
|
+
const handleMouseUp = (e) => {
|
|
2584
|
+
if (!mouseDown) return;
|
|
2585
|
+
const maxDuration = optionsRef.current?.maxDuration ?? 300;
|
|
2586
|
+
const elapsed = Date.now() - mouseDown.time;
|
|
2587
|
+
if (!isPanning && elapsed < maxDuration) {
|
|
2588
|
+
onClickRef.current(e.target);
|
|
2589
|
+
}
|
|
2590
|
+
mouseDown = null;
|
|
2591
|
+
isPanning = false;
|
|
2592
|
+
};
|
|
2593
|
+
canvas.on("mouse:down", handleMouseDown);
|
|
2594
|
+
canvas.on("mouse:move", handleMouseMove);
|
|
2595
|
+
canvas.on("mouse:up", handleMouseUp);
|
|
2596
|
+
return () => {
|
|
2597
|
+
canvas.off("mouse:down", handleMouseDown);
|
|
2598
|
+
canvas.off("mouse:move", handleMouseMove);
|
|
2599
|
+
canvas.off("mouse:up", handleMouseUp);
|
|
2600
|
+
};
|
|
2601
|
+
}, [canvasRef]);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
// src/hooks/useObjectOverlay.ts
|
|
2605
|
+
import { useEffect as useEffect6, useRef as useRef7 } from "react";
|
|
2606
|
+
import { util as util4 } from "fabric";
|
|
2607
|
+
function useObjectOverlay(canvasRef, object, options) {
|
|
2608
|
+
const containerRef = useRef7(null);
|
|
2609
|
+
const optionsRef = useRef7(options);
|
|
2610
|
+
optionsRef.current = options;
|
|
2611
|
+
useEffect6(() => {
|
|
2612
|
+
const canvas = canvasRef.current;
|
|
2613
|
+
if (!canvas || !object) return;
|
|
2614
|
+
function update() {
|
|
2615
|
+
const el = containerRef.current;
|
|
2616
|
+
if (!el || !canvas || !object) return;
|
|
2617
|
+
const zoom = canvas.getZoom();
|
|
2618
|
+
const vt = canvas.viewportTransform;
|
|
2619
|
+
if (!vt) return;
|
|
2620
|
+
const center = object.getCenterPoint();
|
|
2621
|
+
const actualWidth = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
2622
|
+
const actualHeight = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
2623
|
+
const screenCoords = util4.transformPoint(center, vt);
|
|
2624
|
+
const screenWidth = actualWidth * zoom;
|
|
2625
|
+
const screenHeight = actualHeight * zoom;
|
|
2626
|
+
el.style.left = `${screenCoords.x - screenWidth / 2}px`;
|
|
2627
|
+
el.style.top = `${screenCoords.y - screenHeight / 2}px`;
|
|
2628
|
+
el.style.width = `${screenWidth}px`;
|
|
2629
|
+
el.style.height = `${screenHeight}px`;
|
|
2630
|
+
const angle = object.angle ?? 0;
|
|
2631
|
+
el.style.rotate = angle !== 0 ? `${angle}deg` : "";
|
|
2632
|
+
const opts = optionsRef.current;
|
|
2633
|
+
if (opts?.autoScaleContent) {
|
|
2634
|
+
const contentScale = Math.min(screenWidth, screenHeight) / 100;
|
|
2635
|
+
const clampedScale = Math.max(0.1, Math.min(contentScale, 2));
|
|
2636
|
+
el.style.setProperty("--overlay-scale", String(clampedScale));
|
|
2637
|
+
if (opts.textSelector) {
|
|
2638
|
+
const textMinScale = opts.textMinScale ?? 0.5;
|
|
2639
|
+
const textEls = el.querySelectorAll(opts.textSelector);
|
|
2640
|
+
const display = clampedScale < textMinScale ? "none" : "";
|
|
2641
|
+
textEls.forEach((t) => {
|
|
2642
|
+
t.style.display = display;
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
update();
|
|
2648
|
+
canvas.on("after:render", update);
|
|
2649
|
+
canvas.on("mouse:wheel", update);
|
|
2650
|
+
object.on("moving", update);
|
|
2651
|
+
object.on("scaling", update);
|
|
2652
|
+
object.on("rotating", update);
|
|
2653
|
+
return () => {
|
|
2654
|
+
canvas.off("after:render", update);
|
|
2655
|
+
canvas.off("mouse:wheel", update);
|
|
2656
|
+
object.off("moving", update);
|
|
2657
|
+
object.off("scaling", update);
|
|
2658
|
+
object.off("rotating", update);
|
|
2659
|
+
};
|
|
2660
|
+
}, [canvasRef, object]);
|
|
2661
|
+
return containerRef;
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
// src/index.ts
|
|
2665
|
+
import {
|
|
2666
|
+
Canvas as Canvas2,
|
|
2667
|
+
FabricObject as FabricObject5,
|
|
2668
|
+
FabricImage as FabricImage2,
|
|
2669
|
+
Rect as Rect7,
|
|
2670
|
+
Polygon as Polygon5,
|
|
2671
|
+
Point as Point9,
|
|
2672
|
+
util as util5
|
|
2673
|
+
} from "fabric";
|
|
2319
2674
|
export {
|
|
2320
2675
|
Canvas,
|
|
2321
2676
|
DEFAULT_ALIGNMENT_STYLE,
|
|
@@ -2324,6 +2679,12 @@ export {
|
|
|
2324
2679
|
DEFAULT_DRAG_SHAPE_STYLE,
|
|
2325
2680
|
DEFAULT_GUIDELINE_SHAPE_STYLE,
|
|
2326
2681
|
DEFAULT_SHAPE_STYLE,
|
|
2682
|
+
Canvas2 as FabricCanvas,
|
|
2683
|
+
FabricImage2 as FabricImage,
|
|
2684
|
+
FabricObject5 as FabricObject,
|
|
2685
|
+
Point9 as Point,
|
|
2686
|
+
Polygon5 as Polygon,
|
|
2687
|
+
Rect7 as Rect,
|
|
2327
2688
|
createCircle,
|
|
2328
2689
|
createCircleAtPoint,
|
|
2329
2690
|
createPolygon,
|
|
@@ -2348,6 +2709,7 @@ export {
|
|
|
2348
2709
|
fitViewportToBackground,
|
|
2349
2710
|
getBackgroundInverted,
|
|
2350
2711
|
getBackgroundOpacity,
|
|
2712
|
+
getBackgroundSrc,
|
|
2351
2713
|
getBaseStrokeWidth,
|
|
2352
2714
|
getSnapPoints,
|
|
2353
2715
|
loadCanvas,
|
|
@@ -2359,7 +2721,12 @@ export {
|
|
|
2359
2721
|
setBackgroundInverted,
|
|
2360
2722
|
setBackgroundOpacity,
|
|
2361
2723
|
snapCursorPoint,
|
|
2724
|
+
useCanvasClick,
|
|
2725
|
+
useCanvasEvents,
|
|
2726
|
+
useCanvasTooltip,
|
|
2362
2727
|
useEditCanvas,
|
|
2363
|
-
|
|
2728
|
+
useObjectOverlay,
|
|
2729
|
+
useViewCanvas,
|
|
2730
|
+
util5 as util
|
|
2364
2731
|
};
|
|
2365
2732
|
//# sourceMappingURL=index.js.map
|