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