@markup-canvas/core 1.0.6 → 1.0.8
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/README.md +42 -2
- package/dist/lib/MarkupCanvas.d.ts +1 -0
- package/dist/lib/canvas/setupCanvasContainer.d.ts +2 -1
- package/dist/lib/helpers/index.d.ts +1 -0
- package/dist/lib/helpers/withTheme.d.ts +4 -0
- package/dist/lib/rulers/constants.d.ts +3 -6
- package/dist/lib/rulers/ticks/createHorizontalTick.d.ts +1 -1
- package/dist/lib/rulers/ticks/createVerticalTick.d.ts +1 -1
- package/dist/lib/rulers/updateRulerTheme.d.ts +8 -0
- package/dist/markup-canvas.cjs.js +149 -54
- package/dist/markup-canvas.esm.js +149 -54
- package/dist/markup-canvas.umd.js +130 -47
- package/dist/markup-canvas.umd.min.js +1 -1
- package/dist/types/config.d.ts +11 -2
- package/dist/types/rulers.d.ts +2 -0
- package/package.json +4 -4
- package/src/lib/MarkupCanvas.ts +19 -1
- package/src/lib/canvas/createCanvas.ts +1 -1
- package/src/lib/canvas/setupCanvasContainer.ts +9 -1
- package/src/lib/config/constants.ts +24 -9
- package/src/lib/config/presets/editor-preset.ts +23 -7
- package/src/lib/helpers/index.ts +1 -0
- package/src/lib/helpers/withTheme.ts +17 -0
- package/src/lib/rulers/constants.ts +3 -6
- package/src/lib/rulers/createCornerBox.ts +5 -4
- package/src/lib/rulers/createGridOverlay.ts +3 -2
- package/src/lib/rulers/createHorizontalRuler.ts +5 -4
- package/src/lib/rulers/createRulers.ts +19 -0
- package/src/lib/rulers/createVerticalRuler.ts +5 -4
- package/src/lib/rulers/ticks/createHorizontalTick.ts +8 -8
- package/src/lib/rulers/ticks/createVerticalTick.ts +8 -8
- package/src/lib/rulers/updateRulerTheme.ts +46 -0
- package/src/types/config.ts +18 -3
- package/src/types/rulers.ts +2 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Markup Canvas
|
|
3
3
|
* High-performance markup canvas with zoom and pan capabilities
|
|
4
|
-
* @version 1.0.
|
|
4
|
+
* @version 1.0.8
|
|
5
5
|
*/
|
|
6
6
|
(function (global, factory) {
|
|
7
7
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
@@ -239,6 +239,14 @@
|
|
|
239
239
|
return operation(adjustedX, adjustedY);
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
function getThemeValue(config, key) {
|
|
243
|
+
if (config.themeMode === "dark") {
|
|
244
|
+
const darkKey = `${key}Dark`;
|
|
245
|
+
return config[darkKey];
|
|
246
|
+
}
|
|
247
|
+
return config[key];
|
|
248
|
+
}
|
|
249
|
+
|
|
242
250
|
const DEFAULT_CONFIG = {
|
|
243
251
|
// Canvas dimensions
|
|
244
252
|
width: 8000,
|
|
@@ -271,18 +279,30 @@
|
|
|
271
279
|
requireOptionForClickZoom: false,
|
|
272
280
|
// Visual elements
|
|
273
281
|
enableRulers: true,
|
|
274
|
-
enableGrid:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
278
|
-
rulerBorderColor: "#ddd",
|
|
279
|
-
rulerTextColor: "#666",
|
|
280
|
-
rulerMajorTickColor: "#999",
|
|
281
|
-
rulerMinorTickColor: "#ccc",
|
|
282
|
+
enableGrid: false,
|
|
283
|
+
showRulers: true,
|
|
284
|
+
showGrid: false,
|
|
282
285
|
rulerFontSize: 9,
|
|
283
286
|
rulerFontFamily: "Monaco, Menlo, monospace",
|
|
284
287
|
rulerUnits: "px",
|
|
285
288
|
rulerSize: 20,
|
|
289
|
+
// Canvas styling
|
|
290
|
+
canvasBackgroundColor: "rgba(250, 250, 250, 1)",
|
|
291
|
+
canvasBackgroundColorDark: "rgba(40, 40, 40, 1)",
|
|
292
|
+
// Ruler styling (light theme)
|
|
293
|
+
rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
294
|
+
rulerBorderColor: "rgba(240, 240, 240, 1)",
|
|
295
|
+
rulerTextColor: "rgba(102, 102, 102, 1)",
|
|
296
|
+
rulerTickColor: "rgba(204, 204, 204, 1)",
|
|
297
|
+
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
298
|
+
// Ruler styling (dark theme)
|
|
299
|
+
rulerBackgroundColorDark: "rgba(30, 30, 30, 0.95)",
|
|
300
|
+
rulerBorderColorDark: "rgba(68, 68, 68, 1)",
|
|
301
|
+
rulerTextColorDark: "rgba(170, 170, 170, 1)",
|
|
302
|
+
rulerTickColorDark: "rgba(104, 104, 104, 1)",
|
|
303
|
+
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
304
|
+
// Theme
|
|
305
|
+
themeMode: "light",
|
|
286
306
|
// Callbacks
|
|
287
307
|
onTransformUpdate: () => { },
|
|
288
308
|
};
|
|
@@ -514,7 +534,7 @@
|
|
|
514
534
|
}
|
|
515
535
|
}
|
|
516
536
|
|
|
517
|
-
function setupCanvasContainer(container) {
|
|
537
|
+
function setupCanvasContainer(container, config) {
|
|
518
538
|
const currentPosition = getComputedStyle(container).position;
|
|
519
539
|
if (currentPosition === "static") {
|
|
520
540
|
container.style.position = "relative";
|
|
@@ -522,6 +542,11 @@
|
|
|
522
542
|
container.style.overflow = "hidden";
|
|
523
543
|
container.style.cursor = "grab";
|
|
524
544
|
container.style.overscrollBehavior = "none";
|
|
545
|
+
// Apply canvas background color
|
|
546
|
+
if (config) {
|
|
547
|
+
const backgroundColor = getThemeValue(config, "canvasBackgroundColor");
|
|
548
|
+
container.style.backgroundColor = backgroundColor;
|
|
549
|
+
}
|
|
525
550
|
if (!container.hasAttribute("tabindex")) {
|
|
526
551
|
container.setAttribute("tabindex", "0");
|
|
527
552
|
}
|
|
@@ -538,7 +563,7 @@
|
|
|
538
563
|
return null;
|
|
539
564
|
}
|
|
540
565
|
try {
|
|
541
|
-
setupCanvasContainer(container);
|
|
566
|
+
setupCanvasContainer(container, config);
|
|
542
567
|
const { transformLayer, contentLayer } = createCanvasLayers(container, config);
|
|
543
568
|
// Enable hardware acceleration if requested
|
|
544
569
|
if (config.enableAcceleration) {
|
|
@@ -1284,12 +1309,9 @@
|
|
|
1284
1309
|
CORNER: 1001,
|
|
1285
1310
|
};
|
|
1286
1311
|
const TICK_SETTINGS = {
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
MINOR_WIDTH: 4,
|
|
1291
|
-
MAJOR_MULTIPLIER: 5,
|
|
1292
|
-
LABEL_INTERVAL: 100,
|
|
1312
|
+
TICK_HEIGHT: 4,
|
|
1313
|
+
TICK_WIDTH: 4,
|
|
1314
|
+
TICK_LABEL_INTERVAL: 100,
|
|
1293
1315
|
};
|
|
1294
1316
|
const GRID_SETTINGS = {
|
|
1295
1317
|
BASE_SIZE: 100,
|
|
@@ -1306,16 +1328,16 @@
|
|
|
1306
1328
|
left: 0;
|
|
1307
1329
|
width: ${config.rulerSize}px;
|
|
1308
1330
|
height: ${config.rulerSize}px;
|
|
1309
|
-
background:
|
|
1310
|
-
border-right: 1px solid
|
|
1311
|
-
border-bottom: 1px solid
|
|
1331
|
+
background: var(--ruler-background-color);
|
|
1332
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
1333
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
1312
1334
|
z-index: ${RULER_Z_INDEX.CORNER};
|
|
1313
1335
|
display: flex;
|
|
1314
1336
|
align-items: center;
|
|
1315
1337
|
justify-content: center;
|
|
1316
1338
|
font-family: ${config.rulerFontFamily};
|
|
1317
1339
|
font-size: ${config.rulerFontSize - 2}px;
|
|
1318
|
-
color:
|
|
1340
|
+
color: var(--ruler-text-color);
|
|
1319
1341
|
pointer-events: none;
|
|
1320
1342
|
`;
|
|
1321
1343
|
corner.textContent = config.rulerUnits;
|
|
@@ -1334,8 +1356,8 @@
|
|
|
1334
1356
|
pointer-events: none;
|
|
1335
1357
|
z-index: ${RULER_Z_INDEX.GRID};
|
|
1336
1358
|
background-image:
|
|
1337
|
-
linear-gradient(
|
|
1338
|
-
linear-gradient(90deg,
|
|
1359
|
+
linear-gradient(var(--grid-color) 1px, transparent 1px),
|
|
1360
|
+
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
|
|
1339
1361
|
background-size: 100px 100px;
|
|
1340
1362
|
opacity: 0.5;
|
|
1341
1363
|
`;
|
|
@@ -1351,14 +1373,14 @@
|
|
|
1351
1373
|
left: ${config.rulerSize}px;
|
|
1352
1374
|
right: 0;
|
|
1353
1375
|
height: ${config.rulerSize}px;
|
|
1354
|
-
background:
|
|
1355
|
-
border-bottom: 1px solid
|
|
1356
|
-
border-right: 1px solid
|
|
1376
|
+
background: var(--ruler-background-color);
|
|
1377
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
1378
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
1357
1379
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1358
1380
|
pointer-events: none;
|
|
1359
1381
|
font-family: ${config.rulerFontFamily};
|
|
1360
1382
|
font-size: ${config.rulerFontSize}px;
|
|
1361
|
-
color:
|
|
1383
|
+
color: var(--ruler-text-color);
|
|
1362
1384
|
overflow: hidden;
|
|
1363
1385
|
`;
|
|
1364
1386
|
return ruler;
|
|
@@ -1373,14 +1395,14 @@
|
|
|
1373
1395
|
left: 0;
|
|
1374
1396
|
bottom: 0;
|
|
1375
1397
|
width: ${config.rulerSize}px;
|
|
1376
|
-
background:
|
|
1377
|
-
border-right: 1px solid
|
|
1378
|
-
border-bottom: 1px solid
|
|
1398
|
+
background: var(--ruler-background-color);
|
|
1399
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
1400
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
1379
1401
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1380
1402
|
pointer-events: none;
|
|
1381
1403
|
font-family: ${config.rulerFontFamily};
|
|
1382
1404
|
font-size: ${config.rulerFontSize}px;
|
|
1383
|
-
color:
|
|
1405
|
+
color: var(--ruler-text-color);
|
|
1384
1406
|
overflow: hidden;
|
|
1385
1407
|
`;
|
|
1386
1408
|
return ruler;
|
|
@@ -1450,29 +1472,28 @@
|
|
|
1450
1472
|
return niceSpacing * magnitude;
|
|
1451
1473
|
}
|
|
1452
1474
|
|
|
1453
|
-
function createHorizontalTick(container, position, pixelPos,
|
|
1475
|
+
function createHorizontalTick(container, position, pixelPos, _tickSpacing, config) {
|
|
1454
1476
|
const tick = document.createElement("div");
|
|
1455
|
-
|
|
1456
|
-
const tickHeight = isMajor ? TICK_SETTINGS.MAJOR_HEIGHT : TICK_SETTINGS.MINOR_HEIGHT;
|
|
1477
|
+
tick.className = "tick";
|
|
1457
1478
|
tick.style.cssText = `
|
|
1458
1479
|
position: absolute;
|
|
1459
1480
|
left: ${pixelPos}px;
|
|
1460
1481
|
bottom: 0;
|
|
1461
1482
|
width: 1px;
|
|
1462
|
-
height: ${
|
|
1463
|
-
background:
|
|
1483
|
+
height: ${TICK_SETTINGS.TICK_HEIGHT}px;
|
|
1484
|
+
background: var(--ruler-tick-color);
|
|
1464
1485
|
`;
|
|
1465
1486
|
container.appendChild(tick);
|
|
1466
|
-
const shouldShowLabel =
|
|
1487
|
+
const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
|
|
1467
1488
|
if (shouldShowLabel) {
|
|
1468
1489
|
const label = document.createElement("div");
|
|
1469
1490
|
label.style.cssText = `
|
|
1470
1491
|
position: absolute;
|
|
1471
1492
|
left: ${pixelPos}px;
|
|
1472
|
-
bottom: ${
|
|
1493
|
+
bottom: ${TICK_SETTINGS.TICK_HEIGHT + 2}px;
|
|
1473
1494
|
font-size: ${config.rulerFontSize}px;
|
|
1474
1495
|
line-height: 1;
|
|
1475
|
-
color:
|
|
1496
|
+
color: var(--ruler-text-color);
|
|
1476
1497
|
white-space: nowrap;
|
|
1477
1498
|
pointer-events: none;
|
|
1478
1499
|
`;
|
|
@@ -1498,29 +1519,28 @@
|
|
|
1498
1519
|
ruler.appendChild(fragment);
|
|
1499
1520
|
}
|
|
1500
1521
|
|
|
1501
|
-
function createVerticalTick(container, position, pixelPos,
|
|
1522
|
+
function createVerticalTick(container, position, pixelPos, _tickSpacing, config) {
|
|
1502
1523
|
const tick = document.createElement("div");
|
|
1503
|
-
|
|
1504
|
-
const tickWidth = isMajor ? TICK_SETTINGS.MAJOR_WIDTH : TICK_SETTINGS.MINOR_WIDTH;
|
|
1524
|
+
tick.className = "tick";
|
|
1505
1525
|
tick.style.cssText = `
|
|
1506
1526
|
position: absolute;
|
|
1507
1527
|
top: ${pixelPos}px;
|
|
1508
1528
|
right: 0;
|
|
1509
|
-
width: ${
|
|
1529
|
+
width: ${TICK_SETTINGS.TICK_WIDTH}px;
|
|
1510
1530
|
height: 1px;
|
|
1511
|
-
background:
|
|
1531
|
+
background: var(--ruler-tick-color);
|
|
1512
1532
|
`;
|
|
1513
1533
|
container.appendChild(tick);
|
|
1514
|
-
const shouldShowLabel =
|
|
1534
|
+
const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
|
|
1515
1535
|
if (shouldShowLabel) {
|
|
1516
1536
|
const label = document.createElement("div");
|
|
1517
1537
|
label.style.cssText = `
|
|
1518
1538
|
position: absolute;
|
|
1519
1539
|
top: ${pixelPos - 6}px;
|
|
1520
|
-
right: ${
|
|
1540
|
+
right: ${TICK_SETTINGS.TICK_WIDTH + 6}px;
|
|
1521
1541
|
font-size: ${config.rulerFontSize}px;
|
|
1522
1542
|
line-height: 1;
|
|
1523
|
-
color:
|
|
1543
|
+
color: var(--ruler-text-color);
|
|
1524
1544
|
white-space: nowrap;
|
|
1525
1545
|
pointer-events: none;
|
|
1526
1546
|
transform: rotate(-90deg);
|
|
@@ -1566,6 +1586,39 @@
|
|
|
1566
1586
|
}
|
|
1567
1587
|
}
|
|
1568
1588
|
|
|
1589
|
+
function updateRulerTheme(elements, config) {
|
|
1590
|
+
// Get theme-aware colors
|
|
1591
|
+
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
1592
|
+
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
1593
|
+
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1594
|
+
const tickColor = getThemeValue(config, "rulerTickColor");
|
|
1595
|
+
const gridColor = getThemeValue(config, "gridColor");
|
|
1596
|
+
// Update horizontal ruler with CSS variables
|
|
1597
|
+
if (elements.horizontalRuler) {
|
|
1598
|
+
elements.horizontalRuler.style.setProperty("--ruler-background-color", backgroundColor);
|
|
1599
|
+
elements.horizontalRuler.style.setProperty("--ruler-border-color", borderColor);
|
|
1600
|
+
elements.horizontalRuler.style.setProperty("--ruler-text-color", textColor);
|
|
1601
|
+
elements.horizontalRuler.style.setProperty("--ruler-tick-color", tickColor);
|
|
1602
|
+
}
|
|
1603
|
+
// Update vertical ruler with CSS variables
|
|
1604
|
+
if (elements.verticalRuler) {
|
|
1605
|
+
elements.verticalRuler.style.setProperty("--ruler-background-color", backgroundColor);
|
|
1606
|
+
elements.verticalRuler.style.setProperty("--ruler-border-color", borderColor);
|
|
1607
|
+
elements.verticalRuler.style.setProperty("--ruler-text-color", textColor);
|
|
1608
|
+
elements.verticalRuler.style.setProperty("--ruler-tick-color", tickColor);
|
|
1609
|
+
}
|
|
1610
|
+
// Update corner box with CSS variables
|
|
1611
|
+
if (elements.cornerBox) {
|
|
1612
|
+
elements.cornerBox.style.setProperty("--ruler-background-color", backgroundColor);
|
|
1613
|
+
elements.cornerBox.style.setProperty("--ruler-border-color", borderColor);
|
|
1614
|
+
elements.cornerBox.style.setProperty("--ruler-text-color", textColor);
|
|
1615
|
+
}
|
|
1616
|
+
// Update grid overlay with CSS variables
|
|
1617
|
+
if (elements.gridOverlay) {
|
|
1618
|
+
elements.gridOverlay.style.setProperty("--grid-color", gridColor);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1569
1622
|
function createRulers(canvas, config) {
|
|
1570
1623
|
if (!canvas?.container) {
|
|
1571
1624
|
console.error("Invalid canvas provided to createRulers");
|
|
@@ -1582,13 +1635,28 @@
|
|
|
1582
1635
|
try {
|
|
1583
1636
|
elements = createRulerElements(canvas.container, config);
|
|
1584
1637
|
cleanupEvents = setupRulerEvents(canvas, safeUpdate);
|
|
1638
|
+
updateRulerTheme(elements, config);
|
|
1585
1639
|
safeUpdate();
|
|
1640
|
+
if (!config.showRulers) {
|
|
1641
|
+
elements.horizontalRuler.style.display = "none";
|
|
1642
|
+
elements.verticalRuler.style.display = "none";
|
|
1643
|
+
elements.cornerBox.style.display = "none";
|
|
1644
|
+
}
|
|
1645
|
+
if (!config.showGrid && elements.gridOverlay) {
|
|
1646
|
+
elements.gridOverlay.style.display = "none";
|
|
1647
|
+
}
|
|
1586
1648
|
return {
|
|
1587
1649
|
horizontalRuler: elements.horizontalRuler,
|
|
1588
1650
|
verticalRuler: elements.verticalRuler,
|
|
1589
1651
|
cornerBox: elements.cornerBox,
|
|
1590
1652
|
gridOverlay: elements.gridOverlay,
|
|
1591
1653
|
update: safeUpdate,
|
|
1654
|
+
updateTheme: (newConfig) => {
|
|
1655
|
+
if (isDestroyed)
|
|
1656
|
+
return;
|
|
1657
|
+
// Update all ruler theme colors
|
|
1658
|
+
updateRulerTheme(elements, newConfig);
|
|
1659
|
+
},
|
|
1592
1660
|
show: () => {
|
|
1593
1661
|
if (elements.horizontalRuler)
|
|
1594
1662
|
elements.horizontalRuler.style.display = "block";
|
|
@@ -1956,6 +2024,21 @@
|
|
|
1956
2024
|
updateConfig(newConfig) {
|
|
1957
2025
|
this.config = createMarkupCanvasConfig({ ...this.config, ...newConfig });
|
|
1958
2026
|
}
|
|
2027
|
+
// Theme management
|
|
2028
|
+
updateThemeMode(mode) {
|
|
2029
|
+
const newConfig = {
|
|
2030
|
+
...this.config,
|
|
2031
|
+
themeMode: mode,
|
|
2032
|
+
};
|
|
2033
|
+
this.config = createMarkupCanvasConfig(newConfig);
|
|
2034
|
+
// Update canvas background color
|
|
2035
|
+
const backgroundColor = getThemeValue(this.config, "canvasBackgroundColor");
|
|
2036
|
+
this.baseCanvas.container.style.backgroundColor = backgroundColor;
|
|
2037
|
+
// Update rulers if they exist
|
|
2038
|
+
if (this.rulers) {
|
|
2039
|
+
this.rulers.updateTheme(this.config);
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
1959
2042
|
// Cleanup method
|
|
1960
2043
|
cleanup() {
|
|
1961
2044
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).MarkupCanvas=e()}(this,function(){"use strict";const t="canvas-container",e="transform-layer",n="content-layer";function r(t,r){const o=Array.from(t.children);let a=t.querySelector(`.${e}`);a||(a=document.createElement("div"),a.className=e,t.appendChild(a)),function(t,e){t.style.position="absolute";const n=e.rulerSize;t.style.top=`${n}px`,t.style.left=`${n}px`,t.style.width=`${e.width}px`,t.style.height=`${e.height}px`,t.style.transformOrigin="0 0"}(a,r);let s=a.querySelector(`.${n}`);return s||(s=document.createElement("div"),s.className=n,a.appendChild(s),function(t,n,r){t.forEach(t=>{t===r||t.classList.contains(e)||n.appendChild(t)})}(o,s,a)),function(t){t.style.position="relative",t.style.width="100%",t.style.height="100%",t.style.pointerEvents="auto"}(s),{transformLayer:a,contentLayer:s}}function o(t,e,n){if(!n?.inverse)return{x:t,y:e};try{const r=n.inverse(),o=new DOMPoint(t,e).matrixTransform(r);return{x:o.x,y:o.y}}catch(n){return console.warn("Canvas to content conversion failed:",n),{x:t,y:e}}}function a(t,e){return Math.max(e.minZoom,Math.min(e.maxZoom,t))}function s(t,e,n){return new DOMMatrix([t,0,0,t,e,n])}function i(t,e,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:t-(t-c)/l*d,translateY:e-(e-u)/l*d}}function l(t,e){return e(e=>a(e,t))}const c=new Map;function u(t,e,n){return t[e]?n():null}function d(t){let e=null,n=null;const r=(...r)=>{n=r,null===e&&(e=requestAnimationFrame(()=>{n&&t(...n),e=null,n=null}))};return r.cleanup=()=>{null!==e&&(cancelAnimationFrame(e),e=null,n=null)},r}function h(t,e,n){return n(null!==t.container.querySelector(".canvas-ruler")?e:0)}function m(t,e,n,r,o){const a=null!==t.container.querySelector(".canvas-ruler");return o(a?e-r:e,a?n-r:n)}const f={width:8e3,height:8e3,enableAcceleration:!0,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,limitKeyboardEventsToCanvas:!1,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:!0,gridColor:"rgba(0, 123, 255, 0.1)",rulerBackgroundColor:"rgba(255, 255, 255, 0.95)",rulerBorderColor:"#ddd",rulerTextColor:"#666",rulerMajorTickColor:"#999",rulerMinorTickColor:"#ccc",rulerFontSize:9,rulerFontFamily:"Monaco, Menlo, monospace",rulerUnits:"px",rulerSize:20,onTransformUpdate:()=>{}};function g(t){try{const e=t.container,n=t.config,r=t.transform||{scale:1,translateX:0,translateY:0},a=e.getBoundingClientRect(),i=a.width||e.clientWidth||0,l=a.height||e.clientHeight||0,c=h({container:e},n.rulerSize,t=>Math.max(0,i-t)),u=h({container:e},n.rulerSize,t=>Math.max(0,l-t)),d=n.width||f.width,m=n.height||f.height,g=function(t,e,n,r,a){const i=o(0,0,s(a.scale,a.translateX,a.translateY)),l=o(t,e,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(t){return console.error("Failed to calculate canvas bounds:",t),{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 p(t,e){if(!t?.style||!e)return!1;try{return t.style.transform=function(t){return`matrix3d(${t.m11}, ${t.m12}, ${t.m13}, ${t.m14}, ${t.m21}, ${t.m22}, ${t.m23}, ${t.m24}, ${t.m31}, ${t.m32}, ${t.m33}, ${t.m34}, ${t.m41}, ${t.m42}, ${t.m43}, ${t.m44})`}(e),!0}catch(t){return console.warn("Transform application failed:",t),!1}}function v(t,e){try{if(e.enableTransition){window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0);return function(t,e,n){const r=c.get(t);r&&clearTimeout(r);const o=window.setTimeout(()=>{n(),c.delete(t)},e);c.set(t,o)}("disableTransition",1e3*(e.transitionDuration??.2),()=>{t.style.transition="none",window.__markupCanvasTransitionTimeout=void 0}),!0}return!1}catch(t){return console.error("Failed to disable transitions:",t),!0}}function y(t,e,n){!function(t,e){try{return!!e.enableTransition&&(window.__markupCanvasTransitionTimeout&&(clearTimeout(window.__markupCanvasTransitionTimeout),window.__markupCanvasTransitionTimeout=void 0),t.style.transition=`transform ${e.transitionDuration}s linear`,!0)}catch(t){return console.error("Failed to enable transitions:",t),!1}}(t,e);try{return n()}finally{v(t,e)}}function b(e){"static"===getComputedStyle(e).position&&(e.style.position="relative"),e.style.overflow="hidden",e.style.cursor="grab",e.style.overscrollBehavior="none",e.hasAttribute("tabindex")||e.setAttribute("tabindex","0"),function(t){const e=t.getBoundingClientRect(),n=getComputedStyle(t);0===e.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.",t),0===e.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.",t)}(e),e.classList.contains(t)||e.classList.add(t)}function w(t,e){if(!t?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{b(t);const{transformLayer:n,contentLayer:a}=r(t,e);e.enableAcceleration&&function(t){try{return t.style.transform=t.style.transform||"translateZ(0)",t.style.backfaceVisibility="hidden",!0}catch(t){return console.error("Failed to enable hardware acceleration:",t),!1}}(n);const c=e.enableRulers?-e.rulerSize:0,d={scale:1,translateX:c,translateY:c};p(n,s(d.scale,d.translateX,d.translateY));return{container:t,transformLayer:n,contentLayer:a,config:e,transform:d,getBounds:function(){return g(this)},updateTransform:function(t){this.transform={...this.transform,...t};const e=s(this.transform.scale,this.transform.translateX,this.transform.translateY),n=p(this.transformLayer,e);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(t){const e=l(this.config,e=>e(t));return this.updateTransform({scale:e})},canvasToContent:function(t,e){return o(t,e,s(this.transform.scale,this.transform.translateX,this.transform.translateY))},zoomToPoint:function(t,e,n){return y(this.transformLayer,this.config,()=>{const r=i(t,e,this.transform,n/this.transform.scale,this.config);return this.updateTransform(r)})},resetView:function(){return y(this.transformLayer,this.config,()=>h(this,this.config.rulerSize,t=>{const e={scale:1,translateX:-1*t,translateY:-1*t};return this.updateTransform(e)}))},zoomToFitContent:function(){return y(this.transformLayer,this.config,()=>{const t=this.getBounds(),e=t.width/this.config.width,n=t.height/this.config.height,r=l(this.config,t=>t(.9*Math.min(e,n))),o=this.config.width*r,a=this.config.height*r,s=(t.width-o)/2,i=(t.height-a)/2;return this.updateTransform({scale:r,translateX:s,translateY:i})})}}}catch(t){return console.error("Failed to create canvas:",t),null}}function C(t={}){const e={...f,...t};return("number"!=typeof e.width||e.width<=0)&&(console.warn("Invalid width, using default"),e.width=f.width),("number"!=typeof e.height||e.height<=0)&&(console.warn("Invalid height, using default"),e.height=f.height),("number"!=typeof e.zoomSpeed||e.zoomSpeed<=0)&&(console.warn("Invalid zoomSpeed, using default"),e.zoomSpeed=f.zoomSpeed),("number"!=typeof e.minZoom||e.minZoom<=0)&&(console.warn("Invalid minZoom, using default"),e.minZoom=f.minZoom),("number"!=typeof e.maxZoom||e.maxZoom<=e.minZoom)&&(console.warn("Invalid maxZoom, using default"),e.maxZoom=f.maxZoom),("number"!=typeof e.keyboardPanStep||e.keyboardPanStep<=0)&&(console.warn("Invalid keyboardPanStep, using default"),e.keyboardPanStep=f.keyboardPanStep),("number"!=typeof e.keyboardFastMultiplier||e.keyboardFastMultiplier<=0)&&(console.warn("Invalid keyboardFastMultiplier, using default"),e.keyboardFastMultiplier=f.keyboardFastMultiplier),("number"!=typeof e.clickZoomLevel||e.clickZoomLevel<=0)&&(console.warn("Invalid clickZoomLevel, using default"),e.clickZoomLevel=f.clickZoomLevel),("number"!=typeof e.rulerFontSize||e.rulerFontSize<=0)&&(console.warn("Invalid rulerFontSize, using default"),e.rulerFontSize=f.rulerFontSize),("number"!=typeof e.rulerSize||e.rulerSize<=0)&&(console.warn("Invalid rulerSize, using default"),e.rulerSize=f.rulerSize),e}class x{constructor(){this.listeners=new Map}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){const n=this.listeners.get(t);n&&n.delete(e)}emit(t,e){const n=this.listeners.get(t);n&&n.forEach(n=>{try{n(e)}catch(e){console.error(`Error in event handler for "${String(t)}":`,e)}})}removeAllListeners(){this.listeners.clear()}}const T=300,S=5;function k(t,e){if(!t?.getBounds)return e;try{const n=t.getBounds(),r=n.width*n.height;return e*(r/2073600)**1}catch(t){return console.warn("Failed to calculate adaptive zoom speed, using base speed:",t),e}}function D(t,e){let n=0,r=0;function o(o){const a=t.container.getBoundingClientRect(),s=o.clientX-a.left,i=o.clientY-a.top;!function(t,e,n,r,o){h(t,e,t=>o(n-t,r-t))}(t,e.rulerSize,s,i,(t,e)=>{n=t,r=e})}function s(o){if(!(o instanceof KeyboardEvent))return;if(e.limitKeyboardEventsToCanvas&&document.activeElement!==t.container)return;const s=o.shiftKey,l=e.keyboardPanStep*(s?e.keyboardFastMultiplier:1);let c=!1;const u={};switch(o.key){case"ArrowLeft":u.translateX=t.transform.translateX+l,c=!0;break;case"ArrowRight":u.translateX=t.transform.translateX-l,c=!0;break;case"ArrowUp":u.translateY=t.transform.translateY+l,c=!0;break;case"ArrowDown":u.translateY=t.transform.translateY-l,c=!0;break;case"=":case"+":{const n=e.enableAdaptiveSpeed?k(t,e.keyboardZoomStep):e.keyboardZoomStep;u.scale=a(t.transform.scale*(1+n),e),c=!0}break;case"-":{const n=e.enableAdaptiveSpeed?k(t,e.keyboardZoomStep):e.keyboardZoomStep;u.scale=a(t.transform.scale*(1-n),e),c=!0}break;case"0":if(o.metaKey||o.ctrlKey){const o=1/t.transform.scale,a=i(n,r,t.transform,o,e);Object.assign(u,a),c=!0}break;case"g":case"G":t.toggleGrid&&t.toggleGrid(),c=!0;break;case"r":case"R":o.metaKey||o.ctrlKey||o.altKey||!t.toggleRulers||(t.toggleRulers(),c=!0)}c&&(o.preventDefault(),Object.keys(u).length>0&&t.updateTransform(u))}const l=e.limitKeyboardEventsToCanvas?t.container:document;return l.addEventListener("keydown",s),t.container.addEventListener("mousemove",o),()=>{l.removeEventListener("keydown",s),t.container.removeEventListener("mousemove",o)}}function M(t,e,n,r,o){n?e.requireSpaceForMouseDrag?t.container.style.cursor=r?"grab":"default":t.container.style.cursor=o?"grabbing":"grab":t.container.style.cursor="default"}function z(t,e,n,r,o){o.setIsDragging(!1),o.setDragButton(-1),M(t,e,n,r,!1)}function L(t,e,n,r,o,a,s,i,l,c){a&&t.button===s&&z(e,n,r,o,{setIsDragging:c.setIsDragging,setDragButton:c.setDragButton}),r&&0===t.button&&n.enableClickToZoom&&i>0&&function(t,e,n,r,o,a){const s=Date.now()-r,i=t.altKey,l=!n.requireOptionForClickZoom||i;if(s<T&&!o&&!a&&l){t.preventDefault();const r=e.container.getBoundingClientRect(),o=t.clientX-r.left,a=t.clientY-r.top,{clickX:s,clickY:i}=m(e,o,a,n.rulerSize,(t,e)=>({clickX:t,clickY:e})),l=e.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};y(e.transformLayer,e.config,()=>{e.updateTransform(h)})}}(t,e,n,i,l,a),0===t.button&&function(t){t.setMouseDownTime(0),t.setHasDragged(!1)}({setMouseDownTime:c.setMouseDownTime,setHasDragged:c.setHasDragged})}function $(t,e,n=!0){let r=!0,o=!1,a=0,s=0,i=-1,l=!1,c=0,u=0,h=0,m=!1;const f={setIsDragging:t=>{o=t},setDragButton:t=>{i=t},setIsSpacePressed:t=>{l=t},setMouseDownTime:t=>{c=t},setMouseDownX:t=>{u=t},setMouseDownY:t=>{h=t},setHasDragged:t=>{m=t},setLastMouseX:t=>{a=t},setLastMouseY:t=>{s=t}},g=n=>{!function(t,e,n,r,o,a){n.requireSpaceForMouseDrag&&" "===t.key&&(a.setIsSpacePressed(!0),M(e,n,r,!0,o))}(n,t,e,r,o,{setIsSpacePressed:f.setIsSpacePressed})},p=n=>{!function(t,e,n,r,o,a){n.requireSpaceForMouseDrag&&" "===t.key&&(a.setIsSpacePressed(!1),M(e,n,r,!1,o),o&&z(e,n,r,!1,{setIsDragging:a.setIsDragging,setDragButton:a.setDragButton}))}(n,t,e,r,o,{setIsSpacePressed:f.setIsSpacePressed,setIsDragging:f.setIsDragging,setDragButton:f.setDragButton})},v=n=>{!function(t,e,n,r,o,a){const s=0===t.button,i=1===t.button;if(s&&(a.setMouseDownTime(Date.now()),a.setMouseDownX(t.clientX),a.setMouseDownY(t.clientY),a.setHasDragged(!1)),!r)return;(!n.requireSpaceForMouseDrag||o)&&(s&&n.enableLeftDrag||i&&n.enableMiddleDrag)&&(t.preventDefault(),a.setDragButton(t.button),a.setLastMouseX(t.clientX),a.setLastMouseY(t.clientY),M(e,n,r,o,!1))}(n,t,e,r,l,f)},y=e=>{!function(t,e,n,r,o,a,s,i,l,c){if(o>0){const e=Math.abs(t.clientX-a),o=Math.abs(t.clientY-s);(e>S||o>S)&&(c.setHasDragged(!0),!r&&n&&c.setIsDragging(!0))}if(!r||!n)return;t.preventDefault(),d((...t)=>{const o=t[0];if(!r||!n)return;const a=o.clientX-i,s=o.clientY-l,u={translateX:e.transform.translateX+a,translateY:e.transform.translateY+s};e.updateTransform(u),c.setLastMouseX(o.clientX),c.setLastMouseY(o.clientY)})(t)}(e,t,r,o,c,u,h,a,s,{setHasDragged:f.setHasDragged,setIsDragging:f.setIsDragging,setLastMouseX:f.setLastMouseX,setLastMouseY:f.setLastMouseY})},b=n=>{L(n,t,e,r,l,o,i,c,m,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton,setMouseDownTime:f.setMouseDownTime,setHasDragged:f.setHasDragged})},w=()=>{!function(t,e,n,r,o,a){o&&z(t,e,n,r,a)}(t,e,r,l,o,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton})};t.container.addEventListener("mousedown",v),document.addEventListener("mousemove",y),document.addEventListener("mouseup",b),t.container.addEventListener("mouseleave",w),e.requireSpaceForMouseDrag&&(document.addEventListener("keydown",g),document.addEventListener("keyup",p)),M(t,e,r,l,o);const C=()=>{t.container.removeEventListener("mousedown",v),document.removeEventListener("mousemove",y),document.removeEventListener("mouseup",b),t.container.removeEventListener("mouseleave",w),e.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",g),document.removeEventListener("keyup",p))};return n?{cleanup:C,enable:()=>(r=!0,M(t,e,r,l,o),!0),disable:()=>(r=!1,o&&z(t,e,r,l,{setIsDragging:f.setIsDragging,setDragButton:f.setDragButton}),M(t,e,r,l,o),!0),isEnabled:()=>r}:C}function Y(t,e){return{x:(t.clientX+e.clientX)/2,y:(t.clientY+e.clientY)/2}}function E(t,e){const n=t.clientX-e.clientX,r=t.clientY-e.clientY;return Math.sqrt(n*n+r*r)}function X(t,e,n,r){const o=i(n,r,t.transform,e,t.config);return t.updateTransform(o)}function F(t,e,n){t.preventDefault();const r=Array.from(t.touches);d((...t)=>{const r=t[0];if(1===r.length){if(1===n.touches.length){const t=r[0].clientX-n.touches[0].clientX,o=r[0].clientY-n.touches[0].clientY,a={translateX:e.transform.translateX+t,translateY:e.transform.translateY+o};e.updateTransform(a)}}else if(2===r.length){const t=E(r[0],r[1]),o=Y(r[0],r[1]);if(n.lastDistance>0){const r=t/n.lastDistance,a=e.container.getBoundingClientRect();let s=o.x-a.left,i=o.y-a.top;const l=function(t,e,n,r){return h(t,e,t=>{const e={...n,x:n.x-t,y:n.y-t};return r(e)})}(e,e.config.rulerSize,{x:s,y:i},t=>t);s=l.x,i=l.y,X(e,r,s,i)}n.lastDistance=t,n.lastCenter=o}n.touches=r})(r)}function R(t){const e={touches:[],lastDistance:0,lastCenter:{}},n=t=>{!function(t,e){t.preventDefault(),e.touches=Array.from(t.touches),2===e.touches.length&&(e.lastDistance=E(e.touches[0],e.touches[1]),e.lastCenter=Y(e.touches[0],e.touches[1]))}(t,e)},r=n=>{F(n,t,e)},o=t=>{!function(t,e){e.touches=Array.from(t.touches),e.touches.length<2&&(e.lastDistance=0)}(t,e)};return t.container.addEventListener("touchstart",n,{passive:!1}),t.container.addEventListener("touchmove",r,{passive:!1}),t.container.addEventListener("touchend",o,{passive:!1}),()=>{t.container.removeEventListener("touchstart",n),t.container.removeEventListener("touchmove",r),t.container.removeEventListener("touchend",o)}}function B(t){const e=t.ctrlKey||t.metaKey,n=[0===t.deltaMode,Math.abs(t.deltaY)<50,t.deltaY%1!=0,Math.abs(t.deltaX)>0&&Math.abs(t.deltaY)>0].filter(Boolean).length>=2;return{isTrackpad:n,isMouseWheel:!n,isTrackpadScroll:n&&!e,isTrackpadPinch:n&&e,isZoomGesture:e}}function Z(t,e){const n=(t=>d((...e)=>{const n=e[0];if(!n||!t?.updateTransform)return!1;try{const e=t.transform,r=1,o=n.deltaX*r,a=n.deltaY*r,s={scale:e.scale,translateX:e.translateX-o,translateY:e.translateY-a};return v(t.transformLayer,t.config),t.updateTransform(s)}catch(t){return console.error("Error handling trackpad pan:",t),!1}}))(t),r=r=>B(r).isTrackpadScroll?n(r):function(t,e,n){if(!t||"number"!=typeof t.deltaY)return console.warn("Invalid wheel event provided"),!1;if(!e?.updateTransform)return console.warn("Invalid canvas provided to handleWheelEvent"),!1;try{t.preventDefault();const r=e.container.getBoundingClientRect(),o=t.clientX-r.left,a=t.clientY-r.top,{mouseX:s,mouseY:i}=m(e,o,a,n.rulerSize,(t,e)=>({mouseX:t,mouseY:e})),l=n.zoomSpeed,c=B(t);if(!c.isZoomGesture)return!1;let u=n.enableAdaptiveSpeed?k(e,l):l;if(c.isTrackpadPinch){const t=.05*n.zoomSpeed;u=n.enableAdaptiveSpeed?k(e,t):t}return X(e,(t.deltaY<0?1:-1)>0?1+u:1/(1+u),s,i)}catch(t){return console.error("Error handling wheel event:",t),!1}}(r,t,e);return t.container.addEventListener("wheel",r,{passive:!1}),()=>{t.container.removeEventListener("wheel",r)}}const I=100,P=1e3,O=1001,A=6,_=4,H=8,q=4,K=5,G=100,N=100,V=20,U=200;function W(t,e){const n=function(t){const e=document.createElement("div");return e.className="canvas-ruler horizontal-ruler",e.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${t.rulerSize}px;\n\tright: 0;\n\theight: ${t.rulerSize}px;\n\tbackground: ${t.rulerBackgroundColor};\n\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\tborder-right: 1px solid ${t.rulerBorderColor};\n\tz-index: ${P};\n\tpointer-events: none;\n\tfont-family: ${t.rulerFontFamily};\n\tfont-size: ${t.rulerFontSize}px;\n\tcolor: ${t.rulerTextColor};\n\toverflow: hidden;\n `,e}(e),r=function(t){const e=document.createElement("div");return e.className="canvas-ruler vertical-ruler",e.style.cssText=`\n\tposition: absolute;\n\ttop: ${t.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${t.rulerSize}px;\n\tbackground: ${t.rulerBackgroundColor};\n\tborder-right: 1px solid ${t.rulerBorderColor};\n\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\tz-index: ${P};\n\tpointer-events: none;\n\tfont-family: ${t.rulerFontFamily};\n\tfont-size: ${t.rulerFontSize}px;\n\tcolor: ${t.rulerTextColor};\n\toverflow: hidden;\n `,e}(e),o=function(t){const e=document.createElement("div");return e.className="canvas-ruler corner-box",e.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\twidth: ${t.rulerSize}px;\n\t\theight: ${t.rulerSize}px;\n\t\tbackground: ${t.rulerBackgroundColor};\n\t\tborder-right: 1px solid ${t.rulerBorderColor};\n\t\tborder-bottom: 1px solid ${t.rulerBorderColor};\n\t\tz-index: ${O};\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-family: ${t.rulerFontFamily};\n\t\tfont-size: ${t.rulerFontSize-2}px;\n\t\tcolor: ${t.rulerTextColor};\n\t\tpointer-events: none;\n\t`,e.textContent=t.rulerUnits,e}(e),a=e.enableGrid?function(t){const e=document.createElement("div");return e.className="canvas-ruler grid-overlay",e.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${t.rulerSize}px;\n\t\tleft: ${t.rulerSize}px;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tpointer-events: none;\n\t\tz-index: ${I};\n\t\tbackground-image: \n\t\t\tlinear-gradient(${t.gridColor} 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, ${t.gridColor} 1px, transparent 1px);\n\t\tbackground-size: 100px 100px;\n\t\topacity: 0.5;\n\t`,e}(e):void 0;return t.appendChild(n),t.appendChild(r),t.appendChild(o),a&&t.appendChild(a),{horizontalRuler:n,verticalRuler:r,cornerBox:o,gridOverlay:a}}function j(t,e){const n=t/Math.max(5,Math.min(20,e/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(t,e,n,r,o){const a=document.createElement("div"),s=e%(r*K)===0,i=s?A:_;a.style.cssText=`\n\t\tposition: absolute;\n\t\tleft: ${n}px;\n\t\tbottom: 0;\n\t\twidth: 1px;\n\t\theight: ${i}px;\n\t\tbackground: ${s?o.rulerMajorTickColor:o.rulerMinorTickColor};\n\t`,t.appendChild(a);if(s||e%G===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${i}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: ${o.rulerTextColor};\n\t\t\twhite-space: nowrap;\n\t\t\tpointer-events: none;\n\t\t`,r.textContent=Math.round(e).toString(),t.appendChild(r)}}function Q(t,e,n,r,o){const a=document.createElement("div"),s=e%(r*K)===0,i=s?H:q;a.style.cssText=`\n\t\tposition: absolute;\n\t\ttop: ${n}px;\n\t\tright: 0;\n\t\twidth: ${i}px;\n\t\theight: 1px;\n\t\tbackground: ${s?o.rulerMajorTickColor:o.rulerMinorTickColor};\n\t`,t.appendChild(a);if(s||e%G===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: ${i+6}px;\n\t\t\tfont-size: ${o.rulerFontSize}px;\n\t\t\tline-height: 1;\n\t\t\tcolor: ${o.rulerTextColor};\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(e).toString(),t.appendChild(r)}}function tt(t,e,n,r,o){const a=t.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(t,e,n,r,o,a){const s=r,i=j(n-e,s),l=document.createDocumentFragment(),c=Math.floor(e/i)*i,u=Math.ceil(n/i)*i;for(let t=c;t<=u;t+=i){const n=(t-e)*o;n>=-50&&n<=s+50&&J(l,t,n,i,a)}t.innerHTML="",t.appendChild(l)}(e,d,d+c/s,c,s,o),function(t,e,n,r,o,a){const s=r,i=j(n-e,s),l=document.createDocumentFragment(),c=Math.floor(e/i)*i,u=Math.ceil(n/i)*i;for(let t=c;t<=u;t+=i){const n=(t-e)*o;n>=-50&&n<=s+50&&Q(l,t,n,i,a)}t.innerHTML="",t.appendChild(l)}(n,h,m,u,s,o),r&&function(t,e,n,r){let o=N*e;for(;o<V;)o*=2;for(;o>U;)o/=2;t.style.backgroundSize=`${o}px ${o}px`,t.style.backgroundPosition=`${n%o}px ${r%o}px`}(r,s,i,l)}function et(t,e){if(!t?.container)return console.error("Invalid canvas provided to createRulers"),null;let n,r=null,o=!1;const a=()=>{!o&&n.horizontalRuler&&n.verticalRuler&&tt(t,n.horizontalRuler,n.verticalRuler,n.gridOverlay,e)};try{return n=W(t.container,e),r=function(t,e){const n=d(e),r=t.updateTransform;t.updateTransform=function(t){const e=r.call(this,t);return n(),e};const o=d(e);return window.addEventListener("resize",o),()=>{window.removeEventListener("resize",o),t.updateTransform=r,n.cleanup(),o.cleanup()}}(t,a),a(),{horizontalRuler:n.horizontalRuler,verticalRuler:n.verticalRuler,cornerBox:n.cornerBox,gridOverlay:n.gridOverlay,update:a,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 t="none"!==n.gridOverlay.style.display;n.gridOverlay.style.display=t?"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(t){return console.error("Failed to create rulers:",t),null}}return class{constructor(t,e={}){if(this.cleanupFunctions=[],this.rulers=null,this.dragSetup=null,this._isReady=!1,this.listen=new x,!t)throw new Error("Container element is required");this.config=C(e);const n=w(t,this.config);if(!n)throw new Error("Failed to create canvas");this.baseCanvas=n,this.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const t=Z(this,this.config);this.cleanupFunctions.push(t)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=$(this,this.config,!0),this.cleanupFunctions.push(this.dragSetup.cleanup)),u(this.config,"enableKeyboard",()=>{const t=D(this,this.config);this.cleanupFunctions.push(t)}),u(this.config,"enableTouch",()=>{const t=R(this);this.cleanupFunctions.push(t)}),u(this.config,"enableRulers",()=>{this.rulers=et(this.baseCanvas,this.config),this.cleanupFunctions.push(()=>{this.rulers&&this.rulers.destroy()})})}catch(t){throw console.error("Failed to set up event handlers:",t),this.cleanup(),t}}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(t){const e=this.baseCanvas.updateTransform(t);return e&&this.emitTransformEvents(),e}emitTransformEvents(){const t=this.baseCanvas.transform;this.listen.emit("transform",t),this.listen.emit("zoom",t.scale),this.listen.emit("pan",{x:t.translateX,y:t.translateY})}reset(){return this.baseCanvas.reset()}handleResize(){return this.baseCanvas.handleResize()}setZoom(t){return this.baseCanvas.setZoom(t)}canvasToContent(t,e){return this.baseCanvas.canvasToContent(t,e)}zoomToPoint(t,e,n){return y(this.transformLayer,this.config,()=>{const r=this.baseCanvas.zoomToPoint(t,e,n);return r&&this.emitTransformEvents(),r})}resetView(){return y(this.transformLayer,this.config,()=>{const t=!!this.baseCanvas.resetView&&this.baseCanvas.resetView();return t&&this.emitTransformEvents(),t})}zoomToFitContent(){return y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.zoomToFitContent();return t&&this.emitTransformEvents(),t})}panLeft(t){const e=t??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX+e};return this.updateTransform(n)}panRight(t){const e=t??this.config.keyboardPanStep,n={translateX:this.baseCanvas.transform.translateX-e};return this.updateTransform(n)}panUp(t){const e=t??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY+e};return this.updateTransform(n)}panDown(t){const e=t??this.config.keyboardPanStep,n={translateY:this.baseCanvas.transform.translateY-e};return this.updateTransform(n)}zoomIn(t=.1){return y(this.transformLayer,this.config,()=>l(this.config,e=>{const n={scale:e(this.baseCanvas.transform.scale*(1+t))};return this.updateTransform(n)}))}zoomOut(t=.1){return y(this.transformLayer,this.config,()=>l(this.config,e=>{const n={scale:e(this.baseCanvas.transform.scale*(1-t))};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 y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.getBounds(),e=(t.width-t.contentWidth*this.baseCanvas.transform.scale)/2,n=(t.height-t.contentHeight*this.baseCanvas.transform.scale)/2;return this.updateTransform({translateX:e,translateY:n})})}fitToScreen(){return y(this.transformLayer,this.config,()=>{const t=this.baseCanvas.zoomToFitContent();return t&&this.emitTransformEvents(),t})}getVisibleArea(){return this.baseCanvas.getBounds().visibleArea}isPointVisible(t,e){const n=this.getVisibleArea();return t>=n.x&&t<=n.x+n.width&&e>=n.y&&e<=n.y+n.height}scrollToPoint(t,e){return y(this.transformLayer,this.config,()=>{const n=this.baseCanvas.getBounds(),r=n.width/2,o=n.height/2,a=r-t*this.baseCanvas.transform.scale,s=o-e*this.baseCanvas.transform.scale;return this.updateTransform({translateX:a,translateY:s})})}getConfig(){return{...this.config}}updateConfig(t){this.config=C({...this.config,...t})}cleanup(){this.cleanupFunctions.forEach(t=>{try{t()}catch(t){console.warn("Error during cleanup:",t)}}),this.cleanupFunctions=[],this.removeAllListeners()}on(t,e){this.listen.on(t,e)}off(t,e){this.listen.off(t,e)}emit(t,e){this.listen.emit(t,e)}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,enableZoom:!0,enablePan:!0,enableTouch:!0,enableKeyboard:!0,limitKeyboardEventsToCanvas:!1,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 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}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){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(t.limitKeyboardEventsToCanvas&&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=t.limitKeyboardEventsToCanvas?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 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 Y(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=>{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)),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 E(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 F(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function B(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=E(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 $(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=E(t.touches[0],t.touches[1]))}(e,t)},r=n=>{B(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 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=>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 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 I=100,O=1e3,A=1001,_=4,H=4,q=100,G=100,N=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: ${A};\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: ${I};\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 U(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 W(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: ${_}px;\n\t\tbackground: var(--ruler-tick-color);\n\t`,e.appendChild(a);if(t%q===0){const r=document.createElement("div");r.style.cssText=`\n\t\t\tposition: absolute;\n\t\t\tleft: ${n}px;\n\t\t\tbottom: ${_+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%q===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 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=U(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&&W(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=U(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=G*t;for(;o<N;)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.setupEventHandlers(),this._isReady=!0,this.listen.emit("ready",this)}setupEventHandlers(){try{u(this.config,"enableZoom",()=>{const e=Z(this,this.config);this.cleanupFunctions.push(e)}),(this.config.enablePan||this.config.enableClickToZoom)&&(this.dragSetup=Y(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.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
|
@@ -25,15 +25,24 @@ export interface MarkupCanvasConfig {
|
|
|
25
25
|
requireOptionForClickZoom?: boolean;
|
|
26
26
|
enableRulers?: boolean;
|
|
27
27
|
enableGrid?: boolean;
|
|
28
|
+
showRulers?: boolean;
|
|
29
|
+
showGrid?: boolean;
|
|
28
30
|
gridColor?: string;
|
|
31
|
+
canvasBackgroundColor?: string;
|
|
32
|
+
canvasBackgroundColorDark?: string;
|
|
29
33
|
rulerBackgroundColor?: string;
|
|
30
34
|
rulerBorderColor?: string;
|
|
31
35
|
rulerTextColor?: string;
|
|
32
|
-
|
|
33
|
-
rulerMinorTickColor?: string;
|
|
36
|
+
rulerTickColor?: string;
|
|
34
37
|
rulerFontSize?: number;
|
|
35
38
|
rulerFontFamily?: string;
|
|
36
39
|
rulerUnits?: string;
|
|
37
40
|
rulerSize?: number;
|
|
41
|
+
rulerBackgroundColorDark?: string;
|
|
42
|
+
rulerBorderColorDark?: string;
|
|
43
|
+
rulerTextColorDark?: string;
|
|
44
|
+
rulerTickColorDark?: string;
|
|
45
|
+
gridColorDark?: string;
|
|
46
|
+
themeMode?: "light" | "dark";
|
|
38
47
|
onTransformUpdate?: (transform: Transform) => void;
|
|
39
48
|
}
|
package/dist/types/rulers.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { CanvasBounds, Transform } from "./canvas.js";
|
|
2
|
+
import type { MarkupCanvasConfig } from "./config.js";
|
|
2
3
|
export interface RulerSystem {
|
|
3
4
|
horizontalRuler: HTMLElement;
|
|
4
5
|
verticalRuler: HTMLElement;
|
|
5
6
|
cornerBox: HTMLElement;
|
|
6
7
|
gridOverlay?: HTMLElement;
|
|
7
8
|
update: () => void;
|
|
9
|
+
updateTheme: (config: Required<MarkupCanvasConfig>) => void;
|
|
8
10
|
show: () => void;
|
|
9
11
|
hide: () => void;
|
|
10
12
|
toggleGrid: () => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markup-canvas/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "High-performance canvas-like container with pan and zoom capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/markup-canvas.cjs.js",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"@biomejs/biome": "2.2.6",
|
|
36
36
|
"@rollup/plugin-alias": "^5.1.1",
|
|
37
37
|
"@rollup/plugin-commonjs": "^28.0.8",
|
|
38
|
-
"@rollup/plugin-node-resolve": "^
|
|
38
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
39
39
|
"@rollup/plugin-terser": "^0.4.4",
|
|
40
|
-
"@rollup/plugin-typescript": "^
|
|
40
|
+
"@rollup/plugin-typescript": "^12.1.4",
|
|
41
41
|
"glob": "^11.0.3",
|
|
42
|
-
"rollup": "^4.52.
|
|
42
|
+
"rollup": "^4.52.5",
|
|
43
43
|
"tslib": "^2.8.1",
|
|
44
44
|
"ttypescript": "^1.5.15",
|
|
45
45
|
"typescript": "^5.9.3",
|
package/src/lib/MarkupCanvas.ts
CHANGED
|
@@ -2,7 +2,7 @@ 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
4
|
import { setupKeyboardEvents, setupMouseEvents, setupTouchEvents, setupWheelEvents } from "@/lib/events/index.js";
|
|
5
|
-
import { withClampedZoom, withFeatureEnabled } from "@/lib/helpers/index.js";
|
|
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";
|
|
8
8
|
import type {
|
|
@@ -392,6 +392,24 @@ export class MarkupCanvas implements Canvas {
|
|
|
392
392
|
this.config = createMarkupCanvasConfig({ ...this.config, ...newConfig });
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
+
// Theme management
|
|
396
|
+
updateThemeMode(mode: "light" | "dark"): void {
|
|
397
|
+
const newConfig = {
|
|
398
|
+
...this.config,
|
|
399
|
+
themeMode: mode,
|
|
400
|
+
};
|
|
401
|
+
this.config = createMarkupCanvasConfig(newConfig);
|
|
402
|
+
|
|
403
|
+
// Update canvas background color
|
|
404
|
+
const backgroundColor = getThemeValue(this.config, "canvasBackgroundColor");
|
|
405
|
+
this.baseCanvas.container.style.backgroundColor = backgroundColor;
|
|
406
|
+
|
|
407
|
+
// Update rulers if they exist
|
|
408
|
+
if (this.rulers) {
|
|
409
|
+
this.rulers.updateTheme(this.config);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
395
413
|
// Cleanup method
|
|
396
414
|
cleanup(): void {
|
|
397
415
|
this.cleanupFunctions.forEach((cleanup) => {
|
|
@@ -14,7 +14,7 @@ export function createCanvas(container: HTMLElement, config: Required<MarkupCanv
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
try {
|
|
17
|
-
setupCanvasContainer(container);
|
|
17
|
+
setupCanvasContainer(container, config);
|
|
18
18
|
|
|
19
19
|
const { transformLayer, contentLayer } = createCanvasLayers(container, config);
|
|
20
20
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { checkContainerDimensions } from "@/lib/canvas/checkContainerDimensions";
|
|
2
2
|
import { CANVAS_CONTAINER_CLASS } from "@/lib/constants";
|
|
3
|
+
import { getThemeValue } from "@/lib/helpers/index.js";
|
|
4
|
+
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
5
|
|
|
4
|
-
export function setupCanvasContainer(container: HTMLElement): void {
|
|
6
|
+
export function setupCanvasContainer(container: HTMLElement, config?: Required<MarkupCanvasConfig>): void {
|
|
5
7
|
const currentPosition = getComputedStyle(container).position;
|
|
6
8
|
if (currentPosition === "static") {
|
|
7
9
|
container.style.position = "relative";
|
|
@@ -10,6 +12,12 @@ export function setupCanvasContainer(container: HTMLElement): void {
|
|
|
10
12
|
container.style.cursor = "grab";
|
|
11
13
|
container.style.overscrollBehavior = "none";
|
|
12
14
|
|
|
15
|
+
// Apply canvas background color
|
|
16
|
+
if (config) {
|
|
17
|
+
const backgroundColor = getThemeValue(config, "canvasBackgroundColor");
|
|
18
|
+
container.style.backgroundColor = backgroundColor;
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
if (!container.hasAttribute("tabindex")) {
|
|
14
22
|
container.setAttribute("tabindex", "0");
|
|
15
23
|
}
|