@elixpo/lixsketch 5.5.20 → 5.5.22
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/react/{CopyPaste-KJZ34MIP.js → CopyPaste-5OWPTCQ5.js} +43 -11
- package/dist/react/CopyPaste-5OWPTCQ5.js.map +7 -0
- package/dist/react/{EventDispatcher-XDRQS7BD.js → EventDispatcher-O7HCQQNM.js} +13 -13
- package/dist/react/Frame-RLSMJJSK.js +11 -0
- package/dist/react/{GraphEngine-KQXHNTZQ.js → GraphEngine-MM6ALA2N.js} +105 -148
- package/dist/react/{GraphEngine-KQXHNTZQ.js.map → GraphEngine-MM6ALA2N.js.map} +2 -2
- package/dist/react/IconShape-7OPXAKLK.js +10 -0
- package/dist/react/ImageShape-T7UEHP4A.js +10 -0
- package/dist/react/Line-WWQFBNX5.js +10 -0
- package/dist/react/{SceneSerializer-VY3HY4PF.js → SceneSerializer-RDISX4X7.js} +36 -8
- package/dist/react/SceneSerializer-RDISX4X7.js.map +7 -0
- package/dist/react/{Selection-U2AR6NQS.js → Selection-ZL3G6IAO.js} +4 -4
- package/dist/react/{SketchEngine-ZFYUTKET.js → SketchEngine-MYKRKRJG.js} +21 -21
- package/dist/react/{UndoRedo-BZ6W4QTV.js → UndoRedo-NL7KLR5B.js} +2 -2
- package/dist/react/{arrowTool-LKFSZKXC.js → arrowTool-CNVGM6RX.js} +3 -3
- package/dist/react/{chunk-SBSM3GQD.js → chunk-2THKDSWW.js} +4 -4
- package/dist/react/{chunk-JOPQ27YH.js → chunk-4BLMNGTR.js} +3 -3
- package/dist/react/{chunk-C62SXFBL.js → chunk-4TAS67SL.js} +23 -22
- package/dist/react/chunk-4TAS67SL.js.map +7 -0
- package/dist/react/{chunk-7VBI7S7T.js → chunk-AH4PWNEB.js} +10 -11
- package/dist/react/chunk-AH4PWNEB.js.map +7 -0
- package/dist/react/{chunk-RFHMFWVR.js → chunk-EDSKEM6E.js} +70 -6
- package/dist/react/chunk-EDSKEM6E.js.map +7 -0
- package/dist/react/{chunk-R5QXEVZ5.js → chunk-GC3KTQDA.js} +74 -15
- package/dist/react/chunk-GC3KTQDA.js.map +7 -0
- package/dist/react/{chunk-2V7G2PLX.js → chunk-GPIYXREE.js} +3 -3
- package/dist/react/{chunk-73VLPCBC.js → chunk-HFQZYCHJ.js} +3 -3
- package/dist/react/{chunk-C72OHQLE.js → chunk-ILGAFR56.js} +3 -3
- package/dist/react/{chunk-75G7XSZU.js → chunk-KVAQPCUH.js} +17 -3
- package/dist/react/chunk-KVAQPCUH.js.map +7 -0
- package/dist/react/{chunk-WEWMB35W.js → chunk-OFGJJKPH.js} +3 -3
- package/dist/react/{chunk-6G3ITAS5.js → chunk-SZD7DKYJ.js} +18 -9
- package/dist/react/chunk-SZD7DKYJ.js.map +7 -0
- package/dist/react/{chunk-MYYBFZD3.js → chunk-U3TB4KRS.js} +45 -6
- package/dist/react/chunk-U3TB4KRS.js.map +7 -0
- package/dist/react/{chunk-UQBT7F4K.js → chunk-V2QTYSBK.js} +2 -2
- package/dist/react/{chunk-2I3GH65Z.js → chunk-XFQECTTF.js} +44 -19
- package/dist/react/chunk-XFQECTTF.js.map +7 -0
- package/dist/react/{chunk-O64N5JPO.js → chunk-YF3TK7SC.js} +2 -2
- package/dist/react/{circleTool-RDOIMKKV.js → circleTool-KICNRQCI.js} +4 -4
- package/dist/react/{codeTool-VBDB2ES6.js → codeTool-NCQ73R6M.js} +4 -4
- package/dist/react/{frameTool-Z5ZDCX6H.js → frameTool-Y6KB67DO.js} +4 -4
- package/dist/react/{freehandTool-AAQCTMVM.js → freehandTool-MMULHCQ7.js} +4 -4
- package/dist/react/{iconTool-5WNDHI5T.js → iconTool-LSW2DYGB.js} +4 -4
- package/dist/react/{imageTool-ECPMT3BL.js → imageTool-2DSR32RX.js} +4 -4
- package/dist/react/index.js +141 -66
- package/dist/react/index.js.map +3 -3
- package/dist/react/{lineTool-XLOOZE3E.js → lineTool-N5I7IGT7.js} +4 -4
- package/dist/react/{rectangleTool-AEYDDJCA.js → rectangleTool-YUT7ZK2E.js} +4 -4
- package/dist/react/{textTool-5IJKTWVQ.js → textTool-IQOYPELP.js} +5 -5
- package/package.json +1 -1
- package/src/core/CopyPaste.js +38 -4
- package/src/core/GraphEngine.js +129 -185
- package/src/core/SceneSerializer.js +30 -0
- package/src/core/Selection.js +12 -11
- package/src/core/UndoRedo.js +47 -3
- package/src/react/components/canvas/MultiSelectActions.jsx +4 -1
- package/src/react/components/sidebars/IconSidebar.jsx +14 -23
- package/src/react/components/sidebars/ImageSidebar.jsx +47 -24
- package/src/react/store/useUIStore.js +71 -14
- package/src/shapes/Frame.js +19 -2
- package/src/shapes/IconShape.js +23 -25
- package/src/shapes/ImageShape.js +79 -4
- package/src/tools/frameTool.js +19 -9
- package/src/tools/iconTool.js +60 -25
- package/src/tools/imageTool.js +77 -13
- package/dist/react/CopyPaste-KJZ34MIP.js.map +0 -7
- package/dist/react/Frame-QLBAVLGW.js +0 -11
- package/dist/react/IconShape-32EYI2MA.js +0 -10
- package/dist/react/ImageShape-MYP2DVVH.js +0 -10
- package/dist/react/Line-FCCF2BOB.js +0 -10
- package/dist/react/SceneSerializer-VY3HY4PF.js.map +0 -7
- package/dist/react/chunk-2I3GH65Z.js.map +0 -7
- package/dist/react/chunk-6G3ITAS5.js.map +0 -7
- package/dist/react/chunk-75G7XSZU.js.map +0 -7
- package/dist/react/chunk-7VBI7S7T.js.map +0 -7
- package/dist/react/chunk-C62SXFBL.js.map +0 -7
- package/dist/react/chunk-MYYBFZD3.js.map +0 -7
- package/dist/react/chunk-R5QXEVZ5.js.map +0 -7
- package/dist/react/chunk-RFHMFWVR.js.map +0 -7
- /package/dist/react/{EventDispatcher-XDRQS7BD.js.map → EventDispatcher-O7HCQQNM.js.map} +0 -0
- /package/dist/react/{Frame-QLBAVLGW.js.map → Frame-RLSMJJSK.js.map} +0 -0
- /package/dist/react/{IconShape-32EYI2MA.js.map → IconShape-7OPXAKLK.js.map} +0 -0
- /package/dist/react/{ImageShape-MYP2DVVH.js.map → ImageShape-T7UEHP4A.js.map} +0 -0
- /package/dist/react/{Line-FCCF2BOB.js.map → Line-WWQFBNX5.js.map} +0 -0
- /package/dist/react/{Selection-U2AR6NQS.js.map → Selection-ZL3G6IAO.js.map} +0 -0
- /package/dist/react/{SketchEngine-ZFYUTKET.js.map → SketchEngine-MYKRKRJG.js.map} +0 -0
- /package/dist/react/{UndoRedo-BZ6W4QTV.js.map → UndoRedo-NL7KLR5B.js.map} +0 -0
- /package/dist/react/{arrowTool-LKFSZKXC.js.map → arrowTool-CNVGM6RX.js.map} +0 -0
- /package/dist/react/{chunk-SBSM3GQD.js.map → chunk-2THKDSWW.js.map} +0 -0
- /package/dist/react/{chunk-JOPQ27YH.js.map → chunk-4BLMNGTR.js.map} +0 -0
- /package/dist/react/{chunk-2V7G2PLX.js.map → chunk-GPIYXREE.js.map} +0 -0
- /package/dist/react/{chunk-73VLPCBC.js.map → chunk-HFQZYCHJ.js.map} +0 -0
- /package/dist/react/{chunk-C72OHQLE.js.map → chunk-ILGAFR56.js.map} +0 -0
- /package/dist/react/{chunk-WEWMB35W.js.map → chunk-OFGJJKPH.js.map} +0 -0
- /package/dist/react/{chunk-UQBT7F4K.js.map → chunk-V2QTYSBK.js.map} +0 -0
- /package/dist/react/{chunk-O64N5JPO.js.map → chunk-YF3TK7SC.js.map} +0 -0
- /package/dist/react/{circleTool-RDOIMKKV.js.map → circleTool-KICNRQCI.js.map} +0 -0
- /package/dist/react/{codeTool-VBDB2ES6.js.map → codeTool-NCQ73R6M.js.map} +0 -0
- /package/dist/react/{frameTool-Z5ZDCX6H.js.map → frameTool-Y6KB67DO.js.map} +0 -0
- /package/dist/react/{freehandTool-AAQCTMVM.js.map → freehandTool-MMULHCQ7.js.map} +0 -0
- /package/dist/react/{iconTool-5WNDHI5T.js.map → iconTool-LSW2DYGB.js.map} +0 -0
- /package/dist/react/{imageTool-ECPMT3BL.js.map → imageTool-2DSR32RX.js.map} +0 -0
- /package/dist/react/{lineTool-XLOOZE3E.js.map → lineTool-N5I7IGT7.js.map} +0 -0
- /package/dist/react/{rectangleTool-AEYDDJCA.js.map → rectangleTool-YUT7ZK2E.js.map} +0 -0
- /package/dist/react/{textTool-5IJKTWVQ.js.map → textTool-IQOYPELP.js.map} +0 -0
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
} from "./chunk-MB7VS6MK.js";
|
|
5
5
|
import {
|
|
6
6
|
ImageShape
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EDSKEM6E.js";
|
|
8
8
|
import {
|
|
9
9
|
IconShape
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-4TAS67SL.js";
|
|
11
11
|
import {
|
|
12
12
|
Frame
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-KVAQPCUH.js";
|
|
14
14
|
import {
|
|
15
15
|
FreehandStroke
|
|
16
16
|
} from "./chunk-PXFPPO3R.js";
|
|
@@ -30,11 +30,11 @@ import {
|
|
|
30
30
|
} from "./chunk-BT2EIJD4.js";
|
|
31
31
|
import {
|
|
32
32
|
Line
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-V2QTYSBK.js";
|
|
34
|
+
import "./chunk-YF3TK7SC.js";
|
|
35
35
|
import {
|
|
36
36
|
pushCreateAction
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-U3TB4KRS.js";
|
|
38
38
|
import {
|
|
39
39
|
TextShape
|
|
40
40
|
} from "./chunk-PGT3TJOW.js";
|
|
@@ -141,7 +141,13 @@ function serializeShape(shape) {
|
|
|
141
141
|
width: shape.width,
|
|
142
142
|
height: shape.height,
|
|
143
143
|
rotation: shape.rotation,
|
|
144
|
-
href: el.getAttribute("href") || el.getAttributeNS("http://www.w3.org/1999/xlink", "href") || ""
|
|
144
|
+
href: el.getAttribute("href") || el.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "",
|
|
145
|
+
storageProvider: el.getAttribute("data-storage-provider") || null,
|
|
146
|
+
storageCloudName: el.getAttribute("data-storage-cloud-name") || null,
|
|
147
|
+
aiGenerated: el.getAttribute("data-ai-generated") === "true",
|
|
148
|
+
aiModel: el.getAttribute("data-ai-model") || null,
|
|
149
|
+
frameType: shape._frameType || null,
|
|
150
|
+
graphData: shape._frameType === "graph" && shape._graphData ? cloneOptions(shape._graphData) : null
|
|
145
151
|
};
|
|
146
152
|
}
|
|
147
153
|
case "icon": {
|
|
@@ -347,9 +353,22 @@ function createShapeFromData(data, offsetX, offsetY) {
|
|
|
347
353
|
imgEl.setAttribute("data-shape-height", data.height);
|
|
348
354
|
imgEl.setAttribute("preserveAspectRatio", "none");
|
|
349
355
|
imgEl.setAttribute("style", "cursor: pointer;");
|
|
356
|
+
if (data.storageProvider) imgEl.setAttribute("data-storage-provider", data.storageProvider);
|
|
357
|
+
if (data.storageCloudName) imgEl.setAttribute("data-storage-cloud-name", data.storageCloudName);
|
|
358
|
+
if (data.aiGenerated) imgEl.setAttribute("data-ai-generated", "true");
|
|
359
|
+
if (data.aiModel) imgEl.setAttribute("data-ai-model", data.aiModel);
|
|
350
360
|
svgEl.appendChild(imgEl);
|
|
351
361
|
const imageShape = new ImageShape(imgEl);
|
|
352
362
|
imageShape.rotation = data.rotation;
|
|
363
|
+
if (data.frameType === "graph" && data.graphData) {
|
|
364
|
+
if (typeof window.__hydrateGraphShape === "function") {
|
|
365
|
+
window.__hydrateGraphShape(imageShape, data.graphData);
|
|
366
|
+
} else {
|
|
367
|
+
imageShape._frameType = "graph";
|
|
368
|
+
imageShape._graphData = cloneOptions(data.graphData);
|
|
369
|
+
imageShape.element.setAttribute("data-graph-shape", "true");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
353
372
|
return imageShape;
|
|
354
373
|
}
|
|
355
374
|
case "icon": {
|
|
@@ -510,22 +529,32 @@ function handlePasteEvent(e) {
|
|
|
510
529
|
const rawDataUrl = ev.target.result;
|
|
511
530
|
const isSvg = (blob.type || "").toLowerCase() === "image/svg+xml";
|
|
512
531
|
let placedDataUrl = rawDataUrl;
|
|
532
|
+
let placedSize = blob.size;
|
|
513
533
|
if (!isSvg) {
|
|
514
534
|
try {
|
|
515
535
|
const compressed = await compressImage(rawDataUrl);
|
|
516
|
-
if (compressed?.dataUrl)
|
|
536
|
+
if (compressed?.dataUrl) {
|
|
537
|
+
placedDataUrl = compressed.dataUrl;
|
|
538
|
+
placedSize = compressed.compressedSize || placedSize;
|
|
539
|
+
}
|
|
517
540
|
} catch (err) {
|
|
518
541
|
console.warn("[CopyPaste] Pre-placement compression failed, using raw:", err);
|
|
519
542
|
}
|
|
520
543
|
}
|
|
521
|
-
|
|
544
|
+
const limit = Number(window.__roomImageLimitBytes) || 2 * 1024 * 1024;
|
|
545
|
+
const personalStorage = window.__personalCloudinary?.connected && window.__personalCloudinary?.useForUploads;
|
|
546
|
+
if (!personalStorage && (window.__roomImageBytesUsed || 0) + placedSize > limit) {
|
|
547
|
+
alert(`Workspace image limit reached (${Math.round(limit / (1024 * 1024))} MB).`);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
placeImageFromDataUrl(placedDataUrl, placedSize);
|
|
522
551
|
};
|
|
523
552
|
reader.readAsDataURL(blob);
|
|
524
553
|
return;
|
|
525
554
|
}
|
|
526
555
|
}
|
|
527
556
|
}
|
|
528
|
-
function placeImageFromDataUrl(dataUrl) {
|
|
557
|
+
function placeImageFromDataUrl(dataUrl, sizeBytes = 0) {
|
|
529
558
|
const svgEl = getSVGElement();
|
|
530
559
|
if (!svgEl || !window.ImageShape) return;
|
|
531
560
|
const img = new Image();
|
|
@@ -548,6 +577,9 @@ function placeImageFromDataUrl(dataUrl) {
|
|
|
548
577
|
imgEl.setAttribute("data-shape-height", displayH);
|
|
549
578
|
imgEl.setAttribute("type", "image");
|
|
550
579
|
imgEl.setAttribute("preserveAspectRatio", "none");
|
|
580
|
+
imgEl.__fileSize = sizeBytes;
|
|
581
|
+
imgEl.setAttribute("data-file-size", String(sizeBytes));
|
|
582
|
+
window.__roomImageBytesUsed = (window.__roomImageBytesUsed || 0) + sizeBytes;
|
|
551
583
|
svgEl.appendChild(imgEl);
|
|
552
584
|
const imageShape = new ImageShape(imgEl);
|
|
553
585
|
if (window.shapes) window.shapes.push(imageShape);
|
|
@@ -571,4 +603,4 @@ export {
|
|
|
571
603
|
initCopyPaste,
|
|
572
604
|
pasteClipboard
|
|
573
605
|
};
|
|
574
|
-
//# sourceMappingURL=CopyPaste-
|
|
606
|
+
//# sourceMappingURL=CopyPaste-5OWPTCQ5.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/core/CopyPaste.js"],
|
|
4
|
+
"sourcesContent": ["/* eslint-disable */\n// Centralized Copy/Paste system for ALL shape types\n// Supports single and multi-selection copy/paste\n// Pastes at mouse pointer position with offset to prevent stacking\n\nimport { pushCreateAction } from './UndoRedo.js';\nimport { Rectangle } from '../shapes/Rectangle.js';\nimport { Circle } from '../shapes/Circle.js';\nimport { Line } from '../shapes/Line.js';\nimport { Arrow } from '../shapes/Arrow.js';\nimport { FreehandStroke } from '../shapes/FreehandStroke.js';\nimport { Frame } from '../shapes/Frame.js';\nimport { TextShape } from '../shapes/TextShape.js';\nimport { CodeShape } from '../shapes/CodeShape.js';\nimport { ImageShape } from '../shapes/ImageShape.js';\nimport { isAllowedImage, isAllowedImageDataUrl } from '../utils/allowedImageTypes.js';\nimport { compressImage } from '../utils/imageCompressor.js';\nimport { IconShape } from '../shapes/IconShape.js';\n\n// Clipboard storage\nlet clipboard = null; // { shapes: [...clonedData], centerX, centerY }\nlet pasteCount = 0; // Increments per paste to offset repeated pastes\n\n// Last known mouse position in SVG coordinates\nlet lastMouseSVG = { x: 0, y: 0 };\n\nfunction getSVGElement() {\n return document.getElementById('freehand-canvas');\n}\n\nfunction getSVGCoordsFromMouse(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return { x: 0, y: 0 };\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n const svgX = viewBox.x + (mouseX / rect.width) * viewBox.width;\n const svgY = viewBox.y + (mouseY / rect.height) * viewBox.height;\n return { x: svgX, y: svgY };\n}\n\nfunction cloneOptions(options) {\n return JSON.parse(JSON.stringify(options));\n}\n\n// ============================================================\n// SERIALIZE: Extract copyable data from a shape\n// ============================================================\nfunction serializeShape(shape) {\n switch (shape.shapeName) {\n case 'rectangle':\n return {\n type: 'rectangle',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'circle':\n return {\n type: 'circle',\n x: shape.x,\n y: shape.y,\n rx: shape.rx,\n ry: shape.ry,\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'line':\n return {\n type: 'line',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint: shape.controlPoint ? { x: shape.controlPoint.x, y: shape.controlPoint.y } : null,\n isCurved: shape.isCurved || false,\n options: cloneOptions(shape.options)\n };\n\n case 'arrow':\n return {\n type: 'arrow',\n startPoint: { x: shape.startPoint.x, y: shape.startPoint.y },\n endPoint: { x: shape.endPoint.x, y: shape.endPoint.y },\n controlPoint1: shape.controlPoint1 ? { x: shape.controlPoint1.x, y: shape.controlPoint1.y } : null,\n controlPoint2: shape.controlPoint2 ? { x: shape.controlPoint2.x, y: shape.controlPoint2.y } : null,\n options: cloneOptions(shape.options),\n arrowOutlineStyle: shape.arrowOutlineStyle,\n arrowHeadStyle: shape.arrowHeadStyle,\n arrowCurved: shape.arrowCurved,\n arrowCurveAmount: shape.arrowCurveAmount\n };\n\n case 'freehandStroke':\n return {\n type: 'freehandStroke',\n points: JSON.parse(JSON.stringify(shape.points)),\n rotation: shape.rotation,\n options: cloneOptions(shape.options)\n };\n\n case 'frame':\n return {\n type: 'frame',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n frameName: shape.frameName,\n options: cloneOptions(shape.options)\n };\n\n case 'text': {\n const group = shape.group;\n const textEl = group.querySelector('text');\n return {\n type: 'text',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'code': {\n const group = shape.group;\n return {\n type: 'code',\n x: shape.x,\n y: shape.y,\n rotation: shape.rotation,\n groupHTML: group.cloneNode(true).outerHTML\n };\n }\n\n case 'image': {\n const el = shape.element;\n return {\n type: 'image',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n href: el.getAttribute('href') || el.getAttributeNS('http://www.w3.org/1999/xlink', 'href') || '',\n storageProvider: el.getAttribute('data-storage-provider') || null,\n storageCloudName: el.getAttribute('data-storage-cloud-name') || null,\n aiGenerated: el.getAttribute('data-ai-generated') === 'true',\n aiModel: el.getAttribute('data-ai-model') || null,\n frameType: shape._frameType || null,\n graphData: shape._frameType === 'graph' && shape._graphData\n ? cloneOptions(shape._graphData)\n : null\n };\n }\n\n case 'icon': {\n const el = shape.element;\n return {\n type: 'icon',\n x: shape.x,\n y: shape.y,\n width: shape.width,\n height: shape.height,\n rotation: shape.rotation,\n elementHTML: el.cloneNode(true).outerHTML,\n viewboxWidth: parseFloat(el.getAttribute('data-viewbox-width')) || 24,\n viewboxHeight: parseFloat(el.getAttribute('data-viewbox-height')) || 24\n };\n }\n\n default:\n console.warn('Copy not supported for shape type:', shape.shapeName);\n return null;\n }\n}\n\n// ============================================================\n// Get bounding center of a serialized shape\n// ============================================================\nfunction getShapeCenter(data) {\n switch (data.type) {\n case 'rectangle':\n case 'frame':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n case 'circle':\n return { x: data.x, y: data.y };\n case 'line':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'arrow':\n return {\n x: (data.startPoint.x + data.endPoint.x) / 2,\n y: (data.startPoint.y + data.endPoint.y) / 2\n };\n case 'freehandStroke': {\n if (!data.points.length) return { x: 0, y: 0 };\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n data.points.forEach(p => {\n if (p[0] < minX) minX = p[0];\n if (p[1] < minY) minY = p[1];\n if (p[0] > maxX) maxX = p[0];\n if (p[1] > maxY) maxY = p[1];\n });\n return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };\n }\n case 'text':\n case 'code':\n return { x: data.x, y: data.y };\n case 'image':\n case 'icon':\n return { x: data.x + data.width / 2, y: data.y + data.height / 2 };\n default:\n return { x: 0, y: 0 };\n }\n}\n\n// ============================================================\n// DESERIALIZE: Create a new shape from copied data at offset\n// ============================================================\nfunction createShapeFromData(data, offsetX, offsetY) {\n const svgEl = getSVGElement();\n if (!svgEl) return null;\n\n switch (data.type) {\n case 'rectangle': {\n const newRect = new Rectangle(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n cloneOptions(data.options)\n );\n newRect.rotation = data.rotation;\n newRect.draw();\n return newRect;\n }\n\n case 'circle': {\n const newCircle = new Circle(\n data.x + offsetX,\n data.y + offsetY,\n data.rx,\n data.ry,\n cloneOptions(data.options)\n );\n newCircle.rotation = data.rotation;\n newCircle.draw();\n return newCircle;\n }\n\n case 'line': {\n const newLine = new Line(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n cloneOptions(data.options)\n );\n if (data.isCurved && data.controlPoint) {\n newLine.isCurved = true;\n newLine.controlPoint = { x: data.controlPoint.x + offsetX, y: data.controlPoint.y + offsetY };\n }\n newLine.draw();\n return newLine;\n }\n\n case 'arrow': {\n const opts = {\n ...cloneOptions(data.options),\n arrowOutlineStyle: data.arrowOutlineStyle,\n arrowHeadStyle: data.arrowHeadStyle,\n arrowCurved: data.arrowCurved,\n arrowCurveAmount: data.arrowCurveAmount,\n controlPoint1: data.controlPoint1 ? { x: data.controlPoint1.x + offsetX, y: data.controlPoint1.y + offsetY } : null,\n controlPoint2: data.controlPoint2 ? { x: data.controlPoint2.x + offsetX, y: data.controlPoint2.y + offsetY } : null\n };\n const newArrow = new Arrow(\n { x: data.startPoint.x + offsetX, y: data.startPoint.y + offsetY },\n { x: data.endPoint.x + offsetX, y: data.endPoint.y + offsetY },\n opts\n );\n return newArrow;\n }\n\n case 'freehandStroke': {\n const offsetPoints = data.points.map(p => [\n p[0] + offsetX,\n p[1] + offsetY,\n p[2] || 0.5\n ]);\n const newStroke = new FreehandStroke(offsetPoints, cloneOptions(data.options));\n newStroke.rotation = data.rotation;\n newStroke.draw();\n return newStroke;\n }\n\n case 'frame': {\n const newFrame = new Frame(\n data.x + offsetX,\n data.y + offsetY,\n data.width,\n data.height,\n { ...cloneOptions(data.options), frameName: data.frameName, rotation: data.rotation }\n );\n newFrame.rotation = data.rotation;\n return newFrame;\n }\n\n case 'text': {\n // Parse the cloned HTML and insert into SVG\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n // Generate new unique ID\n const newID = `text-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const textChild = clonedGroup.querySelector('text');\n if (textChild) textChild.setAttribute('id', `${newID}-text`);\n\n // Update position\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (textChild && rotation) {\n try {\n const bbox = { x: 0, y: 0, width: 100, height: 30 }; // approximate until appended\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, ${bbox.width / 2}, ${bbox.height / 2})`);\n } catch (e) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const textShape = new TextShape(clonedGroup);\n return textShape;\n }\n\n case 'code': {\n const tempDiv = document.createElement('div');\n tempDiv.innerHTML = data.groupHTML;\n const clonedGroup = tempDiv.firstElementChild;\n if (!clonedGroup) return null;\n\n const newID = `code-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedGroup.setAttribute('id', newID);\n const codeChild = clonedGroup.querySelector('text');\n if (codeChild) codeChild.setAttribute('id', `${newID}-code`);\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const rotation = data.rotation || 0;\n if (rotation) {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY}) rotate(${rotation}, 0, 0)`);\n } else {\n clonedGroup.setAttribute('transform', `translate(${newX}, ${newY})`);\n }\n clonedGroup.setAttribute('data-x', newX);\n clonedGroup.setAttribute('data-y', newY);\n\n svgEl.appendChild(clonedGroup);\n\n const codeShape = new CodeShape(clonedGroup);\n return codeShape;\n }\n\n case 'image': {\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n imgEl.setAttribute('x', newX);\n imgEl.setAttribute('y', newY);\n imgEl.setAttribute('width', data.width);\n imgEl.setAttribute('height', data.height);\n imgEl.setAttribute('href', data.href);\n imgEl.setAttribute('data-shape-x', newX);\n imgEl.setAttribute('data-shape-y', newY);\n imgEl.setAttribute('data-shape-width', data.width);\n imgEl.setAttribute('data-shape-height', data.height);\n imgEl.setAttribute('preserveAspectRatio', 'none');\n imgEl.setAttribute('style', 'cursor: pointer;');\n if (data.storageProvider) imgEl.setAttribute('data-storage-provider', data.storageProvider);\n if (data.storageCloudName) imgEl.setAttribute('data-storage-cloud-name', data.storageCloudName);\n if (data.aiGenerated) imgEl.setAttribute('data-ai-generated', 'true');\n if (data.aiModel) imgEl.setAttribute('data-ai-model', data.aiModel);\n\n // ImageShape constructor moves element into a group and appends to svg\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n imageShape.rotation = data.rotation;\n if (data.frameType === 'graph' && data.graphData) {\n if (typeof window.__hydrateGraphShape === 'function') {\n window.__hydrateGraphShape(imageShape, data.graphData);\n } else {\n imageShape._frameType = 'graph';\n imageShape._graphData = cloneOptions(data.graphData);\n imageShape.element.setAttribute('data-graph-shape', 'true');\n }\n }\n return imageShape;\n }\n\n case 'icon': {\n // Parse inside an SVG document. Parsing a copied <g> through an\n // HTML <div> creates it in the HTML namespace, so it can be added\n // to shapes[] but the SVG renderer will not paint it.\n const parser = new DOMParser();\n const parsed = parser.parseFromString(\n `<svg xmlns=\"http://www.w3.org/2000/svg\">${data.elementHTML}</svg>`,\n 'image/svg+xml'\n );\n const parsedGroup = parsed.querySelector('g');\n if (!parsedGroup || parsed.querySelector('parsererror')) return null;\n const clonedEl = svgEl.ownerDocument.importNode(parsedGroup, true);\n\n const newX = data.x + offsetX;\n const newY = data.y + offsetY;\n const newID = `icon-${String(Date.now()).slice(0, 8)}-${Math.floor(Math.random() * 10000)}`;\n clonedEl.setAttribute('id', newID);\n clonedEl.setAttribute('x', newX);\n clonedEl.setAttribute('y', newY);\n clonedEl.setAttribute('data-shape-x', newX);\n clonedEl.setAttribute('data-shape-y', newY);\n clonedEl.setAttribute('data-shape-width', data.width);\n clonedEl.setAttribute('data-shape-height', data.height);\n clonedEl.setAttribute('data-shape-rotation', data.rotation);\n clonedEl.setAttribute('data-viewbox-width', data.viewboxWidth);\n clonedEl.setAttribute('data-viewbox-height', data.viewboxHeight);\n\n // Recalculate transform\n const scale = data.width / Math.max(data.viewboxWidth, data.viewboxHeight);\n const localCenterX = data.width / 2 / scale;\n const localCenterY = data.height / 2 / scale;\n clonedEl.setAttribute('transform', `translate(${newX}, ${newY}) scale(${scale}) rotate(${data.rotation}, ${localCenterX}, ${localCenterY})`);\n\n svgEl.appendChild(clonedEl);\n\n const iconShape = new IconShape(clonedEl);\n return iconShape;\n }\n\n default:\n return null;\n }\n}\n\n// ============================================================\n// COPY: Serialize currently selected shapes\n// ============================================================\nfunction copySelected() {\n const shapesToCopy = [];\n\n // Check multi-selection first\n if (window.multiSelection && window.multiSelection.selectedShapes && window.multiSelection.selectedShapes.size > 0) {\n window.multiSelection.selectedShapes.forEach(shape => {\n const data = serializeShape(shape);\n if (data) shapesToCopy.push(data);\n });\n }\n // Fall back to single currentShape\n else if (typeof currentShape !== 'undefined' && currentShape && currentShape.isSelected) {\n const data = serializeShape(currentShape);\n if (data) shapesToCopy.push(data);\n }\n\n if (shapesToCopy.length === 0) return false;\n\n // Calculate center of all copied shapes\n let totalX = 0, totalY = 0;\n shapesToCopy.forEach(d => {\n const c = getShapeCenter(d);\n totalX += c.x;\n totalY += c.y;\n });\n const centerX = totalX / shapesToCopy.length;\n const centerY = totalY / shapesToCopy.length;\n\n clipboard = {\n shapes: shapesToCopy,\n centerX,\n centerY\n };\n pasteCount = 0;\n\n return true;\n}\n\n// ============================================================\n// PASTE: Create new shapes from clipboard at mouse position\n// ============================================================\nfunction pasteClipboard() {\n if (!clipboard || clipboard.shapes.length === 0) return false;\n\n pasteCount++;\n const baseOffset = 20 * pasteCount;\n\n // Calculate paste position: center the group on the mouse pointer\n const targetX = lastMouseSVG.x;\n const targetY = lastMouseSVG.y;\n const groupOffsetX = targetX - clipboard.centerX + baseOffset;\n const groupOffsetY = targetY - clipboard.centerY + baseOffset;\n\n // Deselect all currently selected shapes\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.forEach(s => {\n if (s.isSelected && typeof s.removeSelection === 'function') {\n s.removeSelection();\n s.isSelected = false;\n }\n });\n }\n if (window.multiSelection) {\n window.multiSelection.clearSelection();\n }\n if (typeof currentShape !== 'undefined') {\n currentShape = null;\n }\n if (typeof disableAllSideBars === 'function') {\n disableAllSideBars();\n }\n\n const pastedShapes = [];\n\n clipboard.shapes.forEach(data => {\n const newShape = createShapeFromData(data, groupOffsetX, groupOffsetY);\n if (newShape) {\n if (typeof shapes !== 'undefined' && Array.isArray(shapes)) {\n shapes.push(newShape);\n }\n pushCreateAction(newShape);\n pastedShapes.push(newShape);\n }\n });\n\n // Select the pasted shapes\n if (pastedShapes.length === 1) {\n const s = pastedShapes[0];\n s.isSelected = true;\n currentShape = s;\n if (typeof s.addAnchors === 'function') {\n s.addAnchors();\n } else if (typeof s.selectShape === 'function') {\n s.selectShape();\n }\n } else if (pastedShapes.length > 1 && window.multiSelection) {\n pastedShapes.forEach(s => {\n window.multiSelection.addShape(s);\n });\n window.multiSelection.updateControls();\n }\n\n return true;\n}\n\n// ============================================================\n// KEYBOARD HANDLER: Ctrl+C / Ctrl+V\n// ============================================================\nfunction handleCopyPasteKeydown(e) {\n // Don't intercept if user is typing in an input/textarea/contenteditable\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') {\n if (copySelected()) {\n e.preventDefault();\n }\n }\n\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') {\n if (pasteClipboard()) {\n e.preventDefault();\n }\n }\n}\n\n// Track mouse position for paste placement\nfunction handleMouseMoveForPaste(e) {\n const svgEl = getSVGElement();\n if (!svgEl) return;\n const viewBox = svgEl.viewBox.baseVal;\n const rect = svgEl.getBoundingClientRect();\n const mouseX = e.clientX - rect.left;\n const mouseY = e.clientY - rect.top;\n lastMouseSVG.x = viewBox.x + (mouseX / rect.width) * viewBox.width;\n lastMouseSVG.y = viewBox.y + (mouseY / rect.height) * viewBox.height;\n}\n\n// ============================================================\n// PASTE IMAGE FROM CLIPBOARD (external images, screenshots)\n// ============================================================\nfunction handlePasteEvent(e) {\n // Don't intercept if user is typing\n const tag = (e.target.tagName || '').toLowerCase();\n if (tag === 'input' || tag === 'textarea' || e.target.isContentEditable) return;\n\n const items = e.clipboardData?.items;\n if (!items) return;\n\n for (const item of items) {\n if (item.type.startsWith('image/')) {\n e.preventDefault();\n const blob = item.getAsFile();\n if (!blob) return;\n\n // Validate against the canonical allowlist \u2014 clipboard sources\n // can include animated GIFs / HEIC / TIFF / arbitrary mime types.\n if (!isAllowedImage(blob)) {\n console.warn('[CopyPaste] Rejected pasted image type:', blob.type);\n return;\n }\n\n const reader = new FileReader();\n reader.onload = async (ev) => {\n const rawDataUrl = ev.target.result;\n const isSvg = (blob.type || '').toLowerCase() === 'image/svg+xml';\n let placedDataUrl = rawDataUrl;\n let placedSize = blob.size;\n if (!isSvg) {\n try {\n const compressed = await compressImage(rawDataUrl);\n if (compressed?.dataUrl) {\n placedDataUrl = compressed.dataUrl;\n placedSize = compressed.compressedSize || placedSize;\n }\n } catch (err) {\n console.warn('[CopyPaste] Pre-placement compression failed, using raw:', err);\n }\n }\n const limit = Number(window.__roomImageLimitBytes) || 2 * 1024 * 1024;\n const personalStorage = window.__personalCloudinary?.connected && window.__personalCloudinary?.useForUploads;\n if (!personalStorage && (window.__roomImageBytesUsed || 0) + placedSize > limit) {\n alert(`Workspace image limit reached (${Math.round(limit / (1024 * 1024))} MB).`);\n return;\n }\n placeImageFromDataUrl(placedDataUrl, placedSize);\n };\n reader.readAsDataURL(blob);\n return; // only handle first image\n }\n }\n}\n\nfunction placeImageFromDataUrl(dataUrl, sizeBytes = 0) {\n const svgEl = getSVGElement();\n if (!svgEl || !window.ImageShape) return;\n\n const img = new Image();\n img.onload = () => {\n const aspectRatio = img.height / img.width;\n const displayW = Math.min(400, img.width);\n const displayH = displayW * aspectRatio;\n\n // Place at center of current viewport\n const vb = svgEl.viewBox.baseVal;\n const cx = vb.x + vb.width / 2;\n const cy = vb.y + vb.height / 2;\n\n const imgEl = document.createElementNS('http://www.w3.org/2000/svg', 'image');\n imgEl.setAttribute('href', dataUrl);\n imgEl.setAttribute('x', cx - displayW / 2);\n imgEl.setAttribute('y', cy - displayH / 2);\n imgEl.setAttribute('width', displayW);\n imgEl.setAttribute('height', displayH);\n imgEl.setAttribute('data-shape-x', cx - displayW / 2);\n imgEl.setAttribute('data-shape-y', cy - displayH / 2);\n imgEl.setAttribute('data-shape-width', displayW);\n imgEl.setAttribute('data-shape-height', displayH);\n imgEl.setAttribute('type', 'image');\n imgEl.setAttribute('preserveAspectRatio', 'none');\n imgEl.__fileSize = sizeBytes;\n imgEl.setAttribute('data-file-size', String(sizeBytes));\n window.__roomImageBytesUsed = (window.__roomImageBytesUsed || 0) + sizeBytes;\n\n svgEl.appendChild(imgEl);\n const imageShape = new ImageShape(imgEl);\n if (window.shapes) window.shapes.push(imageShape);\n if (window.pushCreateAction) window.pushCreateAction(imageShape);\n\n // Compress and upload to Cloudinary\n if (window.uploadImageToCloudinary) {\n window.uploadImageToCloudinary(imageShape);\n }\n\n console.log('[CopyPaste] Pasted image from clipboard');\n };\n img.src = dataUrl;\n}\n\n// ============================================================\n// INIT: Set up event listeners\n// ============================================================\nfunction initCopyPaste() {\n document.addEventListener('keydown', handleCopyPasteKeydown);\n document.addEventListener('pointermove', handleMouseMoveForPaste);\n document.addEventListener('paste', handlePasteEvent);\n\n // Expose for context menu\n window.copySelected = copySelected;\n window.pasteClipboard = pasteClipboard;\n}\n\nexport { initCopyPaste, copySelected, pasteClipboard };\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -4,32 +4,32 @@ import {
|
|
|
4
4
|
handleTextMouseDown,
|
|
5
5
|
handleTextMouseMove,
|
|
6
6
|
handleTextMouseUp
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2THKDSWW.js";
|
|
8
8
|
import {
|
|
9
9
|
handleCodeMouseDown,
|
|
10
10
|
handleCodeMouseMove,
|
|
11
11
|
handleCodeMouseUp
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HFQZYCHJ.js";
|
|
13
13
|
import {
|
|
14
14
|
handleMouseDownImage,
|
|
15
15
|
handleMouseMoveImage,
|
|
16
16
|
handleMouseUpImage
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GC3KTQDA.js";
|
|
18
18
|
import {
|
|
19
19
|
handleMouseDownIcon,
|
|
20
20
|
handleMouseMoveIcon,
|
|
21
21
|
handleMouseUpIcon
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-XFQECTTF.js";
|
|
23
23
|
import {
|
|
24
24
|
handleMouseDown as handleMouseDown4,
|
|
25
25
|
handleMouseMove as handleMouseMove4,
|
|
26
26
|
handleMouseUp as handleMouseUp4
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-SZD7DKYJ.js";
|
|
28
28
|
import {
|
|
29
29
|
handleMouseDown as handleMouseDown5,
|
|
30
30
|
handleMouseMove as handleMouseMove5,
|
|
31
31
|
handleMouseUp as handleMouseUp5
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-GPIYXREE.js";
|
|
33
33
|
import {
|
|
34
34
|
handleMultiSelectionMouseDown,
|
|
35
35
|
handleMultiSelectionMouseMove,
|
|
@@ -37,30 +37,30 @@ import {
|
|
|
37
37
|
isMultiSelecting,
|
|
38
38
|
multiSelection,
|
|
39
39
|
removeMultiSelectionRect
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-AH4PWNEB.js";
|
|
41
41
|
import {
|
|
42
42
|
handleMouseDownRect,
|
|
43
43
|
handleMouseMoveRect,
|
|
44
44
|
handleMouseUpRect
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-4BLMNGTR.js";
|
|
46
46
|
import {
|
|
47
47
|
handleMouseDown as handleMouseDown2,
|
|
48
48
|
handleMouseMove as handleMouseMove2,
|
|
49
49
|
handleMouseUp as handleMouseUp2
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-OFGJJKPH.js";
|
|
51
51
|
import {
|
|
52
52
|
handleMouseDown as handleMouseDown3,
|
|
53
53
|
handleMouseMove as handleMouseMove3,
|
|
54
54
|
handleMouseUp as handleMouseUp3
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-ILGAFR56.js";
|
|
56
56
|
import "./chunk-DNAG7ML6.js";
|
|
57
57
|
import "./chunk-PAKA6HUX.js";
|
|
58
58
|
import {
|
|
59
59
|
handleMouseDown,
|
|
60
60
|
handleMouseMove,
|
|
61
61
|
handleMouseUp
|
|
62
|
-
} from "./chunk-
|
|
63
|
-
import "./chunk-
|
|
62
|
+
} from "./chunk-YF3TK7SC.js";
|
|
63
|
+
import "./chunk-U3TB4KRS.js";
|
|
64
64
|
|
|
65
65
|
// src/core/EventDispatcher.js
|
|
66
66
|
var EDGE_THRESHOLD = 40;
|
|
@@ -461,4 +461,4 @@ export {
|
|
|
461
461
|
handleMainMouseUp,
|
|
462
462
|
initEventDispatcher
|
|
463
463
|
};
|
|
464
|
-
//# sourceMappingURL=EventDispatcher-
|
|
464
|
+
//# sourceMappingURL=EventDispatcher-O7HCQQNM.js.map
|
|
@@ -230,171 +230,128 @@ function escapeXml(str) {
|
|
|
230
230
|
var NS = "http://www.w3.org/2000/svg";
|
|
231
231
|
var GRAPH_WIDTH = 600;
|
|
232
232
|
var GRAPH_HEIGHT = 420;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
233
|
+
var MAX_PLACED_SCREEN_WIDTH = 480;
|
|
234
|
+
var MAX_VIEWPORT_WIDTH_RATIO = 0.68;
|
|
235
|
+
var MAX_VIEWPORT_HEIGHT_RATIO = 0.58;
|
|
236
|
+
function cloneGraphData(equations, settings) {
|
|
237
|
+
return {
|
|
238
|
+
equations: (equations || []).map((equation) => ({
|
|
239
|
+
expression: equation.expression,
|
|
240
|
+
color: equation.color
|
|
241
|
+
})),
|
|
242
|
+
settings: { ...settings || {} }
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function graphSvgDataUrl(svgMarkup) {
|
|
246
|
+
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svgMarkup)}`;
|
|
247
|
+
}
|
|
248
|
+
function refreshGraphImage(shape) {
|
|
249
|
+
if (!shape?._graphData || !shape.element) return false;
|
|
250
|
+
const svgMarkup = renderGraphSVG(shape._graphData.equations, {
|
|
251
|
+
...shape._graphData.settings,
|
|
241
252
|
width: GRAPH_WIDTH,
|
|
242
253
|
height: GRAPH_HEIGHT
|
|
243
254
|
});
|
|
244
255
|
if (!svgMarkup) return false;
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
256
|
+
const href = graphSvgDataUrl(svgMarkup);
|
|
257
|
+
shape.element.setAttribute("href", href);
|
|
258
|
+
shape.element.setAttribute("data-href", href);
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
function hydrateGraphShape(shape, graphData) {
|
|
262
|
+
if (!shape?.element || !graphData) return shape;
|
|
263
|
+
shape._frameType = "graph";
|
|
264
|
+
shape._graphData = cloneGraphData(graphData.equations, graphData.settings);
|
|
265
|
+
shape.uploadStatus = "done";
|
|
266
|
+
shape.element.setAttribute("data-graph-shape", "true");
|
|
267
|
+
shape.element.setAttribute("preserveAspectRatio", "none");
|
|
268
|
+
shape.element.style.cursor = "move";
|
|
269
|
+
shape._refreshGraphImage = () => refreshGraphImage(shape);
|
|
270
|
+
shape.adaptToBackground = () => refreshGraphImage(shape);
|
|
271
|
+
return shape;
|
|
272
|
+
}
|
|
273
|
+
function selectOnlyGraph(shape) {
|
|
274
|
+
if (!shape) return;
|
|
275
|
+
if (window.multiSelection?.selectedShapes?.size) {
|
|
276
|
+
window.multiSelection.clearSelection();
|
|
277
|
+
}
|
|
278
|
+
if (window.currentShape && window.currentShape !== shape && typeof window.currentShape.removeSelection === "function") {
|
|
279
|
+
window.currentShape.removeSelection();
|
|
280
|
+
}
|
|
281
|
+
window.__sketchStoreApi?.setActiveTool?.("select");
|
|
282
|
+
window.currentShape = shape;
|
|
283
|
+
shape.selectShape?.();
|
|
284
|
+
}
|
|
285
|
+
function placedGraphSize(viewBox) {
|
|
286
|
+
const zoom = Math.max(1e-3, Number(window.currentZoom) || 1);
|
|
287
|
+
const byScreen = MAX_PLACED_SCREEN_WIDTH / zoom;
|
|
288
|
+
const byViewportWidth = viewBox.width * MAX_VIEWPORT_WIDTH_RATIO;
|
|
289
|
+
const byViewportHeight = viewBox.height * MAX_VIEWPORT_HEIGHT_RATIO * (GRAPH_WIDTH / GRAPH_HEIGHT);
|
|
290
|
+
const width = Math.max(80 / zoom, Math.min(GRAPH_WIDTH, byScreen, byViewportWidth, byViewportHeight));
|
|
291
|
+
return { width, height: width * (GRAPH_HEIGHT / GRAPH_WIDTH) };
|
|
292
|
+
}
|
|
293
|
+
function renderGraphOnCanvas(equations, settings, existingShape = null) {
|
|
294
|
+
const validEquations = (equations || []).filter((equation) => equation?.expression?.trim());
|
|
295
|
+
if (validEquations.length === 0) return false;
|
|
296
|
+
if (!window.svg || !window.ImageShape) {
|
|
297
|
+
console.error("[GraphEngine] Engine not initialized");
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const graphData = cloneGraphData(validEquations, settings);
|
|
301
|
+
if (existingShape?._frameType === "graph" && existingShape.element) {
|
|
302
|
+
hydrateGraphShape(existingShape, graphData);
|
|
303
|
+
if (!refreshGraphImage(existingShape)) return false;
|
|
304
|
+
selectOnlyGraph(existingShape);
|
|
305
|
+
window.__adaptCanvasContrast?.(
|
|
306
|
+
window.getComputedStyle(window.svg).backgroundColor || "#15111f"
|
|
307
|
+
);
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
const viewBox = window.currentViewBox || {
|
|
311
|
+
x: 0,
|
|
312
|
+
y: 0,
|
|
313
|
+
width: window.innerWidth,
|
|
314
|
+
height: window.innerHeight
|
|
315
|
+
};
|
|
316
|
+
const size = placedGraphSize(viewBox);
|
|
317
|
+
const x = viewBox.x + (viewBox.width - size.width) / 2;
|
|
318
|
+
const y = viewBox.y + (viewBox.height - size.height) / 2;
|
|
254
319
|
try {
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
320
|
+
const image = document.createElementNS(NS, "image");
|
|
321
|
+
image.setAttribute("x", x);
|
|
322
|
+
image.setAttribute("y", y);
|
|
323
|
+
image.setAttribute("width", size.width);
|
|
324
|
+
image.setAttribute("height", size.height);
|
|
325
|
+
image.setAttribute("data-shape-x", x);
|
|
326
|
+
image.setAttribute("data-shape-y", y);
|
|
327
|
+
image.setAttribute("data-shape-width", size.width);
|
|
328
|
+
image.setAttribute("data-shape-height", size.height);
|
|
329
|
+
const graphShape = hydrateGraphShape(new window.ImageShape(image), graphData);
|
|
330
|
+
if (!refreshGraphImage(graphShape)) {
|
|
331
|
+
graphShape.group?.remove();
|
|
332
|
+
return false;
|
|
266
333
|
}
|
|
267
|
-
while (svgEl.childNodes.length > 0) {
|
|
268
|
-
const child = svgEl.childNodes[0];
|
|
269
|
-
if (child.nodeName === "defs") {
|
|
270
|
-
svgEl.removeChild(child);
|
|
271
|
-
continue;
|
|
272
|
-
}
|
|
273
|
-
graphGroup.appendChild(child);
|
|
274
|
-
}
|
|
275
|
-
window.svg.appendChild(graphGroup);
|
|
276
|
-
const graphShape = {
|
|
277
|
-
shapeName: "graph",
|
|
278
|
-
// first-class shapeName
|
|
279
|
-
shapeID: `graph-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e4)}`,
|
|
280
|
-
group: graphGroup,
|
|
281
|
-
element: graphGroup,
|
|
282
|
-
x: frameX + 20,
|
|
283
|
-
y: frameY + 20,
|
|
284
|
-
width: GRAPH_WIDTH,
|
|
285
|
-
height: GRAPH_HEIGHT,
|
|
286
|
-
rotation: 0,
|
|
287
|
-
isSelected: false,
|
|
288
|
-
_selectionRect: null,
|
|
289
|
-
_graphData: {
|
|
290
|
-
equations: equations.map((eq) => ({ expression: eq.expression, color: eq.color })),
|
|
291
|
-
settings: { ...settings }
|
|
292
|
-
},
|
|
293
|
-
// ── Shape API the engine relies on ────────────────────────
|
|
294
|
-
contains(px, py) {
|
|
295
|
-
return px >= this.x && px <= this.x + this.width && py >= this.y && py <= this.y + this.height;
|
|
296
|
-
},
|
|
297
|
-
move(dx, dy) {
|
|
298
|
-
this.x += dx;
|
|
299
|
-
this.y += dy;
|
|
300
|
-
this.group.setAttribute("transform", `translate(${this.x}, ${this.y})`);
|
|
301
|
-
this._updateSelectionRect();
|
|
302
|
-
},
|
|
303
|
-
selectShape() {
|
|
304
|
-
this.isSelected = true;
|
|
305
|
-
if (this._selectionRect) return;
|
|
306
|
-
const r = document.createElementNS(NS, "rect");
|
|
307
|
-
r.setAttribute("fill", "none");
|
|
308
|
-
r.setAttribute("stroke", "#9b7bf7");
|
|
309
|
-
r.setAttribute("stroke-width", "1.5");
|
|
310
|
-
r.setAttribute("stroke-dasharray", "4 3");
|
|
311
|
-
r.setAttribute("pointer-events", "none");
|
|
312
|
-
window.svg.appendChild(r);
|
|
313
|
-
this._selectionRect = r;
|
|
314
|
-
this._updateSelectionRect();
|
|
315
|
-
},
|
|
316
|
-
removeSelection() {
|
|
317
|
-
this.isSelected = false;
|
|
318
|
-
if (this._selectionRect && this._selectionRect.parentNode) {
|
|
319
|
-
this._selectionRect.parentNode.removeChild(this._selectionRect);
|
|
320
|
-
}
|
|
321
|
-
this._selectionRect = null;
|
|
322
|
-
},
|
|
323
|
-
_updateSelectionRect() {
|
|
324
|
-
if (!this._selectionRect) return;
|
|
325
|
-
const pad = 4;
|
|
326
|
-
this._selectionRect.setAttribute("x", this.x - pad);
|
|
327
|
-
this._selectionRect.setAttribute("y", this.y - pad);
|
|
328
|
-
this._selectionRect.setAttribute("width", this.width + pad * 2);
|
|
329
|
-
this._selectionRect.setAttribute("height", this.height + pad * 2);
|
|
330
|
-
},
|
|
331
|
-
updateAttachedArrows() {
|
|
332
|
-
if (typeof window.updateAttachedArrows === "function") {
|
|
333
|
-
window.updateAttachedArrows(this);
|
|
334
|
-
}
|
|
335
|
-
},
|
|
336
|
-
adaptToBackground(background, foreground, muted) {
|
|
337
|
-
const ensureContrast = window.__ensureCanvasContrast || ((color) => color);
|
|
338
|
-
this.group.querySelectorAll("rect").forEach((rect) => {
|
|
339
|
-
const fill = rect.getAttribute("fill");
|
|
340
|
-
const stroke = rect.getAttribute("stroke");
|
|
341
|
-
if (fill && fill !== "none") rect.setAttribute("fill", background);
|
|
342
|
-
if (stroke && stroke !== "none") {
|
|
343
|
-
rect.setAttribute("stroke", muted);
|
|
344
|
-
rect.setAttribute("stroke-opacity", "0.45");
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
this.group.querySelectorAll("line").forEach((line) => {
|
|
348
|
-
const width = Number.parseFloat(line.getAttribute("stroke-width") || "1");
|
|
349
|
-
line.setAttribute("stroke", foreground);
|
|
350
|
-
line.setAttribute("stroke-opacity", width <= 0.5 ? "0.18" : "0.5");
|
|
351
|
-
});
|
|
352
|
-
this.group.querySelectorAll("path[stroke]").forEach((path) => {
|
|
353
|
-
const original = path.dataset.graphColor || path.getAttribute("stroke");
|
|
354
|
-
if (!original || original === "none") return;
|
|
355
|
-
path.dataset.graphColor = original;
|
|
356
|
-
path.setAttribute("stroke", ensureContrast(original, background, 3));
|
|
357
|
-
});
|
|
358
|
-
this.group.querySelectorAll("circle[fill]").forEach((circle) => {
|
|
359
|
-
const original = circle.dataset.graphColor || circle.getAttribute("fill");
|
|
360
|
-
if (!original || original === "none") return;
|
|
361
|
-
circle.dataset.graphColor = original;
|
|
362
|
-
circle.setAttribute("fill", ensureContrast(original, background, 3));
|
|
363
|
-
});
|
|
364
|
-
this.group.querySelectorAll("text").forEach((text) => {
|
|
365
|
-
const original = text.dataset.graphColor || text.getAttribute("fill");
|
|
366
|
-
if (original) text.dataset.graphColor = original;
|
|
367
|
-
const isAxisLabel = !original || ["#8b949e", "#62627a"].includes(original.toLowerCase());
|
|
368
|
-
text.setAttribute("fill", isAxisLabel ? muted : ensureContrast(original, background, 4.5));
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
};
|
|
372
334
|
window.shapes.push(graphShape);
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
graphShape.selectShape();
|
|
335
|
+
window.pushCreateAction?.(graphShape);
|
|
336
|
+
selectOnlyGraph(graphShape);
|
|
376
337
|
window.__adaptCanvasContrast?.(
|
|
377
|
-
window.getComputedStyle(window.svg).backgroundColor || "#
|
|
338
|
+
window.getComputedStyle(window.svg).backgroundColor || "#15111f"
|
|
378
339
|
);
|
|
379
|
-
|
|
380
|
-
|
|
340
|
+
return true;
|
|
341
|
+
} catch (error) {
|
|
342
|
+
console.error("[GraphEngine] SVG insertion failed:", error);
|
|
381
343
|
return false;
|
|
382
344
|
}
|
|
383
|
-
return true;
|
|
384
345
|
}
|
|
385
346
|
function initGraphEngine() {
|
|
386
|
-
window.__graphPreview = (equations, settings) =>
|
|
387
|
-
return renderGraphPreviewSVG(equations, settings);
|
|
388
|
-
};
|
|
347
|
+
window.__graphPreview = (equations, settings) => renderGraphPreviewSVG(equations, settings);
|
|
389
348
|
window.__graphRenderer = renderGraphOnCanvas;
|
|
390
|
-
window.
|
|
391
|
-
|
|
392
|
-
return fn ? true : false;
|
|
393
|
-
};
|
|
349
|
+
window.__hydrateGraphShape = hydrateGraphShape;
|
|
350
|
+
window.__graphParser = (expression) => Boolean(parseExpression(expression));
|
|
394
351
|
window.__graphValidate = isValidExpression;
|
|
395
352
|
window.__graphColors = GRAPH_COLORS;
|
|
396
353
|
}
|
|
397
354
|
export {
|
|
398
355
|
initGraphEngine
|
|
399
356
|
};
|
|
400
|
-
//# sourceMappingURL=GraphEngine-
|
|
357
|
+
//# sourceMappingURL=GraphEngine-MM6ALA2N.js.map
|