@markup-canvas/core 1.1.7 → 1.2.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/index.d.ts +1 -1
- package/dist/lib/MarkupCanvas.d.ts +9 -12
- package/dist/lib/actions/config/getConfig.d.ts +2 -0
- package/dist/lib/actions/index.d.ts +3 -0
- package/dist/lib/actions/pan/centerContent.d.ts +2 -0
- package/dist/lib/actions/pan/index.d.ts +6 -0
- package/dist/lib/actions/pan/panDown.d.ts +2 -0
- package/dist/lib/actions/pan/panLeft.d.ts +2 -0
- package/dist/lib/actions/pan/panRight.d.ts +2 -0
- package/dist/lib/actions/pan/panUp.d.ts +2 -0
- package/dist/lib/actions/pan/scrollToPoint.d.ts +2 -0
- package/dist/lib/actions/transform/index.d.ts +2 -0
- package/dist/lib/actions/transform/resetTransform.d.ts +2 -0
- package/dist/lib/actions/transform/updateTransform.d.ts +2 -0
- package/dist/lib/actions/ui/grid/hideGrid.d.ts +2 -0
- package/dist/lib/actions/ui/grid/index.d.ts +4 -0
- package/dist/lib/actions/ui/grid/isGridVisible.d.ts +2 -0
- package/dist/lib/actions/ui/grid/showGrid.d.ts +2 -0
- package/dist/lib/actions/ui/grid/toggleGrid.d.ts +2 -0
- package/dist/lib/actions/ui/index.d.ts +4 -0
- package/dist/lib/actions/ui/rulers/areRulersVisible.d.ts +2 -0
- package/dist/lib/actions/ui/rulers/hideRulers.d.ts +2 -0
- package/dist/lib/actions/ui/rulers/index.d.ts +4 -0
- package/dist/lib/actions/ui/rulers/showRulers.d.ts +2 -0
- package/dist/lib/actions/ui/rulers/toggleRulers.d.ts +2 -0
- package/dist/lib/actions/ui/toggleTransition.d.ts +1 -0
- package/dist/lib/actions/ui/updateThemeMode.d.ts +2 -0
- package/dist/lib/actions/zoom/index.d.ts +6 -0
- package/dist/lib/actions/zoom/resetView.d.ts +2 -0
- package/dist/lib/actions/zoom/resetViewToCenter.d.ts +3 -0
- package/dist/lib/actions/zoom/setZoom.d.ts +3 -0
- package/dist/lib/actions/zoom/zoomIn.d.ts +3 -0
- package/dist/lib/actions/zoom/zoomOut.d.ts +3 -0
- package/dist/lib/actions/zoom/zoomToPoint.d.ts +2 -0
- package/dist/lib/canvas/createCanvas.d.ts +2 -2
- package/dist/lib/canvas/fitToScreen.d.ts +2 -0
- package/dist/lib/canvas/getCanvasBounds.d.ts +2 -2
- package/dist/lib/canvas/index.d.ts +1 -1
- package/dist/lib/events/emitTransformEvents.d.ts +3 -0
- package/dist/lib/events/keyboard/handleKeyDown.d.ts +3 -2
- package/dist/lib/events/keyboard/handleKeyUp.d.ts +3 -2
- package/dist/lib/events/keyboard/setupKeyboardEvents.d.ts +3 -2
- package/dist/lib/events/mouse/createMouseDragControls.d.ts +7 -0
- package/dist/lib/events/mouse/handleClickToZoom.d.ts +3 -2
- package/dist/lib/events/mouse/handleMouseDown.d.ts +3 -2
- package/dist/lib/events/mouse/handleMouseLeave.d.ts +3 -2
- package/dist/lib/events/mouse/handleMouseMove.d.ts +3 -2
- package/dist/lib/events/mouse/handleMouseUp.d.ts +3 -2
- package/dist/lib/events/mouse/setupMouseDrag.d.ts +4 -3
- package/dist/lib/events/mouse/setupMouseEvents.d.ts +4 -3
- package/dist/lib/events/touch/handleTouchMove.d.ts +3 -2
- package/dist/lib/events/touch/setupTouchEvents.d.ts +2 -2
- package/dist/lib/events/trackpad/createTrackpadPanHandler.d.ts +2 -2
- package/dist/lib/events/utils/getAdaptiveZoomSpeed.d.ts +2 -2
- package/dist/lib/events/utils/getViewportCenter.d.ts +2 -2
- package/dist/lib/events/utils/resetDragState.d.ts +3 -2
- package/dist/lib/events/utils/updateCursor.d.ts +3 -2
- package/dist/lib/events/wheel/handleWheel.d.ts +3 -2
- package/dist/lib/events/wheel/setupWheelEvents.d.ts +3 -2
- package/dist/lib/events/wheel/setupWheelHandler.d.ts +3 -2
- package/dist/lib/helpers/getVisibleArea.d.ts +7 -0
- package/dist/lib/helpers/index.d.ts +2 -0
- package/dist/lib/helpers/isPointVisible.d.ts +2 -0
- package/dist/lib/transform/applyZoomToCanvas.d.ts +2 -2
- package/dist/lib/window/bindCanvasToWindow.d.ts +3 -0
- package/dist/lib/window/broadcastEvent.d.ts +2 -0
- package/dist/lib/window/cleanupWindowBinding.d.ts +2 -0
- package/dist/lib/window/index.d.ts +3 -0
- package/dist/markup-canvas.cjs.js +686 -530
- package/dist/markup-canvas.esm.js +686 -530
- package/dist/markup-canvas.umd.js +684 -525
- package/dist/markup-canvas.umd.min.js +1 -1
- package/dist/types/canvas.d.ts +1 -48
- package/dist/types/config.d.ts +0 -3
- package/dist/types/events.d.ts +4 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/window.d.ts +84 -0
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/lib/MarkupCanvas.ts +136 -316
- package/src/lib/actions/config/getConfig.ts +5 -0
- package/src/lib/actions/index.ts +6 -0
- package/src/lib/actions/pan/centerContent.ts +21 -0
- package/src/lib/actions/pan/index.ts +6 -0
- package/src/lib/actions/pan/panDown.ts +13 -0
- package/src/lib/actions/pan/panLeft.ts +13 -0
- package/src/lib/actions/pan/panRight.ts +13 -0
- package/src/lib/actions/pan/panUp.ts +13 -0
- package/src/lib/actions/pan/scrollToPoint.ts +27 -0
- package/src/lib/actions/transform/index.ts +2 -0
- package/src/lib/actions/transform/resetTransform.ts +11 -0
- package/src/lib/actions/transform/updateTransform.ts +9 -0
- package/src/lib/actions/ui/grid/hideGrid.ts +9 -0
- package/src/lib/actions/ui/grid/index.ts +4 -0
- package/src/lib/actions/ui/grid/isGridVisible.ts +8 -0
- package/src/lib/actions/ui/grid/showGrid.ts +9 -0
- package/src/lib/actions/ui/grid/toggleGrid.ts +9 -0
- package/src/lib/actions/ui/index.ts +4 -0
- package/src/lib/actions/ui/rulers/areRulersVisible.ts +8 -0
- package/src/lib/actions/ui/rulers/hideRulers.ts +9 -0
- package/src/lib/actions/ui/rulers/index.ts +4 -0
- package/src/lib/actions/ui/rulers/showRulers.ts +9 -0
- package/src/lib/actions/ui/rulers/toggleRulers.ts +14 -0
- package/src/lib/actions/ui/toggleTransition.ts +3 -0
- package/src/lib/actions/ui/updateThemeMode.ts +25 -0
- package/src/lib/actions/zoom/index.ts +6 -0
- package/src/lib/actions/zoom/resetView.ts +17 -0
- package/src/lib/actions/zoom/resetViewToCenter.ts +21 -0
- package/src/lib/actions/zoom/setZoom.ts +22 -0
- package/src/lib/actions/zoom/zoomIn.ts +21 -0
- package/src/lib/actions/zoom/zoomOut.ts +21 -0
- package/src/lib/actions/zoom/zoomToPoint.ts +18 -0
- package/src/lib/canvas/createCanvas.ts +6 -14
- package/src/lib/canvas/fitToScreen.ts +27 -0
- package/src/lib/canvas/getCanvasBounds.ts +3 -4
- package/src/lib/canvas/index.ts +1 -1
- package/src/lib/config/constants.ts +2 -6
- package/src/lib/config/presets/editor-preset.ts +2 -6
- package/src/lib/events/emitTransformEvents.ts +9 -0
- package/src/lib/events/keyboard/handleKeyDown.ts +3 -2
- package/src/lib/events/keyboard/handleKeyUp.ts +3 -2
- package/src/lib/events/keyboard/setupKeyboardEvents.ts +3 -2
- package/src/lib/events/mouse/createMouseDragControls.ts +21 -0
- package/src/lib/events/mouse/handleClickToZoom.ts +3 -2
- package/src/lib/events/mouse/handleMouseDown.ts +3 -2
- package/src/lib/events/mouse/handleMouseLeave.ts +3 -2
- package/src/lib/events/mouse/handleMouseMove.ts +3 -2
- package/src/lib/events/mouse/handleMouseUp.ts +3 -2
- package/src/lib/events/mouse/setupMouseDrag.ts +5 -4
- package/src/lib/events/mouse/setupMouseEvents.ts +5 -4
- package/src/lib/events/postMessage/setupPostMessageEvents.ts +10 -0
- package/src/lib/events/touch/handleTouchMove.ts +3 -2
- package/src/lib/events/touch/setupTouchEvents.ts +3 -2
- package/src/lib/events/trackpad/createTrackpadPanHandler.ts +3 -2
- package/src/lib/events/utils/getAdaptiveZoomSpeed.ts +2 -2
- package/src/lib/events/utils/getViewportCenter.ts +2 -2
- package/src/lib/events/utils/resetDragState.ts +3 -2
- package/src/lib/events/utils/updateCursor.ts +3 -2
- package/src/lib/events/wheel/handleWheel.ts +3 -2
- package/src/lib/events/wheel/setupWheelEvents.ts +3 -2
- package/src/lib/events/wheel/setupWheelHandler.ts +3 -2
- package/src/lib/helpers/getVisibleArea.ts +6 -0
- package/src/lib/helpers/index.ts +2 -0
- package/src/lib/helpers/isPointVisible.ts +7 -0
- package/src/lib/rulers/createRulers.ts +0 -1
- package/src/lib/transform/applyZoomToCanvas.ts +2 -2
- package/src/lib/window/bindCanvasToWindow.ts +128 -0
- package/src/lib/window/broadcastEvent.ts +38 -0
- package/src/lib/window/cleanupWindowBinding.ts +15 -0
- package/src/lib/window/index.ts +3 -0
- package/src/types/canvas.ts +1 -48
- package/src/types/config.ts +1 -7
- package/src/types/events.ts +7 -1
- package/src/types/index.ts +4 -2
- package/src/types/window.ts +77 -0
- package/dist/lib/canvas/config.d.ts +0 -2
- package/dist/lib/canvas/getCanvasMethods.d.ts +0 -12
- package/src/lib/canvas/config.ts +0 -29
- package/src/lib/canvas/getCanvasMethods.ts +0 -102
- /package/dist/lib/canvas/{calcVisibleArea.d.ts → calculateVisibleArea.d.ts} +0 -0
- /package/src/lib/canvas/{calcVisibleArea.ts → calculateVisibleArea.ts} +0 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.
|
|
4
|
+
* @version 1.2.0
|
|
5
5
|
*/
|
|
6
6
|
const EDITOR_PRESET = {
|
|
7
7
|
// Canvas dimensions
|
|
8
8
|
width: 4000,
|
|
9
9
|
height: 4000,
|
|
10
10
|
enableAcceleration: true,
|
|
11
|
-
// Global
|
|
12
|
-
bindToWindow: true,
|
|
11
|
+
// Global Instance Access
|
|
13
12
|
name: "canvas",
|
|
14
13
|
enablePostMessageAPI: true,
|
|
15
14
|
// Interaction controls
|
|
@@ -39,7 +38,7 @@ const EDITOR_PRESET = {
|
|
|
39
38
|
requireOptionForClickZoom: true,
|
|
40
39
|
// Visual elements
|
|
41
40
|
enableRulers: true,
|
|
42
|
-
enableGrid:
|
|
41
|
+
enableGrid: true,
|
|
43
42
|
showRulers: true,
|
|
44
43
|
showGrid: false,
|
|
45
44
|
rulerFontSize: 9,
|
|
@@ -63,72 +62,8 @@ const EDITOR_PRESET = {
|
|
|
63
62
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
64
63
|
// Theme
|
|
65
64
|
themeMode: "light",
|
|
66
|
-
// Callbacks
|
|
67
|
-
onTransformUpdate: () => { },
|
|
68
65
|
};
|
|
69
66
|
|
|
70
|
-
// Default transform values
|
|
71
|
-
const DEFAULT_ZOOM = 1.0;
|
|
72
|
-
// Validation thresholds
|
|
73
|
-
const ZOOM_CHANGE_THRESHOLD = 0.001;
|
|
74
|
-
// CSS transition values
|
|
75
|
-
const FALLBACK_TRANSITION_DURATION = 0.2;
|
|
76
|
-
// Zoom to fit padding factor
|
|
77
|
-
const ZOOM_FIT_PADDING = 0.9;
|
|
78
|
-
// CSS class names
|
|
79
|
-
const CANVAS_CONTAINER_CLASS = "canvas-container";
|
|
80
|
-
const TRANSFORM_LAYER_CLASS = "transform-layer";
|
|
81
|
-
const CONTENT_LAYER_CLASS = "content-layer";
|
|
82
|
-
|
|
83
|
-
function moveExistingContent(existingContent, contentLayer, transformLayer) {
|
|
84
|
-
existingContent.forEach((child) => {
|
|
85
|
-
if (child !== transformLayer && !child.classList.contains(TRANSFORM_LAYER_CLASS)) {
|
|
86
|
-
contentLayer.appendChild(child);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function setupContentLayer(contentLayer) {
|
|
92
|
-
contentLayer.style.position = "relative";
|
|
93
|
-
contentLayer.style.width = "100%";
|
|
94
|
-
contentLayer.style.height = "100%";
|
|
95
|
-
contentLayer.style.pointerEvents = "auto";
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Sets up the transform layer with proper styles and dimensions
|
|
99
|
-
function setupTransformLayer(transformLayer, config) {
|
|
100
|
-
transformLayer.style.position = "absolute";
|
|
101
|
-
const rulerOffset = config.rulerSize;
|
|
102
|
-
transformLayer.style.top = `${rulerOffset}px`;
|
|
103
|
-
transformLayer.style.left = `${rulerOffset}px`;
|
|
104
|
-
transformLayer.style.width = `${config.width}px`;
|
|
105
|
-
transformLayer.style.height = `${config.height}px`;
|
|
106
|
-
transformLayer.style.transformOrigin = "0 0";
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function createCanvasLayers(container, config) {
|
|
110
|
-
const existingContent = Array.from(container.children);
|
|
111
|
-
// Create or find transform layer
|
|
112
|
-
let transformLayer = container.querySelector(`.${TRANSFORM_LAYER_CLASS}`);
|
|
113
|
-
if (!transformLayer) {
|
|
114
|
-
transformLayer = document.createElement("div");
|
|
115
|
-
transformLayer.className = TRANSFORM_LAYER_CLASS;
|
|
116
|
-
container.appendChild(transformLayer);
|
|
117
|
-
}
|
|
118
|
-
setupTransformLayer(transformLayer, config);
|
|
119
|
-
// Create or find content layer
|
|
120
|
-
let contentLayer = transformLayer.querySelector(`.${CONTENT_LAYER_CLASS}`);
|
|
121
|
-
if (!contentLayer) {
|
|
122
|
-
contentLayer = document.createElement("div");
|
|
123
|
-
contentLayer.className = CONTENT_LAYER_CLASS;
|
|
124
|
-
transformLayer.appendChild(contentLayer);
|
|
125
|
-
moveExistingContent(existingContent, contentLayer, transformLayer);
|
|
126
|
-
}
|
|
127
|
-
// Set content layer properties
|
|
128
|
-
setupContentLayer(contentLayer);
|
|
129
|
-
return { transformLayer, contentLayer };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
67
|
function canvasToContent(canvasX, canvasY, matrix) {
|
|
133
68
|
if (!matrix?.inverse) {
|
|
134
69
|
return { x: canvasX, y: canvasY };
|
|
@@ -156,6 +91,19 @@ function createMatrix(scale, translateX, translateY) {
|
|
|
156
91
|
return new DOMMatrix([scale, 0, 0, scale, translateX, translateY]);
|
|
157
92
|
}
|
|
158
93
|
|
|
94
|
+
// Default transform values
|
|
95
|
+
const DEFAULT_ZOOM = 1.0;
|
|
96
|
+
// Validation thresholds
|
|
97
|
+
const ZOOM_CHANGE_THRESHOLD = 0.001;
|
|
98
|
+
// CSS transition values
|
|
99
|
+
const FALLBACK_TRANSITION_DURATION = 0.2;
|
|
100
|
+
// Zoom to fit padding factor
|
|
101
|
+
const ZOOM_FIT_PADDING = 0.9;
|
|
102
|
+
// CSS class names
|
|
103
|
+
const CANVAS_CONTAINER_CLASS = "canvas-container";
|
|
104
|
+
const TRANSFORM_LAYER_CLASS = "transform-layer";
|
|
105
|
+
const CONTENT_LAYER_CLASS = "content-layer";
|
|
106
|
+
|
|
159
107
|
function getZoomToMouseTransform(mouseX, mouseY, currentTransform, zoomFactor, config) {
|
|
160
108
|
const rulerOffset = config.enableRulers ? -config.rulerSize : 0;
|
|
161
109
|
const transform = currentTransform || {
|
|
@@ -217,6 +165,16 @@ function getEmptyBounds() {
|
|
|
217
165
|
};
|
|
218
166
|
}
|
|
219
167
|
|
|
168
|
+
function getVisibleArea(canvas) {
|
|
169
|
+
const bounds = canvas.getBounds();
|
|
170
|
+
return bounds.visibleArea;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function isPointVisible(canvas, x, y) {
|
|
174
|
+
const visibleArea = getVisibleArea(canvas);
|
|
175
|
+
return x >= visibleArea.x && x <= visibleArea.x + visibleArea.width && y >= visibleArea.y && y <= visibleArea.y + visibleArea.height;
|
|
176
|
+
}
|
|
177
|
+
|
|
220
178
|
function withClampedZoom(config, operation) {
|
|
221
179
|
const clampFunction = (scale) => clampZoom(scale, config);
|
|
222
180
|
return operation(clampFunction);
|
|
@@ -303,8 +261,7 @@ const DEFAULT_CONFIG = {
|
|
|
303
261
|
width: 8000,
|
|
304
262
|
height: 8000,
|
|
305
263
|
enableAcceleration: true,
|
|
306
|
-
// Global
|
|
307
|
-
bindToWindow: false,
|
|
264
|
+
// Global Instance Access
|
|
308
265
|
name: "markupCanvas",
|
|
309
266
|
enablePostMessageAPI: false,
|
|
310
267
|
// Interaction controls
|
|
@@ -312,7 +269,7 @@ const DEFAULT_CONFIG = {
|
|
|
312
269
|
enablePan: true,
|
|
313
270
|
enableTouch: true,
|
|
314
271
|
enableKeyboard: true,
|
|
315
|
-
bindKeyboardEventsTo: "
|
|
272
|
+
bindKeyboardEventsTo: "document",
|
|
316
273
|
// Zoom behavior
|
|
317
274
|
zoomSpeed: 1.5,
|
|
318
275
|
minZoom: 0.05,
|
|
@@ -358,14 +315,11 @@ const DEFAULT_CONFIG = {
|
|
|
358
315
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
359
316
|
// Theme
|
|
360
317
|
themeMode: "light",
|
|
361
|
-
// Callbacks
|
|
362
|
-
onTransformUpdate: () => { },
|
|
363
318
|
};
|
|
364
319
|
|
|
365
|
-
function getCanvasBounds(canvas) {
|
|
320
|
+
function getCanvasBounds(canvas, config) {
|
|
366
321
|
try {
|
|
367
322
|
const container = canvas.container;
|
|
368
|
-
const config = canvas.config;
|
|
369
323
|
const transform = canvas.transform || {
|
|
370
324
|
scale: 1.0,
|
|
371
325
|
translateX: 0,
|
|
@@ -415,37 +369,6 @@ function getCanvasBounds(canvas) {
|
|
|
415
369
|
}
|
|
416
370
|
}
|
|
417
371
|
|
|
418
|
-
function createMatrixString(matrix) {
|
|
419
|
-
return `matrix3d(${matrix.m11}, ${matrix.m12}, ${matrix.m13}, ${matrix.m14}, ${matrix.m21}, ${matrix.m22}, ${matrix.m23}, ${matrix.m24}, ${matrix.m31}, ${matrix.m32}, ${matrix.m33}, ${matrix.m34}, ${matrix.m41}, ${matrix.m42}, ${matrix.m43}, ${matrix.m44})`;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function applyTransform(element, matrix) {
|
|
423
|
-
if (!element?.style || !matrix) {
|
|
424
|
-
return false;
|
|
425
|
-
}
|
|
426
|
-
try {
|
|
427
|
-
element.style.transform = createMatrixString(matrix);
|
|
428
|
-
return true;
|
|
429
|
-
}
|
|
430
|
-
catch (error) {
|
|
431
|
-
console.warn("Transform application failed:", error);
|
|
432
|
-
return false;
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function enableHardwareAcceleration(element) {
|
|
437
|
-
try {
|
|
438
|
-
// Set CSS properties for hardware acceleration
|
|
439
|
-
element.style.transform = element.style.transform || "translateZ(0)";
|
|
440
|
-
element.style.backfaceVisibility = "hidden";
|
|
441
|
-
return true;
|
|
442
|
-
}
|
|
443
|
-
catch (error) {
|
|
444
|
-
console.error("Failed to enable hardware acceleration:", error);
|
|
445
|
-
return false;
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
372
|
function disableTransition(element, config) {
|
|
450
373
|
try {
|
|
451
374
|
if (config.enableTransition) {
|
|
@@ -497,85 +420,386 @@ function withTransition(element, config, operation) {
|
|
|
497
420
|
}
|
|
498
421
|
}
|
|
499
422
|
|
|
500
|
-
function
|
|
501
|
-
return {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
423
|
+
function centerContent(canvas, config, updateTransformFn, transformLayer) {
|
|
424
|
+
return withTransition(transformLayer, config, () => {
|
|
425
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
426
|
+
const centerX = (bounds.width - bounds.contentWidth * canvas.transform.scale) / 2;
|
|
427
|
+
const centerY = (bounds.height - bounds.contentHeight * canvas.transform.scale) / 2;
|
|
428
|
+
return updateTransformFn({
|
|
429
|
+
translateX: centerX,
|
|
430
|
+
translateY: centerY,
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function panDown(canvas, config, updateTransform) {
|
|
436
|
+
const panDistance = config.keyboardPanStep;
|
|
437
|
+
const newTransform = {
|
|
438
|
+
translateY: canvas.transform.translateY - panDistance,
|
|
439
|
+
};
|
|
440
|
+
return updateTransform(newTransform);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function panLeft(canvas, config, updateTransform) {
|
|
444
|
+
const panDistance = config.keyboardPanStep;
|
|
445
|
+
const newTransform = {
|
|
446
|
+
translateX: canvas.transform.translateX + panDistance,
|
|
447
|
+
};
|
|
448
|
+
return updateTransform(newTransform);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
function panRight(canvas, config, updateTransform) {
|
|
452
|
+
const panDistance = config.keyboardPanStep;
|
|
453
|
+
const newTransform = {
|
|
454
|
+
translateX: canvas.transform.translateX - panDistance,
|
|
455
|
+
};
|
|
456
|
+
return updateTransform(newTransform);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function panUp(canvas, config, updateTransform) {
|
|
460
|
+
const panDistance = config.keyboardPanStep;
|
|
461
|
+
const newTransform = {
|
|
462
|
+
translateY: canvas.transform.translateY + panDistance,
|
|
463
|
+
};
|
|
464
|
+
return updateTransform(newTransform);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function scrollToPoint(canvas, config, x, y, updateTransform, transformLayer) {
|
|
468
|
+
return withTransition(transformLayer, config, () => {
|
|
469
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
470
|
+
const centerX = bounds.width / 2;
|
|
471
|
+
const centerY = bounds.height / 2;
|
|
472
|
+
// Calculate new translation to center the point
|
|
473
|
+
const newTranslateX = centerX - x * canvas.transform.scale;
|
|
474
|
+
const newTranslateY = centerY - y * canvas.transform.scale;
|
|
475
|
+
return updateTransform({
|
|
476
|
+
translateX: newTranslateX,
|
|
477
|
+
translateY: newTranslateY,
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function createMatrixString(matrix) {
|
|
483
|
+
return `matrix3d(${matrix.m11}, ${matrix.m12}, ${matrix.m13}, ${matrix.m14}, ${matrix.m21}, ${matrix.m22}, ${matrix.m23}, ${matrix.m24}, ${matrix.m31}, ${matrix.m32}, ${matrix.m33}, ${matrix.m34}, ${matrix.m41}, ${matrix.m42}, ${matrix.m43}, ${matrix.m44})`;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function applyTransform(element, matrix) {
|
|
487
|
+
if (!element?.style || !matrix) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
try {
|
|
491
|
+
element.style.transform = createMatrixString(matrix);
|
|
492
|
+
return true;
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
console.warn("Transform application failed:", error);
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function enableHardwareAcceleration(element) {
|
|
501
|
+
try {
|
|
502
|
+
// Set CSS properties for hardware acceleration
|
|
503
|
+
element.style.transform = element.style.transform || "translateZ(0)";
|
|
504
|
+
element.style.backfaceVisibility = "hidden";
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
catch (error) {
|
|
508
|
+
console.error("Failed to enable hardware acceleration:", error);
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function updateTransform(canvas, newTransform) {
|
|
514
|
+
canvas.transform = { ...canvas.transform, ...newTransform };
|
|
515
|
+
const matrix = createMatrix(canvas.transform.scale, canvas.transform.translateX, canvas.transform.translateY);
|
|
516
|
+
return applyTransform(canvas.transformLayer, matrix);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function resetTransform(canvas) {
|
|
520
|
+
const resetTransformData = {
|
|
521
|
+
scale: 1.0,
|
|
522
|
+
translateX: 0,
|
|
523
|
+
translateY: 0,
|
|
524
|
+
};
|
|
525
|
+
return updateTransform(canvas, resetTransformData);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function hideGrid(rulers) {
|
|
529
|
+
if (rulers?.gridOverlay) {
|
|
530
|
+
rulers.gridOverlay.style.display = "none";
|
|
531
|
+
return true;
|
|
532
|
+
}
|
|
533
|
+
return false;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
function isGridVisible(rulers) {
|
|
537
|
+
if (rulers?.gridOverlay) {
|
|
538
|
+
return rulers.gridOverlay.style.display !== "none";
|
|
539
|
+
}
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function showGrid(rulers) {
|
|
544
|
+
if (rulers?.gridOverlay) {
|
|
545
|
+
rulers.gridOverlay.style.display = "block";
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function toggleGrid(rulers) {
|
|
552
|
+
if (rulers?.toggleGrid) {
|
|
553
|
+
rulers.toggleGrid();
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function areRulersVisible(rulers) {
|
|
560
|
+
if (rulers?.horizontalRuler) {
|
|
561
|
+
return rulers.horizontalRuler.style.display !== "none";
|
|
562
|
+
}
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function hideRulers(rulers) {
|
|
567
|
+
if (rulers) {
|
|
568
|
+
rulers.hide();
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function showRulers(rulers) {
|
|
575
|
+
if (rulers) {
|
|
576
|
+
rulers.show();
|
|
577
|
+
return true;
|
|
578
|
+
}
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
function toggleRulers(rulers, areRulersVisible) {
|
|
583
|
+
if (rulers) {
|
|
584
|
+
const isVisible = areRulersVisible();
|
|
585
|
+
if (isVisible) {
|
|
586
|
+
rulers.hide();
|
|
587
|
+
}
|
|
588
|
+
else {
|
|
589
|
+
rulers.show();
|
|
590
|
+
}
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function toggleTransition(enableTransition) {
|
|
597
|
+
return !enableTransition;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
function createMarkupCanvasConfig(options = {}) {
|
|
601
|
+
const config = {
|
|
602
|
+
...DEFAULT_CONFIG,
|
|
603
|
+
...options,
|
|
604
|
+
};
|
|
605
|
+
if (typeof config.width !== "number" || config.width <= 0) {
|
|
606
|
+
console.warn("Invalid width, using default");
|
|
607
|
+
config.width = DEFAULT_CONFIG.width;
|
|
608
|
+
}
|
|
609
|
+
if (typeof config.height !== "number" || config.height <= 0) {
|
|
610
|
+
console.warn("Invalid height, using default");
|
|
611
|
+
config.height = DEFAULT_CONFIG.height;
|
|
612
|
+
}
|
|
613
|
+
if (typeof config.zoomSpeed !== "number" || config.zoomSpeed <= 0) {
|
|
614
|
+
console.warn("Invalid zoomSpeed, using default");
|
|
615
|
+
config.zoomSpeed = DEFAULT_CONFIG.zoomSpeed;
|
|
616
|
+
}
|
|
617
|
+
if (typeof config.minZoom !== "number" || config.minZoom <= 0) {
|
|
618
|
+
console.warn("Invalid minZoom, using default");
|
|
619
|
+
config.minZoom = DEFAULT_CONFIG.minZoom;
|
|
620
|
+
}
|
|
621
|
+
if (typeof config.maxZoom !== "number" || config.maxZoom <= config.minZoom) {
|
|
622
|
+
console.warn("Invalid maxZoom, using default");
|
|
623
|
+
config.maxZoom = DEFAULT_CONFIG.maxZoom;
|
|
624
|
+
}
|
|
625
|
+
if (typeof config.keyboardPanStep !== "number" || config.keyboardPanStep <= 0) {
|
|
626
|
+
console.warn("Invalid keyboardPanStep, using default");
|
|
627
|
+
config.keyboardPanStep = DEFAULT_CONFIG.keyboardPanStep;
|
|
628
|
+
}
|
|
629
|
+
if (typeof config.keyboardFastMultiplier !== "number" || config.keyboardFastMultiplier <= 0) {
|
|
630
|
+
console.warn("Invalid keyboardFastMultiplier, using default");
|
|
631
|
+
config.keyboardFastMultiplier = DEFAULT_CONFIG.keyboardFastMultiplier;
|
|
632
|
+
}
|
|
633
|
+
if (typeof config.clickZoomLevel !== "number" || config.clickZoomLevel <= 0) {
|
|
634
|
+
console.warn("Invalid clickZoomLevel, using default");
|
|
635
|
+
config.clickZoomLevel = DEFAULT_CONFIG.clickZoomLevel;
|
|
636
|
+
}
|
|
637
|
+
if (typeof config.rulerFontSize !== "number" || config.rulerFontSize <= 0) {
|
|
638
|
+
console.warn("Invalid rulerFontSize, using default");
|
|
639
|
+
config.rulerFontSize = DEFAULT_CONFIG.rulerFontSize;
|
|
640
|
+
}
|
|
641
|
+
if (typeof config.rulerSize !== "number" || config.rulerSize <= 0) {
|
|
642
|
+
console.warn("Invalid rulerSize, using default");
|
|
643
|
+
config.rulerSize = DEFAULT_CONFIG.rulerSize;
|
|
644
|
+
}
|
|
645
|
+
return config;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function updateThemeMode(canvasContainer, config, rulers, mode) {
|
|
649
|
+
const newConfig = {
|
|
650
|
+
...config,
|
|
651
|
+
themeMode: mode,
|
|
652
|
+
};
|
|
653
|
+
const updatedConfig = createMarkupCanvasConfig(newConfig);
|
|
654
|
+
// Update canvas background color
|
|
655
|
+
const backgroundColor = getThemeValue(updatedConfig, "canvasBackgroundColor");
|
|
656
|
+
canvasContainer.style.backgroundColor = backgroundColor;
|
|
657
|
+
// Update rulers if they exist
|
|
658
|
+
if (rulers) {
|
|
659
|
+
rulers.updateTheme(updatedConfig);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
function resetView(canvas, transformLayer, config) {
|
|
664
|
+
return withTransition(transformLayer, config, () => {
|
|
665
|
+
return withRulerSize(canvas, config.rulerSize, (rulerSize) => {
|
|
666
|
+
const resetTransformData = {
|
|
667
|
+
scale: 1.0,
|
|
668
|
+
translateX: rulerSize * -1,
|
|
669
|
+
translateY: rulerSize * -1,
|
|
670
|
+
};
|
|
671
|
+
return updateTransform(canvas, resetTransformData);
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
function getViewportCenter(canvas) {
|
|
677
|
+
try {
|
|
678
|
+
const bounds = canvas.getBounds();
|
|
679
|
+
return {
|
|
680
|
+
x: bounds.width / 2,
|
|
681
|
+
y: bounds.height / 2,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
catch (error) {
|
|
685
|
+
console.warn("Failed to calculate viewport center:", error);
|
|
686
|
+
return { x: 0, y: 0 };
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function resetViewToCenter(canvas, transformLayer, config, zoomToPoint) {
|
|
691
|
+
return withTransition(transformLayer, config, () => {
|
|
692
|
+
return withClampedZoom(config, (clamp) => {
|
|
693
|
+
const newScale = clamp(1.0);
|
|
694
|
+
const center = getViewportCenter(canvas);
|
|
695
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
function setZoom(canvas, transformLayer, config, zoomToPoint, zoomLevel) {
|
|
701
|
+
return withTransition(transformLayer, config, () => {
|
|
702
|
+
return withClampedZoom(config, (clamp) => {
|
|
703
|
+
const newScale = clamp(zoomLevel);
|
|
704
|
+
const center = getViewportCenter(canvas);
|
|
705
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
706
|
+
});
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function zoomIn(canvas, transformLayer, config, zoomToPoint, factor = 0.5) {
|
|
711
|
+
return withTransition(transformLayer, config, () => {
|
|
712
|
+
return withClampedZoom(config, (clamp) => {
|
|
713
|
+
const newScale = clamp(canvas.transform.scale * (1 + factor));
|
|
714
|
+
const center = getViewportCenter(canvas);
|
|
715
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function zoomOut(canvas, transformLayer, config, zoomToPoint, factor = 0.5) {
|
|
721
|
+
return withTransition(transformLayer, config, () => {
|
|
722
|
+
return withClampedZoom(config, (clamp) => {
|
|
723
|
+
const newScale = clamp(canvas.transform.scale * (1 - factor));
|
|
724
|
+
const center = getViewportCenter(canvas);
|
|
725
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
726
|
+
});
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function zoomToPoint(canvas, transformLayer, config, x, y, targetScale) {
|
|
731
|
+
return withTransition(transformLayer, config, () => {
|
|
732
|
+
const newTransform = getZoomToMouseTransform(x, y, canvas.transform, targetScale / canvas.transform.scale, config);
|
|
733
|
+
return updateTransform(canvas, newTransform);
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
function fitToScreen(canvas, transformLayer, config) {
|
|
738
|
+
return withTransition(transformLayer, config, () => {
|
|
739
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
740
|
+
const scaleX = bounds.width / config.width;
|
|
741
|
+
const scaleY = bounds.height / config.height;
|
|
742
|
+
const fitScale = withClampedZoom(config, (clamp) => clamp(Math.min(scaleX, scaleY) * ZOOM_FIT_PADDING));
|
|
743
|
+
// Center the content
|
|
744
|
+
const scaledWidth = config.width * fitScale;
|
|
745
|
+
const scaledHeight = config.height * fitScale;
|
|
746
|
+
const centerX = (bounds.width - scaledWidth) / 2;
|
|
747
|
+
const centerY = (bounds.height - scaledHeight) / 2;
|
|
748
|
+
return updateTransform(canvas, {
|
|
749
|
+
scale: fitScale,
|
|
750
|
+
translateX: centerX,
|
|
751
|
+
translateY: centerY,
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
function moveExistingContent(existingContent, contentLayer, transformLayer) {
|
|
757
|
+
existingContent.forEach((child) => {
|
|
758
|
+
if (child !== transformLayer && !child.classList.contains(TRANSFORM_LAYER_CLASS)) {
|
|
759
|
+
contentLayer.appendChild(child);
|
|
760
|
+
}
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function setupContentLayer(contentLayer) {
|
|
765
|
+
contentLayer.style.position = "relative";
|
|
766
|
+
contentLayer.style.width = "100%";
|
|
767
|
+
contentLayer.style.height = "100%";
|
|
768
|
+
contentLayer.style.pointerEvents = "auto";
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Sets up the transform layer with proper styles and dimensions
|
|
772
|
+
function setupTransformLayer(transformLayer, config) {
|
|
773
|
+
transformLayer.style.position = "absolute";
|
|
774
|
+
const rulerOffset = config.rulerSize;
|
|
775
|
+
transformLayer.style.top = `${rulerOffset}px`;
|
|
776
|
+
transformLayer.style.left = `${rulerOffset}px`;
|
|
777
|
+
transformLayer.style.width = `${config.width}px`;
|
|
778
|
+
transformLayer.style.height = `${config.height}px`;
|
|
779
|
+
transformLayer.style.transformOrigin = "0 0";
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
function createCanvasLayers(container, config) {
|
|
783
|
+
const existingContent = Array.from(container.children);
|
|
784
|
+
// Create or find transform layer
|
|
785
|
+
let transformLayer = container.querySelector(`.${TRANSFORM_LAYER_CLASS}`);
|
|
786
|
+
if (!transformLayer) {
|
|
787
|
+
transformLayer = document.createElement("div");
|
|
788
|
+
transformLayer.className = TRANSFORM_LAYER_CLASS;
|
|
789
|
+
container.appendChild(transformLayer);
|
|
790
|
+
}
|
|
791
|
+
setupTransformLayer(transformLayer, config);
|
|
792
|
+
// Create or find content layer
|
|
793
|
+
let contentLayer = transformLayer.querySelector(`.${CONTENT_LAYER_CLASS}`);
|
|
794
|
+
if (!contentLayer) {
|
|
795
|
+
contentLayer = document.createElement("div");
|
|
796
|
+
contentLayer.className = CONTENT_LAYER_CLASS;
|
|
797
|
+
transformLayer.appendChild(contentLayer);
|
|
798
|
+
moveExistingContent(existingContent, contentLayer, transformLayer);
|
|
799
|
+
}
|
|
800
|
+
// Set content layer properties
|
|
801
|
+
setupContentLayer(contentLayer);
|
|
802
|
+
return { transformLayer, contentLayer };
|
|
579
803
|
}
|
|
580
804
|
|
|
581
805
|
function checkContainerDimensions(container) {
|
|
@@ -611,7 +835,6 @@ function setupCanvasContainer(container, config) {
|
|
|
611
835
|
}
|
|
612
836
|
}
|
|
613
837
|
|
|
614
|
-
// Creates and initializes a canvas with the required DOM structure
|
|
615
838
|
function createCanvas(container, config) {
|
|
616
839
|
if (!container?.appendChild) {
|
|
617
840
|
console.error("Invalid container element provided to createCanvas");
|
|
@@ -620,10 +843,9 @@ function createCanvas(container, config) {
|
|
|
620
843
|
try {
|
|
621
844
|
setupCanvasContainer(container, config);
|
|
622
845
|
const { transformLayer, contentLayer } = createCanvasLayers(container, config);
|
|
623
|
-
|
|
624
|
-
if (config.enableAcceleration) {
|
|
846
|
+
withFeatureEnabled(config, "enableAcceleration", () => {
|
|
625
847
|
enableHardwareAcceleration(transformLayer);
|
|
626
|
-
}
|
|
848
|
+
});
|
|
627
849
|
const rulerOffset = config.enableRulers ? -config.rulerSize : 0;
|
|
628
850
|
const initialTransform = {
|
|
629
851
|
scale: DEFAULT_ZOOM,
|
|
@@ -638,12 +860,8 @@ function createCanvas(container, config) {
|
|
|
638
860
|
container,
|
|
639
861
|
transformLayer,
|
|
640
862
|
contentLayer,
|
|
641
|
-
// Configuration
|
|
642
|
-
config: config,
|
|
643
863
|
// Current state
|
|
644
864
|
transform: initialTransform,
|
|
645
|
-
// Add all canvas methods
|
|
646
|
-
...getCanvasMethods(),
|
|
647
865
|
};
|
|
648
866
|
return canvas;
|
|
649
867
|
}
|
|
@@ -653,54 +871,6 @@ function createCanvas(container, config) {
|
|
|
653
871
|
}
|
|
654
872
|
}
|
|
655
873
|
|
|
656
|
-
function createMarkupCanvasConfig(options = {}) {
|
|
657
|
-
const config = {
|
|
658
|
-
...DEFAULT_CONFIG,
|
|
659
|
-
...options,
|
|
660
|
-
};
|
|
661
|
-
if (typeof config.width !== "number" || config.width <= 0) {
|
|
662
|
-
console.warn("Invalid width, using default");
|
|
663
|
-
config.width = DEFAULT_CONFIG.width;
|
|
664
|
-
}
|
|
665
|
-
if (typeof config.height !== "number" || config.height <= 0) {
|
|
666
|
-
console.warn("Invalid height, using default");
|
|
667
|
-
config.height = DEFAULT_CONFIG.height;
|
|
668
|
-
}
|
|
669
|
-
if (typeof config.zoomSpeed !== "number" || config.zoomSpeed <= 0) {
|
|
670
|
-
console.warn("Invalid zoomSpeed, using default");
|
|
671
|
-
config.zoomSpeed = DEFAULT_CONFIG.zoomSpeed;
|
|
672
|
-
}
|
|
673
|
-
if (typeof config.minZoom !== "number" || config.minZoom <= 0) {
|
|
674
|
-
console.warn("Invalid minZoom, using default");
|
|
675
|
-
config.minZoom = DEFAULT_CONFIG.minZoom;
|
|
676
|
-
}
|
|
677
|
-
if (typeof config.maxZoom !== "number" || config.maxZoom <= config.minZoom) {
|
|
678
|
-
console.warn("Invalid maxZoom, using default");
|
|
679
|
-
config.maxZoom = DEFAULT_CONFIG.maxZoom;
|
|
680
|
-
}
|
|
681
|
-
if (typeof config.keyboardPanStep !== "number" || config.keyboardPanStep <= 0) {
|
|
682
|
-
console.warn("Invalid keyboardPanStep, using default");
|
|
683
|
-
config.keyboardPanStep = DEFAULT_CONFIG.keyboardPanStep;
|
|
684
|
-
}
|
|
685
|
-
if (typeof config.keyboardFastMultiplier !== "number" || config.keyboardFastMultiplier <= 0) {
|
|
686
|
-
console.warn("Invalid keyboardFastMultiplier, using default");
|
|
687
|
-
config.keyboardFastMultiplier = DEFAULT_CONFIG.keyboardFastMultiplier;
|
|
688
|
-
}
|
|
689
|
-
if (typeof config.clickZoomLevel !== "number" || config.clickZoomLevel <= 0) {
|
|
690
|
-
console.warn("Invalid clickZoomLevel, using default");
|
|
691
|
-
config.clickZoomLevel = DEFAULT_CONFIG.clickZoomLevel;
|
|
692
|
-
}
|
|
693
|
-
if (typeof config.rulerFontSize !== "number" || config.rulerFontSize <= 0) {
|
|
694
|
-
console.warn("Invalid rulerFontSize, using default");
|
|
695
|
-
config.rulerFontSize = DEFAULT_CONFIG.rulerFontSize;
|
|
696
|
-
}
|
|
697
|
-
if (typeof config.rulerSize !== "number" || config.rulerSize <= 0) {
|
|
698
|
-
console.warn("Invalid rulerSize, using default");
|
|
699
|
-
config.rulerSize = DEFAULT_CONFIG.rulerSize;
|
|
700
|
-
}
|
|
701
|
-
return config;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
874
|
class EventEmitter {
|
|
705
875
|
constructor() {
|
|
706
876
|
this.listeners = new Map();
|
|
@@ -739,6 +909,13 @@ class EventEmitter {
|
|
|
739
909
|
}
|
|
740
910
|
}
|
|
741
911
|
|
|
912
|
+
function emitTransformEvents(listen, canvas) {
|
|
913
|
+
const transform = canvas.transform;
|
|
914
|
+
listen.emit("transform", transform);
|
|
915
|
+
listen.emit("zoom", transform.scale);
|
|
916
|
+
listen.emit("pan", { x: transform.translateX, y: transform.translateY });
|
|
917
|
+
}
|
|
918
|
+
|
|
742
919
|
const REFERENCE_DISPLAY_AREA = 1920 * 1080;
|
|
743
920
|
const TRACKPAD_PINCH_SPEED_FACTOR = 0.05;
|
|
744
921
|
const ADAPTIVE_ZOOM_FACTOR = 1;
|
|
@@ -1233,6 +1410,17 @@ function setupPostMessageEvents(canvas) {
|
|
|
1233
1410
|
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
1234
1411
|
canvas.updateThemeMode(newMode);
|
|
1235
1412
|
}
|
|
1413
|
+
// Transition methods
|
|
1414
|
+
else if (action === "updateTransition") {
|
|
1415
|
+
const enabled = args[0];
|
|
1416
|
+
if (typeof enabled !== "boolean") {
|
|
1417
|
+
throw new Error(`Invalid transition enabled value: ${enabled}. Must be a boolean.`);
|
|
1418
|
+
}
|
|
1419
|
+
canvas.updateTransition(enabled);
|
|
1420
|
+
}
|
|
1421
|
+
else if (action === "toggleTransitionMode") {
|
|
1422
|
+
canvas.toggleTransitionMode();
|
|
1423
|
+
}
|
|
1236
1424
|
else {
|
|
1237
1425
|
throw new Error(`Unknown action: ${action}`);
|
|
1238
1426
|
}
|
|
@@ -1468,20 +1656,6 @@ function setupWheelEvents(canvas, config) {
|
|
|
1468
1656
|
};
|
|
1469
1657
|
}
|
|
1470
1658
|
|
|
1471
|
-
function getViewportCenter(canvas) {
|
|
1472
|
-
try {
|
|
1473
|
-
const bounds = canvas.getBounds();
|
|
1474
|
-
return {
|
|
1475
|
-
x: bounds.width / 2,
|
|
1476
|
-
y: bounds.height / 2,
|
|
1477
|
-
};
|
|
1478
|
-
}
|
|
1479
|
-
catch (error) {
|
|
1480
|
-
console.warn("Failed to calculate viewport center:", error);
|
|
1481
|
-
return { x: 0, y: 0 };
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
|
|
1485
1659
|
// Rulers
|
|
1486
1660
|
const RULER_Z_INDEX = {
|
|
1487
1661
|
GRID: 100,
|
|
@@ -1844,8 +2018,6 @@ function createRulers(canvas, config) {
|
|
|
1844
2018
|
elements.verticalRuler.style.display = "block";
|
|
1845
2019
|
if (elements.cornerBox)
|
|
1846
2020
|
elements.cornerBox.style.display = "flex";
|
|
1847
|
-
if (elements.gridOverlay)
|
|
1848
|
-
elements.gridOverlay.style.display = "block";
|
|
1849
2021
|
},
|
|
1850
2022
|
hide: () => {
|
|
1851
2023
|
if (elements.horizontalRuler)
|
|
@@ -1889,14 +2061,163 @@ function createRulers(canvas, config) {
|
|
|
1889
2061
|
}
|
|
1890
2062
|
}
|
|
1891
2063
|
|
|
2064
|
+
function broadcastEvent(event, data, config) {
|
|
2065
|
+
if (typeof window === "undefined") {
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
// Receivers can get the instance from the window binding
|
|
2069
|
+
let broadcastData = data;
|
|
2070
|
+
if (event === "ready") {
|
|
2071
|
+
broadcastData = { ready: true };
|
|
2072
|
+
}
|
|
2073
|
+
window.postMessage({
|
|
2074
|
+
source: "markup-canvas",
|
|
2075
|
+
event,
|
|
2076
|
+
data: broadcastData,
|
|
2077
|
+
timestamp: Date.now(),
|
|
2078
|
+
canvasName: config.name,
|
|
2079
|
+
}, "*");
|
|
2080
|
+
if (window.parent) {
|
|
2081
|
+
window.parent.postMessage({
|
|
2082
|
+
source: "markup-canvas",
|
|
2083
|
+
event,
|
|
2084
|
+
data: broadcastData,
|
|
2085
|
+
timestamp: Date.now(),
|
|
2086
|
+
canvasName: config.name,
|
|
2087
|
+
}, "*");
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
function cleanupWindowBinding(config) {
|
|
2092
|
+
if (typeof window === "undefined") {
|
|
2093
|
+
return;
|
|
2094
|
+
}
|
|
2095
|
+
const canvasName = config.name || "markupCanvas";
|
|
2096
|
+
const windowObj = window;
|
|
2097
|
+
delete windowObj[canvasName];
|
|
2098
|
+
if (windowObj.__markupCanvasInstances) {
|
|
2099
|
+
windowObj.__markupCanvasInstances.delete(canvasName);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
function bindCanvasToWindow(canvas, config) {
|
|
2104
|
+
if (typeof window === "undefined") {
|
|
2105
|
+
return;
|
|
2106
|
+
}
|
|
2107
|
+
const canvasName = config.name || "markupCanvas";
|
|
2108
|
+
const windowObj = window;
|
|
2109
|
+
const api = {
|
|
2110
|
+
config: {
|
|
2111
|
+
get current() {
|
|
2112
|
+
return canvas.config;
|
|
2113
|
+
},
|
|
2114
|
+
get: canvas.getConfig.bind(canvas),
|
|
2115
|
+
update: canvas.updateConfig.bind(canvas),
|
|
2116
|
+
},
|
|
2117
|
+
// Transform group
|
|
2118
|
+
transform: {
|
|
2119
|
+
update: canvas.updateTransform.bind(canvas),
|
|
2120
|
+
reset: canvas.reset.bind(canvas),
|
|
2121
|
+
},
|
|
2122
|
+
// Zoom group
|
|
2123
|
+
zoom: {
|
|
2124
|
+
set: canvas.setZoom.bind(canvas),
|
|
2125
|
+
toPoint: canvas.zoomToPoint.bind(canvas),
|
|
2126
|
+
in: canvas.zoomIn.bind(canvas),
|
|
2127
|
+
out: canvas.zoomOut.bind(canvas),
|
|
2128
|
+
reset: canvas.resetZoom.bind(canvas),
|
|
2129
|
+
resetToCenter: canvas.resetViewToCenter.bind(canvas),
|
|
2130
|
+
fitToScreen: canvas.fitToScreen.bind(canvas),
|
|
2131
|
+
},
|
|
2132
|
+
// Pan group
|
|
2133
|
+
pan: {
|
|
2134
|
+
left: canvas.panLeft.bind(canvas),
|
|
2135
|
+
right: canvas.panRight.bind(canvas),
|
|
2136
|
+
up: canvas.panUp.bind(canvas),
|
|
2137
|
+
down: canvas.panDown.bind(canvas),
|
|
2138
|
+
toPoint: canvas.scrollToPoint.bind(canvas),
|
|
2139
|
+
toCenter: canvas.centerContent.bind(canvas),
|
|
2140
|
+
},
|
|
2141
|
+
// Mouse drag group
|
|
2142
|
+
mouseDrag: {
|
|
2143
|
+
enable: canvas.enableMouseDrag.bind(canvas),
|
|
2144
|
+
disable: canvas.disableMouseDrag.bind(canvas),
|
|
2145
|
+
isEnabled: canvas.isMouseDragEnabled.bind(canvas),
|
|
2146
|
+
},
|
|
2147
|
+
// Grid group
|
|
2148
|
+
grid: {
|
|
2149
|
+
toggle: canvas.toggleGrid.bind(canvas),
|
|
2150
|
+
show: canvas.showGrid.bind(canvas),
|
|
2151
|
+
hide: canvas.hideGrid.bind(canvas),
|
|
2152
|
+
isVisible: canvas.isGridVisible.bind(canvas),
|
|
2153
|
+
},
|
|
2154
|
+
// Ruler group
|
|
2155
|
+
rulers: {
|
|
2156
|
+
toggle: canvas.toggleRulers.bind(canvas),
|
|
2157
|
+
show: canvas.showRulers.bind(canvas),
|
|
2158
|
+
hide: canvas.hideRulers.bind(canvas),
|
|
2159
|
+
isVisible: canvas.areRulersVisible.bind(canvas),
|
|
2160
|
+
},
|
|
2161
|
+
// Utility group
|
|
2162
|
+
canvas: {
|
|
2163
|
+
canvasToContent: canvas.canvasToContent.bind(canvas),
|
|
2164
|
+
getVisibleArea: canvas.getVisibleArea.bind(canvas),
|
|
2165
|
+
isPointVisible: canvas.isPointVisible.bind(canvas),
|
|
2166
|
+
getBounds: canvas.getBounds.bind(canvas),
|
|
2167
|
+
},
|
|
2168
|
+
theme: {
|
|
2169
|
+
get current() {
|
|
2170
|
+
return canvas.config.themeMode;
|
|
2171
|
+
},
|
|
2172
|
+
update: canvas.updateThemeMode.bind(canvas),
|
|
2173
|
+
toggle: canvas.toggleThemeMode.bind(canvas),
|
|
2174
|
+
},
|
|
2175
|
+
transition: {
|
|
2176
|
+
get current() {
|
|
2177
|
+
return canvas.config.enableTransition;
|
|
2178
|
+
},
|
|
2179
|
+
set: canvas.updateTransition.bind(canvas),
|
|
2180
|
+
toggle: canvas.toggleTransitionMode.bind(canvas),
|
|
2181
|
+
},
|
|
2182
|
+
// Event group
|
|
2183
|
+
event: canvas.event,
|
|
2184
|
+
// Lifecycle group
|
|
2185
|
+
lifecycle: {
|
|
2186
|
+
cleanup: canvas.cleanup.bind(canvas),
|
|
2187
|
+
destroy: canvas.destroy.bind(canvas),
|
|
2188
|
+
},
|
|
2189
|
+
// Properties/State group
|
|
2190
|
+
state: {
|
|
2191
|
+
get isReady() {
|
|
2192
|
+
return canvas.isReady;
|
|
2193
|
+
},
|
|
2194
|
+
get isTransforming() {
|
|
2195
|
+
return canvas.isTransforming;
|
|
2196
|
+
},
|
|
2197
|
+
get visibleBounds() {
|
|
2198
|
+
return canvas.visibleBounds;
|
|
2199
|
+
},
|
|
2200
|
+
get transform() {
|
|
2201
|
+
return canvas.transform;
|
|
2202
|
+
},
|
|
2203
|
+
},
|
|
2204
|
+
};
|
|
2205
|
+
// Bind public API to window
|
|
2206
|
+
windowObj[canvasName] = api;
|
|
2207
|
+
// Track all instances
|
|
2208
|
+
if (!windowObj.__markupCanvasInstances) {
|
|
2209
|
+
windowObj.__markupCanvasInstances = new Map();
|
|
2210
|
+
}
|
|
2211
|
+
windowObj.__markupCanvasInstances.set(canvasName, api);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
1892
2214
|
class MarkupCanvas {
|
|
1893
2215
|
constructor(container, options = {}) {
|
|
1894
|
-
this.
|
|
2216
|
+
this.cleanupCallbacks = [];
|
|
1895
2217
|
this.rulers = null;
|
|
1896
2218
|
this.dragSetup = null;
|
|
2219
|
+
this.event = new EventEmitter();
|
|
1897
2220
|
this._isReady = false;
|
|
1898
|
-
this.listen = new EventEmitter();
|
|
1899
|
-
this.postMessageCleanup = null;
|
|
1900
2221
|
if (!container) {
|
|
1901
2222
|
throw new Error("Container element is required");
|
|
1902
2223
|
}
|
|
@@ -1905,100 +2226,48 @@ class MarkupCanvas {
|
|
|
1905
2226
|
if (!canvas) {
|
|
1906
2227
|
throw new Error("Failed to create canvas");
|
|
1907
2228
|
}
|
|
1908
|
-
this.
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
2229
|
+
this.canvas = canvas;
|
|
2230
|
+
// Always bind canvas to window
|
|
2231
|
+
this.event.setEmitInterceptor((event, data) => {
|
|
2232
|
+
broadcastEvent(event, data, this.config);
|
|
2233
|
+
});
|
|
2234
|
+
bindCanvasToWindow(this, this.config);
|
|
2235
|
+
// Set up postMessage listener
|
|
2236
|
+
if (this.config.enablePostMessageAPI) {
|
|
2237
|
+
const postMessageCleanup = setupPostMessageEvents(this);
|
|
2238
|
+
this.cleanupCallbacks.push(postMessageCleanup);
|
|
1918
2239
|
}
|
|
1919
2240
|
this.setupEventHandlers();
|
|
1920
2241
|
this._isReady = true;
|
|
1921
2242
|
// Emit ready event
|
|
1922
|
-
this.
|
|
1923
|
-
}
|
|
1924
|
-
setupGlobalBinding() {
|
|
1925
|
-
if (typeof window === "undefined") {
|
|
1926
|
-
return;
|
|
1927
|
-
}
|
|
1928
|
-
const canvasName = this.config.name || "markupCanvas";
|
|
1929
|
-
const windowObj = window;
|
|
1930
|
-
// Bind instance to window
|
|
1931
|
-
windowObj[canvasName] = this;
|
|
1932
|
-
// Track all instances
|
|
1933
|
-
if (!windowObj.__markupCanvasInstances) {
|
|
1934
|
-
windowObj.__markupCanvasInstances = new Map();
|
|
1935
|
-
}
|
|
1936
|
-
windowObj.__markupCanvasInstances.set(canvasName, this);
|
|
1937
|
-
}
|
|
1938
|
-
cleanupGlobalBinding() {
|
|
1939
|
-
if (typeof window === "undefined") {
|
|
1940
|
-
return;
|
|
1941
|
-
}
|
|
1942
|
-
const canvasName = this.config.name || "markupCanvas";
|
|
1943
|
-
const windowObj = window;
|
|
1944
|
-
delete windowObj[canvasName];
|
|
1945
|
-
if (windowObj.__markupCanvasInstances) {
|
|
1946
|
-
windowObj.__markupCanvasInstances.delete(canvasName);
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
broadcastEvent(event, data) {
|
|
1950
|
-
if (typeof window === "undefined") {
|
|
1951
|
-
return;
|
|
1952
|
-
}
|
|
1953
|
-
// Receivers can get the instance from the window binding
|
|
1954
|
-
let broadcastData = data;
|
|
1955
|
-
if (event === "ready") {
|
|
1956
|
-
broadcastData = { ready: true };
|
|
1957
|
-
}
|
|
1958
|
-
window.postMessage({
|
|
1959
|
-
source: "markup-canvas",
|
|
1960
|
-
event,
|
|
1961
|
-
data: broadcastData,
|
|
1962
|
-
timestamp: Date.now(),
|
|
1963
|
-
canvasName: this.config.name,
|
|
1964
|
-
}, "*");
|
|
1965
|
-
if (window.parent) {
|
|
1966
|
-
window.parent.postMessage({
|
|
1967
|
-
source: "markup-canvas",
|
|
1968
|
-
event,
|
|
1969
|
-
data: broadcastData,
|
|
1970
|
-
timestamp: Date.now(),
|
|
1971
|
-
canvasName: this.config.name,
|
|
1972
|
-
}, "*");
|
|
1973
|
-
}
|
|
2243
|
+
this.event.emit("ready", this);
|
|
1974
2244
|
}
|
|
1975
2245
|
setupEventHandlers() {
|
|
1976
2246
|
try {
|
|
1977
|
-
// Wheel
|
|
2247
|
+
// Wheel events
|
|
1978
2248
|
withFeatureEnabled(this.config, "enableZoom", () => {
|
|
1979
2249
|
const wheelCleanup = setupWheelEvents(this, this.config);
|
|
1980
|
-
this.
|
|
2250
|
+
this.cleanupCallbacks.push(wheelCleanup);
|
|
1981
2251
|
});
|
|
1982
|
-
// Mouse events
|
|
1983
|
-
// Set up mouse events if either pan or click-to-zoom is enabled
|
|
2252
|
+
// Mouse events
|
|
1984
2253
|
if (this.config.enablePan || this.config.enableClickToZoom) {
|
|
1985
2254
|
this.dragSetup = setupMouseEvents(this, this.config, true);
|
|
1986
|
-
this.
|
|
2255
|
+
this.cleanupCallbacks.push(this.dragSetup.cleanup);
|
|
1987
2256
|
}
|
|
1988
|
-
// Keyboard
|
|
2257
|
+
// Keyboard events
|
|
1989
2258
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
1990
2259
|
const keyboardCleanup = setupKeyboardEvents(this, this.config);
|
|
1991
|
-
this.
|
|
2260
|
+
this.cleanupCallbacks.push(keyboardCleanup);
|
|
1992
2261
|
});
|
|
1993
|
-
// Touch events
|
|
2262
|
+
// Touch events
|
|
1994
2263
|
withFeatureEnabled(this.config, "enableTouch", () => {
|
|
1995
2264
|
const touchCleanup = setupTouchEvents(this);
|
|
1996
|
-
this.
|
|
2265
|
+
this.cleanupCallbacks.push(touchCleanup);
|
|
1997
2266
|
});
|
|
1998
2267
|
// Set up rulers and grid
|
|
1999
2268
|
withFeatureEnabled(this.config, "enableRulers", () => {
|
|
2000
|
-
this.rulers = createRulers(this
|
|
2001
|
-
this.
|
|
2269
|
+
this.rulers = createRulers(this, this.config);
|
|
2270
|
+
this.cleanupCallbacks.push(() => {
|
|
2002
2271
|
if (this.rulers) {
|
|
2003
2272
|
this.rulers.destroy();
|
|
2004
2273
|
}
|
|
@@ -2011,20 +2280,18 @@ class MarkupCanvas {
|
|
|
2011
2280
|
throw error;
|
|
2012
2281
|
}
|
|
2013
2282
|
}
|
|
2014
|
-
// Base canvas properties and methods
|
|
2015
2283
|
get container() {
|
|
2016
|
-
return this.
|
|
2284
|
+
return this.canvas.container;
|
|
2017
2285
|
}
|
|
2018
2286
|
get transformLayer() {
|
|
2019
|
-
return this.
|
|
2287
|
+
return this.canvas.transformLayer;
|
|
2020
2288
|
}
|
|
2021
2289
|
get contentLayer() {
|
|
2022
|
-
return this.
|
|
2290
|
+
return this.canvas.contentLayer;
|
|
2023
2291
|
}
|
|
2024
2292
|
get transform() {
|
|
2025
|
-
return this.
|
|
2293
|
+
return this.canvas.transform;
|
|
2026
2294
|
}
|
|
2027
|
-
// State management getters for React integration
|
|
2028
2295
|
get isReady() {
|
|
2029
2296
|
return this._isReady;
|
|
2030
2297
|
}
|
|
@@ -2032,131 +2299,62 @@ class MarkupCanvas {
|
|
|
2032
2299
|
return this.dragSetup?.isEnabled() || false;
|
|
2033
2300
|
}
|
|
2034
2301
|
get visibleBounds() {
|
|
2035
|
-
return
|
|
2302
|
+
return getVisibleArea(this);
|
|
2036
2303
|
}
|
|
2037
2304
|
getBounds() {
|
|
2038
|
-
return this.
|
|
2305
|
+
return getCanvasBounds(this.canvas, this.config);
|
|
2039
2306
|
}
|
|
2040
2307
|
updateTransform(newTransform) {
|
|
2041
|
-
const result = this.
|
|
2308
|
+
const result = updateTransform(this.canvas, newTransform);
|
|
2042
2309
|
if (result) {
|
|
2043
|
-
this.
|
|
2310
|
+
emitTransformEvents(this.event, this.canvas);
|
|
2044
2311
|
}
|
|
2045
2312
|
return result;
|
|
2046
2313
|
}
|
|
2047
|
-
emitTransformEvents() {
|
|
2048
|
-
const transform = this.baseCanvas.transform;
|
|
2049
|
-
this.listen.emit("transform", transform);
|
|
2050
|
-
this.listen.emit("zoom", transform.scale);
|
|
2051
|
-
this.listen.emit("pan", { x: transform.translateX, y: transform.translateY });
|
|
2052
|
-
}
|
|
2053
2314
|
reset() {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2315
|
+
const result = resetTransform(this.canvas);
|
|
2316
|
+
if (result) {
|
|
2317
|
+
emitTransformEvents(this.event, this.canvas);
|
|
2318
|
+
}
|
|
2319
|
+
return result;
|
|
2058
2320
|
}
|
|
2059
2321
|
setZoom(zoomLevel) {
|
|
2060
|
-
return
|
|
2061
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2062
|
-
const newScale = clamp(zoomLevel);
|
|
2063
|
-
const newTransform = {
|
|
2064
|
-
scale: newScale,
|
|
2065
|
-
};
|
|
2066
|
-
return this.updateTransform(newTransform);
|
|
2067
|
-
});
|
|
2068
|
-
});
|
|
2322
|
+
return setZoom(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), zoomLevel);
|
|
2069
2323
|
}
|
|
2070
2324
|
canvasToContent(x, y) {
|
|
2071
|
-
|
|
2325
|
+
const matrix = createMatrix(this.canvas.transform.scale, this.canvas.transform.translateX, this.canvas.transform.translateY);
|
|
2326
|
+
return canvasToContent(x, y, matrix);
|
|
2072
2327
|
}
|
|
2073
2328
|
zoomToPoint(x, y, targetScale) {
|
|
2074
|
-
return
|
|
2075
|
-
const result = this.baseCanvas.zoomToPoint(x, y, targetScale);
|
|
2076
|
-
if (result) {
|
|
2077
|
-
this.emitTransformEvents();
|
|
2078
|
-
}
|
|
2079
|
-
return result;
|
|
2080
|
-
});
|
|
2329
|
+
return zoomToPoint(this.canvas, this.transformLayer, this.config, x, y, targetScale);
|
|
2081
2330
|
}
|
|
2082
2331
|
resetView() {
|
|
2083
|
-
|
|
2084
|
-
if (result) {
|
|
2085
|
-
this.emitTransformEvents();
|
|
2086
|
-
}
|
|
2087
|
-
return result;
|
|
2332
|
+
return resetView(this.canvas, this.transformLayer, this.config);
|
|
2088
2333
|
}
|
|
2089
2334
|
resetViewToCenter() {
|
|
2090
|
-
return
|
|
2091
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2092
|
-
const newScale = clamp(1.0);
|
|
2093
|
-
const center = getViewportCenter(this);
|
|
2094
|
-
const result = this.zoomToPoint(center.x, center.y, newScale);
|
|
2095
|
-
if (result) {
|
|
2096
|
-
this.emitTransformEvents();
|
|
2097
|
-
}
|
|
2098
|
-
return result;
|
|
2099
|
-
});
|
|
2100
|
-
});
|
|
2101
|
-
}
|
|
2102
|
-
zoomToFitContent() {
|
|
2103
|
-
return withTransition(this.transformLayer, this.config, () => {
|
|
2104
|
-
const result = this.baseCanvas.zoomToFitContent();
|
|
2105
|
-
if (result) {
|
|
2106
|
-
this.emitTransformEvents();
|
|
2107
|
-
}
|
|
2108
|
-
return result;
|
|
2109
|
-
});
|
|
2335
|
+
return resetViewToCenter(this, this.transformLayer, this.config, this.zoomToPoint.bind(this));
|
|
2110
2336
|
}
|
|
2111
|
-
// Pan methods
|
|
2112
2337
|
panLeft(distance) {
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
translateX: this.baseCanvas.transform.translateX + panDistance,
|
|
2116
|
-
};
|
|
2117
|
-
return this.updateTransform(newTransform);
|
|
2338
|
+
return (panLeft(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2339
|
+
(distance ? panLeft(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2118
2340
|
}
|
|
2119
2341
|
panRight(distance) {
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
translateX: this.baseCanvas.transform.translateX - panDistance,
|
|
2123
|
-
};
|
|
2124
|
-
return this.updateTransform(newTransform);
|
|
2342
|
+
return (panRight(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2343
|
+
(distance ? panRight(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2125
2344
|
}
|
|
2126
2345
|
panUp(distance) {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
translateY: this.baseCanvas.transform.translateY + panDistance,
|
|
2130
|
-
};
|
|
2131
|
-
return this.updateTransform(newTransform);
|
|
2346
|
+
return (panUp(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2347
|
+
(distance ? panUp(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2132
2348
|
}
|
|
2133
2349
|
panDown(distance) {
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
translateY: this.baseCanvas.transform.translateY - panDistance,
|
|
2137
|
-
};
|
|
2138
|
-
return this.updateTransform(newTransform);
|
|
2350
|
+
return (panDown(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2351
|
+
(distance ? panDown(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2139
2352
|
}
|
|
2140
|
-
// Zoom methods
|
|
2141
2353
|
zoomIn(factor = 0.5) {
|
|
2142
|
-
return
|
|
2143
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2144
|
-
const newScale = clamp(this.baseCanvas.transform.scale * (1 + factor));
|
|
2145
|
-
// Get the center of the viewport
|
|
2146
|
-
const center = getViewportCenter(this);
|
|
2147
|
-
return this.zoomToPoint(center.x, center.y, newScale);
|
|
2148
|
-
});
|
|
2149
|
-
});
|
|
2354
|
+
return zoomIn(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), factor);
|
|
2150
2355
|
}
|
|
2151
2356
|
zoomOut(factor = 0.5) {
|
|
2152
|
-
return
|
|
2153
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2154
|
-
const newScale = clamp(this.baseCanvas.transform.scale * (1 - factor));
|
|
2155
|
-
// Get the center of the viewport
|
|
2156
|
-
const center = getViewportCenter(this);
|
|
2157
|
-
return this.zoomToPoint(center.x, center.y, newScale);
|
|
2158
|
-
});
|
|
2159
|
-
});
|
|
2357
|
+
return zoomOut(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), factor);
|
|
2160
2358
|
}
|
|
2161
2359
|
resetZoom() {
|
|
2162
2360
|
return this.resetViewToCenter();
|
|
@@ -2171,110 +2369,68 @@ class MarkupCanvas {
|
|
|
2171
2369
|
isMouseDragEnabled() {
|
|
2172
2370
|
return this.dragSetup?.isEnabled() ?? false;
|
|
2173
2371
|
}
|
|
2174
|
-
// Grid control methods
|
|
2175
2372
|
toggleGrid() {
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2373
|
+
const result = toggleGrid(this.rulers);
|
|
2374
|
+
if (result) {
|
|
2375
|
+
this.event.emit("gridVisibility", this.isGridVisible());
|
|
2179
2376
|
}
|
|
2180
|
-
return
|
|
2377
|
+
return result;
|
|
2181
2378
|
}
|
|
2182
2379
|
showGrid() {
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2380
|
+
const result = showGrid(this.rulers);
|
|
2381
|
+
if (result) {
|
|
2382
|
+
this.event.emit("gridVisibility", true);
|
|
2186
2383
|
}
|
|
2187
|
-
return
|
|
2384
|
+
return result;
|
|
2188
2385
|
}
|
|
2189
2386
|
hideGrid() {
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2387
|
+
const result = hideGrid(this.rulers);
|
|
2388
|
+
if (result) {
|
|
2389
|
+
this.event.emit("gridVisibility", false);
|
|
2193
2390
|
}
|
|
2194
|
-
return
|
|
2391
|
+
return result;
|
|
2195
2392
|
}
|
|
2196
2393
|
isGridVisible() {
|
|
2197
|
-
|
|
2198
|
-
return this.rulers.gridOverlay.style.display !== "none";
|
|
2199
|
-
}
|
|
2200
|
-
return false;
|
|
2394
|
+
return isGridVisible(this.rulers);
|
|
2201
2395
|
}
|
|
2202
|
-
// Ruler control methods
|
|
2203
2396
|
toggleRulers() {
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
this.rulers.hide();
|
|
2208
|
-
}
|
|
2209
|
-
else {
|
|
2210
|
-
this.rulers.show();
|
|
2211
|
-
}
|
|
2212
|
-
return true;
|
|
2397
|
+
const result = toggleRulers(this.rulers, () => this.areRulersVisible());
|
|
2398
|
+
if (result) {
|
|
2399
|
+
this.event.emit("rulersVisibility", this.areRulersVisible());
|
|
2213
2400
|
}
|
|
2214
|
-
return
|
|
2401
|
+
return result;
|
|
2215
2402
|
}
|
|
2216
2403
|
showRulers() {
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2404
|
+
const result = showRulers(this.rulers);
|
|
2405
|
+
if (result) {
|
|
2406
|
+
this.event.emit("rulersVisibility", true);
|
|
2220
2407
|
}
|
|
2221
|
-
return
|
|
2408
|
+
return result;
|
|
2222
2409
|
}
|
|
2223
2410
|
hideRulers() {
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2411
|
+
const result = hideRulers(this.rulers);
|
|
2412
|
+
if (result) {
|
|
2413
|
+
this.event.emit("rulersVisibility", false);
|
|
2227
2414
|
}
|
|
2228
|
-
return
|
|
2415
|
+
return result;
|
|
2229
2416
|
}
|
|
2230
2417
|
areRulersVisible() {
|
|
2231
|
-
|
|
2232
|
-
return this.rulers.horizontalRuler.style.display !== "none";
|
|
2233
|
-
}
|
|
2234
|
-
return false;
|
|
2418
|
+
return areRulersVisible(this.rulers);
|
|
2235
2419
|
}
|
|
2236
|
-
// Utility methods
|
|
2237
2420
|
centerContent() {
|
|
2238
|
-
return
|
|
2239
|
-
const bounds = this.baseCanvas.getBounds();
|
|
2240
|
-
const centerX = (bounds.width - bounds.contentWidth * this.baseCanvas.transform.scale) / 2;
|
|
2241
|
-
const centerY = (bounds.height - bounds.contentHeight * this.baseCanvas.transform.scale) / 2;
|
|
2242
|
-
return this.updateTransform({
|
|
2243
|
-
translateX: centerX,
|
|
2244
|
-
translateY: centerY,
|
|
2245
|
-
});
|
|
2246
|
-
});
|
|
2421
|
+
return centerContent(this.canvas, this.config, this.updateTransform.bind(this), this.transformLayer);
|
|
2247
2422
|
}
|
|
2248
2423
|
fitToScreen() {
|
|
2249
|
-
return
|
|
2250
|
-
const result = this.baseCanvas.zoomToFitContent();
|
|
2251
|
-
if (result) {
|
|
2252
|
-
this.emitTransformEvents();
|
|
2253
|
-
}
|
|
2254
|
-
return result;
|
|
2255
|
-
});
|
|
2424
|
+
return fitToScreen(this.canvas, this.transformLayer, this.config);
|
|
2256
2425
|
}
|
|
2257
2426
|
getVisibleArea() {
|
|
2258
|
-
|
|
2259
|
-
return bounds.visibleArea;
|
|
2427
|
+
return getVisibleArea(this);
|
|
2260
2428
|
}
|
|
2261
2429
|
isPointVisible(x, y) {
|
|
2262
|
-
|
|
2263
|
-
return x >= visibleArea.x && x <= visibleArea.x + visibleArea.width && y >= visibleArea.y && y <= visibleArea.y + visibleArea.height;
|
|
2430
|
+
return isPointVisible(this, x, y);
|
|
2264
2431
|
}
|
|
2265
2432
|
scrollToPoint(x, y) {
|
|
2266
|
-
return
|
|
2267
|
-
const bounds = this.baseCanvas.getBounds();
|
|
2268
|
-
const centerX = bounds.width / 2;
|
|
2269
|
-
const centerY = bounds.height / 2;
|
|
2270
|
-
// Calculate new translation to center the point
|
|
2271
|
-
const newTranslateX = centerX - x * this.baseCanvas.transform.scale;
|
|
2272
|
-
const newTranslateY = centerY - y * this.baseCanvas.transform.scale;
|
|
2273
|
-
return this.updateTransform({
|
|
2274
|
-
translateX: newTranslateX,
|
|
2275
|
-
translateY: newTranslateY,
|
|
2276
|
-
});
|
|
2277
|
-
});
|
|
2433
|
+
return scrollToPoint(this.canvas, this.config, x, y, this.updateTransform.bind(this), this.transformLayer);
|
|
2278
2434
|
}
|
|
2279
2435
|
// Configuration access
|
|
2280
2436
|
getConfig() {
|
|
@@ -2285,28 +2441,28 @@ class MarkupCanvas {
|
|
|
2285
2441
|
}
|
|
2286
2442
|
// Theme management
|
|
2287
2443
|
updateThemeMode(mode) {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
this.config
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
}
|
|
2444
|
+
this.config = createMarkupCanvasConfig({ ...this.config, themeMode: mode });
|
|
2445
|
+
updateThemeMode(this.canvas.container, this.config, this.rulers, mode);
|
|
2446
|
+
}
|
|
2447
|
+
toggleThemeMode() {
|
|
2448
|
+
const currentMode = this.config.themeMode;
|
|
2449
|
+
const newMode = currentMode === "light" ? "dark" : "light";
|
|
2450
|
+
this.updateThemeMode(newMode);
|
|
2451
|
+
return newMode;
|
|
2452
|
+
}
|
|
2453
|
+
// Transition management
|
|
2454
|
+
updateTransition(enabled) {
|
|
2455
|
+
this.config = createMarkupCanvasConfig({ ...this.config, enableTransition: enabled });
|
|
2456
|
+
}
|
|
2457
|
+
toggleTransitionMode() {
|
|
2458
|
+
const newEnableTransition = toggleTransition(this.config.enableTransition);
|
|
2459
|
+
this.updateTransition(newEnableTransition);
|
|
2460
|
+
return newEnableTransition;
|
|
2300
2461
|
}
|
|
2301
2462
|
// Cleanup method
|
|
2302
2463
|
cleanup() {
|
|
2303
|
-
this.
|
|
2304
|
-
|
|
2305
|
-
if (this.postMessageCleanup) {
|
|
2306
|
-
this.postMessageCleanup();
|
|
2307
|
-
this.postMessageCleanup = null;
|
|
2308
|
-
}
|
|
2309
|
-
this.cleanupFunctions.forEach((cleanup) => {
|
|
2464
|
+
cleanupWindowBinding(this.config);
|
|
2465
|
+
this.cleanupCallbacks.forEach((cleanup) => {
|
|
2310
2466
|
try {
|
|
2311
2467
|
cleanup();
|
|
2312
2468
|
}
|
|
@@ -2314,22 +2470,22 @@ class MarkupCanvas {
|
|
|
2314
2470
|
console.warn("Error during cleanup:", cleanupError);
|
|
2315
2471
|
}
|
|
2316
2472
|
});
|
|
2317
|
-
this.
|
|
2473
|
+
this.cleanupCallbacks = [];
|
|
2318
2474
|
// Remove all event listeners
|
|
2319
2475
|
this.removeAllListeners();
|
|
2320
2476
|
}
|
|
2321
2477
|
// Event emitter delegation methods
|
|
2322
2478
|
on(event, handler) {
|
|
2323
|
-
this.
|
|
2479
|
+
this.event.on(event, handler);
|
|
2324
2480
|
}
|
|
2325
2481
|
off(event, handler) {
|
|
2326
|
-
this.
|
|
2482
|
+
this.event.off(event, handler);
|
|
2327
2483
|
}
|
|
2328
2484
|
emit(event, data) {
|
|
2329
|
-
this.
|
|
2485
|
+
this.event.emit(event, data);
|
|
2330
2486
|
}
|
|
2331
2487
|
removeAllListeners() {
|
|
2332
|
-
this.
|
|
2488
|
+
this.event.removeAllListeners();
|
|
2333
2489
|
}
|
|
2334
2490
|
destroy() {
|
|
2335
2491
|
this.cleanup();
|