@markup-canvas/core 1.0.7 → 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/dist/lib/rulers/updateRulerTheme.d.ts +0 -5
- package/dist/markup-canvas.cjs.js +46 -67
- package/dist/markup-canvas.esm.js +46 -67
- package/dist/markup-canvas.umd.js +41 -62
- package/dist/markup-canvas.umd.min.js +1 -1
- package/package.json +1 -1
- package/src/lib/config/constants.ts +2 -2
- package/src/lib/config/presets/editor-preset.ts +5 -5
- package/src/lib/rulers/createCornerBox.ts +4 -8
- package/src/lib/rulers/createGridOverlay.ts +2 -4
- package/src/lib/rulers/createHorizontalRuler.ts +4 -8
- package/src/lib/rulers/createRulers.ts +2 -3
- package/src/lib/rulers/createVerticalRuler.ts +4 -8
- package/src/lib/rulers/ticks/createHorizontalTick.ts +3 -5
- package/src/lib/rulers/ticks/createVerticalTick.ts +3 -5
- package/src/lib/rulers/updateRulerTheme.ts +17 -25
|
@@ -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() :
|
|
@@ -291,7 +291,7 @@
|
|
|
291
291
|
canvasBackgroundColorDark: "rgba(40, 40, 40, 1)",
|
|
292
292
|
// Ruler styling (light theme)
|
|
293
293
|
rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
294
|
-
rulerBorderColor: "rgba(
|
|
294
|
+
rulerBorderColor: "rgba(240, 240, 240, 1)",
|
|
295
295
|
rulerTextColor: "rgba(102, 102, 102, 1)",
|
|
296
296
|
rulerTickColor: "rgba(204, 204, 204, 1)",
|
|
297
297
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
rulerBackgroundColorDark: "rgba(30, 30, 30, 0.95)",
|
|
300
300
|
rulerBorderColorDark: "rgba(68, 68, 68, 1)",
|
|
301
301
|
rulerTextColorDark: "rgba(170, 170, 170, 1)",
|
|
302
|
-
rulerTickColorDark: "rgba(
|
|
302
|
+
rulerTickColorDark: "rgba(104, 104, 104, 1)",
|
|
303
303
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
304
304
|
// Theme
|
|
305
305
|
themeMode: "light",
|
|
@@ -1322,25 +1322,22 @@
|
|
|
1322
1322
|
function createCornerBox(config) {
|
|
1323
1323
|
const corner = document.createElement("div");
|
|
1324
1324
|
corner.className = "canvas-ruler corner-box";
|
|
1325
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
1326
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
1327
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1328
1325
|
corner.style.cssText = `
|
|
1329
1326
|
position: absolute;
|
|
1330
1327
|
top: 0;
|
|
1331
1328
|
left: 0;
|
|
1332
1329
|
width: ${config.rulerSize}px;
|
|
1333
1330
|
height: ${config.rulerSize}px;
|
|
1334
|
-
background:
|
|
1335
|
-
border-right: 1px solid
|
|
1336
|
-
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);
|
|
1337
1334
|
z-index: ${RULER_Z_INDEX.CORNER};
|
|
1338
1335
|
display: flex;
|
|
1339
1336
|
align-items: center;
|
|
1340
1337
|
justify-content: center;
|
|
1341
1338
|
font-family: ${config.rulerFontFamily};
|
|
1342
1339
|
font-size: ${config.rulerFontSize - 2}px;
|
|
1343
|
-
color:
|
|
1340
|
+
color: var(--ruler-text-color);
|
|
1344
1341
|
pointer-events: none;
|
|
1345
1342
|
`;
|
|
1346
1343
|
corner.textContent = config.rulerUnits;
|
|
@@ -1350,7 +1347,6 @@
|
|
|
1350
1347
|
function createGridOverlay(config) {
|
|
1351
1348
|
const grid = document.createElement("div");
|
|
1352
1349
|
grid.className = "canvas-ruler grid-overlay";
|
|
1353
|
-
const gridColor = getThemeValue(config, "gridColor");
|
|
1354
1350
|
grid.style.cssText = `
|
|
1355
1351
|
position: absolute;
|
|
1356
1352
|
top: ${config.rulerSize}px;
|
|
@@ -1360,8 +1356,8 @@
|
|
|
1360
1356
|
pointer-events: none;
|
|
1361
1357
|
z-index: ${RULER_Z_INDEX.GRID};
|
|
1362
1358
|
background-image:
|
|
1363
|
-
linear-gradient(
|
|
1364
|
-
linear-gradient(90deg,
|
|
1359
|
+
linear-gradient(var(--grid-color) 1px, transparent 1px),
|
|
1360
|
+
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
|
|
1365
1361
|
background-size: 100px 100px;
|
|
1366
1362
|
opacity: 0.5;
|
|
1367
1363
|
`;
|
|
@@ -1371,23 +1367,20 @@
|
|
|
1371
1367
|
function createHorizontalRuler(config) {
|
|
1372
1368
|
const ruler = document.createElement("div");
|
|
1373
1369
|
ruler.className = "canvas-ruler horizontal-ruler";
|
|
1374
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
1375
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
1376
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1377
1370
|
ruler.style.cssText = `
|
|
1378
1371
|
position: absolute;
|
|
1379
1372
|
top: 0;
|
|
1380
1373
|
left: ${config.rulerSize}px;
|
|
1381
1374
|
right: 0;
|
|
1382
1375
|
height: ${config.rulerSize}px;
|
|
1383
|
-
background:
|
|
1384
|
-
border-bottom: 1px solid
|
|
1385
|
-
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);
|
|
1386
1379
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1387
1380
|
pointer-events: none;
|
|
1388
1381
|
font-family: ${config.rulerFontFamily};
|
|
1389
1382
|
font-size: ${config.rulerFontSize}px;
|
|
1390
|
-
color:
|
|
1383
|
+
color: var(--ruler-text-color);
|
|
1391
1384
|
overflow: hidden;
|
|
1392
1385
|
`;
|
|
1393
1386
|
return ruler;
|
|
@@ -1396,23 +1389,20 @@
|
|
|
1396
1389
|
function createVerticalRuler(config) {
|
|
1397
1390
|
const ruler = document.createElement("div");
|
|
1398
1391
|
ruler.className = "canvas-ruler vertical-ruler";
|
|
1399
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
1400
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
1401
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1402
1392
|
ruler.style.cssText = `
|
|
1403
1393
|
position: absolute;
|
|
1404
1394
|
top: ${config.rulerSize}px;
|
|
1405
1395
|
left: 0;
|
|
1406
1396
|
bottom: 0;
|
|
1407
1397
|
width: ${config.rulerSize}px;
|
|
1408
|
-
background:
|
|
1409
|
-
border-right: 1px solid
|
|
1410
|
-
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);
|
|
1411
1401
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
1412
1402
|
pointer-events: none;
|
|
1413
1403
|
font-family: ${config.rulerFontFamily};
|
|
1414
1404
|
font-size: ${config.rulerFontSize}px;
|
|
1415
|
-
color:
|
|
1405
|
+
color: var(--ruler-text-color);
|
|
1416
1406
|
overflow: hidden;
|
|
1417
1407
|
`;
|
|
1418
1408
|
return ruler;
|
|
@@ -1484,27 +1474,26 @@
|
|
|
1484
1474
|
|
|
1485
1475
|
function createHorizontalTick(container, position, pixelPos, _tickSpacing, config) {
|
|
1486
1476
|
const tick = document.createElement("div");
|
|
1487
|
-
|
|
1477
|
+
tick.className = "tick";
|
|
1488
1478
|
tick.style.cssText = `
|
|
1489
1479
|
position: absolute;
|
|
1490
1480
|
left: ${pixelPos}px;
|
|
1491
1481
|
bottom: 0;
|
|
1492
1482
|
width: 1px;
|
|
1493
1483
|
height: ${TICK_SETTINGS.TICK_HEIGHT}px;
|
|
1494
|
-
background:
|
|
1484
|
+
background: var(--ruler-tick-color);
|
|
1495
1485
|
`;
|
|
1496
1486
|
container.appendChild(tick);
|
|
1497
1487
|
const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
|
|
1498
1488
|
if (shouldShowLabel) {
|
|
1499
1489
|
const label = document.createElement("div");
|
|
1500
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1501
1490
|
label.style.cssText = `
|
|
1502
1491
|
position: absolute;
|
|
1503
1492
|
left: ${pixelPos}px;
|
|
1504
1493
|
bottom: ${TICK_SETTINGS.TICK_HEIGHT + 2}px;
|
|
1505
1494
|
font-size: ${config.rulerFontSize}px;
|
|
1506
1495
|
line-height: 1;
|
|
1507
|
-
color:
|
|
1496
|
+
color: var(--ruler-text-color);
|
|
1508
1497
|
white-space: nowrap;
|
|
1509
1498
|
pointer-events: none;
|
|
1510
1499
|
`;
|
|
@@ -1532,27 +1521,26 @@
|
|
|
1532
1521
|
|
|
1533
1522
|
function createVerticalTick(container, position, pixelPos, _tickSpacing, config) {
|
|
1534
1523
|
const tick = document.createElement("div");
|
|
1535
|
-
|
|
1524
|
+
tick.className = "tick";
|
|
1536
1525
|
tick.style.cssText = `
|
|
1537
1526
|
position: absolute;
|
|
1538
1527
|
top: ${pixelPos}px;
|
|
1539
1528
|
right: 0;
|
|
1540
1529
|
width: ${TICK_SETTINGS.TICK_WIDTH}px;
|
|
1541
1530
|
height: 1px;
|
|
1542
|
-
background:
|
|
1531
|
+
background: var(--ruler-tick-color);
|
|
1543
1532
|
`;
|
|
1544
1533
|
container.appendChild(tick);
|
|
1545
1534
|
const shouldShowLabel = position % TICK_SETTINGS.TICK_LABEL_INTERVAL === 0;
|
|
1546
1535
|
if (shouldShowLabel) {
|
|
1547
1536
|
const label = document.createElement("div");
|
|
1548
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1549
1537
|
label.style.cssText = `
|
|
1550
1538
|
position: absolute;
|
|
1551
1539
|
top: ${pixelPos - 6}px;
|
|
1552
1540
|
right: ${TICK_SETTINGS.TICK_WIDTH + 6}px;
|
|
1553
1541
|
font-size: ${config.rulerFontSize}px;
|
|
1554
1542
|
line-height: 1;
|
|
1555
|
-
color:
|
|
1543
|
+
color: var(--ruler-text-color);
|
|
1556
1544
|
white-space: nowrap;
|
|
1557
1545
|
pointer-events: none;
|
|
1558
1546
|
transform: rotate(-90deg);
|
|
@@ -1598,44 +1586,36 @@
|
|
|
1598
1586
|
}
|
|
1599
1587
|
}
|
|
1600
1588
|
|
|
1601
|
-
/**
|
|
1602
|
-
* Updates all ruler elements with new theme colors
|
|
1603
|
-
* @param elements - The ruler elements to update
|
|
1604
|
-
* @param config - The canvas config containing theme and color settings
|
|
1605
|
-
*/
|
|
1606
1589
|
function updateRulerTheme(elements, config) {
|
|
1607
1590
|
// Get theme-aware colors
|
|
1608
1591
|
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
1609
1592
|
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
1610
1593
|
const textColor = getThemeValue(config, "rulerTextColor");
|
|
1594
|
+
const tickColor = getThemeValue(config, "rulerTickColor");
|
|
1611
1595
|
const gridColor = getThemeValue(config, "gridColor");
|
|
1612
|
-
// Update horizontal ruler
|
|
1596
|
+
// Update horizontal ruler with CSS variables
|
|
1613
1597
|
if (elements.horizontalRuler) {
|
|
1614
|
-
elements.horizontalRuler.style.background
|
|
1615
|
-
elements.horizontalRuler.style.
|
|
1616
|
-
elements.horizontalRuler.style.
|
|
1617
|
-
elements.horizontalRuler.style.color
|
|
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);
|
|
1618
1602
|
}
|
|
1619
|
-
// Update vertical ruler
|
|
1603
|
+
// Update vertical ruler with CSS variables
|
|
1620
1604
|
if (elements.verticalRuler) {
|
|
1621
|
-
elements.verticalRuler.style.background
|
|
1622
|
-
elements.verticalRuler.style.
|
|
1623
|
-
elements.verticalRuler.style.
|
|
1624
|
-
elements.verticalRuler.style.color
|
|
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);
|
|
1625
1609
|
}
|
|
1626
|
-
// Update corner box
|
|
1610
|
+
// Update corner box with CSS variables
|
|
1627
1611
|
if (elements.cornerBox) {
|
|
1628
|
-
elements.cornerBox.style.background
|
|
1629
|
-
elements.cornerBox.style.
|
|
1630
|
-
elements.cornerBox.style.
|
|
1631
|
-
elements.cornerBox.style.color = textColor;
|
|
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);
|
|
1632
1615
|
}
|
|
1633
|
-
// Update grid overlay
|
|
1616
|
+
// Update grid overlay with CSS variables
|
|
1634
1617
|
if (elements.gridOverlay) {
|
|
1635
|
-
elements.gridOverlay.style.
|
|
1636
|
-
linear-gradient(${gridColor} 1px, transparent 1px),
|
|
1637
|
-
linear-gradient(90deg, ${gridColor} 1px, transparent 1px)
|
|
1638
|
-
`;
|
|
1618
|
+
elements.gridOverlay.style.setProperty("--grid-color", gridColor);
|
|
1639
1619
|
}
|
|
1640
1620
|
}
|
|
1641
1621
|
|
|
@@ -1655,6 +1635,7 @@
|
|
|
1655
1635
|
try {
|
|
1656
1636
|
elements = createRulerElements(canvas.container, config);
|
|
1657
1637
|
cleanupEvents = setupRulerEvents(canvas, safeUpdate);
|
|
1638
|
+
updateRulerTheme(elements, config);
|
|
1658
1639
|
safeUpdate();
|
|
1659
1640
|
if (!config.showRulers) {
|
|
1660
1641
|
elements.horizontalRuler.style.display = "none";
|
|
@@ -1675,8 +1656,6 @@
|
|
|
1675
1656
|
return;
|
|
1676
1657
|
// Update all ruler theme colors
|
|
1677
1658
|
updateRulerTheme(elements, newConfig);
|
|
1678
|
-
// Re-render rulers to update tick colors
|
|
1679
|
-
safeUpdate();
|
|
1680
1659
|
},
|
|
1681
1660
|
show: () => {
|
|
1682
1661
|
if (elements.horizontalRuler)
|
|
@@ -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,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(221, 221, 221, 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(56, 56, 56, 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 y(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 v(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{v(e,t)}}function C(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 w(e,t){if(!e?.appendChild)return console.error("Invalid container element provided to createCanvas"),null;try{C(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};y(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=y(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 T{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 k=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 $(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<k&&!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})},y=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)},v=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=>{$(n,e,t,r,l,o,i,c,m,{setIsDragging:g.setIsDragging,setDragButton:g.setDragButton,setMouseDownTime:g.setMouseDownTime,setHasDragged:g.setHasDragged})},C=()=>{!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",y),document.addEventListener("mousemove",v),document.addEventListener("mouseup",b),e.container.addEventListener("mouseleave",C),t.requireSpaceForMouseDrag&&(document.addEventListener("keydown",f),document.addEventListener("keyup",p)),M(e,t,r,l,o);const w=()=>{e.container.removeEventListener("mousedown",y),document.removeEventListener("mousemove",v),document.removeEventListener("mouseup",b),e.container.removeEventListener("mouseleave",C),t.requireSpaceForMouseDrag&&(document.removeEventListener("keydown",f),document.removeEventListener("keyup",p))};return n?{cleanup:w,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}:w}function B(e,t){return{x:(e.clientX+t.clientX)/2,y:(e.clientY+t.clientY)/2}}function Y(e,t){const n=e.clientX-t.clientX,r=e.clientY-t.clientY;return Math.sqrt(n*n+r*r)}function E(e,t,n,r){const o=i(n,r,e.transform,t,e.config);return e.updateTransform(o)}function X(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=Y(r[0],r[1]),o=B(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,E(t,r,s,i)}n.lastDistance=e,n.lastCenter=o}n.touches=r})(r)}function F(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=Y(t.touches[0],t.touches[1]),t.lastCenter=B(t.touches[0],t.touches[1]))}(e,t)},r=n=>{X(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 Z(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 v(e.transformLayer,e.config),e.updateTransform(s)}catch(e){return console.error("Error handling trackpad pan:",e),!1}}))(e),r=r=>Z(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=Z(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 E(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 P=100,O=1e3,A=1001,_=4,H=4,q=100,G=100,K=20,N=200;function V(e,t){const n=function(e){const t=document.createElement("div");t.className="canvas-ruler horizontal-ruler";const n=g(e,"rulerBackgroundColor"),r=g(e,"rulerBorderColor"),o=g(e,"rulerTextColor");return t.style.cssText=`\n\tposition: absolute;\n\ttop: 0;\n\tleft: ${e.rulerSize}px;\n\tright: 0;\n\theight: ${e.rulerSize}px;\n\tbackground: ${n};\n\tborder-bottom: 1px solid ${r};\n\tborder-right: 1px solid ${r};\n\tz-index: ${O};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: ${o};\n\toverflow: hidden;\n `,t}(t),r=function(e){const t=document.createElement("div");t.className="canvas-ruler vertical-ruler";const n=g(e,"rulerBackgroundColor"),r=g(e,"rulerBorderColor"),o=g(e,"rulerTextColor");return t.style.cssText=`\n\tposition: absolute;\n\ttop: ${e.rulerSize}px;\n\tleft: 0;\n\tbottom: 0;\n\twidth: ${e.rulerSize}px;\n\tbackground: ${n};\n\tborder-right: 1px solid ${r};\n\tborder-bottom: 1px solid ${r};\n\tz-index: ${O};\n\tpointer-events: none;\n\tfont-family: ${e.rulerFontFamily};\n\tfont-size: ${e.rulerFontSize}px;\n\tcolor: ${o};\n\toverflow: hidden;\n `,t}(t),o=function(e){const t=document.createElement("div");t.className="canvas-ruler corner-box";const n=g(e,"rulerBackgroundColor"),r=g(e,"rulerBorderColor"),o=g(e,"rulerTextColor");return 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: ${n};\n\t\tborder-right: 1px solid ${r};\n\t\tborder-bottom: 1px solid ${r};\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: ${o};\n\t\tpointer-events: none;\n\t`,t.textContent=e.rulerUnits,t}(t),a=t.enableGrid?function(e){const t=document.createElement("div");t.className="canvas-ruler grid-overlay";const n=g(e,"gridColor");return 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: ${P};\n\t\tbackground-image: \n\t\t\tlinear-gradient(${n} 1px, transparent 1px),\n\t\t\tlinear-gradient(90deg, ${n} 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"),s=g(o,"rulerTickColor");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: ${s};\n\t`,e.appendChild(a);if(t%q===0){const r=document.createElement("div"),a=g(o,"rulerTextColor");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: ${a};\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"),s=g(o,"rulerTickColor");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: ${s};\n\t`,e.appendChild(a);if(t%q===0){const r=document.createElement("div"),a=g(o,"rulerTextColor");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: ${a};\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<K;)o*=2;for(;o>N;)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){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),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||(!function(e,t){const n=g(t,"rulerBackgroundColor"),r=g(t,"rulerBorderColor"),o=g(t,"rulerTextColor"),a=g(t,"gridColor");e.horizontalRuler&&(e.horizontalRuler.style.background=n,e.horizontalRuler.style.borderBottomColor=r,e.horizontalRuler.style.borderRightColor=r,e.horizontalRuler.style.color=o),e.verticalRuler&&(e.verticalRuler.style.background=n,e.verticalRuler.style.borderRightColor=r,e.verticalRuler.style.borderBottomColor=r,e.verticalRuler.style.color=o),e.cornerBox&&(e.cornerBox.style.background=n,e.cornerBox.style.borderRightColor=r,e.cornerBox.style.borderBottomColor=r,e.cornerBox.style.color=o),e.gridOverlay&&(e.gridOverlay.style.backgroundImage=`\n linear-gradient(${a} 1px, transparent 1px),\n linear-gradient(90deg, ${a} 1px, transparent 1px)\n `)}(n,e),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 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 T,!e)throw new Error("Container element is required");this.config=x(t);const n=w(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=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=F(this);this.cleanupFunctions.push(e)}),u(this.config,"enableRulers",()=>{this.rulers=Q(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.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,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/package.json
CHANGED
|
@@ -52,7 +52,7 @@ export const DEFAULT_CONFIG: Required<MarkupCanvasConfig> = {
|
|
|
52
52
|
|
|
53
53
|
// Ruler styling (light theme)
|
|
54
54
|
rulerBackgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
55
|
-
rulerBorderColor: "rgba(
|
|
55
|
+
rulerBorderColor: "rgba(240, 240, 240, 1)",
|
|
56
56
|
rulerTextColor: "rgba(102, 102, 102, 1)",
|
|
57
57
|
rulerTickColor: "rgba(204, 204, 204, 1)",
|
|
58
58
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
@@ -61,7 +61,7 @@ export const DEFAULT_CONFIG: Required<MarkupCanvasConfig> = {
|
|
|
61
61
|
rulerBackgroundColorDark: "rgba(30, 30, 30, 0.95)",
|
|
62
62
|
rulerBorderColorDark: "rgba(68, 68, 68, 1)",
|
|
63
63
|
rulerTextColorDark: "rgba(170, 170, 170, 1)",
|
|
64
|
-
rulerTickColorDark: "rgba(
|
|
64
|
+
rulerTickColorDark: "rgba(104, 104, 104, 1)",
|
|
65
65
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
66
66
|
|
|
67
67
|
// Theme
|
|
@@ -48,19 +48,19 @@ export const EDITOR_PRESET: Required<MarkupCanvasConfig> = {
|
|
|
48
48
|
rulerSize: 20,
|
|
49
49
|
|
|
50
50
|
// Canvas styling
|
|
51
|
-
canvasBackgroundColor: "
|
|
52
|
-
canvasBackgroundColorDark: "
|
|
51
|
+
canvasBackgroundColor: "transparent",
|
|
52
|
+
canvasBackgroundColorDark: "transparent",
|
|
53
53
|
|
|
54
54
|
// Ruler styling
|
|
55
55
|
rulerBackgroundColor: "oklch(100% 0 0 / 0.4)",
|
|
56
|
-
rulerBorderColor: "oklch(
|
|
56
|
+
rulerBorderColor: "oklch(96.7% 0.001 286.375)",
|
|
57
57
|
rulerTextColor: "oklch(70.5% 0.015 286.067)",
|
|
58
|
-
rulerTickColor: "oklch(
|
|
58
|
+
rulerTickColor: "oklch(92% 0.004 286.32)",
|
|
59
59
|
gridColor: "rgba(232, 86, 193, 0.5)",
|
|
60
60
|
|
|
61
61
|
// Ruler styling (dark theme)
|
|
62
62
|
rulerBackgroundColorDark: "oklch(27.4% 0.006 286.033)",
|
|
63
|
-
rulerBorderColorDark: "oklch(
|
|
63
|
+
rulerBorderColorDark: "oklch(44.2% 0.017 285.786)",
|
|
64
64
|
rulerTextColorDark: "oklch(55.2% 0.016 285.938)",
|
|
65
65
|
rulerTickColorDark: "oklch(55.2% 0.016 285.938)",
|
|
66
66
|
gridColorDark: "rgba(232, 86, 193, 0.5)",
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { getThemeValue } from "@/lib/helpers/index.js";
|
|
2
1
|
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
2
|
import { RULER_Z_INDEX } from "./constants";
|
|
4
3
|
|
|
5
4
|
export function createCornerBox(config: Required<MarkupCanvasConfig>): HTMLElement {
|
|
6
5
|
const corner = document.createElement("div");
|
|
7
6
|
corner.className = "canvas-ruler corner-box";
|
|
8
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
9
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
10
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
11
7
|
|
|
12
8
|
corner.style.cssText = `
|
|
13
9
|
position: absolute;
|
|
@@ -15,16 +11,16 @@ export function createCornerBox(config: Required<MarkupCanvasConfig>): HTMLEleme
|
|
|
15
11
|
left: 0;
|
|
16
12
|
width: ${config.rulerSize}px;
|
|
17
13
|
height: ${config.rulerSize}px;
|
|
18
|
-
background:
|
|
19
|
-
border-right: 1px solid
|
|
20
|
-
border-bottom: 1px solid
|
|
14
|
+
background: var(--ruler-background-color);
|
|
15
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
16
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
21
17
|
z-index: ${RULER_Z_INDEX.CORNER};
|
|
22
18
|
display: flex;
|
|
23
19
|
align-items: center;
|
|
24
20
|
justify-content: center;
|
|
25
21
|
font-family: ${config.rulerFontFamily};
|
|
26
22
|
font-size: ${config.rulerFontSize - 2}px;
|
|
27
|
-
color:
|
|
23
|
+
color: var(--ruler-text-color);
|
|
28
24
|
pointer-events: none;
|
|
29
25
|
`;
|
|
30
26
|
corner.textContent = config.rulerUnits;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { getThemeValue } from "@/lib/helpers/index.js";
|
|
2
1
|
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
2
|
import { RULER_Z_INDEX } from "./constants";
|
|
4
3
|
|
|
5
4
|
export function createGridOverlay(config: Required<MarkupCanvasConfig>): HTMLElement {
|
|
6
5
|
const grid = document.createElement("div");
|
|
7
6
|
grid.className = "canvas-ruler grid-overlay";
|
|
8
|
-
const gridColor = getThemeValue(config, "gridColor");
|
|
9
7
|
|
|
10
8
|
grid.style.cssText = `
|
|
11
9
|
position: absolute;
|
|
@@ -16,8 +14,8 @@ export function createGridOverlay(config: Required<MarkupCanvasConfig>): HTMLEle
|
|
|
16
14
|
pointer-events: none;
|
|
17
15
|
z-index: ${RULER_Z_INDEX.GRID};
|
|
18
16
|
background-image:
|
|
19
|
-
linear-gradient(
|
|
20
|
-
linear-gradient(90deg,
|
|
17
|
+
linear-gradient(var(--grid-color) 1px, transparent 1px),
|
|
18
|
+
linear-gradient(90deg, var(--grid-color) 1px, transparent 1px);
|
|
21
19
|
background-size: 100px 100px;
|
|
22
20
|
opacity: 0.5;
|
|
23
21
|
`;
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { getThemeValue } from "@/lib/helpers/index.js";
|
|
2
1
|
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
2
|
import { RULER_Z_INDEX } from "./constants";
|
|
4
3
|
|
|
5
4
|
export function createHorizontalRuler(config: Required<MarkupCanvasConfig>): HTMLElement {
|
|
6
5
|
const ruler = document.createElement("div");
|
|
7
6
|
ruler.className = "canvas-ruler horizontal-ruler";
|
|
8
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
9
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
10
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
11
7
|
|
|
12
8
|
ruler.style.cssText = `
|
|
13
9
|
position: absolute;
|
|
@@ -15,14 +11,14 @@ export function createHorizontalRuler(config: Required<MarkupCanvasConfig>): HTM
|
|
|
15
11
|
left: ${config.rulerSize}px;
|
|
16
12
|
right: 0;
|
|
17
13
|
height: ${config.rulerSize}px;
|
|
18
|
-
background:
|
|
19
|
-
border-bottom: 1px solid
|
|
20
|
-
border-right: 1px solid
|
|
14
|
+
background: var(--ruler-background-color);
|
|
15
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
16
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
21
17
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
22
18
|
pointer-events: none;
|
|
23
19
|
font-family: ${config.rulerFontFamily};
|
|
24
20
|
font-size: ${config.rulerFontSize}px;
|
|
25
|
-
color:
|
|
21
|
+
color: var(--ruler-text-color);
|
|
26
22
|
overflow: hidden;
|
|
27
23
|
`;
|
|
28
24
|
return ruler;
|
|
@@ -24,6 +24,8 @@ export function createRulers(canvas: Canvas, config: Required<MarkupCanvasConfig
|
|
|
24
24
|
elements = createRulerElements(canvas.container, config);
|
|
25
25
|
cleanupEvents = setupRulerEvents(canvas, safeUpdate);
|
|
26
26
|
|
|
27
|
+
updateRulerTheme(elements, config);
|
|
28
|
+
|
|
27
29
|
safeUpdate();
|
|
28
30
|
|
|
29
31
|
if (!config.showRulers) {
|
|
@@ -48,9 +50,6 @@ export function createRulers(canvas: Canvas, config: Required<MarkupCanvasConfig
|
|
|
48
50
|
|
|
49
51
|
// Update all ruler theme colors
|
|
50
52
|
updateRulerTheme(elements, newConfig);
|
|
51
|
-
|
|
52
|
-
// Re-render rulers to update tick colors
|
|
53
|
-
safeUpdate();
|
|
54
53
|
},
|
|
55
54
|
|
|
56
55
|
show: () => {
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { getThemeValue } from "@/lib/helpers/index.js";
|
|
2
1
|
import type { MarkupCanvasConfig } from "@/types/index.js";
|
|
3
2
|
import { RULER_Z_INDEX } from "./constants";
|
|
4
3
|
|
|
5
4
|
export function createVerticalRuler(config: Required<MarkupCanvasConfig>): HTMLElement {
|
|
6
5
|
const ruler = document.createElement("div");
|
|
7
6
|
ruler.className = "canvas-ruler vertical-ruler";
|
|
8
|
-
const backgroundColor = getThemeValue(config, "rulerBackgroundColor");
|
|
9
|
-
const borderColor = getThemeValue(config, "rulerBorderColor");
|
|
10
|
-
const textColor = getThemeValue(config, "rulerTextColor");
|
|
11
7
|
|
|
12
8
|
ruler.style.cssText = `
|
|
13
9
|
position: absolute;
|
|
@@ -15,14 +11,14 @@ export function createVerticalRuler(config: Required<MarkupCanvasConfig>): HTMLE
|
|
|
15
11
|
left: 0;
|
|
16
12
|
bottom: 0;
|
|
17
13
|
width: ${config.rulerSize}px;
|
|
18
|
-
background:
|
|
19
|
-
border-right: 1px solid
|
|
20
|
-
border-bottom: 1px solid
|
|
14
|
+
background: var(--ruler-background-color);
|
|
15
|
+
border-right: 1px solid var(--ruler-border-color);
|
|
16
|
+
border-bottom: 1px solid var(--ruler-border-color);
|
|
21
17
|
z-index: ${RULER_Z_INDEX.RULERS};
|
|
22
18
|
pointer-events: none;
|
|
23
19
|
font-family: ${config.rulerFontFamily};
|
|
24
20
|
font-size: ${config.rulerFontSize}px;
|
|
25
|
-
color:
|
|
21
|
+
color: var(--ruler-text-color);
|
|
26
22
|
overflow: hidden;
|
|
27
23
|
`;
|
|
28
24
|
return ruler;
|