@markup-canvas/core 1.1.0 → 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 +128 -4
- package/dist/markup-canvas.esm.js +128 -4
- package/dist/markup-canvas.umd.js +127 -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 +19 -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
|
}
|
|
@@ -1794,10 +1906,15 @@ class MarkupCanvas {
|
|
|
1794
1906
|
}
|
|
1795
1907
|
this.baseCanvas = canvas;
|
|
1796
1908
|
if (this.config.bindToWindow) {
|
|
1909
|
+
console.log("bindToWindow:", "true");
|
|
1797
1910
|
this.listen.setEmitInterceptor((event, data) => {
|
|
1798
1911
|
this.broadcastEvent(event, data);
|
|
1799
1912
|
});
|
|
1800
1913
|
this.setupGlobalBinding();
|
|
1914
|
+
// Set up postMessage listener
|
|
1915
|
+
if (this.config.enablePostMessageAPI) {
|
|
1916
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1917
|
+
}
|
|
1801
1918
|
}
|
|
1802
1919
|
this.setupEventHandlers();
|
|
1803
1920
|
this._isReady = true;
|
|
@@ -1810,8 +1927,10 @@ class MarkupCanvas {
|
|
|
1810
1927
|
}
|
|
1811
1928
|
const canvasName = this.config.name || "markupCanvas";
|
|
1812
1929
|
const windowObj = window;
|
|
1930
|
+
console.log(windowObj);
|
|
1813
1931
|
// Bind instance to window
|
|
1814
1932
|
windowObj[canvasName] = this;
|
|
1933
|
+
console.log(windowObj[canvasName]);
|
|
1815
1934
|
// Track all instances
|
|
1816
1935
|
if (!windowObj.__markupCanvasInstances) {
|
|
1817
1936
|
windowObj.__markupCanvasInstances = new Map();
|
|
@@ -2158,6 +2277,11 @@ class MarkupCanvas {
|
|
|
2158
2277
|
// Cleanup method
|
|
2159
2278
|
cleanup() {
|
|
2160
2279
|
this.cleanupGlobalBinding();
|
|
2280
|
+
// Cleanup postMessage listener
|
|
2281
|
+
if (this.postMessageCleanup) {
|
|
2282
|
+
this.postMessageCleanup();
|
|
2283
|
+
this.postMessageCleanup = null;
|
|
2284
|
+
}
|
|
2161
2285
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2162
2286
|
try {
|
|
2163
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
|
}
|
|
@@ -1790,10 +1902,15 @@ class MarkupCanvas {
|
|
|
1790
1902
|
}
|
|
1791
1903
|
this.baseCanvas = canvas;
|
|
1792
1904
|
if (this.config.bindToWindow) {
|
|
1905
|
+
console.log("bindToWindow:", "true");
|
|
1793
1906
|
this.listen.setEmitInterceptor((event, data) => {
|
|
1794
1907
|
this.broadcastEvent(event, data);
|
|
1795
1908
|
});
|
|
1796
1909
|
this.setupGlobalBinding();
|
|
1910
|
+
// Set up postMessage listener
|
|
1911
|
+
if (this.config.enablePostMessageAPI) {
|
|
1912
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1913
|
+
}
|
|
1797
1914
|
}
|
|
1798
1915
|
this.setupEventHandlers();
|
|
1799
1916
|
this._isReady = true;
|
|
@@ -1806,8 +1923,10 @@ class MarkupCanvas {
|
|
|
1806
1923
|
}
|
|
1807
1924
|
const canvasName = this.config.name || "markupCanvas";
|
|
1808
1925
|
const windowObj = window;
|
|
1926
|
+
console.log(windowObj);
|
|
1809
1927
|
// Bind instance to window
|
|
1810
1928
|
windowObj[canvasName] = this;
|
|
1929
|
+
console.log(windowObj[canvasName]);
|
|
1811
1930
|
// Track all instances
|
|
1812
1931
|
if (!windowObj.__markupCanvasInstances) {
|
|
1813
1932
|
windowObj.__markupCanvasInstances = new Map();
|
|
@@ -2154,6 +2273,11 @@ class MarkupCanvas {
|
|
|
2154
2273
|
// Cleanup method
|
|
2155
2274
|
cleanup() {
|
|
2156
2275
|
this.cleanupGlobalBinding();
|
|
2276
|
+
// Cleanup postMessage listener
|
|
2277
|
+
if (this.postMessageCleanup) {
|
|
2278
|
+
this.postMessageCleanup();
|
|
2279
|
+
this.postMessageCleanup = null;
|
|
2280
|
+
}
|
|
2157
2281
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2158
2282
|
try {
|
|
2159
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
|
}
|
|
@@ -1733,10 +1844,15 @@
|
|
|
1733
1844
|
}
|
|
1734
1845
|
this.baseCanvas = canvas;
|
|
1735
1846
|
if (this.config.bindToWindow) {
|
|
1847
|
+
console.log("bindToWindow:", "true");
|
|
1736
1848
|
this.listen.setEmitInterceptor((event, data) => {
|
|
1737
1849
|
this.broadcastEvent(event, data);
|
|
1738
1850
|
});
|
|
1739
1851
|
this.setupGlobalBinding();
|
|
1852
|
+
// Set up postMessage listener
|
|
1853
|
+
if (this.config.enablePostMessageAPI) {
|
|
1854
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
1855
|
+
}
|
|
1740
1856
|
}
|
|
1741
1857
|
this.setupEventHandlers();
|
|
1742
1858
|
this._isReady = true;
|
|
@@ -1749,8 +1865,10 @@
|
|
|
1749
1865
|
}
|
|
1750
1866
|
const canvasName = this.config.name || "markupCanvas";
|
|
1751
1867
|
const windowObj = window;
|
|
1868
|
+
console.log(windowObj);
|
|
1752
1869
|
// Bind instance to window
|
|
1753
1870
|
windowObj[canvasName] = this;
|
|
1871
|
+
console.log(windowObj[canvasName]);
|
|
1754
1872
|
// Track all instances
|
|
1755
1873
|
if (!windowObj.__markupCanvasInstances) {
|
|
1756
1874
|
windowObj.__markupCanvasInstances = new Map();
|
|
@@ -2097,6 +2215,11 @@
|
|
|
2097
2215
|
// Cleanup method
|
|
2098
2216
|
cleanup() {
|
|
2099
2217
|
this.cleanupGlobalBinding();
|
|
2218
|
+
// Cleanup postMessage listener
|
|
2219
|
+
if (this.postMessageCleanup) {
|
|
2220
|
+
this.postMessageCleanup();
|
|
2221
|
+
this.postMessageCleanup = null;
|
|
2222
|
+
}
|
|
2100
2223
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
2101
2224
|
try {
|
|
2102
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&&(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;t[e]=this,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) {
|
|
@@ -45,10 +46,16 @@ export class MarkupCanvas implements Canvas {
|
|
|
45
46
|
this.baseCanvas = canvas;
|
|
46
47
|
|
|
47
48
|
if (this.config.bindToWindow) {
|
|
49
|
+
console.log("bindToWindow:", "true");
|
|
48
50
|
this.listen.setEmitInterceptor((event, data) => {
|
|
49
51
|
this.broadcastEvent(event as string, data);
|
|
50
52
|
});
|
|
51
53
|
this.setupGlobalBinding();
|
|
54
|
+
|
|
55
|
+
// Set up postMessage listener
|
|
56
|
+
if (this.config.enablePostMessageAPI) {
|
|
57
|
+
this.postMessageCleanup = setupPostMessageEvents(this);
|
|
58
|
+
}
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
this.setupEventHandlers();
|
|
@@ -66,9 +73,13 @@ export class MarkupCanvas implements Canvas {
|
|
|
66
73
|
const canvasName = this.config.name || "markupCanvas";
|
|
67
74
|
const windowObj = window as unknown as Record<string, unknown>;
|
|
68
75
|
|
|
76
|
+
console.log(windowObj);
|
|
77
|
+
|
|
69
78
|
// Bind instance to window
|
|
70
79
|
windowObj[canvasName] = this;
|
|
71
80
|
|
|
81
|
+
console.log(windowObj[canvasName]);
|
|
82
|
+
|
|
72
83
|
// Track all instances
|
|
73
84
|
if (!windowObj.__markupCanvasInstances) {
|
|
74
85
|
windowObj.__markupCanvasInstances = new Map();
|
|
@@ -477,6 +488,13 @@ export class MarkupCanvas implements Canvas {
|
|
|
477
488
|
// Cleanup method
|
|
478
489
|
cleanup(): void {
|
|
479
490
|
this.cleanupGlobalBinding();
|
|
491
|
+
|
|
492
|
+
// Cleanup postMessage listener
|
|
493
|
+
if (this.postMessageCleanup) {
|
|
494
|
+
this.postMessageCleanup();
|
|
495
|
+
this.postMessageCleanup = null;
|
|
496
|
+
}
|
|
497
|
+
|
|
480
498
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
481
499
|
try {
|
|
482
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
|
+
}
|