@elixpo/lixsketch 4.5.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/LICENSE +21 -0
- package/README.md +169 -0
- package/fonts/fonts.css +29 -0
- package/fonts/lixCode.ttf +0 -0
- package/fonts/lixDefault.ttf +0 -0
- package/fonts/lixDocs.ttf +0 -0
- package/fonts/lixFancy.ttf +0 -0
- package/fonts/lixFont.woff2 +0 -0
- package/package.json +49 -0
- package/src/SketchEngine.js +473 -0
- package/src/core/AIRenderer.js +1390 -0
- package/src/core/CopyPaste.js +655 -0
- package/src/core/EraserTrail.js +234 -0
- package/src/core/EventDispatcher.js +371 -0
- package/src/core/GraphEngine.js +150 -0
- package/src/core/GraphMathParser.js +231 -0
- package/src/core/GraphRenderer.js +255 -0
- package/src/core/LayerOrder.js +91 -0
- package/src/core/LixScriptParser.js +1299 -0
- package/src/core/MermaidFlowchartRenderer.js +475 -0
- package/src/core/MermaidSequenceParser.js +197 -0
- package/src/core/MermaidSequenceRenderer.js +479 -0
- package/src/core/ResizeCode.js +175 -0
- package/src/core/ResizeShapes.js +318 -0
- package/src/core/SceneSerializer.js +778 -0
- package/src/core/Selection.js +1861 -0
- package/src/core/SnapGuides.js +273 -0
- package/src/core/UndoRedo.js +1358 -0
- package/src/core/ZoomPan.js +258 -0
- package/src/core/ai-system-prompt.js +663 -0
- package/src/index.js +69 -0
- package/src/shapes/Arrow.js +1979 -0
- package/src/shapes/Circle.js +751 -0
- package/src/shapes/CodeShape.js +244 -0
- package/src/shapes/Frame.js +1460 -0
- package/src/shapes/FreehandStroke.js +724 -0
- package/src/shapes/IconShape.js +265 -0
- package/src/shapes/ImageShape.js +270 -0
- package/src/shapes/Line.js +738 -0
- package/src/shapes/Rectangle.js +794 -0
- package/src/shapes/TextShape.js +225 -0
- package/src/tools/arrowTool.js +581 -0
- package/src/tools/circleTool.js +619 -0
- package/src/tools/codeTool.js +2103 -0
- package/src/tools/eraserTool.js +131 -0
- package/src/tools/frameTool.js +241 -0
- package/src/tools/freehandTool.js +620 -0
- package/src/tools/iconTool.js +1344 -0
- package/src/tools/imageTool.js +1323 -0
- package/src/tools/laserTool.js +317 -0
- package/src/tools/lineTool.js +502 -0
- package/src/tools/rectangleTool.js +544 -0
- package/src/tools/textTool.js +1823 -0
- package/src/utils/imageCompressor.js +107 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// Zoom and Pan controls - combined from zoomFunction.js + panCanvas.js
|
|
3
|
+
// Depends on globals: svg, freehandCanvas, currentZoom, currentViewBox, isPanningToolActive, isPanning
|
|
4
|
+
// Depends on globals: minScale, maxScale, zoomInBtn, zoomOutBtn, zoomPercentSpan, panStart, startCanvasX, startCanvasY
|
|
5
|
+
|
|
6
|
+
// === Zoom Functions ===
|
|
7
|
+
let currentY = 0;
|
|
8
|
+
const scrollRate = 50;
|
|
9
|
+
|
|
10
|
+
function updateZoomDisplay() {
|
|
11
|
+
zoomPercentSpan.innerText = Math.round(currentZoom * 100) + "%";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function updateViewBox(anchorX = null, anchorY = null) {
|
|
15
|
+
const width = window.innerWidth;
|
|
16
|
+
const height = window.innerHeight;
|
|
17
|
+
const scaledWidth = width / currentZoom;
|
|
18
|
+
const scaledHeight = height / currentZoom;
|
|
19
|
+
|
|
20
|
+
let centerX, centerY;
|
|
21
|
+
|
|
22
|
+
if (anchorX === null || anchorY === null) {
|
|
23
|
+
centerX = currentViewBox.x + (currentViewBox.width / 2);
|
|
24
|
+
centerY = currentViewBox.y + (currentViewBox.height / 2);
|
|
25
|
+
} else {
|
|
26
|
+
|
|
27
|
+
centerX = anchorX;
|
|
28
|
+
centerY = anchorY;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const viewBoxX = centerX - (scaledWidth / 2);
|
|
32
|
+
const viewBoxY = centerY - (scaledHeight / 2);
|
|
33
|
+
|
|
34
|
+
freehandCanvas.setAttribute(
|
|
35
|
+
"viewBox",
|
|
36
|
+
`${viewBoxX} ${viewBoxY} ${scaledWidth} ${scaledHeight}`
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
currentViewBox.x = viewBoxX;
|
|
40
|
+
currentViewBox.y = viewBoxY;
|
|
41
|
+
currentViewBox.width = scaledWidth;
|
|
42
|
+
currentViewBox.height = scaledHeight;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
zoomInBtn.addEventListener("click", function() {
|
|
46
|
+
currentZoom *= 1.1;
|
|
47
|
+
if (currentZoom > maxScale) currentZoom = maxScale;
|
|
48
|
+
updateViewBox();
|
|
49
|
+
updateZoomDisplay();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
zoomOutBtn.addEventListener("click", function() {
|
|
53
|
+
currentZoom /= 1.1;
|
|
54
|
+
if (currentZoom < minScale) currentZoom = minScale;
|
|
55
|
+
updateViewBox();
|
|
56
|
+
updateZoomDisplay();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Exposed for React Footer buttons — zoom from center of canvas
|
|
60
|
+
window.zoomFromCenter = function(direction) {
|
|
61
|
+
if (direction > 0) {
|
|
62
|
+
currentZoom *= 1.1;
|
|
63
|
+
if (currentZoom > maxScale) currentZoom = maxScale;
|
|
64
|
+
} else {
|
|
65
|
+
currentZoom /= 1.1;
|
|
66
|
+
if (currentZoom < minScale) currentZoom = minScale;
|
|
67
|
+
}
|
|
68
|
+
updateViewBox(); // null anchors = zoom from center
|
|
69
|
+
updateZoomDisplay();
|
|
70
|
+
// Sync React zoom state
|
|
71
|
+
if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {
|
|
72
|
+
window.__sketchStoreApi.setZoom(currentZoom);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
window.zoomReset = function() {
|
|
77
|
+
currentZoom = 1;
|
|
78
|
+
currentViewBox.x = 0;
|
|
79
|
+
currentViewBox.y = 0;
|
|
80
|
+
currentViewBox.width = window.innerWidth;
|
|
81
|
+
currentViewBox.height = window.innerHeight;
|
|
82
|
+
freehandCanvas.setAttribute(
|
|
83
|
+
"viewBox",
|
|
84
|
+
`0 0 ${window.innerWidth} ${window.innerHeight}`
|
|
85
|
+
);
|
|
86
|
+
updateZoomDisplay();
|
|
87
|
+
if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {
|
|
88
|
+
window.__sketchStoreApi.setZoom(1);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
freehandCanvas.addEventListener("wheel", function(e) {
|
|
93
|
+
if (!e.ctrlKey) return;
|
|
94
|
+
e.preventDefault();
|
|
95
|
+
|
|
96
|
+
// Determine the zoom delta
|
|
97
|
+
const delta = e.deltaY > 0 ? -0.1 : 0.1;
|
|
98
|
+
let newZoom = currentZoom + delta;
|
|
99
|
+
if (newZoom < minScale) newZoom = minScale;
|
|
100
|
+
if (newZoom > maxScale) newZoom = maxScale;
|
|
101
|
+
|
|
102
|
+
// Get canvas bounding rect (in case canvas doesn't fill the window exactly)
|
|
103
|
+
const rect = freehandCanvas.getBoundingClientRect();
|
|
104
|
+
|
|
105
|
+
// Calculate mouse position relative to the canvas in pixels
|
|
106
|
+
const mouseX = e.clientX - rect.left;
|
|
107
|
+
const mouseY = e.clientY - rect.top;
|
|
108
|
+
|
|
109
|
+
// Determine what fraction of the canvas the mouse is at
|
|
110
|
+
const mouseFracX = mouseX / rect.width;
|
|
111
|
+
const mouseFracY = mouseY / rect.height;
|
|
112
|
+
|
|
113
|
+
// Compute the current viewBox coordinate under the mouse.
|
|
114
|
+
// currentViewBox.width and .height represent the current viewBox dimensions.
|
|
115
|
+
const anchorViewBoxX = currentViewBox.x + mouseFracX * currentViewBox.width;
|
|
116
|
+
const anchorViewBoxY = currentViewBox.y + mouseFracY * currentViewBox.height;
|
|
117
|
+
|
|
118
|
+
// Now compute the new viewBox dimensions based on the new zoom level.
|
|
119
|
+
// We assume the canvas pixel size stays the same.
|
|
120
|
+
const newViewBoxWidth = window.innerWidth / newZoom;
|
|
121
|
+
const newViewBoxHeight = window.innerHeight / newZoom;
|
|
122
|
+
|
|
123
|
+
// Compute the new viewBox's x and y so that the anchor remains at the same screen fraction.
|
|
124
|
+
// That means:
|
|
125
|
+
// newViewBox.x + mouseFracX * newViewBoxWidth === anchorViewBoxX
|
|
126
|
+
// Solve for newViewBox.x:
|
|
127
|
+
const newViewBoxX = anchorViewBoxX - mouseFracX * newViewBoxWidth;
|
|
128
|
+
const newViewBoxY = anchorViewBoxY - mouseFracY * newViewBoxHeight;
|
|
129
|
+
|
|
130
|
+
// Update the viewBox attribute with the new values.
|
|
131
|
+
freehandCanvas.setAttribute(
|
|
132
|
+
"viewBox",
|
|
133
|
+
`${newViewBoxX} ${newViewBoxY} ${newViewBoxWidth} ${newViewBoxHeight}`
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// Update our state
|
|
137
|
+
currentZoom = newZoom;
|
|
138
|
+
currentViewBox = {
|
|
139
|
+
x: newViewBoxX,
|
|
140
|
+
y: newViewBoxY,
|
|
141
|
+
width: newViewBoxWidth,
|
|
142
|
+
height: newViewBoxHeight
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
updateZoomDisplay();
|
|
146
|
+
// Sync React zoom state
|
|
147
|
+
if (window.__sketchStoreApi && window.__sketchStoreApi.setZoom) {
|
|
148
|
+
window.__sketchStoreApi.setZoom(currentZoom);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Function to resize the canvas to fill the screen (initial setup)
|
|
153
|
+
function resizeCanvas() {
|
|
154
|
+
const width = window.innerWidth;
|
|
155
|
+
const height = window.innerHeight;
|
|
156
|
+
|
|
157
|
+
freehandCanvas.style.width = `${width}px`;
|
|
158
|
+
freehandCanvas.style.height = `${height}px`;
|
|
159
|
+
|
|
160
|
+
// Set initial viewBox based on initial zoom
|
|
161
|
+
updateViewBox(); // Initial center anchor
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
let isMiddleMousePanning = false;
|
|
167
|
+
|
|
168
|
+
freehandCanvas.addEventListener("mousedown", function (e) {
|
|
169
|
+
// Middle mouse button panning
|
|
170
|
+
if (e.button === 1) {
|
|
171
|
+
e.preventDefault();
|
|
172
|
+
isMiddleMousePanning = true;
|
|
173
|
+
isPanning = true;
|
|
174
|
+
startCanvasX = e.clientX;
|
|
175
|
+
startCanvasY = e.clientY;
|
|
176
|
+
panStart = { x: e.clientX, y: e.clientY };
|
|
177
|
+
freehandCanvas.style.cursor = 'grabbing';
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (isPanningToolActive) {
|
|
181
|
+
isPanning = true;
|
|
182
|
+
startCanvasX = e.clientX;
|
|
183
|
+
startCanvasY = e.clientY;
|
|
184
|
+
panStart = { x: e.clientX, y: e.clientY };
|
|
185
|
+
freehandCanvas.style.cursor = 'grabbing';
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
freehandCanvas.addEventListener("mousemove", (e) => {
|
|
190
|
+
if (!isPanning) return;
|
|
191
|
+
|
|
192
|
+
const dx = e.clientX - panStart.x;
|
|
193
|
+
const dy = e.clientY - panStart.y;
|
|
194
|
+
const dxViewBox = dx / currentZoom;
|
|
195
|
+
const dyViewBox = dy / currentZoom;
|
|
196
|
+
|
|
197
|
+
currentViewBox.x -= dxViewBox;
|
|
198
|
+
currentViewBox.y -= dyViewBox;
|
|
199
|
+
|
|
200
|
+
freehandCanvas.setAttribute(
|
|
201
|
+
"viewBox",
|
|
202
|
+
`${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
panStart = { x: e.clientX, y: e.clientY };
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
freehandCanvas.addEventListener("mouseup", (e) => {
|
|
209
|
+
if (isMiddleMousePanning) {
|
|
210
|
+
isMiddleMousePanning = false;
|
|
211
|
+
isPanning = false;
|
|
212
|
+
freehandCanvas.style.cursor = '';
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if(isPanningToolActive)
|
|
216
|
+
{
|
|
217
|
+
isPanning = false;
|
|
218
|
+
freehandCanvas.style.cursor = 'grab';
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
freehandCanvas.addEventListener("mouseleave", () => {
|
|
223
|
+
if (isMiddleMousePanning) {
|
|
224
|
+
isMiddleMousePanning = false;
|
|
225
|
+
isPanning = false;
|
|
226
|
+
freehandCanvas.style.cursor = '';
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
if(isPanningToolActive)
|
|
230
|
+
{
|
|
231
|
+
isPanning = false;
|
|
232
|
+
freehandCanvas.style.cursor = 'grab';
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Prevent default middle-click auto-scroll behavior
|
|
237
|
+
freehandCanvas.addEventListener("auxclick", (e) => {
|
|
238
|
+
if (e.button === 1) e.preventDefault();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
svg.addEventListener("wheel", (e) => {
|
|
243
|
+
e.preventDefault();
|
|
244
|
+
if (e.ctrlKey) return; // Ignore zoom gestures
|
|
245
|
+
|
|
246
|
+
if (e.shiftKey) {
|
|
247
|
+
// Pan sideways when Shift is held
|
|
248
|
+
currentViewBox.x += e.deltaY > 0 ? scrollRate : -scrollRate;
|
|
249
|
+
} else {
|
|
250
|
+
// Pan vertically
|
|
251
|
+
currentViewBox.y += e.deltaY > 0 ? scrollRate : -scrollRate;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
svg.setAttribute(
|
|
255
|
+
"viewBox",
|
|
256
|
+
`${currentViewBox.x} ${currentViewBox.y} ${currentViewBox.width} ${currentViewBox.height}`
|
|
257
|
+
);
|
|
258
|
+
});
|