@markup-canvas/core 1.1.7 → 1.2.1
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 +689 -529
- package/dist/markup-canvas.esm.js +689 -529
- package/dist/markup-canvas.umd.js +687 -524
- 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 +139 -315
- 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,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.1
|
|
4
|
+
* @version 1.2.1
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -9,68 +9,6 @@
|
|
|
9
9
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.MarkupCanvas = factory());
|
|
10
10
|
})(this, (function () { 'use strict';
|
|
11
11
|
|
|
12
|
-
// Default transform values
|
|
13
|
-
const DEFAULT_ZOOM = 1.0;
|
|
14
|
-
// Validation thresholds
|
|
15
|
-
const ZOOM_CHANGE_THRESHOLD = 0.001;
|
|
16
|
-
// CSS transition values
|
|
17
|
-
const FALLBACK_TRANSITION_DURATION = 0.2;
|
|
18
|
-
// Zoom to fit padding factor
|
|
19
|
-
const ZOOM_FIT_PADDING = 0.9;
|
|
20
|
-
// CSS class names
|
|
21
|
-
const CANVAS_CONTAINER_CLASS = "canvas-container";
|
|
22
|
-
const TRANSFORM_LAYER_CLASS = "transform-layer";
|
|
23
|
-
const CONTENT_LAYER_CLASS = "content-layer";
|
|
24
|
-
|
|
25
|
-
function moveExistingContent(existingContent, contentLayer, transformLayer) {
|
|
26
|
-
existingContent.forEach((child) => {
|
|
27
|
-
if (child !== transformLayer && !child.classList.contains(TRANSFORM_LAYER_CLASS)) {
|
|
28
|
-
contentLayer.appendChild(child);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function setupContentLayer(contentLayer) {
|
|
34
|
-
contentLayer.style.position = "relative";
|
|
35
|
-
contentLayer.style.width = "100%";
|
|
36
|
-
contentLayer.style.height = "100%";
|
|
37
|
-
contentLayer.style.pointerEvents = "auto";
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Sets up the transform layer with proper styles and dimensions
|
|
41
|
-
function setupTransformLayer(transformLayer, config) {
|
|
42
|
-
transformLayer.style.position = "absolute";
|
|
43
|
-
const rulerOffset = config.rulerSize;
|
|
44
|
-
transformLayer.style.top = `${rulerOffset}px`;
|
|
45
|
-
transformLayer.style.left = `${rulerOffset}px`;
|
|
46
|
-
transformLayer.style.width = `${config.width}px`;
|
|
47
|
-
transformLayer.style.height = `${config.height}px`;
|
|
48
|
-
transformLayer.style.transformOrigin = "0 0";
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function createCanvasLayers(container, config) {
|
|
52
|
-
const existingContent = Array.from(container.children);
|
|
53
|
-
// Create or find transform layer
|
|
54
|
-
let transformLayer = container.querySelector(`.${TRANSFORM_LAYER_CLASS}`);
|
|
55
|
-
if (!transformLayer) {
|
|
56
|
-
transformLayer = document.createElement("div");
|
|
57
|
-
transformLayer.className = TRANSFORM_LAYER_CLASS;
|
|
58
|
-
container.appendChild(transformLayer);
|
|
59
|
-
}
|
|
60
|
-
setupTransformLayer(transformLayer, config);
|
|
61
|
-
// Create or find content layer
|
|
62
|
-
let contentLayer = transformLayer.querySelector(`.${CONTENT_LAYER_CLASS}`);
|
|
63
|
-
if (!contentLayer) {
|
|
64
|
-
contentLayer = document.createElement("div");
|
|
65
|
-
contentLayer.className = CONTENT_LAYER_CLASS;
|
|
66
|
-
transformLayer.appendChild(contentLayer);
|
|
67
|
-
moveExistingContent(existingContent, contentLayer, transformLayer);
|
|
68
|
-
}
|
|
69
|
-
// Set content layer properties
|
|
70
|
-
setupContentLayer(contentLayer);
|
|
71
|
-
return { transformLayer, contentLayer };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
12
|
function canvasToContent(canvasX, canvasY, matrix) {
|
|
75
13
|
if (!matrix?.inverse) {
|
|
76
14
|
return { x: canvasX, y: canvasY };
|
|
@@ -98,6 +36,19 @@
|
|
|
98
36
|
return new DOMMatrix([scale, 0, 0, scale, translateX, translateY]);
|
|
99
37
|
}
|
|
100
38
|
|
|
39
|
+
// Default transform values
|
|
40
|
+
const DEFAULT_ZOOM = 1.0;
|
|
41
|
+
// Validation thresholds
|
|
42
|
+
const ZOOM_CHANGE_THRESHOLD = 0.001;
|
|
43
|
+
// CSS transition values
|
|
44
|
+
const FALLBACK_TRANSITION_DURATION = 0.2;
|
|
45
|
+
// Zoom to fit padding factor
|
|
46
|
+
const ZOOM_FIT_PADDING = 0.9;
|
|
47
|
+
// CSS class names
|
|
48
|
+
const CANVAS_CONTAINER_CLASS = "canvas-container";
|
|
49
|
+
const TRANSFORM_LAYER_CLASS = "transform-layer";
|
|
50
|
+
const CONTENT_LAYER_CLASS = "content-layer";
|
|
51
|
+
|
|
101
52
|
function getZoomToMouseTransform(mouseX, mouseY, currentTransform, zoomFactor, config) {
|
|
102
53
|
const rulerOffset = config.enableRulers ? -config.rulerSize : 0;
|
|
103
54
|
const transform = currentTransform || {
|
|
@@ -159,6 +110,16 @@
|
|
|
159
110
|
};
|
|
160
111
|
}
|
|
161
112
|
|
|
113
|
+
function getVisibleArea(canvas) {
|
|
114
|
+
const bounds = canvas.getBounds();
|
|
115
|
+
return bounds.visibleArea;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function isPointVisible(canvas, x, y) {
|
|
119
|
+
const visibleArea = getVisibleArea(canvas);
|
|
120
|
+
return x >= visibleArea.x && x <= visibleArea.x + visibleArea.width && y >= visibleArea.y && y <= visibleArea.y + visibleArea.height;
|
|
121
|
+
}
|
|
122
|
+
|
|
162
123
|
function withClampedZoom(config, operation) {
|
|
163
124
|
const clampFunction = (scale) => clampZoom(scale, config);
|
|
164
125
|
return operation(clampFunction);
|
|
@@ -245,8 +206,7 @@
|
|
|
245
206
|
width: 8000,
|
|
246
207
|
height: 8000,
|
|
247
208
|
enableAcceleration: true,
|
|
248
|
-
// Global
|
|
249
|
-
bindToWindow: false,
|
|
209
|
+
// Global Instance Access
|
|
250
210
|
name: "markupCanvas",
|
|
251
211
|
enablePostMessageAPI: false,
|
|
252
212
|
// Interaction controls
|
|
@@ -254,7 +214,7 @@
|
|
|
254
214
|
enablePan: true,
|
|
255
215
|
enableTouch: true,
|
|
256
216
|
enableKeyboard: true,
|
|
257
|
-
bindKeyboardEventsTo: "
|
|
217
|
+
bindKeyboardEventsTo: "document",
|
|
258
218
|
// Zoom behavior
|
|
259
219
|
zoomSpeed: 1.5,
|
|
260
220
|
minZoom: 0.05,
|
|
@@ -300,14 +260,11 @@
|
|
|
300
260
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
301
261
|
// Theme
|
|
302
262
|
themeMode: "light",
|
|
303
|
-
// Callbacks
|
|
304
|
-
onTransformUpdate: () => { },
|
|
305
263
|
};
|
|
306
264
|
|
|
307
|
-
function getCanvasBounds(canvas) {
|
|
265
|
+
function getCanvasBounds(canvas, config) {
|
|
308
266
|
try {
|
|
309
267
|
const container = canvas.container;
|
|
310
|
-
const config = canvas.config;
|
|
311
268
|
const transform = canvas.transform || {
|
|
312
269
|
scale: 1.0,
|
|
313
270
|
translateX: 0,
|
|
@@ -357,37 +314,6 @@
|
|
|
357
314
|
}
|
|
358
315
|
}
|
|
359
316
|
|
|
360
|
-
function createMatrixString(matrix) {
|
|
361
|
-
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})`;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
function applyTransform(element, matrix) {
|
|
365
|
-
if (!element?.style || !matrix) {
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
try {
|
|
369
|
-
element.style.transform = createMatrixString(matrix);
|
|
370
|
-
return true;
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
console.warn("Transform application failed:", error);
|
|
374
|
-
return false;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function enableHardwareAcceleration(element) {
|
|
379
|
-
try {
|
|
380
|
-
// Set CSS properties for hardware acceleration
|
|
381
|
-
element.style.transform = element.style.transform || "translateZ(0)";
|
|
382
|
-
element.style.backfaceVisibility = "hidden";
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
catch (error) {
|
|
386
|
-
console.error("Failed to enable hardware acceleration:", error);
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
317
|
function disableTransition(element, config) {
|
|
392
318
|
try {
|
|
393
319
|
if (config.enableTransition) {
|
|
@@ -439,85 +365,386 @@
|
|
|
439
365
|
}
|
|
440
366
|
}
|
|
441
367
|
|
|
442
|
-
function
|
|
443
|
-
return {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
368
|
+
function centerContent(canvas, config, updateTransformFn, transformLayer) {
|
|
369
|
+
return withTransition(transformLayer, config, () => {
|
|
370
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
371
|
+
const centerX = (bounds.width - bounds.contentWidth * canvas.transform.scale) / 2;
|
|
372
|
+
const centerY = (bounds.height - bounds.contentHeight * canvas.transform.scale) / 2;
|
|
373
|
+
return updateTransformFn({
|
|
374
|
+
translateX: centerX,
|
|
375
|
+
translateY: centerY,
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function panDown(canvas, config, updateTransform) {
|
|
381
|
+
const panDistance = config.keyboardPanStep;
|
|
382
|
+
const newTransform = {
|
|
383
|
+
translateY: canvas.transform.translateY - panDistance,
|
|
384
|
+
};
|
|
385
|
+
return updateTransform(newTransform);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function panLeft(canvas, config, updateTransform) {
|
|
389
|
+
const panDistance = config.keyboardPanStep;
|
|
390
|
+
const newTransform = {
|
|
391
|
+
translateX: canvas.transform.translateX + panDistance,
|
|
392
|
+
};
|
|
393
|
+
return updateTransform(newTransform);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function panRight(canvas, config, updateTransform) {
|
|
397
|
+
const panDistance = config.keyboardPanStep;
|
|
398
|
+
const newTransform = {
|
|
399
|
+
translateX: canvas.transform.translateX - panDistance,
|
|
400
|
+
};
|
|
401
|
+
return updateTransform(newTransform);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function panUp(canvas, config, updateTransform) {
|
|
405
|
+
const panDistance = config.keyboardPanStep;
|
|
406
|
+
const newTransform = {
|
|
407
|
+
translateY: canvas.transform.translateY + panDistance,
|
|
408
|
+
};
|
|
409
|
+
return updateTransform(newTransform);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function scrollToPoint(canvas, config, x, y, updateTransform, transformLayer) {
|
|
413
|
+
return withTransition(transformLayer, config, () => {
|
|
414
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
415
|
+
const centerX = bounds.width / 2;
|
|
416
|
+
const centerY = bounds.height / 2;
|
|
417
|
+
// Calculate new translation to center the point
|
|
418
|
+
const newTranslateX = centerX - x * canvas.transform.scale;
|
|
419
|
+
const newTranslateY = centerY - y * canvas.transform.scale;
|
|
420
|
+
return updateTransform({
|
|
421
|
+
translateX: newTranslateX,
|
|
422
|
+
translateY: newTranslateY,
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function createMatrixString(matrix) {
|
|
428
|
+
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})`;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function applyTransform(element, matrix) {
|
|
432
|
+
if (!element?.style || !matrix) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
try {
|
|
436
|
+
element.style.transform = createMatrixString(matrix);
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
console.warn("Transform application failed:", error);
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function enableHardwareAcceleration(element) {
|
|
446
|
+
try {
|
|
447
|
+
// Set CSS properties for hardware acceleration
|
|
448
|
+
element.style.transform = element.style.transform || "translateZ(0)";
|
|
449
|
+
element.style.backfaceVisibility = "hidden";
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
catch (error) {
|
|
453
|
+
console.error("Failed to enable hardware acceleration:", error);
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function updateTransform(canvas, newTransform) {
|
|
459
|
+
canvas.transform = { ...canvas.transform, ...newTransform };
|
|
460
|
+
const matrix = createMatrix(canvas.transform.scale, canvas.transform.translateX, canvas.transform.translateY);
|
|
461
|
+
return applyTransform(canvas.transformLayer, matrix);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function resetTransform(canvas) {
|
|
465
|
+
const resetTransformData = {
|
|
466
|
+
scale: 1.0,
|
|
467
|
+
translateX: 0,
|
|
468
|
+
translateY: 0,
|
|
469
|
+
};
|
|
470
|
+
return updateTransform(canvas, resetTransformData);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function hideGrid(rulers) {
|
|
474
|
+
if (rulers?.gridOverlay) {
|
|
475
|
+
rulers.gridOverlay.style.display = "none";
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function isGridVisible(rulers) {
|
|
482
|
+
if (rulers?.gridOverlay) {
|
|
483
|
+
return rulers.gridOverlay.style.display !== "none";
|
|
484
|
+
}
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function showGrid(rulers) {
|
|
489
|
+
if (rulers?.gridOverlay) {
|
|
490
|
+
rulers.gridOverlay.style.display = "block";
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function toggleGrid(rulers) {
|
|
497
|
+
if (rulers?.toggleGrid) {
|
|
498
|
+
rulers.toggleGrid();
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function areRulersVisible(rulers) {
|
|
505
|
+
if (rulers?.horizontalRuler) {
|
|
506
|
+
return rulers.horizontalRuler.style.display !== "none";
|
|
507
|
+
}
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function hideRulers(rulers) {
|
|
512
|
+
if (rulers) {
|
|
513
|
+
rulers.hide();
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function showRulers(rulers) {
|
|
520
|
+
if (rulers) {
|
|
521
|
+
rulers.show();
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
function toggleRulers(rulers, areRulersVisible) {
|
|
528
|
+
if (rulers) {
|
|
529
|
+
const isVisible = areRulersVisible();
|
|
530
|
+
if (isVisible) {
|
|
531
|
+
rulers.hide();
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
rulers.show();
|
|
535
|
+
}
|
|
536
|
+
return true;
|
|
537
|
+
}
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function toggleTransition(enableTransition) {
|
|
542
|
+
return !enableTransition;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function createMarkupCanvasConfig(options = {}) {
|
|
546
|
+
const config = {
|
|
547
|
+
...DEFAULT_CONFIG,
|
|
548
|
+
...options,
|
|
549
|
+
};
|
|
550
|
+
if (typeof config.width !== "number" || config.width <= 0) {
|
|
551
|
+
console.warn("Invalid width, using default");
|
|
552
|
+
config.width = DEFAULT_CONFIG.width;
|
|
553
|
+
}
|
|
554
|
+
if (typeof config.height !== "number" || config.height <= 0) {
|
|
555
|
+
console.warn("Invalid height, using default");
|
|
556
|
+
config.height = DEFAULT_CONFIG.height;
|
|
557
|
+
}
|
|
558
|
+
if (typeof config.zoomSpeed !== "number" || config.zoomSpeed <= 0) {
|
|
559
|
+
console.warn("Invalid zoomSpeed, using default");
|
|
560
|
+
config.zoomSpeed = DEFAULT_CONFIG.zoomSpeed;
|
|
561
|
+
}
|
|
562
|
+
if (typeof config.minZoom !== "number" || config.minZoom <= 0) {
|
|
563
|
+
console.warn("Invalid minZoom, using default");
|
|
564
|
+
config.minZoom = DEFAULT_CONFIG.minZoom;
|
|
565
|
+
}
|
|
566
|
+
if (typeof config.maxZoom !== "number" || config.maxZoom <= config.minZoom) {
|
|
567
|
+
console.warn("Invalid maxZoom, using default");
|
|
568
|
+
config.maxZoom = DEFAULT_CONFIG.maxZoom;
|
|
569
|
+
}
|
|
570
|
+
if (typeof config.keyboardPanStep !== "number" || config.keyboardPanStep <= 0) {
|
|
571
|
+
console.warn("Invalid keyboardPanStep, using default");
|
|
572
|
+
config.keyboardPanStep = DEFAULT_CONFIG.keyboardPanStep;
|
|
573
|
+
}
|
|
574
|
+
if (typeof config.keyboardFastMultiplier !== "number" || config.keyboardFastMultiplier <= 0) {
|
|
575
|
+
console.warn("Invalid keyboardFastMultiplier, using default");
|
|
576
|
+
config.keyboardFastMultiplier = DEFAULT_CONFIG.keyboardFastMultiplier;
|
|
577
|
+
}
|
|
578
|
+
if (typeof config.clickZoomLevel !== "number" || config.clickZoomLevel <= 0) {
|
|
579
|
+
console.warn("Invalid clickZoomLevel, using default");
|
|
580
|
+
config.clickZoomLevel = DEFAULT_CONFIG.clickZoomLevel;
|
|
581
|
+
}
|
|
582
|
+
if (typeof config.rulerFontSize !== "number" || config.rulerFontSize <= 0) {
|
|
583
|
+
console.warn("Invalid rulerFontSize, using default");
|
|
584
|
+
config.rulerFontSize = DEFAULT_CONFIG.rulerFontSize;
|
|
585
|
+
}
|
|
586
|
+
if (typeof config.rulerSize !== "number" || config.rulerSize <= 0) {
|
|
587
|
+
console.warn("Invalid rulerSize, using default");
|
|
588
|
+
config.rulerSize = DEFAULT_CONFIG.rulerSize;
|
|
589
|
+
}
|
|
590
|
+
return config;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function updateThemeMode(canvasContainer, config, rulers, mode) {
|
|
594
|
+
const newConfig = {
|
|
595
|
+
...config,
|
|
596
|
+
themeMode: mode,
|
|
597
|
+
};
|
|
598
|
+
const updatedConfig = createMarkupCanvasConfig(newConfig);
|
|
599
|
+
// Update canvas background color
|
|
600
|
+
const backgroundColor = getThemeValue(updatedConfig, "canvasBackgroundColor");
|
|
601
|
+
canvasContainer.style.backgroundColor = backgroundColor;
|
|
602
|
+
// Update rulers if they exist
|
|
603
|
+
if (rulers) {
|
|
604
|
+
rulers.updateTheme(updatedConfig);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function resetView(canvas, transformLayer, config) {
|
|
609
|
+
return withTransition(transformLayer, config, () => {
|
|
610
|
+
return withRulerSize(canvas, config.rulerSize, (rulerSize) => {
|
|
611
|
+
const resetTransformData = {
|
|
612
|
+
scale: 1.0,
|
|
613
|
+
translateX: rulerSize * -1,
|
|
614
|
+
translateY: rulerSize * -1,
|
|
615
|
+
};
|
|
616
|
+
return updateTransform(canvas, resetTransformData);
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function getViewportCenter(canvas) {
|
|
622
|
+
try {
|
|
623
|
+
const bounds = canvas.getBounds();
|
|
624
|
+
return {
|
|
625
|
+
x: bounds.width / 2,
|
|
626
|
+
y: bounds.height / 2,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
console.warn("Failed to calculate viewport center:", error);
|
|
631
|
+
return { x: 0, y: 0 };
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
function resetViewToCenter(canvas, transformLayer, config, zoomToPoint) {
|
|
636
|
+
return withTransition(transformLayer, config, () => {
|
|
637
|
+
return withClampedZoom(config, (clamp) => {
|
|
638
|
+
const newScale = clamp(1.0);
|
|
639
|
+
const center = getViewportCenter(canvas);
|
|
640
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
641
|
+
});
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function setZoom(canvas, transformLayer, config, zoomToPoint, zoomLevel) {
|
|
646
|
+
return withTransition(transformLayer, config, () => {
|
|
647
|
+
return withClampedZoom(config, (clamp) => {
|
|
648
|
+
const newScale = clamp(zoomLevel);
|
|
649
|
+
const center = getViewportCenter(canvas);
|
|
650
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function zoomIn(canvas, transformLayer, config, zoomToPoint, factor = 0.5) {
|
|
656
|
+
return withTransition(transformLayer, config, () => {
|
|
657
|
+
return withClampedZoom(config, (clamp) => {
|
|
658
|
+
const newScale = clamp(canvas.transform.scale * (1 + factor));
|
|
659
|
+
const center = getViewportCenter(canvas);
|
|
660
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function zoomOut(canvas, transformLayer, config, zoomToPoint, factor = 0.5) {
|
|
666
|
+
return withTransition(transformLayer, config, () => {
|
|
667
|
+
return withClampedZoom(config, (clamp) => {
|
|
668
|
+
const newScale = clamp(canvas.transform.scale * (1 - factor));
|
|
669
|
+
const center = getViewportCenter(canvas);
|
|
670
|
+
return zoomToPoint(center.x, center.y, newScale);
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
function zoomToPoint(canvas, transformLayer, config, x, y, targetScale) {
|
|
676
|
+
return withTransition(transformLayer, config, () => {
|
|
677
|
+
const newTransform = getZoomToMouseTransform(x, y, canvas.transform, targetScale / canvas.transform.scale, config);
|
|
678
|
+
return updateTransform(canvas, newTransform);
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function fitToScreen(canvas, transformLayer, config) {
|
|
683
|
+
return withTransition(transformLayer, config, () => {
|
|
684
|
+
const bounds = getCanvasBounds(canvas, config);
|
|
685
|
+
const scaleX = bounds.width / config.width;
|
|
686
|
+
const scaleY = bounds.height / config.height;
|
|
687
|
+
const fitScale = withClampedZoom(config, (clamp) => clamp(Math.min(scaleX, scaleY) * ZOOM_FIT_PADDING));
|
|
688
|
+
// Center the content
|
|
689
|
+
const scaledWidth = config.width * fitScale;
|
|
690
|
+
const scaledHeight = config.height * fitScale;
|
|
691
|
+
const centerX = (bounds.width - scaledWidth) / 2;
|
|
692
|
+
const centerY = (bounds.height - scaledHeight) / 2;
|
|
693
|
+
return updateTransform(canvas, {
|
|
694
|
+
scale: fitScale,
|
|
695
|
+
translateX: centerX,
|
|
696
|
+
translateY: centerY,
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function moveExistingContent(existingContent, contentLayer, transformLayer) {
|
|
702
|
+
existingContent.forEach((child) => {
|
|
703
|
+
if (child !== transformLayer && !child.classList.contains(TRANSFORM_LAYER_CLASS)) {
|
|
704
|
+
contentLayer.appendChild(child);
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function setupContentLayer(contentLayer) {
|
|
710
|
+
contentLayer.style.position = "relative";
|
|
711
|
+
contentLayer.style.width = "100%";
|
|
712
|
+
contentLayer.style.height = "100%";
|
|
713
|
+
contentLayer.style.pointerEvents = "auto";
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Sets up the transform layer with proper styles and dimensions
|
|
717
|
+
function setupTransformLayer(transformLayer, config) {
|
|
718
|
+
transformLayer.style.position = "absolute";
|
|
719
|
+
const rulerOffset = config.rulerSize;
|
|
720
|
+
transformLayer.style.top = `${rulerOffset}px`;
|
|
721
|
+
transformLayer.style.left = `${rulerOffset}px`;
|
|
722
|
+
transformLayer.style.width = `${config.width}px`;
|
|
723
|
+
transformLayer.style.height = `${config.height}px`;
|
|
724
|
+
transformLayer.style.transformOrigin = "0 0";
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
function createCanvasLayers(container, config) {
|
|
728
|
+
const existingContent = Array.from(container.children);
|
|
729
|
+
// Create or find transform layer
|
|
730
|
+
let transformLayer = container.querySelector(`.${TRANSFORM_LAYER_CLASS}`);
|
|
731
|
+
if (!transformLayer) {
|
|
732
|
+
transformLayer = document.createElement("div");
|
|
733
|
+
transformLayer.className = TRANSFORM_LAYER_CLASS;
|
|
734
|
+
container.appendChild(transformLayer);
|
|
735
|
+
}
|
|
736
|
+
setupTransformLayer(transformLayer, config);
|
|
737
|
+
// Create or find content layer
|
|
738
|
+
let contentLayer = transformLayer.querySelector(`.${CONTENT_LAYER_CLASS}`);
|
|
739
|
+
if (!contentLayer) {
|
|
740
|
+
contentLayer = document.createElement("div");
|
|
741
|
+
contentLayer.className = CONTENT_LAYER_CLASS;
|
|
742
|
+
transformLayer.appendChild(contentLayer);
|
|
743
|
+
moveExistingContent(existingContent, contentLayer, transformLayer);
|
|
744
|
+
}
|
|
745
|
+
// Set content layer properties
|
|
746
|
+
setupContentLayer(contentLayer);
|
|
747
|
+
return { transformLayer, contentLayer };
|
|
521
748
|
}
|
|
522
749
|
|
|
523
750
|
function checkContainerDimensions(container) {
|
|
@@ -553,7 +780,6 @@
|
|
|
553
780
|
}
|
|
554
781
|
}
|
|
555
782
|
|
|
556
|
-
// Creates and initializes a canvas with the required DOM structure
|
|
557
783
|
function createCanvas(container, config) {
|
|
558
784
|
if (!container?.appendChild) {
|
|
559
785
|
console.error("Invalid container element provided to createCanvas");
|
|
@@ -562,10 +788,9 @@
|
|
|
562
788
|
try {
|
|
563
789
|
setupCanvasContainer(container, config);
|
|
564
790
|
const { transformLayer, contentLayer } = createCanvasLayers(container, config);
|
|
565
|
-
|
|
566
|
-
if (config.enableAcceleration) {
|
|
791
|
+
withFeatureEnabled(config, "enableAcceleration", () => {
|
|
567
792
|
enableHardwareAcceleration(transformLayer);
|
|
568
|
-
}
|
|
793
|
+
});
|
|
569
794
|
const rulerOffset = config.enableRulers ? -config.rulerSize : 0;
|
|
570
795
|
const initialTransform = {
|
|
571
796
|
scale: DEFAULT_ZOOM,
|
|
@@ -580,12 +805,8 @@
|
|
|
580
805
|
container,
|
|
581
806
|
transformLayer,
|
|
582
807
|
contentLayer,
|
|
583
|
-
// Configuration
|
|
584
|
-
config: config,
|
|
585
808
|
// Current state
|
|
586
809
|
transform: initialTransform,
|
|
587
|
-
// Add all canvas methods
|
|
588
|
-
...getCanvasMethods(),
|
|
589
810
|
};
|
|
590
811
|
return canvas;
|
|
591
812
|
}
|
|
@@ -595,54 +816,6 @@
|
|
|
595
816
|
}
|
|
596
817
|
}
|
|
597
818
|
|
|
598
|
-
function createMarkupCanvasConfig(options = {}) {
|
|
599
|
-
const config = {
|
|
600
|
-
...DEFAULT_CONFIG,
|
|
601
|
-
...options,
|
|
602
|
-
};
|
|
603
|
-
if (typeof config.width !== "number" || config.width <= 0) {
|
|
604
|
-
console.warn("Invalid width, using default");
|
|
605
|
-
config.width = DEFAULT_CONFIG.width;
|
|
606
|
-
}
|
|
607
|
-
if (typeof config.height !== "number" || config.height <= 0) {
|
|
608
|
-
console.warn("Invalid height, using default");
|
|
609
|
-
config.height = DEFAULT_CONFIG.height;
|
|
610
|
-
}
|
|
611
|
-
if (typeof config.zoomSpeed !== "number" || config.zoomSpeed <= 0) {
|
|
612
|
-
console.warn("Invalid zoomSpeed, using default");
|
|
613
|
-
config.zoomSpeed = DEFAULT_CONFIG.zoomSpeed;
|
|
614
|
-
}
|
|
615
|
-
if (typeof config.minZoom !== "number" || config.minZoom <= 0) {
|
|
616
|
-
console.warn("Invalid minZoom, using default");
|
|
617
|
-
config.minZoom = DEFAULT_CONFIG.minZoom;
|
|
618
|
-
}
|
|
619
|
-
if (typeof config.maxZoom !== "number" || config.maxZoom <= config.minZoom) {
|
|
620
|
-
console.warn("Invalid maxZoom, using default");
|
|
621
|
-
config.maxZoom = DEFAULT_CONFIG.maxZoom;
|
|
622
|
-
}
|
|
623
|
-
if (typeof config.keyboardPanStep !== "number" || config.keyboardPanStep <= 0) {
|
|
624
|
-
console.warn("Invalid keyboardPanStep, using default");
|
|
625
|
-
config.keyboardPanStep = DEFAULT_CONFIG.keyboardPanStep;
|
|
626
|
-
}
|
|
627
|
-
if (typeof config.keyboardFastMultiplier !== "number" || config.keyboardFastMultiplier <= 0) {
|
|
628
|
-
console.warn("Invalid keyboardFastMultiplier, using default");
|
|
629
|
-
config.keyboardFastMultiplier = DEFAULT_CONFIG.keyboardFastMultiplier;
|
|
630
|
-
}
|
|
631
|
-
if (typeof config.clickZoomLevel !== "number" || config.clickZoomLevel <= 0) {
|
|
632
|
-
console.warn("Invalid clickZoomLevel, using default");
|
|
633
|
-
config.clickZoomLevel = DEFAULT_CONFIG.clickZoomLevel;
|
|
634
|
-
}
|
|
635
|
-
if (typeof config.rulerFontSize !== "number" || config.rulerFontSize <= 0) {
|
|
636
|
-
console.warn("Invalid rulerFontSize, using default");
|
|
637
|
-
config.rulerFontSize = DEFAULT_CONFIG.rulerFontSize;
|
|
638
|
-
}
|
|
639
|
-
if (typeof config.rulerSize !== "number" || config.rulerSize <= 0) {
|
|
640
|
-
console.warn("Invalid rulerSize, using default");
|
|
641
|
-
config.rulerSize = DEFAULT_CONFIG.rulerSize;
|
|
642
|
-
}
|
|
643
|
-
return config;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
819
|
class EventEmitter {
|
|
647
820
|
constructor() {
|
|
648
821
|
this.listeners = new Map();
|
|
@@ -681,6 +854,13 @@
|
|
|
681
854
|
}
|
|
682
855
|
}
|
|
683
856
|
|
|
857
|
+
function emitTransformEvents(listen, canvas) {
|
|
858
|
+
const transform = canvas.transform;
|
|
859
|
+
listen.emit("transform", transform);
|
|
860
|
+
listen.emit("zoom", transform.scale);
|
|
861
|
+
listen.emit("pan", { x: transform.translateX, y: transform.translateY });
|
|
862
|
+
}
|
|
863
|
+
|
|
684
864
|
const REFERENCE_DISPLAY_AREA = 1920 * 1080;
|
|
685
865
|
const TRACKPAD_PINCH_SPEED_FACTOR = 0.05;
|
|
686
866
|
const ADAPTIVE_ZOOM_FACTOR = 1;
|
|
@@ -1175,6 +1355,17 @@
|
|
|
1175
1355
|
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
1176
1356
|
canvas.updateThemeMode(newMode);
|
|
1177
1357
|
}
|
|
1358
|
+
// Transition methods
|
|
1359
|
+
else if (action === "updateTransition") {
|
|
1360
|
+
const enabled = args[0];
|
|
1361
|
+
if (typeof enabled !== "boolean") {
|
|
1362
|
+
throw new Error(`Invalid transition enabled value: ${enabled}. Must be a boolean.`);
|
|
1363
|
+
}
|
|
1364
|
+
canvas.updateTransition(enabled);
|
|
1365
|
+
}
|
|
1366
|
+
else if (action === "toggleTransitionMode") {
|
|
1367
|
+
canvas.toggleTransitionMode();
|
|
1368
|
+
}
|
|
1178
1369
|
else {
|
|
1179
1370
|
throw new Error(`Unknown action: ${action}`);
|
|
1180
1371
|
}
|
|
@@ -1410,20 +1601,6 @@
|
|
|
1410
1601
|
};
|
|
1411
1602
|
}
|
|
1412
1603
|
|
|
1413
|
-
function getViewportCenter(canvas) {
|
|
1414
|
-
try {
|
|
1415
|
-
const bounds = canvas.getBounds();
|
|
1416
|
-
return {
|
|
1417
|
-
x: bounds.width / 2,
|
|
1418
|
-
y: bounds.height / 2,
|
|
1419
|
-
};
|
|
1420
|
-
}
|
|
1421
|
-
catch (error) {
|
|
1422
|
-
console.warn("Failed to calculate viewport center:", error);
|
|
1423
|
-
return { x: 0, y: 0 };
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
1604
|
// Rulers
|
|
1428
1605
|
const RULER_Z_INDEX = {
|
|
1429
1606
|
GRID: 100,
|
|
@@ -1786,8 +1963,6 @@
|
|
|
1786
1963
|
elements.verticalRuler.style.display = "block";
|
|
1787
1964
|
if (elements.cornerBox)
|
|
1788
1965
|
elements.cornerBox.style.display = "flex";
|
|
1789
|
-
if (elements.gridOverlay)
|
|
1790
|
-
elements.gridOverlay.style.display = "block";
|
|
1791
1966
|
},
|
|
1792
1967
|
hide: () => {
|
|
1793
1968
|
if (elements.horizontalRuler)
|
|
@@ -1831,14 +2006,163 @@
|
|
|
1831
2006
|
}
|
|
1832
2007
|
}
|
|
1833
2008
|
|
|
2009
|
+
function broadcastEvent(event, data, config) {
|
|
2010
|
+
if (typeof window === "undefined") {
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
// Receivers can get the instance from the window binding
|
|
2014
|
+
let broadcastData = data;
|
|
2015
|
+
if (event === "ready") {
|
|
2016
|
+
broadcastData = { ready: true };
|
|
2017
|
+
}
|
|
2018
|
+
window.postMessage({
|
|
2019
|
+
source: "markup-canvas",
|
|
2020
|
+
event,
|
|
2021
|
+
data: broadcastData,
|
|
2022
|
+
timestamp: Date.now(),
|
|
2023
|
+
canvasName: config.name,
|
|
2024
|
+
}, "*");
|
|
2025
|
+
if (window.parent) {
|
|
2026
|
+
window.parent.postMessage({
|
|
2027
|
+
source: "markup-canvas",
|
|
2028
|
+
event,
|
|
2029
|
+
data: broadcastData,
|
|
2030
|
+
timestamp: Date.now(),
|
|
2031
|
+
canvasName: config.name,
|
|
2032
|
+
}, "*");
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
function cleanupWindowBinding(config) {
|
|
2037
|
+
if (typeof window === "undefined") {
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
const canvasName = config.name || "markupCanvas";
|
|
2041
|
+
const windowObj = window;
|
|
2042
|
+
delete windowObj[canvasName];
|
|
2043
|
+
if (windowObj.__markupCanvasInstances) {
|
|
2044
|
+
windowObj.__markupCanvasInstances.delete(canvasName);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
function bindCanvasToWindow(canvas, config) {
|
|
2049
|
+
if (typeof window === "undefined") {
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
const canvasName = config.name || "markupCanvas";
|
|
2053
|
+
const windowObj = window;
|
|
2054
|
+
const api = {
|
|
2055
|
+
config: {
|
|
2056
|
+
get current() {
|
|
2057
|
+
return canvas.config;
|
|
2058
|
+
},
|
|
2059
|
+
get: canvas.getConfig.bind(canvas),
|
|
2060
|
+
update: canvas.updateConfig.bind(canvas),
|
|
2061
|
+
},
|
|
2062
|
+
// Transform group
|
|
2063
|
+
transform: {
|
|
2064
|
+
update: canvas.updateTransform.bind(canvas),
|
|
2065
|
+
reset: canvas.reset.bind(canvas),
|
|
2066
|
+
},
|
|
2067
|
+
// Zoom group
|
|
2068
|
+
zoom: {
|
|
2069
|
+
set: canvas.setZoom.bind(canvas),
|
|
2070
|
+
toPoint: canvas.zoomToPoint.bind(canvas),
|
|
2071
|
+
in: canvas.zoomIn.bind(canvas),
|
|
2072
|
+
out: canvas.zoomOut.bind(canvas),
|
|
2073
|
+
reset: canvas.resetZoom.bind(canvas),
|
|
2074
|
+
resetToCenter: canvas.resetViewToCenter.bind(canvas),
|
|
2075
|
+
fitToScreen: canvas.fitToScreen.bind(canvas),
|
|
2076
|
+
},
|
|
2077
|
+
// Pan group
|
|
2078
|
+
pan: {
|
|
2079
|
+
left: canvas.panLeft.bind(canvas),
|
|
2080
|
+
right: canvas.panRight.bind(canvas),
|
|
2081
|
+
up: canvas.panUp.bind(canvas),
|
|
2082
|
+
down: canvas.panDown.bind(canvas),
|
|
2083
|
+
toPoint: canvas.scrollToPoint.bind(canvas),
|
|
2084
|
+
toCenter: canvas.centerContent.bind(canvas),
|
|
2085
|
+
},
|
|
2086
|
+
// Mouse drag group
|
|
2087
|
+
mouseDrag: {
|
|
2088
|
+
enable: canvas.enableMouseDrag.bind(canvas),
|
|
2089
|
+
disable: canvas.disableMouseDrag.bind(canvas),
|
|
2090
|
+
isEnabled: canvas.isMouseDragEnabled.bind(canvas),
|
|
2091
|
+
},
|
|
2092
|
+
// Grid group
|
|
2093
|
+
grid: {
|
|
2094
|
+
toggle: canvas.toggleGrid.bind(canvas),
|
|
2095
|
+
show: canvas.showGrid.bind(canvas),
|
|
2096
|
+
hide: canvas.hideGrid.bind(canvas),
|
|
2097
|
+
isVisible: canvas.isGridVisible.bind(canvas),
|
|
2098
|
+
},
|
|
2099
|
+
// Ruler group
|
|
2100
|
+
rulers: {
|
|
2101
|
+
toggle: canvas.toggleRulers.bind(canvas),
|
|
2102
|
+
show: canvas.showRulers.bind(canvas),
|
|
2103
|
+
hide: canvas.hideRulers.bind(canvas),
|
|
2104
|
+
isVisible: canvas.areRulersVisible.bind(canvas),
|
|
2105
|
+
},
|
|
2106
|
+
// Utility group
|
|
2107
|
+
canvas: {
|
|
2108
|
+
canvasToContent: canvas.canvasToContent.bind(canvas),
|
|
2109
|
+
getVisibleArea: canvas.getVisibleArea.bind(canvas),
|
|
2110
|
+
isPointVisible: canvas.isPointVisible.bind(canvas),
|
|
2111
|
+
getBounds: canvas.getBounds.bind(canvas),
|
|
2112
|
+
},
|
|
2113
|
+
theme: {
|
|
2114
|
+
get current() {
|
|
2115
|
+
return canvas.config.themeMode;
|
|
2116
|
+
},
|
|
2117
|
+
update: canvas.updateThemeMode.bind(canvas),
|
|
2118
|
+
toggle: canvas.toggleThemeMode.bind(canvas),
|
|
2119
|
+
},
|
|
2120
|
+
transition: {
|
|
2121
|
+
get current() {
|
|
2122
|
+
return canvas.config.enableTransition;
|
|
2123
|
+
},
|
|
2124
|
+
set: canvas.updateTransition.bind(canvas),
|
|
2125
|
+
toggle: canvas.toggleTransitionMode.bind(canvas),
|
|
2126
|
+
},
|
|
2127
|
+
// Event group
|
|
2128
|
+
event: canvas.event,
|
|
2129
|
+
// Lifecycle group
|
|
2130
|
+
lifecycle: {
|
|
2131
|
+
cleanup: canvas.cleanup.bind(canvas),
|
|
2132
|
+
destroy: canvas.destroy.bind(canvas),
|
|
2133
|
+
},
|
|
2134
|
+
// Properties/State group
|
|
2135
|
+
state: {
|
|
2136
|
+
get isReady() {
|
|
2137
|
+
return canvas.isReady;
|
|
2138
|
+
},
|
|
2139
|
+
get isTransforming() {
|
|
2140
|
+
return canvas.isTransforming;
|
|
2141
|
+
},
|
|
2142
|
+
get visibleBounds() {
|
|
2143
|
+
return canvas.visibleBounds;
|
|
2144
|
+
},
|
|
2145
|
+
get transform() {
|
|
2146
|
+
return canvas.transform;
|
|
2147
|
+
},
|
|
2148
|
+
},
|
|
2149
|
+
};
|
|
2150
|
+
// Bind public API to window
|
|
2151
|
+
windowObj[canvasName] = api;
|
|
2152
|
+
// Track all instances
|
|
2153
|
+
if (!windowObj.__markupCanvasInstances) {
|
|
2154
|
+
windowObj.__markupCanvasInstances = new Map();
|
|
2155
|
+
}
|
|
2156
|
+
windowObj.__markupCanvasInstances.set(canvasName, api);
|
|
2157
|
+
}
|
|
2158
|
+
|
|
1834
2159
|
class MarkupCanvas {
|
|
1835
2160
|
constructor(container, options = {}) {
|
|
1836
|
-
this.
|
|
2161
|
+
this.cleanupCallbacks = [];
|
|
1837
2162
|
this.rulers = null;
|
|
1838
2163
|
this.dragSetup = null;
|
|
2164
|
+
this.event = new EventEmitter();
|
|
1839
2165
|
this._isReady = false;
|
|
1840
|
-
this.listen = new EventEmitter();
|
|
1841
|
-
this.postMessageCleanup = null;
|
|
1842
2166
|
if (!container) {
|
|
1843
2167
|
throw new Error("Container element is required");
|
|
1844
2168
|
}
|
|
@@ -1847,100 +2171,48 @@
|
|
|
1847
2171
|
if (!canvas) {
|
|
1848
2172
|
throw new Error("Failed to create canvas");
|
|
1849
2173
|
}
|
|
1850
|
-
this.
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
2174
|
+
this.canvas = canvas;
|
|
2175
|
+
// Always bind canvas to window
|
|
2176
|
+
this.event.setEmitInterceptor((event, data) => {
|
|
2177
|
+
broadcastEvent(event, data, this.config);
|
|
2178
|
+
});
|
|
2179
|
+
bindCanvasToWindow(this, this.config);
|
|
2180
|
+
// Set up postMessage listener
|
|
2181
|
+
if (this.config.enablePostMessageAPI) {
|
|
2182
|
+
const postMessageCleanup = setupPostMessageEvents(this);
|
|
2183
|
+
this.cleanupCallbacks.push(postMessageCleanup);
|
|
1860
2184
|
}
|
|
1861
2185
|
this.setupEventHandlers();
|
|
1862
2186
|
this._isReady = true;
|
|
1863
2187
|
// Emit ready event
|
|
1864
|
-
this.
|
|
1865
|
-
}
|
|
1866
|
-
setupGlobalBinding() {
|
|
1867
|
-
if (typeof window === "undefined") {
|
|
1868
|
-
return;
|
|
1869
|
-
}
|
|
1870
|
-
const canvasName = this.config.name || "markupCanvas";
|
|
1871
|
-
const windowObj = window;
|
|
1872
|
-
// Bind instance to window
|
|
1873
|
-
windowObj[canvasName] = this;
|
|
1874
|
-
// Track all instances
|
|
1875
|
-
if (!windowObj.__markupCanvasInstances) {
|
|
1876
|
-
windowObj.__markupCanvasInstances = new Map();
|
|
1877
|
-
}
|
|
1878
|
-
windowObj.__markupCanvasInstances.set(canvasName, this);
|
|
1879
|
-
}
|
|
1880
|
-
cleanupGlobalBinding() {
|
|
1881
|
-
if (typeof window === "undefined") {
|
|
1882
|
-
return;
|
|
1883
|
-
}
|
|
1884
|
-
const canvasName = this.config.name || "markupCanvas";
|
|
1885
|
-
const windowObj = window;
|
|
1886
|
-
delete windowObj[canvasName];
|
|
1887
|
-
if (windowObj.__markupCanvasInstances) {
|
|
1888
|
-
windowObj.__markupCanvasInstances.delete(canvasName);
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
broadcastEvent(event, data) {
|
|
1892
|
-
if (typeof window === "undefined") {
|
|
1893
|
-
return;
|
|
1894
|
-
}
|
|
1895
|
-
// Receivers can get the instance from the window binding
|
|
1896
|
-
let broadcastData = data;
|
|
1897
|
-
if (event === "ready") {
|
|
1898
|
-
broadcastData = { ready: true };
|
|
1899
|
-
}
|
|
1900
|
-
window.postMessage({
|
|
1901
|
-
source: "markup-canvas",
|
|
1902
|
-
event,
|
|
1903
|
-
data: broadcastData,
|
|
1904
|
-
timestamp: Date.now(),
|
|
1905
|
-
canvasName: this.config.name,
|
|
1906
|
-
}, "*");
|
|
1907
|
-
if (window.parent) {
|
|
1908
|
-
window.parent.postMessage({
|
|
1909
|
-
source: "markup-canvas",
|
|
1910
|
-
event,
|
|
1911
|
-
data: broadcastData,
|
|
1912
|
-
timestamp: Date.now(),
|
|
1913
|
-
canvasName: this.config.name,
|
|
1914
|
-
}, "*");
|
|
1915
|
-
}
|
|
2188
|
+
this.event.emit("ready", this);
|
|
1916
2189
|
}
|
|
1917
2190
|
setupEventHandlers() {
|
|
1918
2191
|
try {
|
|
1919
|
-
// Wheel
|
|
2192
|
+
// Wheel events
|
|
1920
2193
|
withFeatureEnabled(this.config, "enableZoom", () => {
|
|
1921
2194
|
const wheelCleanup = setupWheelEvents(this, this.config);
|
|
1922
|
-
this.
|
|
2195
|
+
this.cleanupCallbacks.push(wheelCleanup);
|
|
1923
2196
|
});
|
|
1924
|
-
// Mouse events
|
|
1925
|
-
// Set up mouse events if either pan or click-to-zoom is enabled
|
|
2197
|
+
// Mouse events
|
|
1926
2198
|
if (this.config.enablePan || this.config.enableClickToZoom) {
|
|
1927
2199
|
this.dragSetup = setupMouseEvents(this, this.config, true);
|
|
1928
|
-
this.
|
|
2200
|
+
this.cleanupCallbacks.push(this.dragSetup.cleanup);
|
|
1929
2201
|
}
|
|
1930
|
-
// Keyboard
|
|
2202
|
+
// Keyboard events
|
|
1931
2203
|
withFeatureEnabled(this.config, "enableKeyboard", () => {
|
|
1932
2204
|
const keyboardCleanup = setupKeyboardEvents(this, this.config);
|
|
1933
|
-
this.
|
|
2205
|
+
this.cleanupCallbacks.push(keyboardCleanup);
|
|
1934
2206
|
});
|
|
1935
|
-
// Touch events
|
|
2207
|
+
// Touch events
|
|
1936
2208
|
withFeatureEnabled(this.config, "enableTouch", () => {
|
|
1937
2209
|
const touchCleanup = setupTouchEvents(this);
|
|
1938
|
-
this.
|
|
2210
|
+
this.cleanupCallbacks.push(touchCleanup);
|
|
1939
2211
|
});
|
|
1940
2212
|
// Set up rulers and grid
|
|
1941
2213
|
withFeatureEnabled(this.config, "enableRulers", () => {
|
|
1942
|
-
this.rulers = createRulers(this
|
|
1943
|
-
this.
|
|
2214
|
+
this.rulers = createRulers(this, this.config);
|
|
2215
|
+
this.cleanupCallbacks.push(() => {
|
|
1944
2216
|
if (this.rulers) {
|
|
1945
2217
|
this.rulers.destroy();
|
|
1946
2218
|
}
|
|
@@ -1953,20 +2225,18 @@
|
|
|
1953
2225
|
throw error;
|
|
1954
2226
|
}
|
|
1955
2227
|
}
|
|
1956
|
-
// Base canvas properties and methods
|
|
1957
2228
|
get container() {
|
|
1958
|
-
return this.
|
|
2229
|
+
return this.canvas.container;
|
|
1959
2230
|
}
|
|
1960
2231
|
get transformLayer() {
|
|
1961
|
-
return this.
|
|
2232
|
+
return this.canvas.transformLayer;
|
|
1962
2233
|
}
|
|
1963
2234
|
get contentLayer() {
|
|
1964
|
-
return this.
|
|
2235
|
+
return this.canvas.contentLayer;
|
|
1965
2236
|
}
|
|
1966
2237
|
get transform() {
|
|
1967
|
-
return this.
|
|
2238
|
+
return this.canvas.transform;
|
|
1968
2239
|
}
|
|
1969
|
-
// State management getters for React integration
|
|
1970
2240
|
get isReady() {
|
|
1971
2241
|
return this._isReady;
|
|
1972
2242
|
}
|
|
@@ -1974,131 +2244,66 @@
|
|
|
1974
2244
|
return this.dragSetup?.isEnabled() || false;
|
|
1975
2245
|
}
|
|
1976
2246
|
get visibleBounds() {
|
|
1977
|
-
return
|
|
2247
|
+
return getVisibleArea(this);
|
|
1978
2248
|
}
|
|
1979
2249
|
getBounds() {
|
|
1980
|
-
return this.
|
|
2250
|
+
return getCanvasBounds(this.canvas, this.config);
|
|
1981
2251
|
}
|
|
1982
2252
|
updateTransform(newTransform) {
|
|
1983
|
-
const result = this.
|
|
2253
|
+
const result = updateTransform(this.canvas, newTransform);
|
|
1984
2254
|
if (result) {
|
|
1985
|
-
this.
|
|
2255
|
+
emitTransformEvents(this.event, this.canvas);
|
|
1986
2256
|
}
|
|
1987
2257
|
return result;
|
|
1988
2258
|
}
|
|
1989
|
-
emitTransformEvents() {
|
|
1990
|
-
const transform = this.baseCanvas.transform;
|
|
1991
|
-
this.listen.emit("transform", transform);
|
|
1992
|
-
this.listen.emit("zoom", transform.scale);
|
|
1993
|
-
this.listen.emit("pan", { x: transform.translateX, y: transform.translateY });
|
|
1994
|
-
}
|
|
1995
2259
|
reset() {
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2260
|
+
const result = resetTransform(this.canvas);
|
|
2261
|
+
if (result) {
|
|
2262
|
+
emitTransformEvents(this.event, this.canvas);
|
|
2263
|
+
}
|
|
2264
|
+
return result;
|
|
2000
2265
|
}
|
|
2001
2266
|
setZoom(zoomLevel) {
|
|
2002
|
-
return
|
|
2003
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2004
|
-
const newScale = clamp(zoomLevel);
|
|
2005
|
-
const newTransform = {
|
|
2006
|
-
scale: newScale,
|
|
2007
|
-
};
|
|
2008
|
-
return this.updateTransform(newTransform);
|
|
2009
|
-
});
|
|
2010
|
-
});
|
|
2267
|
+
return setZoom(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), zoomLevel);
|
|
2011
2268
|
}
|
|
2012
2269
|
canvasToContent(x, y) {
|
|
2013
|
-
|
|
2270
|
+
const matrix = createMatrix(this.canvas.transform.scale, this.canvas.transform.translateX, this.canvas.transform.translateY);
|
|
2271
|
+
return canvasToContent(x, y, matrix);
|
|
2014
2272
|
}
|
|
2015
2273
|
zoomToPoint(x, y, targetScale) {
|
|
2016
|
-
|
|
2017
|
-
const result = this.baseCanvas.zoomToPoint(x, y, targetScale);
|
|
2018
|
-
if (result) {
|
|
2019
|
-
this.emitTransformEvents();
|
|
2020
|
-
}
|
|
2021
|
-
return result;
|
|
2022
|
-
});
|
|
2023
|
-
}
|
|
2024
|
-
resetView() {
|
|
2025
|
-
const result = this.baseCanvas.resetView ? this.baseCanvas.resetView() : false;
|
|
2274
|
+
const result = zoomToPoint(this.canvas, this.transformLayer, this.config, x, y, targetScale);
|
|
2026
2275
|
if (result) {
|
|
2027
|
-
this.
|
|
2276
|
+
emitTransformEvents(this.event, this.canvas);
|
|
2028
2277
|
}
|
|
2029
2278
|
return result;
|
|
2030
2279
|
}
|
|
2031
|
-
|
|
2032
|
-
return
|
|
2033
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2034
|
-
const newScale = clamp(1.0);
|
|
2035
|
-
const center = getViewportCenter(this);
|
|
2036
|
-
const result = this.zoomToPoint(center.x, center.y, newScale);
|
|
2037
|
-
if (result) {
|
|
2038
|
-
this.emitTransformEvents();
|
|
2039
|
-
}
|
|
2040
|
-
return result;
|
|
2041
|
-
});
|
|
2042
|
-
});
|
|
2280
|
+
resetView() {
|
|
2281
|
+
return resetView(this.canvas, this.transformLayer, this.config);
|
|
2043
2282
|
}
|
|
2044
|
-
|
|
2045
|
-
return
|
|
2046
|
-
const result = this.baseCanvas.zoomToFitContent();
|
|
2047
|
-
if (result) {
|
|
2048
|
-
this.emitTransformEvents();
|
|
2049
|
-
}
|
|
2050
|
-
return result;
|
|
2051
|
-
});
|
|
2283
|
+
resetViewToCenter() {
|
|
2284
|
+
return resetViewToCenter(this, this.transformLayer, this.config, this.zoomToPoint.bind(this));
|
|
2052
2285
|
}
|
|
2053
|
-
// Pan methods
|
|
2054
2286
|
panLeft(distance) {
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
translateX: this.baseCanvas.transform.translateX + panDistance,
|
|
2058
|
-
};
|
|
2059
|
-
return this.updateTransform(newTransform);
|
|
2287
|
+
return (panLeft(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2288
|
+
(distance ? panLeft(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2060
2289
|
}
|
|
2061
2290
|
panRight(distance) {
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
translateX: this.baseCanvas.transform.translateX - panDistance,
|
|
2065
|
-
};
|
|
2066
|
-
return this.updateTransform(newTransform);
|
|
2291
|
+
return (panRight(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2292
|
+
(distance ? panRight(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2067
2293
|
}
|
|
2068
2294
|
panUp(distance) {
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
translateY: this.baseCanvas.transform.translateY + panDistance,
|
|
2072
|
-
};
|
|
2073
|
-
return this.updateTransform(newTransform);
|
|
2295
|
+
return (panUp(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2296
|
+
(distance ? panUp(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2074
2297
|
}
|
|
2075
2298
|
panDown(distance) {
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
translateY: this.baseCanvas.transform.translateY - panDistance,
|
|
2079
|
-
};
|
|
2080
|
-
return this.updateTransform(newTransform);
|
|
2299
|
+
return (panDown(this.canvas, this.config, this.updateTransform.bind(this)) ||
|
|
2300
|
+
(distance ? panDown(this.canvas, { ...this.config, keyboardPanStep: distance }, this.updateTransform.bind(this)) : false));
|
|
2081
2301
|
}
|
|
2082
|
-
// Zoom methods
|
|
2083
2302
|
zoomIn(factor = 0.5) {
|
|
2084
|
-
return
|
|
2085
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2086
|
-
const newScale = clamp(this.baseCanvas.transform.scale * (1 + factor));
|
|
2087
|
-
// Get the center of the viewport
|
|
2088
|
-
const center = getViewportCenter(this);
|
|
2089
|
-
return this.zoomToPoint(center.x, center.y, newScale);
|
|
2090
|
-
});
|
|
2091
|
-
});
|
|
2303
|
+
return zoomIn(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), factor);
|
|
2092
2304
|
}
|
|
2093
2305
|
zoomOut(factor = 0.5) {
|
|
2094
|
-
return
|
|
2095
|
-
return withClampedZoom(this.config, (clamp) => {
|
|
2096
|
-
const newScale = clamp(this.baseCanvas.transform.scale * (1 - factor));
|
|
2097
|
-
// Get the center of the viewport
|
|
2098
|
-
const center = getViewportCenter(this);
|
|
2099
|
-
return this.zoomToPoint(center.x, center.y, newScale);
|
|
2100
|
-
});
|
|
2101
|
-
});
|
|
2306
|
+
return zoomOut(this, this.transformLayer, this.config, this.zoomToPoint.bind(this), factor);
|
|
2102
2307
|
}
|
|
2103
2308
|
resetZoom() {
|
|
2104
2309
|
return this.resetViewToCenter();
|
|
@@ -2113,110 +2318,68 @@
|
|
|
2113
2318
|
isMouseDragEnabled() {
|
|
2114
2319
|
return this.dragSetup?.isEnabled() ?? false;
|
|
2115
2320
|
}
|
|
2116
|
-
// Grid control methods
|
|
2117
2321
|
toggleGrid() {
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2322
|
+
const result = toggleGrid(this.rulers);
|
|
2323
|
+
if (result) {
|
|
2324
|
+
this.event.emit("gridVisibility", this.isGridVisible());
|
|
2121
2325
|
}
|
|
2122
|
-
return
|
|
2326
|
+
return result;
|
|
2123
2327
|
}
|
|
2124
2328
|
showGrid() {
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2329
|
+
const result = showGrid(this.rulers);
|
|
2330
|
+
if (result) {
|
|
2331
|
+
this.event.emit("gridVisibility", true);
|
|
2128
2332
|
}
|
|
2129
|
-
return
|
|
2333
|
+
return result;
|
|
2130
2334
|
}
|
|
2131
2335
|
hideGrid() {
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2336
|
+
const result = hideGrid(this.rulers);
|
|
2337
|
+
if (result) {
|
|
2338
|
+
this.event.emit("gridVisibility", false);
|
|
2135
2339
|
}
|
|
2136
|
-
return
|
|
2340
|
+
return result;
|
|
2137
2341
|
}
|
|
2138
2342
|
isGridVisible() {
|
|
2139
|
-
|
|
2140
|
-
return this.rulers.gridOverlay.style.display !== "none";
|
|
2141
|
-
}
|
|
2142
|
-
return false;
|
|
2343
|
+
return isGridVisible(this.rulers);
|
|
2143
2344
|
}
|
|
2144
|
-
// Ruler control methods
|
|
2145
2345
|
toggleRulers() {
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
this.rulers.hide();
|
|
2150
|
-
}
|
|
2151
|
-
else {
|
|
2152
|
-
this.rulers.show();
|
|
2153
|
-
}
|
|
2154
|
-
return true;
|
|
2346
|
+
const result = toggleRulers(this.rulers, () => this.areRulersVisible());
|
|
2347
|
+
if (result) {
|
|
2348
|
+
this.event.emit("rulersVisibility", this.areRulersVisible());
|
|
2155
2349
|
}
|
|
2156
|
-
return
|
|
2350
|
+
return result;
|
|
2157
2351
|
}
|
|
2158
2352
|
showRulers() {
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2353
|
+
const result = showRulers(this.rulers);
|
|
2354
|
+
if (result) {
|
|
2355
|
+
this.event.emit("rulersVisibility", true);
|
|
2162
2356
|
}
|
|
2163
|
-
return
|
|
2357
|
+
return result;
|
|
2164
2358
|
}
|
|
2165
2359
|
hideRulers() {
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2360
|
+
const result = hideRulers(this.rulers);
|
|
2361
|
+
if (result) {
|
|
2362
|
+
this.event.emit("rulersVisibility", false);
|
|
2169
2363
|
}
|
|
2170
|
-
return
|
|
2364
|
+
return result;
|
|
2171
2365
|
}
|
|
2172
2366
|
areRulersVisible() {
|
|
2173
|
-
|
|
2174
|
-
return this.rulers.horizontalRuler.style.display !== "none";
|
|
2175
|
-
}
|
|
2176
|
-
return false;
|
|
2367
|
+
return areRulersVisible(this.rulers);
|
|
2177
2368
|
}
|
|
2178
|
-
// Utility methods
|
|
2179
2369
|
centerContent() {
|
|
2180
|
-
return
|
|
2181
|
-
const bounds = this.baseCanvas.getBounds();
|
|
2182
|
-
const centerX = (bounds.width - bounds.contentWidth * this.baseCanvas.transform.scale) / 2;
|
|
2183
|
-
const centerY = (bounds.height - bounds.contentHeight * this.baseCanvas.transform.scale) / 2;
|
|
2184
|
-
return this.updateTransform({
|
|
2185
|
-
translateX: centerX,
|
|
2186
|
-
translateY: centerY,
|
|
2187
|
-
});
|
|
2188
|
-
});
|
|
2370
|
+
return centerContent(this.canvas, this.config, this.updateTransform.bind(this), this.transformLayer);
|
|
2189
2371
|
}
|
|
2190
2372
|
fitToScreen() {
|
|
2191
|
-
return
|
|
2192
|
-
const result = this.baseCanvas.zoomToFitContent();
|
|
2193
|
-
if (result) {
|
|
2194
|
-
this.emitTransformEvents();
|
|
2195
|
-
}
|
|
2196
|
-
return result;
|
|
2197
|
-
});
|
|
2373
|
+
return fitToScreen(this.canvas, this.transformLayer, this.config);
|
|
2198
2374
|
}
|
|
2199
2375
|
getVisibleArea() {
|
|
2200
|
-
|
|
2201
|
-
return bounds.visibleArea;
|
|
2376
|
+
return getVisibleArea(this);
|
|
2202
2377
|
}
|
|
2203
2378
|
isPointVisible(x, y) {
|
|
2204
|
-
|
|
2205
|
-
return x >= visibleArea.x && x <= visibleArea.x + visibleArea.width && y >= visibleArea.y && y <= visibleArea.y + visibleArea.height;
|
|
2379
|
+
return isPointVisible(this, x, y);
|
|
2206
2380
|
}
|
|
2207
2381
|
scrollToPoint(x, y) {
|
|
2208
|
-
return
|
|
2209
|
-
const bounds = this.baseCanvas.getBounds();
|
|
2210
|
-
const centerX = bounds.width / 2;
|
|
2211
|
-
const centerY = bounds.height / 2;
|
|
2212
|
-
// Calculate new translation to center the point
|
|
2213
|
-
const newTranslateX = centerX - x * this.baseCanvas.transform.scale;
|
|
2214
|
-
const newTranslateY = centerY - y * this.baseCanvas.transform.scale;
|
|
2215
|
-
return this.updateTransform({
|
|
2216
|
-
translateX: newTranslateX,
|
|
2217
|
-
translateY: newTranslateY,
|
|
2218
|
-
});
|
|
2219
|
-
});
|
|
2382
|
+
return scrollToPoint(this.canvas, this.config, x, y, this.updateTransform.bind(this), this.transformLayer);
|
|
2220
2383
|
}
|
|
2221
2384
|
// Configuration access
|
|
2222
2385
|
getConfig() {
|
|
@@ -2227,28 +2390,28 @@
|
|
|
2227
2390
|
}
|
|
2228
2391
|
// Theme management
|
|
2229
2392
|
updateThemeMode(mode) {
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
this.config
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
}
|
|
2393
|
+
this.config = createMarkupCanvasConfig({ ...this.config, themeMode: mode });
|
|
2394
|
+
updateThemeMode(this.canvas.container, this.config, this.rulers, mode);
|
|
2395
|
+
}
|
|
2396
|
+
toggleThemeMode() {
|
|
2397
|
+
const currentMode = this.config.themeMode;
|
|
2398
|
+
const newMode = currentMode === "light" ? "dark" : "light";
|
|
2399
|
+
this.updateThemeMode(newMode);
|
|
2400
|
+
return newMode;
|
|
2401
|
+
}
|
|
2402
|
+
// Transition management
|
|
2403
|
+
updateTransition(enabled) {
|
|
2404
|
+
this.config = createMarkupCanvasConfig({ ...this.config, enableTransition: enabled });
|
|
2405
|
+
}
|
|
2406
|
+
toggleTransitionMode() {
|
|
2407
|
+
const newEnableTransition = toggleTransition(this.config.enableTransition);
|
|
2408
|
+
this.updateTransition(newEnableTransition);
|
|
2409
|
+
return newEnableTransition;
|
|
2242
2410
|
}
|
|
2243
2411
|
// Cleanup method
|
|
2244
2412
|
cleanup() {
|
|
2245
|
-
this.
|
|
2246
|
-
|
|
2247
|
-
if (this.postMessageCleanup) {
|
|
2248
|
-
this.postMessageCleanup();
|
|
2249
|
-
this.postMessageCleanup = null;
|
|
2250
|
-
}
|
|
2251
|
-
this.cleanupFunctions.forEach((cleanup) => {
|
|
2413
|
+
cleanupWindowBinding(this.config);
|
|
2414
|
+
this.cleanupCallbacks.forEach((cleanup) => {
|
|
2252
2415
|
try {
|
|
2253
2416
|
cleanup();
|
|
2254
2417
|
}
|
|
@@ -2256,22 +2419,22 @@
|
|
|
2256
2419
|
console.warn("Error during cleanup:", cleanupError);
|
|
2257
2420
|
}
|
|
2258
2421
|
});
|
|
2259
|
-
this.
|
|
2422
|
+
this.cleanupCallbacks = [];
|
|
2260
2423
|
// Remove all event listeners
|
|
2261
2424
|
this.removeAllListeners();
|
|
2262
2425
|
}
|
|
2263
2426
|
// Event emitter delegation methods
|
|
2264
2427
|
on(event, handler) {
|
|
2265
|
-
this.
|
|
2428
|
+
this.event.on(event, handler);
|
|
2266
2429
|
}
|
|
2267
2430
|
off(event, handler) {
|
|
2268
|
-
this.
|
|
2431
|
+
this.event.off(event, handler);
|
|
2269
2432
|
}
|
|
2270
2433
|
emit(event, data) {
|
|
2271
|
-
this.
|
|
2434
|
+
this.event.emit(event, data);
|
|
2272
2435
|
}
|
|
2273
2436
|
removeAllListeners() {
|
|
2274
|
-
this.
|
|
2437
|
+
this.event.removeAllListeners();
|
|
2275
2438
|
}
|
|
2276
2439
|
destroy() {
|
|
2277
2440
|
this.cleanup();
|