@bwp-web/canvas 0.4.2 → 0.5.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.
- package/dist/Canvas/Canvas.d.ts +11 -1
- package/dist/Canvas/Canvas.d.ts.map +1 -1
- package/dist/background.d.ts +21 -8
- package/dist/background.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +2 -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/useEditCanvas.d.ts +4 -2
- 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 +253 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +246 -33
- 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 +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/dist/viewport.d.ts +18 -7
- package/dist/viewport.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -27,11 +27,12 @@ __export(index_exports, {
|
|
|
27
27
|
DEFAULT_DRAG_SHAPE_STYLE: () => DEFAULT_DRAG_SHAPE_STYLE,
|
|
28
28
|
DEFAULT_GUIDELINE_SHAPE_STYLE: () => DEFAULT_GUIDELINE_SHAPE_STYLE,
|
|
29
29
|
DEFAULT_SHAPE_STYLE: () => DEFAULT_SHAPE_STYLE,
|
|
30
|
-
FabricCanvas: () =>
|
|
31
|
-
FabricImage: () =>
|
|
32
|
-
FabricObject: () =>
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
FabricCanvas: () => import_fabric20.Canvas,
|
|
31
|
+
FabricImage: () => import_fabric20.FabricImage,
|
|
32
|
+
FabricObject: () => import_fabric20.FabricObject,
|
|
33
|
+
Point: () => import_fabric20.Point,
|
|
34
|
+
Polygon: () => import_fabric20.Polygon,
|
|
35
|
+
Rect: () => import_fabric20.Rect,
|
|
35
36
|
createCircle: () => createCircle,
|
|
36
37
|
createCircleAtPoint: () => createCircleAtPoint,
|
|
37
38
|
createPolygon: () => createPolygon,
|
|
@@ -54,8 +55,9 @@ __export(index_exports, {
|
|
|
54
55
|
enableScaledStrokes: () => enableScaledStrokes,
|
|
55
56
|
enableVertexEdit: () => enableVertexEdit,
|
|
56
57
|
fitViewportToBackground: () => fitViewportToBackground,
|
|
58
|
+
getBackgroundContrast: () => getBackgroundContrast,
|
|
57
59
|
getBackgroundInverted: () => getBackgroundInverted,
|
|
58
|
-
|
|
60
|
+
getBackgroundSrc: () => getBackgroundSrc,
|
|
59
61
|
getBaseStrokeWidth: () => getBaseStrokeWidth,
|
|
60
62
|
getSnapPoints: () => getSnapPoints,
|
|
61
63
|
loadCanvas: () => loadCanvas,
|
|
@@ -63,15 +65,17 @@ __export(index_exports, {
|
|
|
63
65
|
resetViewport: () => resetViewport,
|
|
64
66
|
resizeImageUrl: () => resizeImageUrl,
|
|
65
67
|
serializeCanvas: () => serializeCanvas,
|
|
68
|
+
setBackgroundContrast: () => setBackgroundContrast,
|
|
66
69
|
setBackgroundImage: () => setBackgroundImage,
|
|
67
70
|
setBackgroundInverted: () => setBackgroundInverted,
|
|
68
|
-
setBackgroundOpacity: () => setBackgroundOpacity,
|
|
69
71
|
snapCursorPoint: () => snapCursorPoint,
|
|
70
72
|
useCanvasClick: () => useCanvasClick,
|
|
71
73
|
useCanvasEvents: () => useCanvasEvents,
|
|
72
74
|
useCanvasTooltip: () => useCanvasTooltip,
|
|
73
75
|
useEditCanvas: () => useEditCanvas,
|
|
74
|
-
|
|
76
|
+
useObjectOverlay: () => useObjectOverlay,
|
|
77
|
+
useViewCanvas: () => useViewCanvas,
|
|
78
|
+
util: () => import_fabric20.util
|
|
75
79
|
});
|
|
76
80
|
module.exports = __toCommonJS(index_exports);
|
|
77
81
|
|
|
@@ -106,27 +110,56 @@ function enableKeyboardShortcuts(canvas) {
|
|
|
106
110
|
// src/Canvas/Canvas.tsx
|
|
107
111
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
108
112
|
function Canvas({
|
|
109
|
-
width
|
|
110
|
-
height
|
|
113
|
+
width,
|
|
114
|
+
height,
|
|
111
115
|
className,
|
|
112
116
|
style,
|
|
113
117
|
onReady
|
|
114
118
|
}) {
|
|
115
119
|
const canvasRef = (0, import_react.useRef)(null);
|
|
120
|
+
const wrapperRef = (0, import_react.useRef)(null);
|
|
121
|
+
const isFixedSize = width !== void 0 && height !== void 0;
|
|
116
122
|
(0, import_react.useEffect)(() => {
|
|
117
123
|
const el = canvasRef.current;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
124
|
+
const wrapper = wrapperRef.current;
|
|
125
|
+
if (!el || !wrapper) return;
|
|
126
|
+
const initialWidth = isFixedSize ? width : wrapper.clientWidth || 800;
|
|
127
|
+
const initialHeight = isFixedSize ? height : wrapper.clientHeight || 600;
|
|
128
|
+
const fabricCanvas = new import_fabric2.Canvas(el, {
|
|
129
|
+
width: initialWidth,
|
|
130
|
+
height: initialHeight
|
|
131
|
+
});
|
|
122
132
|
onReady?.(fabricCanvas);
|
|
123
133
|
const cleanupShortcuts = enableKeyboardShortcuts(fabricCanvas);
|
|
134
|
+
let observer;
|
|
135
|
+
let rafId = 0;
|
|
136
|
+
if (!isFixedSize) {
|
|
137
|
+
let currentWidth = initialWidth;
|
|
138
|
+
let currentHeight = initialHeight;
|
|
139
|
+
observer = new ResizeObserver((entries) => {
|
|
140
|
+
cancelAnimationFrame(rafId);
|
|
141
|
+
rafId = requestAnimationFrame(() => {
|
|
142
|
+
const entry = entries[0];
|
|
143
|
+
if (!entry) return;
|
|
144
|
+
const { width: newWidth, height: newHeight } = entry.contentRect;
|
|
145
|
+
if (newWidth > 0 && newHeight > 0 && (newWidth !== currentWidth || newHeight !== currentHeight)) {
|
|
146
|
+
currentWidth = newWidth;
|
|
147
|
+
currentHeight = newHeight;
|
|
148
|
+
fabricCanvas.setDimensions({ width: newWidth, height: newHeight });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
observer.observe(wrapper);
|
|
153
|
+
}
|
|
124
154
|
return () => {
|
|
155
|
+
cancelAnimationFrame(rafId);
|
|
156
|
+
observer?.disconnect();
|
|
125
157
|
cleanupShortcuts();
|
|
126
158
|
fabricCanvas.dispose();
|
|
127
159
|
};
|
|
128
160
|
}, []);
|
|
129
|
-
|
|
161
|
+
const wrapperStyle = isFixedSize ? { ...style } : { width: "100%", height: "100%", ...style };
|
|
162
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: wrapperRef, className, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("canvas", { ref: canvasRef }) });
|
|
130
163
|
}
|
|
131
164
|
|
|
132
165
|
// src/hooks/useEditCanvas.ts
|
|
@@ -140,7 +173,7 @@ var import_fabric3 = require("fabric");
|
|
|
140
173
|
var DEFAULT_MIN_ZOOM = 0.2;
|
|
141
174
|
var DEFAULT_MAX_ZOOM = 10;
|
|
142
175
|
var DEFAULT_ZOOM_FACTOR = 1.03;
|
|
143
|
-
var DEFAULT_ZOOM_STEP =
|
|
176
|
+
var DEFAULT_ZOOM_STEP = 1.2;
|
|
144
177
|
var DEFAULT_VIEWPORT_PADDING = 0.05;
|
|
145
178
|
var BASE_CANVAS_SIZE = 1e3;
|
|
146
179
|
var DEFAULT_SNAP_MARGIN = 6;
|
|
@@ -322,20 +355,68 @@ function enablePanAndZoom(canvas, options) {
|
|
|
322
355
|
setEnabled(value) {
|
|
323
356
|
enabled = value;
|
|
324
357
|
},
|
|
325
|
-
zoomIn(
|
|
326
|
-
const z = Math.min(canvas.getZoom()
|
|
358
|
+
zoomIn(factor = DEFAULT_ZOOM_STEP) {
|
|
359
|
+
const z = Math.min(canvas.getZoom() * factor, bounds.maxZoom);
|
|
327
360
|
canvas.zoomToPoint(
|
|
328
361
|
new import_fabric3.Point(canvas.getWidth() / 2, canvas.getHeight() / 2),
|
|
329
362
|
z
|
|
330
363
|
);
|
|
331
364
|
},
|
|
332
|
-
zoomOut(
|
|
333
|
-
const z = Math.max(canvas.getZoom()
|
|
365
|
+
zoomOut(factor = DEFAULT_ZOOM_STEP) {
|
|
366
|
+
const z = Math.max(canvas.getZoom() / factor, bounds.minZoom);
|
|
334
367
|
canvas.zoomToPoint(
|
|
335
368
|
new import_fabric3.Point(canvas.getWidth() / 2, canvas.getHeight() / 2),
|
|
336
369
|
z
|
|
337
370
|
);
|
|
338
371
|
},
|
|
372
|
+
panToObject(object, panOpts) {
|
|
373
|
+
const zoom = canvas.getZoom();
|
|
374
|
+
const objectCenter = object.getCenterPoint();
|
|
375
|
+
const canvasCenterX = canvas.getWidth() / 2;
|
|
376
|
+
const canvasCenterY = canvas.getHeight() / 2;
|
|
377
|
+
const targetX = canvasCenterX - objectCenter.x * zoom;
|
|
378
|
+
const targetY = canvasCenterY - objectCenter.y * zoom;
|
|
379
|
+
if (!panOpts?.animate) {
|
|
380
|
+
const vt2 = canvas.viewportTransform;
|
|
381
|
+
if (!vt2) return;
|
|
382
|
+
canvas.setViewportTransform([
|
|
383
|
+
vt2[0],
|
|
384
|
+
vt2[1],
|
|
385
|
+
vt2[2],
|
|
386
|
+
vt2[3],
|
|
387
|
+
targetX,
|
|
388
|
+
targetY
|
|
389
|
+
]);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const duration = panOpts.duration ?? 300;
|
|
393
|
+
const vt = canvas.viewportTransform;
|
|
394
|
+
if (!vt) return;
|
|
395
|
+
const startX = vt[4];
|
|
396
|
+
const startY = vt[5];
|
|
397
|
+
const startTime = performance.now();
|
|
398
|
+
function step(now) {
|
|
399
|
+
const elapsed = now - startTime;
|
|
400
|
+
const t = Math.min(elapsed / duration, 1);
|
|
401
|
+
const eased = 1 - Math.pow(1 - t, 3);
|
|
402
|
+
const currentX = startX + (targetX - startX) * eased;
|
|
403
|
+
const currentY = startY + (targetY - startY) * eased;
|
|
404
|
+
const currentVt = canvas.viewportTransform;
|
|
405
|
+
if (!currentVt) return;
|
|
406
|
+
canvas.setViewportTransform([
|
|
407
|
+
currentVt[0],
|
|
408
|
+
currentVt[1],
|
|
409
|
+
currentVt[2],
|
|
410
|
+
currentVt[3],
|
|
411
|
+
currentX,
|
|
412
|
+
currentY
|
|
413
|
+
]);
|
|
414
|
+
if (t < 1) {
|
|
415
|
+
requestAnimationFrame(step);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
requestAnimationFrame(step);
|
|
419
|
+
},
|
|
339
420
|
cleanup() {
|
|
340
421
|
canvas.off("mouse:wheel", handleWheel);
|
|
341
422
|
canvas.off("mouse:down", panHandlers.handleMouseDown);
|
|
@@ -354,6 +435,11 @@ var import_fabric4 = require("fabric");
|
|
|
354
435
|
function getBackgroundImage(canvas) {
|
|
355
436
|
return canvas.backgroundImage;
|
|
356
437
|
}
|
|
438
|
+
function getBackgroundSrc(canvas) {
|
|
439
|
+
const bg = getBackgroundImage(canvas);
|
|
440
|
+
if (!bg) return null;
|
|
441
|
+
return bg.getSrc() || null;
|
|
442
|
+
}
|
|
357
443
|
function fitViewportToBackground(canvas, options) {
|
|
358
444
|
const bg = getBackgroundImage(canvas);
|
|
359
445
|
if (!bg) return;
|
|
@@ -376,15 +462,37 @@ function fitViewportToBackground(canvas, options) {
|
|
|
376
462
|
canvas.setViewportTransform([scale, 0, 0, scale, offsetX, offsetY]);
|
|
377
463
|
canvas.requestRenderAll();
|
|
378
464
|
}
|
|
379
|
-
function
|
|
465
|
+
function setBackgroundContrast(canvas, value) {
|
|
380
466
|
const bg = getBackgroundImage(canvas);
|
|
381
467
|
if (!bg) return;
|
|
382
|
-
|
|
468
|
+
const contrast = Math.min(Math.max(value, 0), 2) - 1;
|
|
469
|
+
const currentFilters = bg.filters ?? [];
|
|
470
|
+
const contrastIdx = currentFilters.findIndex(
|
|
471
|
+
(f) => f instanceof import_fabric4.filters.Contrast
|
|
472
|
+
);
|
|
473
|
+
if (contrast === 0) {
|
|
474
|
+
if (contrastIdx >= 0) {
|
|
475
|
+
bg.filters = currentFilters.filter(
|
|
476
|
+
(f) => !(f instanceof import_fabric4.filters.Contrast)
|
|
477
|
+
);
|
|
478
|
+
bg.applyFilters();
|
|
479
|
+
}
|
|
480
|
+
} else if (contrastIdx >= 0) {
|
|
481
|
+
currentFilters[contrastIdx].contrast = contrast;
|
|
482
|
+
bg.applyFilters();
|
|
483
|
+
} else {
|
|
484
|
+
bg.filters = [...currentFilters, new import_fabric4.filters.Contrast({ contrast })];
|
|
485
|
+
bg.applyFilters();
|
|
486
|
+
}
|
|
383
487
|
canvas.requestRenderAll();
|
|
384
488
|
}
|
|
385
|
-
function
|
|
489
|
+
function getBackgroundContrast(canvas) {
|
|
386
490
|
const bg = getBackgroundImage(canvas);
|
|
387
|
-
|
|
491
|
+
if (!bg) return 1;
|
|
492
|
+
const contrastFilter = bg.filters?.find(
|
|
493
|
+
(f) => f instanceof import_fabric4.filters.Contrast
|
|
494
|
+
);
|
|
495
|
+
return 1 + (contrastFilter?.contrast ?? 0);
|
|
388
496
|
}
|
|
389
497
|
function setBackgroundInverted(canvas, inverted) {
|
|
390
498
|
const bg = getBackgroundImage(canvas);
|
|
@@ -450,7 +558,7 @@ function resizeImageUrl(url, options) {
|
|
|
450
558
|
});
|
|
451
559
|
}
|
|
452
560
|
async function setBackgroundImage(canvas, url, options) {
|
|
453
|
-
const
|
|
561
|
+
const prevContrast = options?.preserveContrast ? getBackgroundContrast(canvas) : void 0;
|
|
454
562
|
let imageUrl = url;
|
|
455
563
|
if (options !== void 0) {
|
|
456
564
|
const result = await resizeImageUrl(url, options);
|
|
@@ -458,8 +566,8 @@ async function setBackgroundImage(canvas, url, options) {
|
|
|
458
566
|
}
|
|
459
567
|
const img = await import_fabric4.FabricImage.fromURL(imageUrl, { crossOrigin: "anonymous" });
|
|
460
568
|
canvas.backgroundImage = img;
|
|
461
|
-
if (
|
|
462
|
-
|
|
569
|
+
if (prevContrast !== void 0 && prevContrast !== 1) {
|
|
570
|
+
setBackgroundContrast(canvas, prevContrast);
|
|
463
571
|
}
|
|
464
572
|
canvas.requestRenderAll();
|
|
465
573
|
return img;
|
|
@@ -489,7 +597,10 @@ function createViewportActions(canvasRef, viewportRef, setZoom) {
|
|
|
489
597
|
viewportRef.current?.zoomOut(step);
|
|
490
598
|
syncZoom(canvasRef, setZoom);
|
|
491
599
|
};
|
|
492
|
-
|
|
600
|
+
const panToObject = (object, panOpts) => {
|
|
601
|
+
viewportRef.current?.panToObject(object, panOpts);
|
|
602
|
+
};
|
|
603
|
+
return { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject };
|
|
493
604
|
}
|
|
494
605
|
function resolveAlignmentEnabled(enableAlignment, alignmentProp) {
|
|
495
606
|
if (enableAlignment !== void 0) return enableAlignment;
|
|
@@ -1381,21 +1492,39 @@ function enableDragToCreate(canvas, factory, options) {
|
|
|
1381
1492
|
options?.onCreated?.(obj);
|
|
1382
1493
|
previewRect = null;
|
|
1383
1494
|
};
|
|
1495
|
+
const handleKeyDown = (e) => {
|
|
1496
|
+
if (e.key === "Escape") {
|
|
1497
|
+
e.stopImmediatePropagation();
|
|
1498
|
+
e.preventDefault();
|
|
1499
|
+
cleanup("cancel");
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1384
1502
|
canvas.on("mouse:down", handleMouseDown);
|
|
1385
1503
|
canvas.on("mouse:move", handleMouseMove);
|
|
1386
1504
|
canvas.on("mouse:up", handleMouseUp);
|
|
1387
|
-
|
|
1505
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
1506
|
+
let exited = false;
|
|
1507
|
+
function cleanup(reason) {
|
|
1508
|
+
if (exited) return;
|
|
1509
|
+
exited = true;
|
|
1388
1510
|
canvas.off("mouse:down", handleMouseDown);
|
|
1389
1511
|
canvas.off("mouse:move", handleMouseMove);
|
|
1390
1512
|
canvas.off("mouse:up", handleMouseUp);
|
|
1513
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
1391
1514
|
shiftTracker.cleanup();
|
|
1392
1515
|
snapping.cleanup();
|
|
1393
1516
|
if (isDrawing && previewRect) {
|
|
1517
|
+
snapping.excludeSet.delete(previewRect);
|
|
1394
1518
|
canvas.remove(previewRect);
|
|
1519
|
+
canvas.selection = previousSelection;
|
|
1395
1520
|
canvas.requestRenderAll();
|
|
1396
1521
|
}
|
|
1397
1522
|
restoreViewport(options?.viewport);
|
|
1398
|
-
|
|
1523
|
+
if (reason === "cancel") {
|
|
1524
|
+
options?.onCancel?.();
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
return () => cleanup();
|
|
1399
1528
|
}
|
|
1400
1529
|
|
|
1401
1530
|
// src/interactions/drawToCreate.ts
|
|
@@ -1671,6 +1800,9 @@ function enableDrawToCreate(canvas, options) {
|
|
|
1671
1800
|
removePreviewElements();
|
|
1672
1801
|
snapping.clearSnapResult();
|
|
1673
1802
|
const polygon = createPolygonFromVertices(canvas, points, options?.style);
|
|
1803
|
+
if (options?.data) {
|
|
1804
|
+
polygon.data = options.data;
|
|
1805
|
+
}
|
|
1674
1806
|
canvas.selection = previousSelection;
|
|
1675
1807
|
canvas.requestRenderAll();
|
|
1676
1808
|
restoreViewport(options?.viewport);
|
|
@@ -2041,6 +2173,7 @@ function serializeCanvas(canvas, options) {
|
|
|
2041
2173
|
}
|
|
2042
2174
|
});
|
|
2043
2175
|
const json = canvas.toObject(properties);
|
|
2176
|
+
delete json.backgroundColor;
|
|
2044
2177
|
scaledWidths.forEach((scaled, obj) => {
|
|
2045
2178
|
obj.strokeWidth = scaled;
|
|
2046
2179
|
});
|
|
@@ -2055,6 +2188,17 @@ async function loadCanvas(canvas, json, options) {
|
|
|
2055
2188
|
});
|
|
2056
2189
|
for (const obj of toRemove) canvas.remove(obj);
|
|
2057
2190
|
}
|
|
2191
|
+
canvas.forEachObject((obj) => {
|
|
2192
|
+
if (obj.originX === "center" && obj.originY === "center") return;
|
|
2193
|
+
const center = obj.getCenterPoint();
|
|
2194
|
+
obj.set({
|
|
2195
|
+
originX: "center",
|
|
2196
|
+
originY: "center",
|
|
2197
|
+
left: center.x,
|
|
2198
|
+
top: center.y
|
|
2199
|
+
});
|
|
2200
|
+
obj.setCoords();
|
|
2201
|
+
});
|
|
2058
2202
|
canvas.forEachObject((obj) => {
|
|
2059
2203
|
obj.set(DEFAULT_CONTROL_STYLE);
|
|
2060
2204
|
if (obj.shapeType === "circle" && obj instanceof import_fabric16.Rect) {
|
|
@@ -2062,6 +2206,7 @@ async function loadCanvas(canvas, json, options) {
|
|
|
2062
2206
|
}
|
|
2063
2207
|
});
|
|
2064
2208
|
canvas.requestRenderAll();
|
|
2209
|
+
return canvas.getObjects();
|
|
2065
2210
|
}
|
|
2066
2211
|
|
|
2067
2212
|
// src/hooks/useEditCanvas.ts
|
|
@@ -2207,7 +2352,7 @@ function useEditCanvas(options) {
|
|
|
2207
2352
|
viewportRef.current?.setMode(mode);
|
|
2208
2353
|
setViewportModeState(mode);
|
|
2209
2354
|
}, []);
|
|
2210
|
-
const { resetViewport: resetViewport2, zoomIn, zoomOut } = createViewportActions(
|
|
2355
|
+
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject } = createViewportActions(
|
|
2211
2356
|
canvasRef,
|
|
2212
2357
|
viewportRef,
|
|
2213
2358
|
setZoom
|
|
@@ -2216,7 +2361,7 @@ function useEditCanvas(options) {
|
|
|
2216
2361
|
async (url, bgOpts) => {
|
|
2217
2362
|
const canvas = canvasRef.current;
|
|
2218
2363
|
if (!canvas) throw new Error("Canvas not ready");
|
|
2219
|
-
const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.
|
|
2364
|
+
const resizeOpts = options?.backgroundResize !== false ? typeof options?.backgroundResize === "object" ? { ...options.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
|
|
2220
2365
|
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2221
2366
|
if (options?.autoFitToBackground !== false) {
|
|
2222
2367
|
fitViewportToBackground(canvas);
|
|
@@ -2247,7 +2392,9 @@ function useEditCanvas(options) {
|
|
|
2247
2392
|
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2248
2393
|
zoomIn,
|
|
2249
2394
|
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2250
|
-
zoomOut
|
|
2395
|
+
zoomOut,
|
|
2396
|
+
/** Pan the viewport to center on a specific object. */
|
|
2397
|
+
panToObject
|
|
2251
2398
|
},
|
|
2252
2399
|
/** Whether vertex edit mode is currently active (reactive). */
|
|
2253
2400
|
isEditingVertices,
|
|
@@ -2272,7 +2419,7 @@ function useEditCanvas(options) {
|
|
|
2272
2419
|
* exceeds the configured limits (opt out via `backgroundResize: false`),
|
|
2273
2420
|
* and fits the viewport after setting if `autoFitToBackground` is enabled.
|
|
2274
2421
|
*
|
|
2275
|
-
* Pass `{
|
|
2422
|
+
* Pass `{ preserveContrast: true }` to keep the current background contrast
|
|
2276
2423
|
* when replacing the image.
|
|
2277
2424
|
*/
|
|
2278
2425
|
setBackground,
|
|
@@ -2337,7 +2484,7 @@ function useViewCanvas(options) {
|
|
|
2337
2484
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2338
2485
|
[]
|
|
2339
2486
|
);
|
|
2340
|
-
const { resetViewport: resetViewport2, zoomIn, zoomOut } = createViewportActions(
|
|
2487
|
+
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject } = createViewportActions(
|
|
2341
2488
|
canvasRef,
|
|
2342
2489
|
viewportRef,
|
|
2343
2490
|
setZoom
|
|
@@ -2403,7 +2550,9 @@ function useViewCanvas(options) {
|
|
|
2403
2550
|
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2404
2551
|
zoomIn,
|
|
2405
2552
|
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2406
|
-
zoomOut
|
|
2553
|
+
zoomOut,
|
|
2554
|
+
/** Pan the viewport to center on a specific object. */
|
|
2555
|
+
panToObject
|
|
2407
2556
|
},
|
|
2408
2557
|
/** Update a single object's visual style by its `data.id`. */
|
|
2409
2558
|
setObjectStyle,
|
|
@@ -2554,8 +2703,68 @@ function useCanvasClick(canvasRef, onClick, options) {
|
|
|
2554
2703
|
}, [canvasRef]);
|
|
2555
2704
|
}
|
|
2556
2705
|
|
|
2557
|
-
// src/
|
|
2706
|
+
// src/hooks/useObjectOverlay.ts
|
|
2707
|
+
var import_react7 = require("react");
|
|
2558
2708
|
var import_fabric19 = require("fabric");
|
|
2709
|
+
function useObjectOverlay(canvasRef, object, options) {
|
|
2710
|
+
const containerRef = (0, import_react7.useRef)(null);
|
|
2711
|
+
const optionsRef = (0, import_react7.useRef)(options);
|
|
2712
|
+
optionsRef.current = options;
|
|
2713
|
+
(0, import_react7.useEffect)(() => {
|
|
2714
|
+
const canvas = canvasRef.current;
|
|
2715
|
+
if (!canvas || !object) return;
|
|
2716
|
+
function update() {
|
|
2717
|
+
const el = containerRef.current;
|
|
2718
|
+
if (!el || !canvas || !object) return;
|
|
2719
|
+
const zoom = canvas.getZoom();
|
|
2720
|
+
const vt = canvas.viewportTransform;
|
|
2721
|
+
if (!vt) return;
|
|
2722
|
+
const center = object.getCenterPoint();
|
|
2723
|
+
const actualWidth = (object.width ?? 0) * (object.scaleX ?? 1);
|
|
2724
|
+
const actualHeight = (object.height ?? 0) * (object.scaleY ?? 1);
|
|
2725
|
+
const screenCoords = import_fabric19.util.transformPoint(center, vt);
|
|
2726
|
+
const screenWidth = actualWidth * zoom;
|
|
2727
|
+
const screenHeight = actualHeight * zoom;
|
|
2728
|
+
el.style.left = `${screenCoords.x - screenWidth / 2}px`;
|
|
2729
|
+
el.style.top = `${screenCoords.y - screenHeight / 2}px`;
|
|
2730
|
+
el.style.width = `${screenWidth}px`;
|
|
2731
|
+
el.style.height = `${screenHeight}px`;
|
|
2732
|
+
const angle = object.angle ?? 0;
|
|
2733
|
+
el.style.rotate = angle !== 0 ? `${angle}deg` : "";
|
|
2734
|
+
const opts = optionsRef.current;
|
|
2735
|
+
if (opts?.autoScaleContent) {
|
|
2736
|
+
const contentScale = Math.min(screenWidth, screenHeight) / 100;
|
|
2737
|
+
const clampedScale = Math.max(0.1, Math.min(contentScale, 2));
|
|
2738
|
+
el.style.setProperty("--overlay-scale", String(clampedScale));
|
|
2739
|
+
if (opts.textSelector) {
|
|
2740
|
+
const textMinScale = opts.textMinScale ?? 0.5;
|
|
2741
|
+
const textEls = el.querySelectorAll(opts.textSelector);
|
|
2742
|
+
const display = clampedScale < textMinScale ? "none" : "";
|
|
2743
|
+
textEls.forEach((t) => {
|
|
2744
|
+
t.style.display = display;
|
|
2745
|
+
});
|
|
2746
|
+
}
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
update();
|
|
2750
|
+
canvas.on("after:render", update);
|
|
2751
|
+
canvas.on("mouse:wheel", update);
|
|
2752
|
+
object.on("moving", update);
|
|
2753
|
+
object.on("scaling", update);
|
|
2754
|
+
object.on("rotating", update);
|
|
2755
|
+
return () => {
|
|
2756
|
+
canvas.off("after:render", update);
|
|
2757
|
+
canvas.off("mouse:wheel", update);
|
|
2758
|
+
object.off("moving", update);
|
|
2759
|
+
object.off("scaling", update);
|
|
2760
|
+
object.off("rotating", update);
|
|
2761
|
+
};
|
|
2762
|
+
}, [canvasRef, object]);
|
|
2763
|
+
return containerRef;
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
// src/index.ts
|
|
2767
|
+
var import_fabric20 = require("fabric");
|
|
2559
2768
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2560
2769
|
0 && (module.exports = {
|
|
2561
2770
|
Canvas,
|
|
@@ -2568,6 +2777,7 @@ var import_fabric19 = require("fabric");
|
|
|
2568
2777
|
FabricCanvas,
|
|
2569
2778
|
FabricImage,
|
|
2570
2779
|
FabricObject,
|
|
2780
|
+
Point,
|
|
2571
2781
|
Polygon,
|
|
2572
2782
|
Rect,
|
|
2573
2783
|
createCircle,
|
|
@@ -2592,8 +2802,9 @@ var import_fabric19 = require("fabric");
|
|
|
2592
2802
|
enableScaledStrokes,
|
|
2593
2803
|
enableVertexEdit,
|
|
2594
2804
|
fitViewportToBackground,
|
|
2805
|
+
getBackgroundContrast,
|
|
2595
2806
|
getBackgroundInverted,
|
|
2596
|
-
|
|
2807
|
+
getBackgroundSrc,
|
|
2597
2808
|
getBaseStrokeWidth,
|
|
2598
2809
|
getSnapPoints,
|
|
2599
2810
|
loadCanvas,
|
|
@@ -2601,14 +2812,16 @@ var import_fabric19 = require("fabric");
|
|
|
2601
2812
|
resetViewport,
|
|
2602
2813
|
resizeImageUrl,
|
|
2603
2814
|
serializeCanvas,
|
|
2815
|
+
setBackgroundContrast,
|
|
2604
2816
|
setBackgroundImage,
|
|
2605
2817
|
setBackgroundInverted,
|
|
2606
|
-
setBackgroundOpacity,
|
|
2607
2818
|
snapCursorPoint,
|
|
2608
2819
|
useCanvasClick,
|
|
2609
2820
|
useCanvasEvents,
|
|
2610
2821
|
useCanvasTooltip,
|
|
2611
2822
|
useEditCanvas,
|
|
2612
|
-
|
|
2823
|
+
useObjectOverlay,
|
|
2824
|
+
useViewCanvas,
|
|
2825
|
+
util
|
|
2613
2826
|
});
|
|
2614
2827
|
//# sourceMappingURL=index.cjs.map
|