@markup-canvas/core 1.1.1 → 1.1.2
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/lib/MarkupCanvas.d.ts +1 -0
- package/dist/lib/events/index.d.ts +1 -0
- package/dist/lib/events/postMessage/sendError.d.ts +1 -0
- package/dist/lib/events/postMessage/setupPostMessageEvents.d.ts +2 -0
- package/dist/markup-canvas.cjs.js +125 -4
- package/dist/markup-canvas.esm.js +125 -4
- package/dist/markup-canvas.umd.js +124 -4
- package/dist/markup-canvas.umd.min.js +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/events.d.ts +7 -0
- package/package.json +1 -1
- package/src/lib/MarkupCanvas.ts +14 -1
- package/src/lib/config/constants.ts +5 -4
- package/src/lib/config/presets/editor-preset.ts +1 -0
- package/src/lib/events/index.ts +1 -0
- package/src/lib/events/postMessage/sendError.ts +12 -0
- package/src/lib/events/postMessage/setupPostMessageEvents.ts +90 -0
- package/src/types/config.ts +3 -0
- package/src/types/events.ts +28 -0
|
@@ -12,6 +12,7 @@ export declare class MarkupCanvas implements Canvas {
|
|
|
12
12
|
config: Required<MarkupCanvasConfig>;
|
|
13
13
|
private _isReady;
|
|
14
14
|
private listen;
|
|
15
|
+
private postMessageCleanup;
|
|
15
16
|
constructor(container: HTMLElement, options?: MarkupCanvasConfig);
|
|
16
17
|
private setupGlobalBinding;
|
|
17
18
|
private cleanupGlobalBinding;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { setupKeyboardEvents } from "./keyboard/setupKeyboardEvents.js";
|
|
2
2
|
export { setupMouseEvents } from "./mouse/setupMouseEvents.js";
|
|
3
|
+
export { setupPostMessageEvents } from "./postMessage/setupPostMessageEvents.js";
|
|
3
4
|
export { setupTouchEvents } from "./touch/setupTouchEvents.js";
|
|
4
5
|
export { detectTrackpadGesture } from "./trackpad/detectTrackpadGesture.js";
|
|
5
6
|
export { getAdaptiveZoomSpeed } from "./utils/getAdaptiveZoomSpeed.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sendPostMessageError(canvasName: string, action: string, error: string): void;
|
|
@@ -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.1.2
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
@@ -15,6 +15,7 @@ const EDITOR_PRESET = {
|
|
|
15
15
|
// Global Binding & Instance Access
|
|
16
16
|
bindToWindow: true,
|
|
17
17
|
name: "canvas",
|
|
18
|
+
enablePostMessageAPI: true,
|
|
18
19
|
// Interaction controls
|
|
19
20
|
enableZoom: true,
|
|
20
21
|
enablePan: true,
|
|
@@ -313,6 +314,10 @@ const DEFAULT_CONFIG = {
|
|
|
313
314
|
width: 8000,
|
|
314
315
|
height: 8000,
|
|
315
316
|
enableAcceleration: true,
|
|
317
|
+
// Global Binding & Instance Access
|
|
318
|
+
bindToWindow: false,
|
|
319
|
+
name: "markupCanvas",
|
|
320
|
+
enablePostMessageAPI: false,
|
|
316
321
|
// Interaction controls
|
|
317
322
|
enableZoom: true,
|
|
318
323
|
enablePan: true,
|
|
@@ -364,9 +369,6 @@ const DEFAULT_CONFIG = {
|
|
|
364
369
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
365
370
|
// Theme
|
|
366
371
|
themeMode: "light",
|
|
367
|
-
// Global Binding & Instance Access
|
|
368
|
-
bindToWindow: false,
|
|
369
|
-
name: "markupCanvas",
|
|
370
372
|
// Callbacks
|
|
371
373
|
onTransformUpdate: () => { },
|
|
372
374
|
};
|
|
@@ -1154,6 +1156,115 @@ function setupMouseEvents(canvas, config, withControls = true) {
|
|
|
1154
1156
|
return cleanup;
|
|
1155
1157
|
}
|
|
1156
1158
|
|
|
1159
|
+
function sendPostMessageError(canvasName, action, error) {
|
|
1160
|
+
window.postMessage({
|
|
1161
|
+
source: "markup-canvas-error",
|
|
1162
|
+
canvasName,
|
|
1163
|
+
action,
|
|
1164
|
+
error,
|
|
1165
|
+
timestamp: Date.now(),
|
|
1166
|
+
}, "*");
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
function setupPostMessageEvents(canvas) {
|
|
1170
|
+
const handleMessage = (event) => {
|
|
1171
|
+
const data = event.data;
|
|
1172
|
+
// Validate message structure
|
|
1173
|
+
if (data.source !== "markup-canvas") {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const canvasName = canvas.config.name || "markupCanvas";
|
|
1177
|
+
if (data.canvasName !== canvasName) {
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
const action = data.action;
|
|
1181
|
+
const args = data.args || [];
|
|
1182
|
+
try {
|
|
1183
|
+
// View methods
|
|
1184
|
+
if (action === "zoomIn") {
|
|
1185
|
+
canvas.zoomIn(args[0]);
|
|
1186
|
+
}
|
|
1187
|
+
else if (action === "zoomOut") {
|
|
1188
|
+
canvas.zoomOut(args[0]);
|
|
1189
|
+
}
|
|
1190
|
+
else if (action === "resetZoom") {
|
|
1191
|
+
canvas.resetZoom();
|
|
1192
|
+
}
|
|
1193
|
+
else if (action === "panLeft") {
|
|
1194
|
+
canvas.panLeft(args[0]);
|
|
1195
|
+
}
|
|
1196
|
+
else if (action === "panRight") {
|
|
1197
|
+
canvas.panRight(args[0]);
|
|
1198
|
+
}
|
|
1199
|
+
else if (action === "panUp") {
|
|
1200
|
+
canvas.panUp(args[0]);
|
|
1201
|
+
}
|
|
1202
|
+
else if (action === "panDown") {
|
|
1203
|
+
canvas.panDown(args[0]);
|
|
1204
|
+
}
|
|
1205
|
+
else if (action === "fitToScreen") {
|
|
1206
|
+
canvas.fitToScreen();
|
|
1207
|
+
}
|
|
1208
|
+
else if (action === "centerContent") {
|
|
1209
|
+
canvas.centerContent();
|
|
1210
|
+
}
|
|
1211
|
+
else if (action === "scrollToPoint") {
|
|
1212
|
+
canvas.scrollToPoint(args[0], args[1]);
|
|
1213
|
+
}
|
|
1214
|
+
else if (action === "resetView") {
|
|
1215
|
+
canvas.resetView();
|
|
1216
|
+
}
|
|
1217
|
+
// Ruler/Grid methods
|
|
1218
|
+
else if (action === "toggleRulers") {
|
|
1219
|
+
canvas.toggleRulers();
|
|
1220
|
+
}
|
|
1221
|
+
else if (action === "showRulers") {
|
|
1222
|
+
canvas.showRulers();
|
|
1223
|
+
}
|
|
1224
|
+
else if (action === "hideRulers") {
|
|
1225
|
+
canvas.hideRulers();
|
|
1226
|
+
}
|
|
1227
|
+
else if (action === "toggleGrid") {
|
|
1228
|
+
canvas.toggleGrid();
|
|
1229
|
+
}
|
|
1230
|
+
else if (action === "showGrid") {
|
|
1231
|
+
canvas.showGrid();
|
|
1232
|
+
}
|
|
1233
|
+
else if (action === "hideGrid") {
|
|
1234
|
+
canvas.hideGrid();
|
|
1235
|
+
}
|
|
1236
|
+
// Config methods
|
|
1237
|
+
else if (action === "updateThemeMode") {
|
|
1238
|
+
const mode = args[0];
|
|
1239
|
+
if (mode !== "light" && mode !== "dark") {
|
|
1240
|
+
throw new Error(`Invalid theme mode: ${mode}`);
|
|
1241
|
+
}
|
|
1242
|
+
canvas.updateThemeMode(mode);
|
|
1243
|
+
}
|
|
1244
|
+
else if (action === "toggleThemeMode") {
|
|
1245
|
+
const currentConfig = canvas.getConfig();
|
|
1246
|
+
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
1247
|
+
canvas.updateThemeMode(newMode);
|
|
1248
|
+
}
|
|
1249
|
+
else {
|
|
1250
|
+
throw new Error(`Unknown action: ${action}`);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
catch (error) {
|
|
1254
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1255
|
+
sendPostMessageError(canvasName, action, errorMessage);
|
|
1256
|
+
}
|
|
1257
|
+
};
|
|
1258
|
+
if (typeof window !== "undefined") {
|
|
1259
|
+
window.addEventListener("message", handleMessage);
|
|
1260
|
+
}
|
|
1261
|
+
return () => {
|
|
1262
|
+
if (typeof window !== "undefined") {
|
|
1263
|
+
window.removeEventListener("message", handleMessage);
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1157
1268
|
function handleTouchEnd(event, touchState) {
|
|
1158
1269
|
touchState.touches = Array.from(event.touches);
|
|
1159
1270
|
if (touchState.touches.length < 2) {
|
|
@@ -1784,6 +1895,7 @@ class MarkupCanvas {
|
|
|
1784
1895
|
this.dragSetup = null;
|
|
1785
1896
|
this._isReady = false;
|
|
1786
1897
|
this.listen = new EventEmitter();
|
|
1898
|
+
this.postMessageCleanup = null;
|
|
1787
1899
|
if (!container) {
|
|
1788
1900
|
throw new Error("Container element is required");
|
|
1789
1901
|
}
|
|
@@ -1799,6 +1911,10 @@ class MarkupCanvas {
|
|
|
1799
1911
|
this.broadcastEvent(event, data);
|
|
1800
1912
|
});
|
|
1801
1913
|
this.setupGlobalBinding();
|
|
1914
|
+
// Set up postMessage listener
|
|
1915
|
+
if (this.config.enablePostMessageAPI) {
|
|
1916
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1917
|
+
}
|
|
1802
1918
|
}
|
|
1803
1919
|
this.setupEventHandlers();
|
|
1804
1920
|
this._isReady = true;
|
|
@@ -2161,6 +2277,11 @@ class MarkupCanvas {
|
|
|
2161
2277
|
// Cleanup method
|
|
2162
2278
|
cleanup() {
|
|
2163
2279
|
this.cleanupGlobalBinding();
|
|
2280
|
+
// Cleanup postMessage listener
|
|
2281
|
+
if (this.postMessageCleanup) {
|
|
2282
|
+
this.postMessageCleanup();
|
|
2283
|
+
this.postMessageCleanup = null;
|
|
2284
|
+
}
|
|
2164
2285
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2165
2286
|
try {
|
|
2166
2287
|
cleanup();
|
|
@@ -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.1.2
|
|
5
5
|
*/
|
|
6
6
|
const EDITOR_PRESET = {
|
|
7
7
|
// Canvas dimensions
|
|
@@ -11,6 +11,7 @@ const EDITOR_PRESET = {
|
|
|
11
11
|
// Global Binding & Instance Access
|
|
12
12
|
bindToWindow: true,
|
|
13
13
|
name: "canvas",
|
|
14
|
+
enablePostMessageAPI: true,
|
|
14
15
|
// Interaction controls
|
|
15
16
|
enableZoom: true,
|
|
16
17
|
enablePan: true,
|
|
@@ -309,6 +310,10 @@ const DEFAULT_CONFIG = {
|
|
|
309
310
|
width: 8000,
|
|
310
311
|
height: 8000,
|
|
311
312
|
enableAcceleration: true,
|
|
313
|
+
// Global Binding & Instance Access
|
|
314
|
+
bindToWindow: false,
|
|
315
|
+
name: "markupCanvas",
|
|
316
|
+
enablePostMessageAPI: false,
|
|
312
317
|
// Interaction controls
|
|
313
318
|
enableZoom: true,
|
|
314
319
|
enablePan: true,
|
|
@@ -360,9 +365,6 @@ const DEFAULT_CONFIG = {
|
|
|
360
365
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
361
366
|
// Theme
|
|
362
367
|
themeMode: "light",
|
|
363
|
-
// Global Binding & Instance Access
|
|
364
|
-
bindToWindow: false,
|
|
365
|
-
name: "markupCanvas",
|
|
366
368
|
// Callbacks
|
|
367
369
|
onTransformUpdate: () => { },
|
|
368
370
|
};
|
|
@@ -1150,6 +1152,115 @@ function setupMouseEvents(canvas, config, withControls = true) {
|
|
|
1150
1152
|
return cleanup;
|
|
1151
1153
|
}
|
|
1152
1154
|
|
|
1155
|
+
function sendPostMessageError(canvasName, action, error) {
|
|
1156
|
+
window.postMessage({
|
|
1157
|
+
source: "markup-canvas-error",
|
|
1158
|
+
canvasName,
|
|
1159
|
+
action,
|
|
1160
|
+
error,
|
|
1161
|
+
timestamp: Date.now(),
|
|
1162
|
+
}, "*");
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
function setupPostMessageEvents(canvas) {
|
|
1166
|
+
const handleMessage = (event) => {
|
|
1167
|
+
const data = event.data;
|
|
1168
|
+
// Validate message structure
|
|
1169
|
+
if (data.source !== "markup-canvas") {
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
const canvasName = canvas.config.name || "markupCanvas";
|
|
1173
|
+
if (data.canvasName !== canvasName) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
const action = data.action;
|
|
1177
|
+
const args = data.args || [];
|
|
1178
|
+
try {
|
|
1179
|
+
// View methods
|
|
1180
|
+
if (action === "zoomIn") {
|
|
1181
|
+
canvas.zoomIn(args[0]);
|
|
1182
|
+
}
|
|
1183
|
+
else if (action === "zoomOut") {
|
|
1184
|
+
canvas.zoomOut(args[0]);
|
|
1185
|
+
}
|
|
1186
|
+
else if (action === "resetZoom") {
|
|
1187
|
+
canvas.resetZoom();
|
|
1188
|
+
}
|
|
1189
|
+
else if (action === "panLeft") {
|
|
1190
|
+
canvas.panLeft(args[0]);
|
|
1191
|
+
}
|
|
1192
|
+
else if (action === "panRight") {
|
|
1193
|
+
canvas.panRight(args[0]);
|
|
1194
|
+
}
|
|
1195
|
+
else if (action === "panUp") {
|
|
1196
|
+
canvas.panUp(args[0]);
|
|
1197
|
+
}
|
|
1198
|
+
else if (action === "panDown") {
|
|
1199
|
+
canvas.panDown(args[0]);
|
|
1200
|
+
}
|
|
1201
|
+
else if (action === "fitToScreen") {
|
|
1202
|
+
canvas.fitToScreen();
|
|
1203
|
+
}
|
|
1204
|
+
else if (action === "centerContent") {
|
|
1205
|
+
canvas.centerContent();
|
|
1206
|
+
}
|
|
1207
|
+
else if (action === "scrollToPoint") {
|
|
1208
|
+
canvas.scrollToPoint(args[0], args[1]);
|
|
1209
|
+
}
|
|
1210
|
+
else if (action === "resetView") {
|
|
1211
|
+
canvas.resetView();
|
|
1212
|
+
}
|
|
1213
|
+
// Ruler/Grid methods
|
|
1214
|
+
else if (action === "toggleRulers") {
|
|
1215
|
+
canvas.toggleRulers();
|
|
1216
|
+
}
|
|
1217
|
+
else if (action === "showRulers") {
|
|
1218
|
+
canvas.showRulers();
|
|
1219
|
+
}
|
|
1220
|
+
else if (action === "hideRulers") {
|
|
1221
|
+
canvas.hideRulers();
|
|
1222
|
+
}
|
|
1223
|
+
else if (action === "toggleGrid") {
|
|
1224
|
+
canvas.toggleGrid();
|
|
1225
|
+
}
|
|
1226
|
+
else if (action === "showGrid") {
|
|
1227
|
+
canvas.showGrid();
|
|
1228
|
+
}
|
|
1229
|
+
else if (action === "hideGrid") {
|
|
1230
|
+
canvas.hideGrid();
|
|
1231
|
+
}
|
|
1232
|
+
// Config methods
|
|
1233
|
+
else if (action === "updateThemeMode") {
|
|
1234
|
+
const mode = args[0];
|
|
1235
|
+
if (mode !== "light" && mode !== "dark") {
|
|
1236
|
+
throw new Error(`Invalid theme mode: ${mode}`);
|
|
1237
|
+
}
|
|
1238
|
+
canvas.updateThemeMode(mode);
|
|
1239
|
+
}
|
|
1240
|
+
else if (action === "toggleThemeMode") {
|
|
1241
|
+
const currentConfig = canvas.getConfig();
|
|
1242
|
+
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
1243
|
+
canvas.updateThemeMode(newMode);
|
|
1244
|
+
}
|
|
1245
|
+
else {
|
|
1246
|
+
throw new Error(`Unknown action: ${action}`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
catch (error) {
|
|
1250
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1251
|
+
sendPostMessageError(canvasName, action, errorMessage);
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
if (typeof window !== "undefined") {
|
|
1255
|
+
window.addEventListener("message", handleMessage);
|
|
1256
|
+
}
|
|
1257
|
+
return () => {
|
|
1258
|
+
if (typeof window !== "undefined") {
|
|
1259
|
+
window.removeEventListener("message", handleMessage);
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1153
1264
|
function handleTouchEnd(event, touchState) {
|
|
1154
1265
|
touchState.touches = Array.from(event.touches);
|
|
1155
1266
|
if (touchState.touches.length < 2) {
|
|
@@ -1780,6 +1891,7 @@ class MarkupCanvas {
|
|
|
1780
1891
|
this.dragSetup = null;
|
|
1781
1892
|
this._isReady = false;
|
|
1782
1893
|
this.listen = new EventEmitter();
|
|
1894
|
+
this.postMessageCleanup = null;
|
|
1783
1895
|
if (!container) {
|
|
1784
1896
|
throw new Error("Container element is required");
|
|
1785
1897
|
}
|
|
@@ -1795,6 +1907,10 @@ class MarkupCanvas {
|
|
|
1795
1907
|
this.broadcastEvent(event, data);
|
|
1796
1908
|
});
|
|
1797
1909
|
this.setupGlobalBinding();
|
|
1910
|
+
// Set up postMessage listener
|
|
1911
|
+
if (this.config.enablePostMessageAPI) {
|
|
1912
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1913
|
+
}
|
|
1798
1914
|
}
|
|
1799
1915
|
this.setupEventHandlers();
|
|
1800
1916
|
this._isReady = true;
|
|
@@ -2157,6 +2273,11 @@ class MarkupCanvas {
|
|
|
2157
2273
|
// Cleanup method
|
|
2158
2274
|
cleanup() {
|
|
2159
2275
|
this.cleanupGlobalBinding();
|
|
2276
|
+
// Cleanup postMessage listener
|
|
2277
|
+
if (this.postMessageCleanup) {
|
|
2278
|
+
this.postMessageCleanup();
|
|
2279
|
+
this.postMessageCleanup = null;
|
|
2280
|
+
}
|
|
2160
2281
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2161
2282
|
try {
|
|
2162
2283
|
cleanup();
|
|
@@ -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.1.2
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -252,6 +252,10 @@
|
|
|
252
252
|
width: 8000,
|
|
253
253
|
height: 8000,
|
|
254
254
|
enableAcceleration: true,
|
|
255
|
+
// Global Binding & Instance Access
|
|
256
|
+
bindToWindow: false,
|
|
257
|
+
name: "markupCanvas",
|
|
258
|
+
enablePostMessageAPI: false,
|
|
255
259
|
// Interaction controls
|
|
256
260
|
enableZoom: true,
|
|
257
261
|
enablePan: true,
|
|
@@ -303,9 +307,6 @@
|
|
|
303
307
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
304
308
|
// Theme
|
|
305
309
|
themeMode: "light",
|
|
306
|
-
// Global Binding & Instance Access
|
|
307
|
-
bindToWindow: false,
|
|
308
|
-
name: "markupCanvas",
|
|
309
310
|
// Callbacks
|
|
310
311
|
onTransformUpdate: () => { },
|
|
311
312
|
};
|
|
@@ -1093,6 +1094,115 @@
|
|
|
1093
1094
|
return cleanup;
|
|
1094
1095
|
}
|
|
1095
1096
|
|
|
1097
|
+
function sendPostMessageError(canvasName, action, error) {
|
|
1098
|
+
window.postMessage({
|
|
1099
|
+
source: "markup-canvas-error",
|
|
1100
|
+
canvasName,
|
|
1101
|
+
action,
|
|
1102
|
+
error,
|
|
1103
|
+
timestamp: Date.now(),
|
|
1104
|
+
}, "*");
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function setupPostMessageEvents(canvas) {
|
|
1108
|
+
const handleMessage = (event) => {
|
|
1109
|
+
const data = event.data;
|
|
1110
|
+
// Validate message structure
|
|
1111
|
+
if (data.source !== "markup-canvas") {
|
|
1112
|
+
return;
|
|
1113
|
+
}
|
|
1114
|
+
const canvasName = canvas.config.name || "markupCanvas";
|
|
1115
|
+
if (data.canvasName !== canvasName) {
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
const action = data.action;
|
|
1119
|
+
const args = data.args || [];
|
|
1120
|
+
try {
|
|
1121
|
+
// View methods
|
|
1122
|
+
if (action === "zoomIn") {
|
|
1123
|
+
canvas.zoomIn(args[0]);
|
|
1124
|
+
}
|
|
1125
|
+
else if (action === "zoomOut") {
|
|
1126
|
+
canvas.zoomOut(args[0]);
|
|
1127
|
+
}
|
|
1128
|
+
else if (action === "resetZoom") {
|
|
1129
|
+
canvas.resetZoom();
|
|
1130
|
+
}
|
|
1131
|
+
else if (action === "panLeft") {
|
|
1132
|
+
canvas.panLeft(args[0]);
|
|
1133
|
+
}
|
|
1134
|
+
else if (action === "panRight") {
|
|
1135
|
+
canvas.panRight(args[0]);
|
|
1136
|
+
}
|
|
1137
|
+
else if (action === "panUp") {
|
|
1138
|
+
canvas.panUp(args[0]);
|
|
1139
|
+
}
|
|
1140
|
+
else if (action === "panDown") {
|
|
1141
|
+
canvas.panDown(args[0]);
|
|
1142
|
+
}
|
|
1143
|
+
else if (action === "fitToScreen") {
|
|
1144
|
+
canvas.fitToScreen();
|
|
1145
|
+
}
|
|
1146
|
+
else if (action === "centerContent") {
|
|
1147
|
+
canvas.centerContent();
|
|
1148
|
+
}
|
|
1149
|
+
else if (action === "scrollToPoint") {
|
|
1150
|
+
canvas.scrollToPoint(args[0], args[1]);
|
|
1151
|
+
}
|
|
1152
|
+
else if (action === "resetView") {
|
|
1153
|
+
canvas.resetView();
|
|
1154
|
+
}
|
|
1155
|
+
// Ruler/Grid methods
|
|
1156
|
+
else if (action === "toggleRulers") {
|
|
1157
|
+
canvas.toggleRulers();
|
|
1158
|
+
}
|
|
1159
|
+
else if (action === "showRulers") {
|
|
1160
|
+
canvas.showRulers();
|
|
1161
|
+
}
|
|
1162
|
+
else if (action === "hideRulers") {
|
|
1163
|
+
canvas.hideRulers();
|
|
1164
|
+
}
|
|
1165
|
+
else if (action === "toggleGrid") {
|
|
1166
|
+
canvas.toggleGrid();
|
|
1167
|
+
}
|
|
1168
|
+
else if (action === "showGrid") {
|
|
1169
|
+
canvas.showGrid();
|
|
1170
|
+
}
|
|
1171
|
+
else if (action === "hideGrid") {
|
|
1172
|
+
canvas.hideGrid();
|
|
1173
|
+
}
|
|
1174
|
+
// Config methods
|
|
1175
|
+
else if (action === "updateThemeMode") {
|
|
1176
|
+
const mode = args[0];
|
|
1177
|
+
if (mode !== "light" && mode !== "dark") {
|
|
1178
|
+
throw new Error(`Invalid theme mode: ${mode}`);
|
|
1179
|
+
}
|
|
1180
|
+
canvas.updateThemeMode(mode);
|
|
1181
|
+
}
|
|
1182
|
+
else if (action === "toggleThemeMode") {
|
|
1183
|
+
const currentConfig = canvas.getConfig();
|
|
1184
|
+
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
1185
|
+
canvas.updateThemeMode(newMode);
|
|
1186
|
+
}
|
|
1187
|
+
else {
|
|
1188
|
+
throw new Error(`Unknown action: ${action}`);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
catch (error) {
|
|
1192
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1193
|
+
sendPostMessageError(canvasName, action, errorMessage);
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
if (typeof window !== "undefined") {
|
|
1197
|
+
window.addEventListener("message", handleMessage);
|
|
1198
|
+
}
|
|
1199
|
+
return () => {
|
|
1200
|
+
if (typeof window !== "undefined") {
|
|
1201
|
+
window.removeEventListener("message", handleMessage);
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1096
1206
|
function handleTouchEnd(event, touchState) {
|
|
1097
1207
|
touchState.touches = Array.from(event.touches);
|
|
1098
1208
|
if (touchState.touches.length < 2) {
|
|
@@ -1723,6 +1833,7 @@
|
|
|
1723
1833
|
this.dragSetup = null;
|
|
1724
1834
|
this._isReady = false;
|
|
1725
1835
|
this.listen = new EventEmitter();
|
|
1836
|
+
this.postMessageCleanup = null;
|
|
1726
1837
|
if (!container) {
|
|
1727
1838
|
throw new Error("Container element is required");
|
|
1728
1839
|
}
|
|
@@ -1738,6 +1849,10 @@
|
|
|
1738
1849
|
this.broadcastEvent(event, data);
|
|
1739
1850
|
});
|
|
1740
1851
|
this.setupGlobalBinding();
|
|
1852
|
+
// Set up postMessage listener
|
|
1853
|
+
if (this.config.enablePostMessageAPI) {
|
|
1854
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1855
|
+
}
|
|
1741
1856
|
}
|
|
1742
1857
|
this.setupEventHandlers();
|
|
1743
1858
|
this._isReady = true;
|
|
@@ -2100,6 +2215,11 @@
|
|
|
2100
2215
|
// Cleanup method
|
|
2101
2216
|
cleanup() {
|
|
2102
2217
|
this.cleanupGlobalBinding();
|
|
2218
|
+
// Cleanup postMessage listener
|
|
2219
|
+
if (this.postMessageCleanup) {
|
|
2220
|
+
this.postMessageCleanup();
|
|
2221
|
+
this.postMessageCleanup = null;
|
|
2222
|
+
}
|
|
2103
2223
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2104
2224
|
try {
|
|
2105
2225
|
cleanup();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas=t()}(this,function(){"use strict";const e="canvas-container",t="transform-layer",n="content-layer";function r(e,r){const o=Array.from(e.children);let a=e.querySelector(`.${t}`);a||(a=document.createElement("div"),a.className=t,e.appendChild(a)),function(e,t){e.style.position="absolute";const n=t.rulerSize;e.style.top=`${n}px`,e.style.left=`${n}px`,e.style.width=`${t.width}px`,e.style.height=`${t.height}px`,e.style.transformOrigin="0 0"}(a,r);let s=a.querySelector(`.${n}`);return s||(s=document.createElement("div"),s.className=n,a.appendChild(s),function(e,n,r){e.forEach(e=>{e===r||e.classList.contains(t)||n.appendChild(e)})}(o,s,a)),function(e){e.style.position="relative",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}(s),{transformLayer:a,contentLayer:s}}function o(e,t,n){if(!n?.inverse)return{x:e,y:t};try{const r=n.inverse(),o=new DOMPoint(e,t).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:e,y:t}}}function a(e,t){return Math.max(t.minZoom,Math.min(t.maxZoom,e))}function s(e,t,n){return new DOMMatrix([e,0,0,e,t,n])}function i(e,t,n,r,o){const s=o.enableRulers?-o.rulerSize:0,i=n||{scale:1,translateX:s,translateY:s},{scale:l,translateX:c,translateY:u}=i,d=a(l*r,o);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:e-(e-c)/l*d,translateY:t-(t-u)/l*d}}function l(e,t){return t(t=>a(t,e))}const c=new Map;function u(e,t,n){return e[t]?n():null}function d(e){let t=null,n=null;const r=(...r)=>{n=r,null===t&&(t=requestAnimationFrame(()=>{n&&e(...n),t=null,n=null}))};return r.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null,n=null)},r}function h(e,t,n){return n(null!==e.container.querySelector(".canvas-ruler")?t:0)}function m(e,t,n,r,o){const a=null!==e.container.querySelector(".canvas-ruler");return o(a?t-r:t,a?n-r:n)}function g(e,t){if("dark"===e.themeMode){return e[`${t}Dark`]}return e[t]}const f={width:8e3,height:8e3,enableAcceleration:!0,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,bindKeyboardEventsTo:"canvas",zoomSpeed:1.5,minZoom:.05,maxZoom:80,enableTransition:!0,transitionDuration:.2,enableAdaptiveSpeed:!0,enableLeftDrag:!0,enableMiddleDrag:!0,requireSpaceForMouseDrag:!1,keyboardPanStep:50,keyboardFastMultiplier:20,keyboardZoomStep:.2,enableClickToZoom:!0,clickZoomLevel:1,requireOptionForClickZoom:!1,enableRulers:!0,enableGrid:!1,showRulers:!0,showGrid:!1,rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,canvasBackgroundColor:"rgba(250, 250, 250, 1)",canvasBackgroundColorDark:"rgba(40, 40, 40, 1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"rgba(240, 240, 240, 1)",rulerTextColor:"rgba(102, 102, 102, 1)",rulerTickColor:"rgba(204, 204, 204, 1)",gridColor:"rgba(232, 86, 193, 0.5)",rulerBackgroundColorDark:"rgba(30, 30, 30, 0.95)",rulerBorderColorDark:"rgba(68, 68, 68, 1)",rulerTextColorDark:"rgba(170, 170, 170, 1)",rulerTickColorDark:"rgba(104, 104, 104, 1)",gridColorDark:"rgba(232, 86, 193, 0.5)",themeMode:"light",bindToWindow:!1,name:"markupCanvas",onTransformUpdate:()=>{}};function p(e){try{const t=e.container,n=e.config,r=e.transform||{scale:1,translateX:0,translateY:0},a=t.getBoundingClientRect(),i=a.width||t.clientWidth||0,l=a.height||t.clientHeight||0,c=h({container:t},n.rulerSize,e=>Math.max(0,i-e)),u=h({container:t},n.rulerSize,e=>Math.max(0,l-e)),d=n.width||f.width,m=n.height||f.height,g=function(e,t,n,r,a){const i=o(0,0,s(a.scale,a.translateX,a.translateY)),l=o(e,t,s(a.scale,a.translateX,a.translateY));return{x:Math.max(0,Math.min(n,i.x)),y:Math.max(0,Math.min(r,i.y)),width:Math.max(0,Math.min(n-i.x,l.x-i.x)),height:Math.max(0,Math.min(r-i.y,l.y-i.y))}}(c,u,d,m,r);return{width:c,height:u,contentWidth:d,contentHeight:m,scale:r.scale,translateX:r.translateX,translateY:r.translateY,visibleArea:g,scaledContentWidth:d*r.scale,scaledContentHeight:m*r.scale,canPanLeft:r.translateX<0,canPanRight:r.translateX+d*r.scale>c,canPanUp:r.translateY<0,canPanDown:r.translateY+m*r.scale>u,canZoomIn:r.scale<3.5,canZoomOut:r.scale>.1}}catch(e){return console.error("Failed to calculate canvas bounds:",e),{width:0,height:0,contentWidth:0,contentHeight:0,scale:1,translateX:0,translateY:0,visibleArea:{x:0,y:0,width:0,height:0},scaledContentWidth:0,scaledContentHeight:0,canPanLeft:!1,canPanRight:!1,canPanUp:!1,canPanDown:!1,canZoomIn:!1,canZoomOut:!1}}}function v(e,t){if(!e?.style||!t)return!1;try{return e.style.transform=function(e){return`matrix3d(${e.m11}, ${e.m12}, ${e.m13}, ${e.m14}, ${e.m21}, ${e.m22}, ${e.m23}, ${e.m24}, ${e.m31}, ${e.m32}, ${e.m33}, ${e.m34}, ${e.m41}, ${e.m42}, ${e.m43}, ${e.m44})`}(t),!0}catch(e){return console.warn("Transform application failed:",e),!1}}function y(e,t){try{if(t.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(e,t,n){const r=c.get(e);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(e)},t);c.set(e,o)}("disableTransition",1e3*(t.transitionDuration??.2),()=>{e.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(e){return console.error("Failed to disable transitions:",e),!0}}function b(e,t,n){!function(e,t){try{return!!t.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),e.style.transition=`transform ${t.transitionDuration}s linear`,!0)}catch(e){return console.error("Failed to enable transitions:",e),!1}}(e,t);try{return n()}finally{y(e,t)}}function w(t,n){if("static"===getComputedStyle(t).position&&(t.style.position="relative"),t.style.overflow="hidden",t.style.cursor="grab",t.style.overscrollBehavior="none",n){const e=g(n,"canvasBackgroundColor");t.style.backgroundColor=e}t.hasAttribute("tabindex")||t.setAttribute("tabindex","0"),function(e){const t=e.getBoundingClientRect(),n=getComputedStyle(e);0===t.height&&"auto"===n.height&&console.error("MarkupCanvas: Container height is 0. Please set a height on your container element using CSS.","Examples: height: 100vh, height: 500px, or use flexbox/grid layout.",e),0===t.width&&"auto"===n.width&&console.error("MarkupCanvas: Container width is 0. Please set a width on your container element using CSS.","Examples: width: 100vw, width: 800px, or use flexbox/grid layout.",e)}(t),t.classList.contains(e)||t.classList.add(e)}function x(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{w(e,t);const{transformLayer:n,contentLayer:a}=r(e,t);t.enableAcceleration&&function(e){try{return e.style.transform=e.style.transform||"translateZ(0)",e.style.backfaceVisibility="hidden",!0}catch(e){return console.error("Failed to enable hardware acceleration:",e),!1}}(n);const c=t.enableRulers?-t.rulerSize:0,d={scale:1,translateX:c,translateY:c};v(n,s(d.scale,d.translateX,d.translateY));return{container:e,transformLayer:n,contentLayer:a,config:t,transform:d,getBounds:function(){return p(this)},updateTransform:function(e){this.transform={...this.transform,...e};const t=s(this.transform.scale,this.transform.translateX,this.transform.translateY),n=v(this.transformLayer,t);return u(this.config,"onTransformUpdate",()=>{this.config.onTransformUpdate(this.transform)}),n},reset:function(){return this.updateTransform({scale:1,translateX:0,translateY:0})},handleResize:function(){return!0},setZoom:function(e){const t=l(this.config,t=>t(e));return this.updateTransform({scale:t})},canvasToContent:function(e,t){return o(e,t,s(this.transform.scale,this.transform.translateX,this.transform.translateY))},zoomToPoint:function(e,t,n){return b(this.transformLayer,this.config,()=>{const r=i(e,t,this.transform,n/this.transform.scale,this.config);return this.updateTransform(r)})},resetView:function(){return b(this.transformLayer,this.config,()=>h(this,this.config.rulerSize,e=>{const t={scale:1,translateX:-1*e,translateY:-1*e};return this.updateTransform(t)}))},zoomToFitContent:function(){return b(this.transformLayer,this.config,()=>{const e=this.getBounds(),t=e.width/this.config.width,n=e.height/this.config.height,r=l(this.config,e=>e(.9*Math.min(t,n))),o=this.config.width*r,a=this.config.height*r,s=(e.width-o)/2,i=(e.height-a)/2;return this.updateTransform({scale:r,translateX:s,translateY:i})})}}}catch(e){return console.error("Failed to create canvas:",e),null}}function C(e={}){const t={...f,...e};return("number"!=typeof t.width||t.width<=0)&&(console.warn("Invalid width, using default"),t.width=f.width),("number"!=typeof t.height||t.height<=0)&&(console.warn("Invalid height, using default"),t.height=f.height),("number"!=typeof t.zoomSpeed||t.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),t.zoomSpeed=f.zoomSpeed),("number"!=typeof t.minZoom||t.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),t.minZoom=f.minZoom),("number"!=typeof t.maxZoom||t.maxZoom<=t.minZoom)&&(console.warn("Invalid maxZoom, using default"),t.maxZoom=f.maxZoom),("number"!=typeof t.keyboardPanStep||t.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),t.keyboardPanStep=f.keyboardPanStep),("number"!=typeof t.keyboardFastMultiplier||t.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),t.keyboardFastMultiplier=f.keyboardFastMultiplier),("number"!=typeof t.clickZoomLevel||t.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),t.clickZoomLevel=f.clickZoomLevel),("number"!=typeof t.rulerFontSize||t.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),t.rulerFontSize=f.rulerFontSize),("number"!=typeof t.rulerSize||t.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),t.rulerSize=f.rulerSize),t}class k{constructor(){this.listeners=new Map}setEmitInterceptor(e){this.emitInterceptor=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){const n=this.listeners.get(e);n&&n.delete(t)}emit(e,t){this.emitInterceptor?.(e,t);const n=this.listeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(){this.listeners.clear()}}const T=300,S=5;function D(e,t){if(!e?.getBounds)return t;try{const n=e.getBounds(),r=n.width*n.height;return t*(r/2073600)**1}catch(e){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",e),t}}function z(e,t){let n=0,r=0;function o(o){const a=e.container.getBoundingClientRect(),s=o.clientX-a.left,i=o.clientY-a.top;!function(e,t,n,r,o){h(e,t,e=>o(n-e,r-e))}(e,t.rulerSize,s,i,(e,t)=>{n=e,r=t})}function s(o){if(!(o instanceof KeyboardEvent))return;if("canvas"===t.bindKeyboardEventsTo&&document.activeElement!==e.container)return;const s=o.shiftKey,l=t.keyboardPanStep*(s?t.keyboardFastMultiplier:1);let c=!1;const u={};switch(o.key){case"ArrowLeft":u.translateX=e.transform.translateX+l,c=!0;break;case"ArrowRight":u.translateX=e.transform.translateX-l,c=!0;break;case"ArrowUp":u.translateY=e.transform.translateY+l,c=!0;break;case"ArrowDown":u.translateY=e.transform.translateY-l,c=!0;break;case"=":case"+":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1+n),t),c=!0}break;case"-":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1-n),t),c=!0}break;case"0":if(o.metaKey||o.ctrlKey){const o=1/e.transform.scale,a=i(n,r,e.transform,o,t);Object.assign(u,a),c=!0}break;case"g":case"G":e.toggleGrid&&e.toggleGrid(),c=!0;break;case"r":case"R":o.metaKey||o.ctrlKey||o.altKey||!e.toggleRulers||(e.toggleRulers(),c=!0)}c&&(o.preventDefault(),Object.keys(u).length>0&&e.updateTransform(u))}const l="canvas"===t.bindKeyboardEventsTo?e.container:document;return l.addEventListener("keydown",s),e.container.addEventListener("mousemove",o),()=>{l.removeEventListener("keydown",s),e.container.removeEventListener("mousemove",o)}}function M(e,t,n,r,o){n?t.requireSpaceForMouseDrag?e.container.style.cursor=r?"grab":"default":e.container.style.cursor=o?"grabbing":"grab":e.container.style.cursor="default"}function L(e,t,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),M(e,t,n,r,!1)}function E(e,t,n,r,o,a,s,i,l,c){a&&e.button===s&&L(t,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===e.button&&n.enableClickToZoom&&i>0&&function(e,t,n,r,o,a){const s=Date.now()-r,i=e.altKey,l=!n.requireOptionForClickZoom||i;if(s<T&&!o&&!a&&l){e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{clickX:s,clickY:i}=m(t,o,a,n.rulerSize,(e,t)=>({clickX:e,clickY:t})),l=t.canvasToContent(s,i),c=r.width/2,u=r.height/2,d=n.clickZoomLevel,h={scale:d,translateX:c-l.x*d,translateY:u-l.y*d};b(t.transformLayer,t.config,()=>{t.updateTransform(h)})}}(e,t,n,i,l,a),0===e.button&&function(e){e.setMouseDownTime(0),e.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function R(e,t,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,m=!1;const g={setIsDragging:e=>{o=e},setDragButton:e=>{i=e},setIsSpacePressed:e=>{l=e},setMouseDownTime:e=>{c=e},setMouseDownX:e=>{u=e},setMouseDownY:e=>{h=e},setHasDragged:e=>{m=e},setLastMouseX:e=>{a=e},setLastMouseY:e=>{s=e}},f=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!0),M(t,n,r,!0,o))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed})},p=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!1),M(t,n,r,!1,o),o&&L(t,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed,setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})},v=n=>{!function(e,t,n,r,o,a){const s=0===e.button,i=1===e.button;if(s&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(e.clientX),a.setMouseDownY(e.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(s&&n.enableLeftDrag||i&&n.enableMiddleDrag)&&(e.preventDefault(),a.setDragButton(e.button),a.setLastMouseX(e.clientX),a.setLastMouseY(e.clientY),M(t,n,r,o,!1))}(n,e,t,r,l,g)},y=t=>{!function(e,t,n,r,o,a,s,i,l,c){if(o>0){const t=Math.abs(e.clientX-a),o=Math.abs(e.clientY-s);(t>S||o>S)&&(c.setHasDragged(!0),!r&&n&&c.setIsDragging(!0))}if(!r||!n)return;e.preventDefault(),d((...e)=>{const o=e[0];if(!r||!n)return;const a=o.clientX-i,s=o.clientY-l,u={translateX:t.transform.translateX+a,translateY:t.transform.translateY+s};t.updateTransform(u),c.setLastMouseX(o.clientX),c.setLastMouseY(o.clientY)})(e)}(t,e,r,o,c,u,h,a,s,{setHasDragged:g.setHasDragged,setIsDragging:g.setIsDragging,setLastMouseX:g.setLastMouseX,setLastMouseY:g.setLastMouseY})},b=n=>{E(n,e,t,r,l,o,i,c,m,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton,setMouseDownTime:g.setMouseDownTime,setHasDragged:g.setHasDragged})},w=()=>{!function(e,t,n,r,o,a){o&&L(e,t,n,r,a)}(e,t,r,l,o,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})};e.container.addEventListener("mousedown",v),document.addEventListener("mousemove",y),document.addEventListener("mouseup",b),e.container.addEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",f),document.addEventListener("keyup",p)),M(e,t,r,l,o);const x=()=>{e.container.removeEventListener("mousedown",v),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",b),e.container.removeEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",f),document.removeEventListener("keyup",p))};return n?{cleanup:x,enable:()=>(r=!0,M(e,t,r,l,o),!0),disable:()=>(r=!1,o&&L(e,t,r,l,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton}),M(e,t,r,l,o),!0),isEnabled:()=>r}:x}function Y(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function X(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function B(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function F(e,t,n){e.preventDefault();const r=Array.from(e.touches);d((...e)=>{const r=e[0];if(1===r.length){if(1===n.touches.length){const e=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:t.transform.translateX+e,translateY:t.transform.translateY+o};t.updateTransform(a)}}else if(2===r.length){const e=X(r[0],r[1]),o=Y(r[0],r[1]);if(n.lastDistance>0){const r=e/n.lastDistance,a=t.container.getBoundingClientRect();let s=o.x-a.left,i=o.y-a.top;const l=function(e,t,n,r){return h(e,t,e=>{const t={...n,x:n.x-e,y:n.y-e};return r(t)})}(t,t.config.rulerSize,{x:s,y:i},e=>e);s=l.x,i=l.y,B(t,r,s,i)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function $(e){const t={touches:[],lastDistance:0,lastCenter:{}},n=e=>{!function(e,t){e.preventDefault(),t.touches=Array.from(e.touches),2===t.touches.length&&(t.lastDistance=X(t.touches[0],t.touches[1]),t.lastCenter=Y(t.touches[0],t.touches[1]))}(e,t)},r=n=>{F(n,e,t)},o=e=>{!function(e,t){t.touches=Array.from(e.touches),t.touches.length<2&&(t.lastDistance=0)}(e,t)};return e.container.addEventListener("touchstart",n,{passive:!1}),e.container.addEventListener("touchmove",r,{passive:!1}),e.container.addEventListener("touchend",o,{passive:!1}),()=>{e.container.removeEventListener("touchstart",n),e.container.removeEventListener("touchmove",r),e.container.removeEventListener("touchend",o)}}function P(e){const t=e.ctrlKey||e.metaKey,n=[0===e.deltaMode,Math.abs(e.deltaY)<50,e.deltaY%1!=0,Math.abs(e.deltaX)>0&&Math.abs(e.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!t,isTrackpadPinch:n&&t,isZoomGesture:t}}function I(e,t){const n=(e=>d((...t)=>{const n=t[0];if(!n||!e?.updateTransform)return!1;try{const t=e.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,s={scale:t.scale,translateX:t.translateX-o,translateY:t.translateY-a};return y(e.transformLayer,e.config),e.updateTransform(s)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>P(r).isTrackpadScroll?n(r):function(e,t,n){if(!e||"number"!=typeof e.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!t?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{mouseX:s,mouseY:i}=m(t,o,a,n.rulerSize,(e,t)=>({mouseX:e,mouseY:t})),l=n.zoomSpeed,c=P(e);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?D(t,l):l;if(c.isTrackpadPinch){const e=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?D(t,e):e}return B(t,(e.deltaY<0?1:-1)>0?1+u:1/(1+u),s,i)}catch(e){return console.error("Error handling wheel event:",e),!1}}(r,e,t);return e.container.addEventListener("wheel",r,{passive:!1}),()=>{e.container.removeEventListener("wheel",r)}}const Z=100,O=1e3,_=1001,A=4,G=4,H=100,N=100,q=20,K=200;function V(e,t){const n=function(e){const t=document.createElement("div");return t.className="canvas-ruler horizontal-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${e.rulerSize}px;\n\tright: 0;\n\theight: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tz-index: ${O};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),r=function(e){const t=document.createElement("div");return t.className="canvas-ruler vertical-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: ${e.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tz-index: ${O};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),o=function(e){const t=document.createElement("div");return t.className="canvas-ruler corner-box",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${e.rulerSize}px;\n\t\theight: ${e.rulerSize}px;\n\t\tbackground: var(--ruler-background-color);\n\t\tborder-right: 1px solid var(--ruler-border-color);\n\t\tborder-bottom: 1px solid var(--ruler-border-color);\n\t\tz-index: ${_};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${e.rulerFontFamily};\n\t\tfont-size: ${e.rulerFontSize-2}px;\n\t\tcolor: var(--ruler-text-color);\n\t\tpointer-events: none;\n\t`,t.textContent=e.rulerUnits,t}(t),a=t.enableGrid?function(e){const t=document.createElement("div");return t.className="canvas-ruler grid-overlay",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${e.rulerSize}px;\n\t\tleft: ${e.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${Z};\n\t\tbackground-image: \n\t\t\tlinear-gradient(var(--grid-color) 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, var(--grid-color) 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,t}(t):void 0;return e.appendChild(n),e.appendChild(r),e.appendChild(o),a&&e.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function W(e,t){const n=e/Math.max(5,Math.min(20,t/50)),r=10**Math.floor(Math.log10(n)),o=n/r;let a;return a=o<=1?1:o<=2?2:o<=5?5:10,a*r}function U(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${A}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%H===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${A+2}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function j(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${G}px;\n\t\theight: 1px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%H===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\ttop: ${n-6}px;\n\t\t\tright: ${G+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t\ttransform: rotate(-90deg);\n\t\t\ttransform-origin: right center;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function J(e,t,n,r,o){const a=e.getBounds(),s=a.scale||1,i=a.translateX||0,l=a.translateY||0,c=a.width-o.rulerSize,u=a.height-o.rulerSize,d=-i/s,h=-l/s,m=h+u/s;!function(e,t,n,r,o,a){const s=r,i=W(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&U(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(t,d,d+c/s,c,s,o),function(e,t,n,r,o,a){const s=r,i=W(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&j(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(n,h,m,u,s,o),r&&function(e,t,n,r){let o=N*t;for(;o<q;)o*=2;for(;o>K;)o/=2;e.style.backgroundSize=`${o}px ${o}px`,e.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function Q(e,t){const n=g(t,"rulerBackgroundColor"),r=g(t,"rulerBorderColor"),o=g(t,"rulerTextColor"),a=g(t,"rulerTickColor"),s=g(t,"gridColor");e.horizontalRuler&&(e.horizontalRuler.style.setProperty("--ruler-background-color",n),e.horizontalRuler.style.setProperty("--ruler-border-color",r),e.horizontalRuler.style.setProperty("--ruler-text-color",o),e.horizontalRuler.style.setProperty("--ruler-tick-color",a)),e.verticalRuler&&(e.verticalRuler.style.setProperty("--ruler-background-color",n),e.verticalRuler.style.setProperty("--ruler-border-color",r),e.verticalRuler.style.setProperty("--ruler-text-color",o),e.verticalRuler.style.setProperty("--ruler-tick-color",a)),e.cornerBox&&(e.cornerBox.style.setProperty("--ruler-background-color",n),e.cornerBox.style.setProperty("--ruler-border-color",r),e.cornerBox.style.setProperty("--ruler-text-color",o)),e.gridOverlay&&e.gridOverlay.style.setProperty("--grid-color",s)}function ee(e,t){if(!e?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&J(e,n.horizontalRuler,n.verticalRuler,n.gridOverlay,t)};try{return n=V(e.container,t),r=function(e,t){const n=d(t),r=e.updateTransform;e.updateTransform=function(e){const t=r.call(this,e);return n(),t};const o=d(t);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),e.updateTransform=r,n.cleanup(),o.cleanup()}}(e,a),Q(n,t),a(),t.showRulers||(n.horizontalRuler.style.display="none",n.verticalRuler.style.display="none",n.cornerBox.style.display="none"),!t.showGrid&&n.gridOverlay&&(n.gridOverlay.style.display="none"),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,updateTheme:e=>{o||Q(n,e)},show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex"),n.gridOverlay&&(n.gridOverlay.style.display="block")},hide:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="none"),n.verticalRuler&&(n.verticalRuler.style.display="none"),n.cornerBox&&(n.cornerBox.style.display="none"),n.gridOverlay&&(n.gridOverlay.style.display="none")},toggleGrid:()=>{if(n.gridOverlay){const e="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=e?"none":"block"}},destroy:()=>{o=!0,r&&r(),n.horizontalRuler?.parentNode&&n.horizontalRuler.parentNode.removeChild(n.horizontalRuler),n.verticalRuler?.parentNode&&n.verticalRuler.parentNode.removeChild(n.verticalRuler),n.cornerBox?.parentNode&&n.cornerBox.parentNode.removeChild(n.cornerBox),n.gridOverlay?.parentNode&&n.gridOverlay.parentNode.removeChild(n.gridOverlay)}}}catch(e){return console.error("Failed to create rulers:",e),null}}return class{constructor(e,t={}){if(this.cleanupFunctions=[],this.rulers=null,this.dragSetup=null,this._isReady=!1,this.listen=new k,!e)throw new Error("Container element is required");this.config=C(t);const n=x(e,this.config);if(!n)throw new Error("Failed to create canvas");this.baseCanvas=n,this.config.bindToWindow&&(console.log("bindToWindow:","true"),this.listen.setEmitInterceptor((e,t)=>{this.broadcastEvent(e,t)}),this.setupGlobalBinding()),this.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupGlobalBinding(){if("undefined"==typeof window)return;const e=this.config.name||"markupCanvas",t=window;console.log(t),t[e]=this,console.log(t[e]),t.__markupCanvasInstances||(t.__markupCanvasInstances=new Map),t.__markupCanvasInstances.set(e,this)}cleanupGlobalBinding(){if("undefined"==typeof window)return;const e=this.config.name||"markupCanvas",t=window;delete t[e],t.__markupCanvasInstances&&t.__markupCanvasInstances.delete(e)}broadcastEvent(e,t){if("undefined"==typeof window)return;let n=t;"ready"===e&&(n={ready:!0}),window.postMessage({source:"markup-canvas",event:e,data:n,timestamp:Date.now(),canvasName:this.config.name},"*")}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=I(this,this.config);this.cleanupFunctions.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=R(this,this.config,!0),this.cleanupFunctions.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const e=z(this,this.config);this.cleanupFunctions.push(e)}),u(this.config,"enableTouch",()=>{const e=$(this);this.cleanupFunctions.push(e)}),u(this.config,"enableRulers",()=>{this.rulers=ee(this.baseCanvas,this.config),this.cleanupFunctions.push(()=>{this.rulers&&this.rulers.destroy()})})}catch(e){throw console.error("Failed to set up event handlers:",e),this.cleanup(),e}}get container(){return this.baseCanvas.container}get transformLayer(){return this.baseCanvas.transformLayer}get contentLayer(){return this.baseCanvas.contentLayer}get transform(){return this.baseCanvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return this.getVisibleArea()}getBounds(){return this.baseCanvas.getBounds()}updateTransform(e){const t=this.baseCanvas.updateTransform(e);return t&&this.emitTransformEvents(),t}emitTransformEvents(){const e=this.baseCanvas.transform;this.listen.emit("transform",e),this.listen.emit("zoom",e.scale),this.listen.emit("pan",{x:e.translateX,y:e.translateY})}reset(){return this.baseCanvas.reset()}handleResize(){return this.baseCanvas.handleResize()}setZoom(e){return this.baseCanvas.setZoom(e)}canvasToContent(e,t){return this.baseCanvas.canvasToContent(e,t)}zoomToPoint(e,t,n){return b(this.transformLayer,this.config,()=>{const r=this.baseCanvas.zoomToPoint(e,t,n);return r&&this.emitTransformEvents(),r})}resetView(){return b(this.transformLayer,this.config,()=>{const e=!!this.baseCanvas.resetView&&this.baseCanvas.resetView();return e&&this.emitTransformEvents(),e})}zoomToFitContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}panLeft(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX+t};return this.updateTransform(n)}panRight(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX-t};return this.updateTransform(n)}panUp(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY+t};return this.updateTransform(n)}panDown(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY-t};return this.updateTransform(n)}zoomIn(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1+e))};return this.updateTransform(n)}))}zoomOut(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1-e))};return this.updateTransform(n)}))}resetZoom(){return this.resetView()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}toggleGrid(){return!!this.rulers?.toggleGrid&&(this.rulers.toggleGrid(),!0)}showGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="block",!0)}hideGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="none",!0)}isGridVisible(){return!!this.rulers?.gridOverlay&&"none"!==this.rulers.gridOverlay.style.display}toggleRulers(){if(this.rulers){return this.areRulersVisible()?this.rulers.hide():this.rulers.show(),!0}return!1}showRulers(){return!!this.rulers&&(this.rulers.show(),!0)}hideRulers(){return!!this.rulers&&(this.rulers.hide(),!0)}areRulersVisible(){return!!this.rulers?.horizontalRuler&&"none"!==this.rulers.horizontalRuler.style.display}centerContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.getBounds(),t=(e.width-e.contentWidth*this.baseCanvas.transform.scale)/2,n=(e.height-e.contentHeight*this.baseCanvas.transform.scale)/2;return this.updateTransform({translateX:t,translateY:n})})}fitToScreen(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}getVisibleArea(){return this.baseCanvas.getBounds().visibleArea}isPointVisible(e,t){const n=this.getVisibleArea();return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}scrollToPoint(e,t){return b(this.transformLayer,this.config,()=>{const n=this.baseCanvas.getBounds(),r=n.width/2,o=n.height/2,a=r-e*this.baseCanvas.transform.scale,s=o-t*this.baseCanvas.transform.scale;return this.updateTransform({translateX:a,translateY:s})})}getConfig(){return{...this.config}}updateConfig(e){this.config=C({...this.config,...e})}updateThemeMode(e){const t={...this.config,themeMode:e};this.config=C(t);const n=g(this.config,"canvasBackgroundColor");this.baseCanvas.container.style.backgroundColor=n,this.rulers&&this.rulers.updateTheme(this.config)}cleanup(){this.cleanupGlobalBinding(),this.cleanupFunctions.forEach(e=>{try{e()}catch(e){console.warn("Error during cleanup:",e)}}),this.cleanupFunctions=[],this.removeAllListeners()}on(e,t){this.listen.on(e,t)}off(e,t){this.listen.off(e,t)}emit(e,t){this.listen.emit(e,t)}removeAllListeners(){this.listen.removeAllListeners()}destroy(){this.cleanup(),window.__markupCanvasTransitionTimeout&&clearTimeout(window.__markupCanvasTransitionTimeout)}}});
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).MarkupCanvas=t()}(this,function(){"use strict";const e="canvas-container",t="transform-layer",n="content-layer";function r(e,r){const o=Array.from(e.children);let a=e.querySelector(`.${t}`);a||(a=document.createElement("div"),a.className=t,e.appendChild(a)),function(e,t){e.style.position="absolute";const n=t.rulerSize;e.style.top=`${n}px`,e.style.left=`${n}px`,e.style.width=`${t.width}px`,e.style.height=`${t.height}px`,e.style.transformOrigin="0 0"}(a,r);let s=a.querySelector(`.${n}`);return s||(s=document.createElement("div"),s.className=n,a.appendChild(s),function(e,n,r){e.forEach(e=>{e===r||e.classList.contains(t)||n.appendChild(e)})}(o,s,a)),function(e){e.style.position="relative",e.style.width="100%",e.style.height="100%",e.style.pointerEvents="auto"}(s),{transformLayer:a,contentLayer:s}}function o(e,t,n){if(!n?.inverse)return{x:e,y:t};try{const r=n.inverse(),o=new DOMPoint(e,t).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:e,y:t}}}function a(e,t){return Math.max(t.minZoom,Math.min(t.maxZoom,e))}function s(e,t,n){return new DOMMatrix([e,0,0,e,t,n])}function i(e,t,n,r,o){const s=o.enableRulers?-o.rulerSize:0,i=n||{scale:1,translateX:s,translateY:s},{scale:l,translateX:c,translateY:u}=i,d=a(l*r,o);if(Math.abs(d-l)<.001)return{scale:l,translateX:c,translateY:u};return{scale:d,translateX:e-(e-c)/l*d,translateY:t-(t-u)/l*d}}function l(e,t){return t(t=>a(t,e))}const c=new Map;function u(e,t,n){return e[t]?n():null}function d(e){let t=null,n=null;const r=(...r)=>{n=r,null===t&&(t=requestAnimationFrame(()=>{n&&e(...n),t=null,n=null}))};return r.cleanup=()=>{null!==t&&(cancelAnimationFrame(t),t=null,n=null)},r}function h(e,t,n){return n(null!==e.container.querySelector(".canvas-ruler")?t:0)}function m(e,t,n,r,o){const a=null!==e.container.querySelector(".canvas-ruler");return o(a?t-r:t,a?n-r:n)}function g(e,t){if("dark"===e.themeMode){return e[`${t}Dark`]}return e[t]}const f={width:8e3,height:8e3,enableAcceleration:!0,bindToWindow:!1,name:"markupCanvas",enablePostMessageAPI:!1,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,bindKeyboardEventsTo:"canvas",zoomSpeed:1.5,minZoom:.05,maxZoom:80,enableTransition:!0,transitionDuration:.2,enableAdaptiveSpeed:!0,enableLeftDrag:!0,enableMiddleDrag:!0,requireSpaceForMouseDrag:!1,keyboardPanStep:50,keyboardFastMultiplier:20,keyboardZoomStep:.2,enableClickToZoom:!0,clickZoomLevel:1,requireOptionForClickZoom:!1,enableRulers:!0,enableGrid:!1,showRulers:!0,showGrid:!1,rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,canvasBackgroundColor:"rgba(250, 250, 250, 1)",canvasBackgroundColorDark:"rgba(40, 40, 40, 1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"rgba(240, 240, 240, 1)",rulerTextColor:"rgba(102, 102, 102, 1)",rulerTickColor:"rgba(204, 204, 204, 1)",gridColor:"rgba(232, 86, 193, 0.5)",rulerBackgroundColorDark:"rgba(30, 30, 30, 0.95)",rulerBorderColorDark:"rgba(68, 68, 68, 1)",rulerTextColorDark:"rgba(170, 170, 170, 1)",rulerTickColorDark:"rgba(104, 104, 104, 1)",gridColorDark:"rgba(232, 86, 193, 0.5)",themeMode:"light",onTransformUpdate:()=>{}};function p(e){try{const t=e.container,n=e.config,r=e.transform||{scale:1,translateX:0,translateY:0},a=t.getBoundingClientRect(),i=a.width||t.clientWidth||0,l=a.height||t.clientHeight||0,c=h({container:t},n.rulerSize,e=>Math.max(0,i-e)),u=h({container:t},n.rulerSize,e=>Math.max(0,l-e)),d=n.width||f.width,m=n.height||f.height,g=function(e,t,n,r,a){const i=o(0,0,s(a.scale,a.translateX,a.translateY)),l=o(e,t,s(a.scale,a.translateX,a.translateY));return{x:Math.max(0,Math.min(n,i.x)),y:Math.max(0,Math.min(r,i.y)),width:Math.max(0,Math.min(n-i.x,l.x-i.x)),height:Math.max(0,Math.min(r-i.y,l.y-i.y))}}(c,u,d,m,r);return{width:c,height:u,contentWidth:d,contentHeight:m,scale:r.scale,translateX:r.translateX,translateY:r.translateY,visibleArea:g,scaledContentWidth:d*r.scale,scaledContentHeight:m*r.scale,canPanLeft:r.translateX<0,canPanRight:r.translateX+d*r.scale>c,canPanUp:r.translateY<0,canPanDown:r.translateY+m*r.scale>u,canZoomIn:r.scale<3.5,canZoomOut:r.scale>.1}}catch(e){return console.error("Failed to calculate canvas bounds:",e),{width:0,height:0,contentWidth:0,contentHeight:0,scale:1,translateX:0,translateY:0,visibleArea:{x:0,y:0,width:0,height:0},scaledContentWidth:0,scaledContentHeight:0,canPanLeft:!1,canPanRight:!1,canPanUp:!1,canPanDown:!1,canZoomIn:!1,canZoomOut:!1}}}function v(e,t){if(!e?.style||!t)return!1;try{return e.style.transform=function(e){return`matrix3d(${e.m11}, ${e.m12}, ${e.m13}, ${e.m14}, ${e.m21}, ${e.m22}, ${e.m23}, ${e.m24}, ${e.m31}, ${e.m32}, ${e.m33}, ${e.m34}, ${e.m41}, ${e.m42}, ${e.m43}, ${e.m44})`}(t),!0}catch(e){return console.warn("Transform application failed:",e),!1}}function y(e,t){try{if(t.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(e,t,n){const r=c.get(e);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(e)},t);c.set(e,o)}("disableTransition",1e3*(t.transitionDuration??.2),()=>{e.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(e){return console.error("Failed to disable transitions:",e),!0}}function b(e,t,n){!function(e,t){try{return!!t.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),e.style.transition=`transform ${t.transitionDuration}s linear`,!0)}catch(e){return console.error("Failed to enable transitions:",e),!1}}(e,t);try{return n()}finally{y(e,t)}}function w(t,n){if("static"===getComputedStyle(t).position&&(t.style.position="relative"),t.style.overflow="hidden",t.style.cursor="grab",t.style.overscrollBehavior="none",n){const e=g(n,"canvasBackgroundColor");t.style.backgroundColor=e}t.hasAttribute("tabindex")||t.setAttribute("tabindex","0"),function(e){const t=e.getBoundingClientRect(),n=getComputedStyle(e);0===t.height&&"auto"===n.height&&console.error("MarkupCanvas: Container height is 0. Please set a height on your container element using CSS.","Examples: height: 100vh, height: 500px, or use flexbox/grid layout.",e),0===t.width&&"auto"===n.width&&console.error("MarkupCanvas: Container width is 0. Please set a width on your container element using CSS.","Examples: width: 100vw, width: 800px, or use flexbox/grid layout.",e)}(t),t.classList.contains(e)||t.classList.add(e)}function C(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{w(e,t);const{transformLayer:n,contentLayer:a}=r(e,t);t.enableAcceleration&&function(e){try{return e.style.transform=e.style.transform||"translateZ(0)",e.style.backfaceVisibility="hidden",!0}catch(e){return console.error("Failed to enable hardware acceleration:",e),!1}}(n);const c=t.enableRulers?-t.rulerSize:0,d={scale:1,translateX:c,translateY:c};v(n,s(d.scale,d.translateX,d.translateY));return{container:e,transformLayer:n,contentLayer:a,config:t,transform:d,getBounds:function(){return p(this)},updateTransform:function(e){this.transform={...this.transform,...e};const t=s(this.transform.scale,this.transform.translateX,this.transform.translateY),n=v(this.transformLayer,t);return u(this.config,"onTransformUpdate",()=>{this.config.onTransformUpdate(this.transform)}),n},reset:function(){return this.updateTransform({scale:1,translateX:0,translateY:0})},handleResize:function(){return!0},setZoom:function(e){const t=l(this.config,t=>t(e));return this.updateTransform({scale:t})},canvasToContent:function(e,t){return o(e,t,s(this.transform.scale,this.transform.translateX,this.transform.translateY))},zoomToPoint:function(e,t,n){return b(this.transformLayer,this.config,()=>{const r=i(e,t,this.transform,n/this.transform.scale,this.config);return this.updateTransform(r)})},resetView:function(){return b(this.transformLayer,this.config,()=>h(this,this.config.rulerSize,e=>{const t={scale:1,translateX:-1*e,translateY:-1*e};return this.updateTransform(t)}))},zoomToFitContent:function(){return b(this.transformLayer,this.config,()=>{const e=this.getBounds(),t=e.width/this.config.width,n=e.height/this.config.height,r=l(this.config,e=>e(.9*Math.min(t,n))),o=this.config.width*r,a=this.config.height*r,s=(e.width-o)/2,i=(e.height-a)/2;return this.updateTransform({scale:r,translateX:s,translateY:i})})}}}catch(e){return console.error("Failed to create canvas:",e),null}}function x(e={}){const t={...f,...e};return("number"!=typeof t.width||t.width<=0)&&(console.warn("Invalid width, using default"),t.width=f.width),("number"!=typeof t.height||t.height<=0)&&(console.warn("Invalid height, using default"),t.height=f.height),("number"!=typeof t.zoomSpeed||t.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),t.zoomSpeed=f.zoomSpeed),("number"!=typeof t.minZoom||t.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),t.minZoom=f.minZoom),("number"!=typeof t.maxZoom||t.maxZoom<=t.minZoom)&&(console.warn("Invalid maxZoom, using default"),t.maxZoom=f.maxZoom),("number"!=typeof t.keyboardPanStep||t.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),t.keyboardPanStep=f.keyboardPanStep),("number"!=typeof t.keyboardFastMultiplier||t.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),t.keyboardFastMultiplier=f.keyboardFastMultiplier),("number"!=typeof t.clickZoomLevel||t.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),t.clickZoomLevel=f.clickZoomLevel),("number"!=typeof t.rulerFontSize||t.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),t.rulerFontSize=f.rulerFontSize),("number"!=typeof t.rulerSize||t.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),t.rulerSize=f.rulerSize),t}class k{constructor(){this.listeners=new Map}setEmitInterceptor(e){this.emitInterceptor=e}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t)}off(e,t){const n=this.listeners.get(e);n&&n.delete(t)}emit(e,t){this.emitInterceptor?.(e,t);const n=this.listeners.get(e);n&&n.forEach(n=>{try{n(t)}catch(t){console.error(`Error in event handler for "${String(e)}":`,t)}})}removeAllListeners(){this.listeners.clear()}}const T=300,S=5;function D(e,t){if(!e?.getBounds)return t;try{const n=e.getBounds(),r=n.width*n.height;return t*(r/2073600)**1}catch(e){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",e),t}}function M(e,t){let n=0,r=0;function o(o){const a=e.container.getBoundingClientRect(),s=o.clientX-a.left,i=o.clientY-a.top;!function(e,t,n,r,o){h(e,t,e=>o(n-e,r-e))}(e,t.rulerSize,s,i,(e,t)=>{n=e,r=t})}function s(o){if(!(o instanceof KeyboardEvent))return;if("canvas"===t.bindKeyboardEventsTo&&document.activeElement!==e.container)return;const s=o.shiftKey,l=t.keyboardPanStep*(s?t.keyboardFastMultiplier:1);let c=!1;const u={};switch(o.key){case"ArrowLeft":u.translateX=e.transform.translateX+l,c=!0;break;case"ArrowRight":u.translateX=e.transform.translateX-l,c=!0;break;case"ArrowUp":u.translateY=e.transform.translateY+l,c=!0;break;case"ArrowDown":u.translateY=e.transform.translateY-l,c=!0;break;case"=":case"+":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1+n),t),c=!0}break;case"-":{const n=t.enableAdaptiveSpeed?D(e,t.keyboardZoomStep):t.keyboardZoomStep;u.scale=a(e.transform.scale*(1-n),t),c=!0}break;case"0":if(o.metaKey||o.ctrlKey){const o=1/e.transform.scale,a=i(n,r,e.transform,o,t);Object.assign(u,a),c=!0}break;case"g":case"G":e.toggleGrid&&e.toggleGrid(),c=!0;break;case"r":case"R":o.metaKey||o.ctrlKey||o.altKey||!e.toggleRulers||(e.toggleRulers(),c=!0)}c&&(o.preventDefault(),Object.keys(u).length>0&&e.updateTransform(u))}const l="canvas"===t.bindKeyboardEventsTo?e.container:document;return l.addEventListener("keydown",s),e.container.addEventListener("mousemove",o),()=>{l.removeEventListener("keydown",s),e.container.removeEventListener("mousemove",o)}}function z(e,t,n,r,o){n?t.requireSpaceForMouseDrag?e.container.style.cursor=r?"grab":"default":e.container.style.cursor=o?"grabbing":"grab":e.container.style.cursor="default"}function L(e,t,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),z(e,t,n,r,!1)}function R(e,t,n,r,o,a,s,i,l,c){a&&e.button===s&&L(t,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===e.button&&n.enableClickToZoom&&i>0&&function(e,t,n,r,o,a){const s=Date.now()-r,i=e.altKey,l=!n.requireOptionForClickZoom||i;if(s<T&&!o&&!a&&l){e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{clickX:s,clickY:i}=m(t,o,a,n.rulerSize,(e,t)=>({clickX:e,clickY:t})),l=t.canvasToContent(s,i),c=r.width/2,u=r.height/2,d=n.clickZoomLevel,h={scale:d,translateX:c-l.x*d,translateY:u-l.y*d};b(t.transformLayer,t.config,()=>{t.updateTransform(h)})}}(e,t,n,i,l,a),0===e.button&&function(e){e.setMouseDownTime(0),e.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function E(e,t,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,m=!1;const g={setIsDragging:e=>{o=e},setDragButton:e=>{i=e},setIsSpacePressed:e=>{l=e},setMouseDownTime:e=>{c=e},setMouseDownX:e=>{u=e},setMouseDownY:e=>{h=e},setHasDragged:e=>{m=e},setLastMouseX:e=>{a=e},setLastMouseY:e=>{s=e}},f=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!0),z(t,n,r,!0,o))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed})},p=n=>{!function(e,t,n,r,o,a){n.requireSpaceForMouseDrag&&" "===e.key&&(a.setIsSpacePressed(!1),z(t,n,r,!1,o),o&&L(t,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,e,t,r,o,{setIsSpacePressed:g.setIsSpacePressed,setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})},v=n=>{!function(e,t,n,r,o,a){const s=0===e.button,i=1===e.button;if(s&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(e.clientX),a.setMouseDownY(e.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(s&&n.enableLeftDrag||i&&n.enableMiddleDrag)&&(e.preventDefault(),a.setDragButton(e.button),a.setLastMouseX(e.clientX),a.setLastMouseY(e.clientY),z(t,n,r,o,!1))}(n,e,t,r,l,g)},y=t=>{!function(e,t,n,r,o,a,s,i,l,c){if(o>0){const t=Math.abs(e.clientX-a),o=Math.abs(e.clientY-s);(t>S||o>S)&&(c.setHasDragged(!0),!r&&n&&c.setIsDragging(!0))}if(!r||!n)return;e.preventDefault(),d((...e)=>{const o=e[0];if(!r||!n)return;const a=o.clientX-i,s=o.clientY-l,u={translateX:t.transform.translateX+a,translateY:t.transform.translateY+s};t.updateTransform(u),c.setLastMouseX(o.clientX),c.setLastMouseY(o.clientY)})(e)}(t,e,r,o,c,u,h,a,s,{setHasDragged:g.setHasDragged,setIsDragging:g.setIsDragging,setLastMouseX:g.setLastMouseX,setLastMouseY:g.setLastMouseY})},b=n=>{R(n,e,t,r,l,o,i,c,m,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton,setMouseDownTime:g.setMouseDownTime,setHasDragged:g.setHasDragged})},w=()=>{!function(e,t,n,r,o,a){o&&L(e,t,n,r,a)}(e,t,r,l,o,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton})};e.container.addEventListener("mousedown",v),document.addEventListener("mousemove",y),document.addEventListener("mouseup",b),e.container.addEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",f),document.addEventListener("keyup",p)),z(e,t,r,l,o);const C=()=>{e.container.removeEventListener("mousedown",v),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",b),e.container.removeEventListener("mouseleave",w),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",f),document.removeEventListener("keyup",p))};return n?{cleanup:C,enable:()=>(r=!0,z(e,t,r,l,o),!0),disable:()=>(r=!1,o&&L(e,t,r,l,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton}),z(e,t,r,l,o),!0),isEnabled:()=>r}:C}function Y(e){const t=t=>{const n=t.data;if("markup-canvas"!==n.source)return;const r=e.config.name||"markupCanvas";if(n.canvasName!==r)return;const o=n.action,a=n.args||[];try{if("zoomIn"===o)e.zoomIn(a[0]);else if("zoomOut"===o)e.zoomOut(a[0]);else if("resetZoom"===o)e.resetZoom();else if("panLeft"===o)e.panLeft(a[0]);else if("panRight"===o)e.panRight(a[0]);else if("panUp"===o)e.panUp(a[0]);else if("panDown"===o)e.panDown(a[0]);else if("fitToScreen"===o)e.fitToScreen();else if("centerContent"===o)e.centerContent();else if("scrollToPoint"===o)e.scrollToPoint(a[0],a[1]);else if("resetView"===o)e.resetView();else if("toggleRulers"===o)e.toggleRulers();else if("showRulers"===o)e.showRulers();else if("hideRulers"===o)e.hideRulers();else if("toggleGrid"===o)e.toggleGrid();else if("showGrid"===o)e.showGrid();else if("hideGrid"===o)e.hideGrid();else if("updateThemeMode"===o){const t=a[0];if("light"!==t&&"dark"!==t)throw new Error(`Invalid theme mode: ${t}`);e.updateThemeMode(t)}else{if("toggleThemeMode"!==o)throw new Error(`Unknown action: ${o}`);{const t="light"===e.getConfig().themeMode?"dark":"light";e.updateThemeMode(t)}}}catch(e){!function(e,t,n){window.postMessage({source:"markup-canvas-error",canvasName:e,action:t,error:n,timestamp:Date.now()},"*")}(r,o,e instanceof Error?e.message:String(e))}};return"undefined"!=typeof window&&window.addEventListener("message",t),()=>{"undefined"!=typeof window&&window.removeEventListener("message",t)}}function X(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function B(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function F(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function $(e,t,n){e.preventDefault();const r=Array.from(e.touches);d((...e)=>{const r=e[0];if(1===r.length){if(1===n.touches.length){const e=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:t.transform.translateX+e,translateY:t.transform.translateY+o};t.updateTransform(a)}}else if(2===r.length){const e=B(r[0],r[1]),o=X(r[0],r[1]);if(n.lastDistance>0){const r=e/n.lastDistance,a=t.container.getBoundingClientRect();let s=o.x-a.left,i=o.y-a.top;const l=function(e,t,n,r){return h(e,t,e=>{const t={...n,x:n.x-e,y:n.y-e};return r(t)})}(t,t.config.rulerSize,{x:s,y:i},e=>e);s=l.x,i=l.y,F(t,r,s,i)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function P(e){const t={touches:[],lastDistance:0,lastCenter:{}},n=e=>{!function(e,t){e.preventDefault(),t.touches=Array.from(e.touches),2===t.touches.length&&(t.lastDistance=B(t.touches[0],t.touches[1]),t.lastCenter=X(t.touches[0],t.touches[1]))}(e,t)},r=n=>{$(n,e,t)},o=e=>{!function(e,t){t.touches=Array.from(e.touches),t.touches.length<2&&(t.lastDistance=0)}(e,t)};return e.container.addEventListener("touchstart",n,{passive:!1}),e.container.addEventListener("touchmove",r,{passive:!1}),e.container.addEventListener("touchend",o,{passive:!1}),()=>{e.container.removeEventListener("touchstart",n),e.container.removeEventListener("touchmove",r),e.container.removeEventListener("touchend",o)}}function I(e){const t=e.ctrlKey||e.metaKey,n=[0===e.deltaMode,Math.abs(e.deltaY)<50,e.deltaY%1!=0,Math.abs(e.deltaX)>0&&Math.abs(e.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!t,isTrackpadPinch:n&&t,isZoomGesture:t}}function Z(e,t){const n=(e=>d((...t)=>{const n=t[0];if(!n||!e?.updateTransform)return!1;try{const t=e.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,s={scale:t.scale,translateX:t.translateX-o,translateY:t.translateY-a};return y(e.transformLayer,e.config),e.updateTransform(s)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>I(r).isTrackpadScroll?n(r):function(e,t,n){if(!e||"number"!=typeof e.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!t?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{e.preventDefault();const r=t.container.getBoundingClientRect(),o=e.clientX-r.left,a=e.clientY-r.top,{mouseX:s,mouseY:i}=m(t,o,a,n.rulerSize,(e,t)=>({mouseX:e,mouseY:t})),l=n.zoomSpeed,c=I(e);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?D(t,l):l;if(c.isTrackpadPinch){const e=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?D(t,e):e}return F(t,(e.deltaY<0?1:-1)>0?1+u:1/(1+u),s,i)}catch(e){return console.error("Error handling wheel event:",e),!1}}(r,e,t);return e.container.addEventListener("wheel",r,{passive:!1}),()=>{e.container.removeEventListener("wheel",r)}}const O=100,A=1e3,_=1001,G=4,H=4,N=100,q=100,K=20,V=200;function U(e,t){const n=function(e){const t=document.createElement("div");return t.className="canvas-ruler horizontal-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${e.rulerSize}px;\n\tright: 0;\n\theight: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tz-index: ${A};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),r=function(e){const t=document.createElement("div");return t.className="canvas-ruler vertical-ruler",t.style.cssText=`\n\tposition: absolute;\n\ttop: ${e.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${e.rulerSize}px;\n\tbackground: var(--ruler-background-color);\n\tborder-right: 1px solid var(--ruler-border-color);\n\tborder-bottom: 1px solid var(--ruler-border-color);\n\tz-index: ${A};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: var(--ruler-text-color);\n\toverflow: hidden;\n `,t}(t),o=function(e){const t=document.createElement("div");return t.className="canvas-ruler corner-box",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${e.rulerSize}px;\n\t\theight: ${e.rulerSize}px;\n\t\tbackground: var(--ruler-background-color);\n\t\tborder-right: 1px solid var(--ruler-border-color);\n\t\tborder-bottom: 1px solid var(--ruler-border-color);\n\t\tz-index: ${_};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${e.rulerFontFamily};\n\t\tfont-size: ${e.rulerFontSize-2}px;\n\t\tcolor: var(--ruler-text-color);\n\t\tpointer-events: none;\n\t`,t.textContent=e.rulerUnits,t}(t),a=t.enableGrid?function(e){const t=document.createElement("div");return t.className="canvas-ruler grid-overlay",t.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${e.rulerSize}px;\n\t\tleft: ${e.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${O};\n\t\tbackground-image: \n\t\t\tlinear-gradient(var(--grid-color) 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, var(--grid-color) 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,t}(t):void 0;return e.appendChild(n),e.appendChild(r),e.appendChild(o),a&&e.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function W(e,t){const n=e/Math.max(5,Math.min(20,t/50)),r=10**Math.floor(Math.log10(n)),o=n/r;let a;return a=o<=1?1:o<=2?2:o<=5?5:10,a*r}function j(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${G}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%N===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${G+2}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function J(e,t,n,r,o){const a=document.createElement("div");a.className="tick",a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${H}px;\n\t\theight: 1px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%N===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\ttop: ${n-6}px;\n\t\t\tright: ${H+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: var(--ruler-text-color);\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t\ttransform: rotate(-90deg);\n\t\t\ttransform-origin: right center;\n\t\t`,r.textContent=Math.round(t).toString(),e.appendChild(r)}}function Q(e,t,n,r,o){const a=e.getBounds(),s=a.scale||1,i=a.translateX||0,l=a.translateY||0,c=a.width-o.rulerSize,u=a.height-o.rulerSize,d=-i/s,h=-l/s,m=h+u/s;!function(e,t,n,r,o,a){const s=r,i=W(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&j(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(t,d,d+c/s,c,s,o),function(e,t,n,r,o,a){const s=r,i=W(n-t,s),l=document.createDocumentFragment(),c=Math.floor(t/i)*i,u=Math.ceil(n/i)*i;for(let e=c;e<=u;e+=i){const n=(e-t)*o;n>=-50&&n<=s+50&&J(l,e,n,0,a)}e.innerHTML="",e.appendChild(l)}(n,h,m,u,s,o),r&&function(e,t,n,r){let o=q*t;for(;o<K;)o*=2;for(;o>V;)o/=2;e.style.backgroundSize=`${o}px ${o}px`,e.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function ee(e,t){const n=g(t,"rulerBackgroundColor"),r=g(t,"rulerBorderColor"),o=g(t,"rulerTextColor"),a=g(t,"rulerTickColor"),s=g(t,"gridColor");e.horizontalRuler&&(e.horizontalRuler.style.setProperty("--ruler-background-color",n),e.horizontalRuler.style.setProperty("--ruler-border-color",r),e.horizontalRuler.style.setProperty("--ruler-text-color",o),e.horizontalRuler.style.setProperty("--ruler-tick-color",a)),e.verticalRuler&&(e.verticalRuler.style.setProperty("--ruler-background-color",n),e.verticalRuler.style.setProperty("--ruler-border-color",r),e.verticalRuler.style.setProperty("--ruler-text-color",o),e.verticalRuler.style.setProperty("--ruler-tick-color",a)),e.cornerBox&&(e.cornerBox.style.setProperty("--ruler-background-color",n),e.cornerBox.style.setProperty("--ruler-border-color",r),e.cornerBox.style.setProperty("--ruler-text-color",o)),e.gridOverlay&&e.gridOverlay.style.setProperty("--grid-color",s)}function te(e,t){if(!e?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&Q(e,n.horizontalRuler,n.verticalRuler,n.gridOverlay,t)};try{return n=U(e.container,t),r=function(e,t){const n=d(t),r=e.updateTransform;e.updateTransform=function(e){const t=r.call(this,e);return n(),t};const o=d(t);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),e.updateTransform=r,n.cleanup(),o.cleanup()}}(e,a),ee(n,t),a(),t.showRulers||(n.horizontalRuler.style.display="none",n.verticalRuler.style.display="none",n.cornerBox.style.display="none"),!t.showGrid&&n.gridOverlay&&(n.gridOverlay.style.display="none"),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,updateTheme:e=>{o||ee(n,e)},show:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="block"),n.verticalRuler&&(n.verticalRuler.style.display="block"),n.cornerBox&&(n.cornerBox.style.display="flex"),n.gridOverlay&&(n.gridOverlay.style.display="block")},hide:()=>{n.horizontalRuler&&(n.horizontalRuler.style.display="none"),n.verticalRuler&&(n.verticalRuler.style.display="none"),n.cornerBox&&(n.cornerBox.style.display="none"),n.gridOverlay&&(n.gridOverlay.style.display="none")},toggleGrid:()=>{if(n.gridOverlay){const e="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=e?"none":"block"}},destroy:()=>{o=!0,r&&r(),n.horizontalRuler?.parentNode&&n.horizontalRuler.parentNode.removeChild(n.horizontalRuler),n.verticalRuler?.parentNode&&n.verticalRuler.parentNode.removeChild(n.verticalRuler),n.cornerBox?.parentNode&&n.cornerBox.parentNode.removeChild(n.cornerBox),n.gridOverlay?.parentNode&&n.gridOverlay.parentNode.removeChild(n.gridOverlay)}}}catch(e){return console.error("Failed to create rulers:",e),null}}return class{constructor(e,t={}){if(this.cleanupFunctions=[],this.rulers=null,this.dragSetup=null,this._isReady=!1,this.listen=new k,this.postMessageCleanup=null,!e)throw new Error("Container element is required");this.config=x(t);const n=C(e,this.config);if(!n)throw new Error("Failed to create canvas");this.baseCanvas=n,this.config.bindToWindow&&(console.log("bindToWindow:","true"),this.listen.setEmitInterceptor((e,t)=>{this.broadcastEvent(e,t)}),this.setupGlobalBinding(),this.config.enablePostMessageAPI&&(this.postMessageCleanup=Y(this))),this.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupGlobalBinding(){if("undefined"==typeof window)return;const e=this.config.name||"markupCanvas",t=window;console.log(t),t[e]=this,console.log(t[e]),t.__markupCanvasInstances||(t.__markupCanvasInstances=new Map),t.__markupCanvasInstances.set(e,this)}cleanupGlobalBinding(){if("undefined"==typeof window)return;const e=this.config.name||"markupCanvas",t=window;delete t[e],t.__markupCanvasInstances&&t.__markupCanvasInstances.delete(e)}broadcastEvent(e,t){if("undefined"==typeof window)return;let n=t;"ready"===e&&(n={ready:!0}),window.postMessage({source:"markup-canvas",event:e,data:n,timestamp:Date.now(),canvasName:this.config.name},"*")}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=Z(this,this.config);this.cleanupFunctions.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=E(this,this.config,!0),this.cleanupFunctions.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const e=M(this,this.config);this.cleanupFunctions.push(e)}),u(this.config,"enableTouch",()=>{const e=P(this);this.cleanupFunctions.push(e)}),u(this.config,"enableRulers",()=>{this.rulers=te(this.baseCanvas,this.config),this.cleanupFunctions.push(()=>{this.rulers&&this.rulers.destroy()})})}catch(e){throw console.error("Failed to set up event handlers:",e),this.cleanup(),e}}get container(){return this.baseCanvas.container}get transformLayer(){return this.baseCanvas.transformLayer}get contentLayer(){return this.baseCanvas.contentLayer}get transform(){return this.baseCanvas.transform}get isReady(){return this._isReady}get isTransforming(){return this.dragSetup?.isEnabled()||!1}get visibleBounds(){return this.getVisibleArea()}getBounds(){return this.baseCanvas.getBounds()}updateTransform(e){const t=this.baseCanvas.updateTransform(e);return t&&this.emitTransformEvents(),t}emitTransformEvents(){const e=this.baseCanvas.transform;this.listen.emit("transform",e),this.listen.emit("zoom",e.scale),this.listen.emit("pan",{x:e.translateX,y:e.translateY})}reset(){return this.baseCanvas.reset()}handleResize(){return this.baseCanvas.handleResize()}setZoom(e){return this.baseCanvas.setZoom(e)}canvasToContent(e,t){return this.baseCanvas.canvasToContent(e,t)}zoomToPoint(e,t,n){return b(this.transformLayer,this.config,()=>{const r=this.baseCanvas.zoomToPoint(e,t,n);return r&&this.emitTransformEvents(),r})}resetView(){return b(this.transformLayer,this.config,()=>{const e=!!this.baseCanvas.resetView&&this.baseCanvas.resetView();return e&&this.emitTransformEvents(),e})}zoomToFitContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}panLeft(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX+t};return this.updateTransform(n)}panRight(e){const t=e??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX-t};return this.updateTransform(n)}panUp(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY+t};return this.updateTransform(n)}panDown(e){const t=e??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY-t};return this.updateTransform(n)}zoomIn(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1+e))};return this.updateTransform(n)}))}zoomOut(e=.1){return b(this.transformLayer,this.config,()=>l(this.config,t=>{const n={scale:t(this.baseCanvas.transform.scale*(1-e))};return this.updateTransform(n)}))}resetZoom(){return this.resetView()}enableMouseDrag(){return this.dragSetup?.enable()??!1}disableMouseDrag(){return this.dragSetup?.disable()??!1}isMouseDragEnabled(){return this.dragSetup?.isEnabled()??!1}toggleGrid(){return!!this.rulers?.toggleGrid&&(this.rulers.toggleGrid(),!0)}showGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="block",!0)}hideGrid(){return!!this.rulers?.gridOverlay&&(this.rulers.gridOverlay.style.display="none",!0)}isGridVisible(){return!!this.rulers?.gridOverlay&&"none"!==this.rulers.gridOverlay.style.display}toggleRulers(){if(this.rulers){return this.areRulersVisible()?this.rulers.hide():this.rulers.show(),!0}return!1}showRulers(){return!!this.rulers&&(this.rulers.show(),!0)}hideRulers(){return!!this.rulers&&(this.rulers.hide(),!0)}areRulersVisible(){return!!this.rulers?.horizontalRuler&&"none"!==this.rulers.horizontalRuler.style.display}centerContent(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.getBounds(),t=(e.width-e.contentWidth*this.baseCanvas.transform.scale)/2,n=(e.height-e.contentHeight*this.baseCanvas.transform.scale)/2;return this.updateTransform({translateX:t,translateY:n})})}fitToScreen(){return b(this.transformLayer,this.config,()=>{const e=this.baseCanvas.zoomToFitContent();return e&&this.emitTransformEvents(),e})}getVisibleArea(){return this.baseCanvas.getBounds().visibleArea}isPointVisible(e,t){const n=this.getVisibleArea();return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}scrollToPoint(e,t){return b(this.transformLayer,this.config,()=>{const n=this.baseCanvas.getBounds(),r=n.width/2,o=n.height/2,a=r-e*this.baseCanvas.transform.scale,s=o-t*this.baseCanvas.transform.scale;return this.updateTransform({translateX:a,translateY:s})})}getConfig(){return{...this.config}}updateConfig(e){this.config=x({...this.config,...e})}updateThemeMode(e){const t={...this.config,themeMode:e};this.config=x(t);const n=g(this.config,"canvasBackgroundColor");this.baseCanvas.container.style.backgroundColor=n,this.rulers&&this.rulers.updateTheme(this.config)}cleanup(){this.cleanupGlobalBinding(),this.postMessageCleanup&&(this.postMessageCleanup(),this.postMessageCleanup=null),this.cleanupFunctions.forEach(e=>{try{e()}catch(e){console.warn("Error during cleanup:",e)}}),this.cleanupFunctions=[],this.removeAllListeners()}on(e,t){this.listen.on(e,t)}off(e,t){this.listen.off(e,t)}emit(e,t){this.listen.emit(e,t)}removeAllListeners(){this.listen.removeAllListeners()}destroy(){this.cleanup(),window.__markupCanvasTransitionTimeout&&clearTimeout(window.__markupCanvasTransitionTimeout)}}});
|
package/dist/types/config.d.ts
CHANGED
package/dist/types/events.d.ts
CHANGED
|
@@ -31,3 +31,10 @@ export interface MouseDragControls {
|
|
|
31
31
|
disable: () => boolean;
|
|
32
32
|
isEnabled: () => boolean;
|
|
33
33
|
}
|
|
34
|
+
export type PostMessageAction = "zoomIn" | "zoomOut" | "resetZoom" | "panLeft" | "panRight" | "panUp" | "panDown" | "fitToScreen" | "centerContent" | "scrollToPoint" | "resetView" | "toggleRulers" | "showRulers" | "hideRulers" | "toggleGrid" | "showGrid" | "hideGrid" | "updateThemeMode" | "toggleThemeMode";
|
|
35
|
+
export interface PostMessageRequest {
|
|
36
|
+
source: "markup-canvas";
|
|
37
|
+
canvasName: string;
|
|
38
|
+
action: PostMessageAction;
|
|
39
|
+
args?: unknown[];
|
|
40
|
+
}
|
package/package.json
CHANGED
package/src/lib/MarkupCanvas.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createCanvas } from "@/lib/canvas/index.js";
|
|
2
2
|
import { createMarkupCanvasConfig } from "@/lib/config/createMarkupCanvasConfig.js";
|
|
3
3
|
import { EventEmitter } from "@/lib/events/EventEmitter.js";
|
|
4
|
-
import { setupKeyboardEvents, setupMouseEvents, setupTouchEvents, setupWheelEvents } from "@/lib/events/index.js";
|
|
4
|
+
import { setupKeyboardEvents, setupMouseEvents, setupPostMessageEvents, setupTouchEvents, setupWheelEvents } from "@/lib/events/index.js";
|
|
5
5
|
import { getThemeValue, withClampedZoom, withFeatureEnabled } from "@/lib/helpers/index.js";
|
|
6
6
|
import { createRulers } from "@/lib/rulers/index.js";
|
|
7
7
|
import { withTransition } from "@/lib/transition/withTransition.js";
|
|
@@ -29,6 +29,7 @@ export class MarkupCanvas implements Canvas {
|
|
|
29
29
|
public config: Required<MarkupCanvasConfig>;
|
|
30
30
|
private _isReady = false;
|
|
31
31
|
private listen = new EventEmitter<MarkupCanvasEvents>();
|
|
32
|
+
private postMessageCleanup: (() => void) | null = null;
|
|
32
33
|
|
|
33
34
|
constructor(container: HTMLElement, options: MarkupCanvasConfig = {}) {
|
|
34
35
|
if (!container) {
|
|
@@ -50,6 +51,11 @@ export class MarkupCanvas implements Canvas {
|
|
|
50
51
|
this.broadcastEvent(event as string, data);
|
|
51
52
|
});
|
|
52
53
|
this.setupGlobalBinding();
|
|
54
|
+
|
|
55
|
+
// Set up postMessage listener
|
|
56
|
+
if (this.config.enablePostMessageAPI) {
|
|
57
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
58
|
+
}
|
|
53
59
|
}
|
|
54
60
|
|
|
55
61
|
this.setupEventHandlers();
|
|
@@ -482,6 +488,13 @@ export class MarkupCanvas implements Canvas {
|
|
|
482
488
|
// Cleanup method
|
|
483
489
|
cleanup(): void {
|
|
484
490
|
this.cleanupGlobalBinding();
|
|
491
|
+
|
|
492
|
+
// Cleanup postMessage listener
|
|
493
|
+
if (this.postMessageCleanup) {
|
|
494
|
+
this.postMessageCleanup();
|
|
495
|
+
this.postMessageCleanup = null;
|
|
496
|
+
}
|
|
497
|
+
|
|
485
498
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
486
499
|
try {
|
|
487
500
|
cleanup();
|
|
@@ -6,6 +6,11 @@ export const DEFAULT_CONFIG: Required<MarkupCanvasConfig> = {
|
|
|
6
6
|
height: 8000,
|
|
7
7
|
enableAcceleration: true,
|
|
8
8
|
|
|
9
|
+
// Global Binding & Instance Access
|
|
10
|
+
bindToWindow: false,
|
|
11
|
+
name: "markupCanvas",
|
|
12
|
+
enablePostMessageAPI: false,
|
|
13
|
+
|
|
9
14
|
// Interaction controls
|
|
10
15
|
enableZoom: true,
|
|
11
16
|
enablePan: true,
|
|
@@ -67,10 +72,6 @@ export const DEFAULT_CONFIG: Required<MarkupCanvasConfig> = {
|
|
|
67
72
|
// Theme
|
|
68
73
|
themeMode: "light",
|
|
69
74
|
|
|
70
|
-
// Global Binding & Instance Access
|
|
71
|
-
bindToWindow: false,
|
|
72
|
-
name: "markupCanvas",
|
|
73
|
-
|
|
74
75
|
// Callbacks
|
|
75
76
|
onTransformUpdate: () => {},
|
|
76
77
|
};
|
package/src/lib/events/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { setupKeyboardEvents } from "./keyboard/setupKeyboardEvents.js";
|
|
2
2
|
export { setupMouseEvents } from "./mouse/setupMouseEvents.js";
|
|
3
|
+
export { setupPostMessageEvents } from "./postMessage/setupPostMessageEvents.js";
|
|
3
4
|
export { setupTouchEvents } from "./touch/setupTouchEvents.js";
|
|
4
5
|
export { detectTrackpadGesture } from "./trackpad/detectTrackpadGesture.js";
|
|
5
6
|
export { getAdaptiveZoomSpeed } from "./utils/getAdaptiveZoomSpeed.js";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { MarkupCanvas } from "@/lib/MarkupCanvas.js";
|
|
2
|
+
import type { PostMessageAction, PostMessageRequest } from "@/types/events";
|
|
3
|
+
import { sendPostMessageError } from "./sendError";
|
|
4
|
+
|
|
5
|
+
export function setupPostMessageEvents(canvas: MarkupCanvas): () => void {
|
|
6
|
+
const handleMessage = (event: MessageEvent): void => {
|
|
7
|
+
const data = event.data as PostMessageRequest;
|
|
8
|
+
|
|
9
|
+
// Validate message structure
|
|
10
|
+
if (data.source !== "markup-canvas") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const canvasName = canvas.config.name || "markupCanvas";
|
|
15
|
+
if (data.canvasName !== canvasName) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const action = data.action as PostMessageAction;
|
|
20
|
+
const args = data.args || [];
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// View methods
|
|
24
|
+
if (action === "zoomIn") {
|
|
25
|
+
canvas.zoomIn(args[0] as number | undefined);
|
|
26
|
+
} else if (action === "zoomOut") {
|
|
27
|
+
canvas.zoomOut(args[0] as number | undefined);
|
|
28
|
+
} else if (action === "resetZoom") {
|
|
29
|
+
canvas.resetZoom();
|
|
30
|
+
} else if (action === "panLeft") {
|
|
31
|
+
canvas.panLeft(args[0] as number | undefined);
|
|
32
|
+
} else if (action === "panRight") {
|
|
33
|
+
canvas.panRight(args[0] as number | undefined);
|
|
34
|
+
} else if (action === "panUp") {
|
|
35
|
+
canvas.panUp(args[0] as number | undefined);
|
|
36
|
+
} else if (action === "panDown") {
|
|
37
|
+
canvas.panDown(args[0] as number | undefined);
|
|
38
|
+
} else if (action === "fitToScreen") {
|
|
39
|
+
canvas.fitToScreen();
|
|
40
|
+
} else if (action === "centerContent") {
|
|
41
|
+
canvas.centerContent();
|
|
42
|
+
} else if (action === "scrollToPoint") {
|
|
43
|
+
canvas.scrollToPoint(args[0] as number, args[1] as number);
|
|
44
|
+
} else if (action === "resetView") {
|
|
45
|
+
canvas.resetView();
|
|
46
|
+
}
|
|
47
|
+
// Ruler/Grid methods
|
|
48
|
+
else if (action === "toggleRulers") {
|
|
49
|
+
canvas.toggleRulers();
|
|
50
|
+
} else if (action === "showRulers") {
|
|
51
|
+
canvas.showRulers();
|
|
52
|
+
} else if (action === "hideRulers") {
|
|
53
|
+
canvas.hideRulers();
|
|
54
|
+
} else if (action === "toggleGrid") {
|
|
55
|
+
canvas.toggleGrid();
|
|
56
|
+
} else if (action === "showGrid") {
|
|
57
|
+
canvas.showGrid();
|
|
58
|
+
} else if (action === "hideGrid") {
|
|
59
|
+
canvas.hideGrid();
|
|
60
|
+
}
|
|
61
|
+
// Config methods
|
|
62
|
+
else if (action === "updateThemeMode") {
|
|
63
|
+
const mode = args[0] as "light" | "dark";
|
|
64
|
+
if (mode !== "light" && mode !== "dark") {
|
|
65
|
+
throw new Error(`Invalid theme mode: ${mode}`);
|
|
66
|
+
}
|
|
67
|
+
canvas.updateThemeMode(mode);
|
|
68
|
+
} else if (action === "toggleThemeMode") {
|
|
69
|
+
const currentConfig = canvas.getConfig();
|
|
70
|
+
const newMode = currentConfig.themeMode === "light" ? "dark" : "light";
|
|
71
|
+
canvas.updateThemeMode(newMode);
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(`Unknown action: ${action}`);
|
|
74
|
+
}
|
|
75
|
+
} catch (error) {
|
|
76
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
77
|
+
sendPostMessageError(canvasName, action, errorMessage);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (typeof window !== "undefined") {
|
|
82
|
+
window.addEventListener("message", handleMessage);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return () => {
|
|
86
|
+
if (typeof window !== "undefined") {
|
|
87
|
+
window.removeEventListener("message", handleMessage);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
package/src/types/config.ts
CHANGED
package/src/types/events.ts
CHANGED
|
@@ -29,3 +29,31 @@ export interface MouseDragControls {
|
|
|
29
29
|
disable: () => boolean;
|
|
30
30
|
isEnabled: () => boolean;
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
export type PostMessageAction =
|
|
34
|
+
| "zoomIn"
|
|
35
|
+
| "zoomOut"
|
|
36
|
+
| "resetZoom"
|
|
37
|
+
| "panLeft"
|
|
38
|
+
| "panRight"
|
|
39
|
+
| "panUp"
|
|
40
|
+
| "panDown"
|
|
41
|
+
| "fitToScreen"
|
|
42
|
+
| "centerContent"
|
|
43
|
+
| "scrollToPoint"
|
|
44
|
+
| "resetView"
|
|
45
|
+
| "toggleRulers"
|
|
46
|
+
| "showRulers"
|
|
47
|
+
| "hideRulers"
|
|
48
|
+
| "toggleGrid"
|
|
49
|
+
| "showGrid"
|
|
50
|
+
| "hideGrid"
|
|
51
|
+
| "updateThemeMode"
|
|
52
|
+
| "toggleThemeMode";
|
|
53
|
+
|
|
54
|
+
export interface PostMessageRequest {
|
|
55
|
+
source: "markup-canvas";
|
|
56
|
+
canvasName: string;
|
|
57
|
+
action: PostMessageAction;
|
|
58
|
+
args?: unknown[];
|
|
59
|
+
}
|