@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.
Files changed (54) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -0
  3. package/fonts/fonts.css +29 -0
  4. package/fonts/lixCode.ttf +0 -0
  5. package/fonts/lixDefault.ttf +0 -0
  6. package/fonts/lixDocs.ttf +0 -0
  7. package/fonts/lixFancy.ttf +0 -0
  8. package/fonts/lixFont.woff2 +0 -0
  9. package/package.json +49 -0
  10. package/src/SketchEngine.js +473 -0
  11. package/src/core/AIRenderer.js +1390 -0
  12. package/src/core/CopyPaste.js +655 -0
  13. package/src/core/EraserTrail.js +234 -0
  14. package/src/core/EventDispatcher.js +371 -0
  15. package/src/core/GraphEngine.js +150 -0
  16. package/src/core/GraphMathParser.js +231 -0
  17. package/src/core/GraphRenderer.js +255 -0
  18. package/src/core/LayerOrder.js +91 -0
  19. package/src/core/LixScriptParser.js +1299 -0
  20. package/src/core/MermaidFlowchartRenderer.js +475 -0
  21. package/src/core/MermaidSequenceParser.js +197 -0
  22. package/src/core/MermaidSequenceRenderer.js +479 -0
  23. package/src/core/ResizeCode.js +175 -0
  24. package/src/core/ResizeShapes.js +318 -0
  25. package/src/core/SceneSerializer.js +778 -0
  26. package/src/core/Selection.js +1861 -0
  27. package/src/core/SnapGuides.js +273 -0
  28. package/src/core/UndoRedo.js +1358 -0
  29. package/src/core/ZoomPan.js +258 -0
  30. package/src/core/ai-system-prompt.js +663 -0
  31. package/src/index.js +69 -0
  32. package/src/shapes/Arrow.js +1979 -0
  33. package/src/shapes/Circle.js +751 -0
  34. package/src/shapes/CodeShape.js +244 -0
  35. package/src/shapes/Frame.js +1460 -0
  36. package/src/shapes/FreehandStroke.js +724 -0
  37. package/src/shapes/IconShape.js +265 -0
  38. package/src/shapes/ImageShape.js +270 -0
  39. package/src/shapes/Line.js +738 -0
  40. package/src/shapes/Rectangle.js +794 -0
  41. package/src/shapes/TextShape.js +225 -0
  42. package/src/tools/arrowTool.js +581 -0
  43. package/src/tools/circleTool.js +619 -0
  44. package/src/tools/codeTool.js +2103 -0
  45. package/src/tools/eraserTool.js +131 -0
  46. package/src/tools/frameTool.js +241 -0
  47. package/src/tools/freehandTool.js +620 -0
  48. package/src/tools/iconTool.js +1344 -0
  49. package/src/tools/imageTool.js +1323 -0
  50. package/src/tools/laserTool.js +317 -0
  51. package/src/tools/lineTool.js +502 -0
  52. package/src/tools/rectangleTool.js +544 -0
  53. package/src/tools/textTool.js +1823 -0
  54. package/src/utils/imageCompressor.js +107 -0
@@ -0,0 +1,619 @@
1
+ /* eslint-disable */
2
+ // Circle tool event handlers - extracted from drawCircle.js
3
+ import { pushCreateAction, pushDeleteAction, pushOptionsChangeAction, pushTransformAction, pushFrameAttachmentAction } from '../core/UndoRedo.js';
4
+ import { cleanupAttachments } from './arrowTool.js';
5
+ import { calculateSnap, clearSnapGuides } from '../core/SnapGuides.js';
6
+
7
+ let isDrawingCircle = false;
8
+ let isDraggingShapeCircle = false;
9
+ let isResizingShapeCircle = false;
10
+ let isRotatingShapeCircle = false;
11
+ let resizingAnchorIndexCircle = null;
12
+
13
+ let startRotationMouseAngleCircle = null;
14
+ let startShapeRotationCircle = null;
15
+ const rc = rough.svg(svg);
16
+ let startX, startY;
17
+
18
+
19
+ let circleStrokecolor = "#fff";
20
+ let circleBackgroundColor = "transparent";
21
+ let circleFillStyleValue = "none";
22
+ let circleStrokeThicknes = 2;
23
+ let circleOutlineStyle = "solid";
24
+
25
+ let dragOldPosCircle = null;
26
+ let draggedShapeInitialFrameCircle = null;
27
+ let hoveredFrameCircle = null;
28
+ let colorOptionsCircle = document.querySelectorAll(".circleStrokeSpan");
29
+ let backgroundColorOptionsCircle = document.querySelectorAll(".circleBackgroundSpan");
30
+ let fillStyleOptionsCircle = document.querySelectorAll(".circleFillStyleSpan");
31
+ let strokeThicknessValueCircle = document.querySelectorAll(".circleStrokeThickSpan");
32
+ let outlineStyleValueCircle = document.querySelectorAll(".circleOutlineStyle");
33
+
34
+
35
+
36
+ function getSVGCoordsFromMouse(e) {
37
+ const viewBox = svg.viewBox.baseVal;
38
+ const rect = svg.getBoundingClientRect();
39
+ const mouseX = e.clientX - rect.left;
40
+ const mouseY = e.clientY - rect.top;
41
+ const svgX = viewBox.x + (mouseX / rect.width) * viewBox.width;
42
+ const svgY = viewBox.y + (mouseY / rect.height) * viewBox.height;
43
+ return { x: svgX, y: svgY };
44
+ }
45
+
46
+
47
+ function deleteCurrentShape() {
48
+ if (currentShape && currentShape.shapeName === 'circle') {
49
+ const idx = shapes.indexOf(currentShape);
50
+ if (idx !== -1) shapes.splice(idx, 1);
51
+
52
+ // Clean up any arrow attachments before deleting
53
+ cleanupAttachments(currentShape);
54
+
55
+ if (currentShape.group.parentNode) {
56
+ currentShape.group.parentNode.removeChild(currentShape.group);
57
+ }
58
+ pushDeleteAction(currentShape);
59
+ currentShape = null;
60
+ disableAllSideBars();
61
+ }
62
+ }
63
+
64
+ document.addEventListener('keydown', (e) => {
65
+ if (e.key === 'Delete' && currentShape && currentShape.shapeName === 'circle') {
66
+ deleteCurrentShape();
67
+ }
68
+ });
69
+
70
+ const handleMouseDown = (e) => {
71
+ const {x: svgMouseX, y: svgMouseY} = getSVGCoordsFromMouse(e);
72
+
73
+ if(isCircleToolActive)
74
+ {
75
+ startX = svgMouseX;
76
+ startY = svgMouseY;
77
+ isDrawingCircle = true;
78
+
79
+ if(currentShape)
80
+ {
81
+ currentShape.removeSelection();
82
+ currentShape = null;
83
+ disableAllSideBars();
84
+ }
85
+ let initialOptions = {
86
+ stroke: circleStrokecolor,
87
+ fill: circleBackgroundColor,
88
+ fillStyle: circleFillStyleValue,
89
+ strokeWidth: circleStrokeThicknes,
90
+ };
91
+ if(circleOutlineStyle === "dashed") {
92
+ initialOptions.strokeDasharray = "5,5";
93
+ }
94
+ else if(circleOutlineStyle === "dotted") {
95
+ initialOptions.strokeDasharray = "2,8";
96
+ } else {
97
+ initialOptions.strokeDasharray = "";
98
+ }
99
+
100
+ currentShape = new Circle(startX, startY, 0, 0, initialOptions);
101
+ }
102
+
103
+ else if(isSelectionToolActive)
104
+ {
105
+ let clickedOnShape = false;
106
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected)
107
+ {
108
+ const anchorInfo = currentShape.isNearAnchor(svgMouseX, svgMouseY);
109
+ if (anchorInfo) {
110
+ dragOldPosCircle = {
111
+ x: currentShape.x,
112
+ y: currentShape.y,
113
+ rx: currentShape.rx,
114
+ ry: currentShape.ry,
115
+ rotation: currentShape.rotation
116
+ };
117
+ if(anchorInfo.type === 'resize')
118
+ {
119
+ isResizingShapeCircle = true;
120
+ resizingAnchorIndexCircle = anchorInfo.index;
121
+ }
122
+ else if(anchorInfo.type === 'rotate')
123
+ {
124
+ isRotatingShapeCircle = true;
125
+ const CTM = currentShape.group.getCTM();
126
+ if(CTM)
127
+ {
128
+ const svgPoint = svg.createSVGPoint();
129
+ svgPoint.x = currentShape.x;
130
+ svgPoint.y = currentShape.y;
131
+ const centerSVGPoint = svgPoint.matrixTransform(CTM);
132
+ startRotationMouseAngleCircle = Math.atan2(svgMouseY - centerSVGPoint.y, svgMouseX - centerSVGPoint.x) * (180 / Math.PI);
133
+ startShapeRotationCircle = currentShape.rotation;
134
+ }
135
+ else
136
+ {
137
+ isRotatingShapeCircle = false;
138
+ }
139
+ }
140
+ clickedOnShape = true;
141
+ }
142
+ else if (currentShape.contains(svgMouseX, svgMouseY))
143
+ {
144
+ isDraggingShapeCircle = true;
145
+ dragOldPosCircle = {
146
+ x: currentShape.x,
147
+ y: currentShape.y,
148
+ rx: currentShape.rx,
149
+ ry: currentShape.ry,
150
+ rotation: currentShape.rotation
151
+ };
152
+
153
+ // Store initial frame state
154
+ draggedShapeInitialFrameCircle = currentShape.parentFrame || null;
155
+
156
+ // Temporarily remove from frame clipping if dragging
157
+ if (currentShape.parentFrame) {
158
+ currentShape.parentFrame.temporarilyRemoveFromFrame(currentShape);
159
+ }
160
+
161
+ startX = svgMouseX;
162
+ startY = svgMouseY;
163
+ clickedOnShape = true;
164
+ }
165
+ }
166
+ if (!clickedOnShape)
167
+ {
168
+ let shapeToSelect = null;
169
+ for (let i = shapes.length - 1; i >= 0; i--) {
170
+ const shape = shapes[i];
171
+ if (shape.shapeName === 'circle' && shape.contains(svgMouseX, svgMouseY)) {
172
+ shapeToSelect = shape;
173
+ break;
174
+ }
175
+ }
176
+ if (currentShape && currentShape !== shapeToSelect) {
177
+ currentShape.removeSelection();
178
+ currentShape = null;
179
+ disableAllSideBars();
180
+ }
181
+ if(shapeToSelect)
182
+ {
183
+ currentShape = shapeToSelect;
184
+ currentShape.isSelected = true;
185
+ currentShape.draw();
186
+ isDraggingShapeCircle = true;
187
+ dragOldPosCircle = {
188
+ x: currentShape.x,
189
+ y: currentShape.y,
190
+ rx: currentShape.rx,
191
+ ry: currentShape.ry,
192
+ rotation: currentShape.rotation
193
+ };
194
+
195
+ // Store initial frame state
196
+ draggedShapeInitialFrameCircle = currentShape.parentFrame || null;
197
+
198
+ // Temporarily remove from frame clipping if dragging
199
+ if (currentShape.parentFrame) {
200
+ currentShape.parentFrame.temporarilyRemoveFromFrame(currentShape);
201
+ }
202
+
203
+ startX = svgMouseX;
204
+ startY = svgMouseY;
205
+ clickedOnShape = true;
206
+ }
207
+ }
208
+ if(!clickedOnShape && currentShape) {
209
+ currentShape.removeSelection();
210
+ currentShape = null;
211
+ disableAllSideBars();
212
+ }
213
+ }
214
+ };
215
+
216
+ const handleMouseMove = (e) => {
217
+
218
+ const {x: svgMouseX, y: svgMouseY} = getSVGCoordsFromMouse(e);
219
+
220
+ // Keep lastMousePos in screen coordinates for other functions
221
+ const svgRect = svg.getBoundingClientRect();
222
+ lastMousePos = {
223
+ x: e.clientX - svgRect.left,
224
+ y: e.clientY - svgRect.top
225
+ };
226
+
227
+ if(isDrawingCircle && isCircleToolActive && currentShape)
228
+ {
229
+ currentShape.x = (startX + svgMouseX) / 2;
230
+ currentShape.y = (startY + svgMouseY) / 2;
231
+ currentShape.rx = Math.abs(svgMouseX - startX) / 2;
232
+ currentShape.ry = Math.abs(svgMouseY - startY) / 2;
233
+ currentShape.draw();
234
+
235
+ // Check for frame containment while drawing (but don't apply clipping yet)
236
+ shapes.forEach(frame => {
237
+ if (frame.shapeName === 'frame') {
238
+ if (frame.isShapeInFrame(currentShape)) {
239
+ frame.highlightFrame();
240
+ hoveredFrameCircle = frame;
241
+ } else if (hoveredFrameCircle === frame) {
242
+ frame.removeHighlight();
243
+ hoveredFrameCircle = null;
244
+ }
245
+ }
246
+ });
247
+ }
248
+ else if (isDraggingShapeCircle && currentShape && currentShape.isSelected) {
249
+ const dx = svgMouseX - startX;
250
+ const dy = svgMouseY - startY;
251
+ currentShape.move(dx, dy);
252
+ startX = svgMouseX;
253
+ startY = svgMouseY;
254
+
255
+ // Snap guides
256
+ if (window.__sketchStoreApi && window.__sketchStoreApi.getState().snapToObjects) {
257
+ const snap = calculateSnap(currentShape, e.shiftKey, e.clientX, e.clientY);
258
+ if (snap.dx || snap.dy) {
259
+ currentShape.move(snap.dx, snap.dy);
260
+ }
261
+ } else {
262
+ clearSnapGuides();
263
+ }
264
+ }
265
+
266
+ else if(isResizingShapeCircle && currentShape && currentShape.isSelected)
267
+ {
268
+ currentShape.updatePosition(resizingAnchorIndexCircle, svgMouseX, svgMouseY);
269
+ currentShape._skipAnchors = true;
270
+ currentShape.draw();
271
+ currentShape._skipAnchors = false;
272
+ }
273
+ else if (isRotatingShapeCircle && currentShape && currentShape.isSelected)
274
+ {
275
+ const CTM = currentShape.group.getCTM();
276
+ if(CTM) {
277
+ const svgPoint = svg.createSVGPoint();
278
+ svgPoint.x = currentShape.x;
279
+ svgPoint.y = currentShape.y;
280
+ const centerSVGPoint = svgPoint.matrixTransform(CTM);
281
+ const currentMouseAngle = Math.atan2(svgMouseY - centerSVGPoint.y, svgMouseX - centerSVGPoint.x) * (180 / Math.PI);
282
+ const angleDiff = currentMouseAngle - startRotationMouseAngleCircle;
283
+ let newRotation = startShapeRotationCircle + angleDiff;
284
+ const snapAngle = 15;
285
+ if (e.shiftKey) {
286
+ newRotation = Math.round(newRotation / snapAngle) * snapAngle;
287
+ }
288
+ currentShape.rotate(newRotation);
289
+ currentShape._skipAnchors = true;
290
+ currentShape.draw();
291
+ currentShape._skipAnchors = false;
292
+ svg.style.cursor = 'grabbing';
293
+ }
294
+ else
295
+ {
296
+ isRotatingShapeCircle = false;
297
+ svg.style.cursor = 'default';
298
+ }
299
+ }
300
+ else if (isSelectionToolActive && !isDrawingCircle && currentShape && currentShape.isSelected)
301
+ {
302
+ const anchorInfo = currentShape.isNearAnchor(svgMouseX, svgMouseY);
303
+ if(anchorInfo)
304
+ {
305
+ if(anchorInfo.type === 'resize') {
306
+ const baseDirection = anchorInfo.index;
307
+ const rotatedCursor = currentShape.getRotatedCursor(baseDirection, currentShape.rotation);
308
+ svg.style.cursor = rotatedCursor + '-resize';
309
+ }
310
+ else if(anchorInfo.type === 'rotate') {
311
+ svg.style.cursor = 'grab';
312
+ }
313
+ }
314
+ else if(currentShape.contains(svgMouseX, svgMouseY)) {
315
+ svg.style.cursor = 'move';
316
+ }
317
+ else
318
+ {
319
+ svg.style.cursor = 'default';
320
+ }
321
+ }
322
+ else if (isSelectionToolActive && !isDrawingCircle && !isDraggingShapeCircle && !isResizingShapeCircle && !isRotatingShapeCircle)
323
+ {
324
+ let hoveredShape = null;
325
+ for (let i = shapes.length - 1; i >= 0; i--) {
326
+ const shape = shapes[i];
327
+ if (shape.shapeName === 'circle' && shape.contains(svgMouseX, svgMouseY)) {
328
+ hoveredShape = shape;
329
+ break;
330
+ }
331
+ }
332
+ if (hoveredShape) {
333
+ svg.style.cursor = 'pointer';
334
+ } else {
335
+ svg.style.cursor = 'default';
336
+ }
337
+ }
338
+ }
339
+
340
+ const handleMouseUp = (e) => {
341
+ if (isDrawingCircle && currentShape) {
342
+ if(currentShape.rx === 0 && currentShape.ry === 0) {
343
+ if (currentShape.group.parentNode) {
344
+ currentShape.group.parentNode.removeChild(currentShape.group);
345
+ }
346
+ currentShape = null;
347
+ } else {
348
+ shapes.push(currentShape);
349
+ pushCreateAction(currentShape);
350
+
351
+ // Check for frame containment and track attachment
352
+ const finalFrame = hoveredFrameCircle;
353
+ if (finalFrame) {
354
+ finalFrame.addShapeToFrame(currentShape);
355
+ // Track the attachment for undo
356
+ pushFrameAttachmentAction(finalFrame, currentShape, 'attach', null);
357
+ }
358
+
359
+ // Auto-select the drawn shape and switch to selection tool
360
+ const drawnShape = currentShape;
361
+ if (window.__sketchStoreApi) window.__sketchStoreApi.setActiveTool('select', { afterDraw: true });
362
+ currentShape = drawnShape;
363
+ currentShape.isSelected = true;
364
+ if (typeof currentShape.addAnchors === 'function') {
365
+ currentShape.addAnchors();
366
+ }
367
+ }
368
+
369
+ // Clear frame highlighting
370
+ if (hoveredFrameCircle) {
371
+ hoveredFrameCircle.removeHighlight();
372
+ hoveredFrameCircle = null;
373
+ }
374
+ }
375
+
376
+ if((isDraggingShapeCircle || isResizingShapeCircle || isRotatingShapeCircle) && dragOldPosCircle && currentShape) {
377
+ const newPos = {
378
+ x: currentShape.x,
379
+ y: currentShape.y,
380
+ rx: currentShape.rx,
381
+ ry: currentShape.ry,
382
+ rotation: currentShape.rotation,
383
+ parentFrame: currentShape.parentFrame
384
+ };
385
+ const oldPos = {
386
+ ...dragOldPosCircle,
387
+ parentFrame: draggedShapeInitialFrameCircle
388
+ };
389
+
390
+ const stateChanged = oldPos.x !== newPos.x || oldPos.y !== newPos.y ||
391
+ oldPos.rx !== newPos.rx || oldPos.ry !== newPos.ry ||
392
+ oldPos.rotation !== newPos.rotation;
393
+
394
+ const frameChanged = oldPos.parentFrame !== newPos.parentFrame;
395
+
396
+ if (stateChanged || frameChanged) {
397
+ const oldPosForUndo = {
398
+ x: oldPos.x,
399
+ y: oldPos.y,
400
+ rx: oldPos.rx,
401
+ ry: oldPos.ry,
402
+ rotation: oldPos.rotation,
403
+ parentFrame: oldPos.parentFrame
404
+ };
405
+ const newPosForUndo = {
406
+ x: newPos.x,
407
+ y: newPos.y,
408
+ rx: newPos.rx,
409
+ ry: newPos.ry,
410
+ rotation: newPos.rotation,
411
+ parentFrame: newPos.parentFrame
412
+ };
413
+ pushTransformAction(currentShape, oldPosForUndo, newPosForUndo);
414
+ }
415
+
416
+ // Handle frame containment changes after drag
417
+ if (isDraggingShapeCircle) {
418
+ const finalFrame = hoveredFrameCircle;
419
+
420
+ // If shape moved to a different frame
421
+ if (draggedShapeInitialFrameCircle !== finalFrame) {
422
+ // Remove from initial frame
423
+ if (draggedShapeInitialFrameCircle) {
424
+ draggedShapeInitialFrameCircle.removeShapeFromFrame(currentShape);
425
+ }
426
+
427
+ // Add to new frame
428
+ if (finalFrame) {
429
+ finalFrame.addShapeToFrame(currentShape);
430
+ }
431
+
432
+ // Track the frame change for undo
433
+ if (frameChanged) {
434
+ pushFrameAttachmentAction(finalFrame || draggedShapeInitialFrameCircle, currentShape,
435
+ finalFrame ? 'attach' : 'detach', draggedShapeInitialFrameCircle);
436
+ }
437
+ } else if (draggedShapeInitialFrameCircle) {
438
+ // Shape stayed in same frame, restore clipping
439
+ draggedShapeInitialFrameCircle.restoreToFrame(currentShape);
440
+ }
441
+ }
442
+
443
+ dragOldPosCircle = null;
444
+ draggedShapeInitialFrameCircle = null;
445
+ }
446
+
447
+ // Clear frame highlighting
448
+ if (hoveredFrameCircle) {
449
+ hoveredFrameCircle.removeHighlight();
450
+ hoveredFrameCircle = null;
451
+ }
452
+
453
+ clearSnapGuides();
454
+ isDrawingCircle = false;
455
+ isDraggingShapeCircle = false;
456
+ isResizingShapeCircle = false;
457
+ isRotatingShapeCircle = false;
458
+ resizingAnchorIndexCircle = null;
459
+ startRotationMouseAngleCircle = null;
460
+ startShapeRotationCircle = 0;
461
+ svg.style.cursor = 'default';
462
+ }
463
+
464
+
465
+ colorOptionsCircle.forEach(span => {
466
+ span.addEventListener('click', function(event) {
467
+ event.stopPropagation();
468
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
469
+ const color = this.getAttribute('data-id');
470
+ const oldOptions = {...currentShape.options};
471
+ currentShape.options.stroke = color;
472
+ currentShape.draw();
473
+ currentShape.updateSidebar();
474
+ pushOptionsChangeAction(currentShape, oldOptions);
475
+ }
476
+ else
477
+ {
478
+ circleStrokecolor = this.getAttribute('data-id');
479
+ }
480
+ colorOptionsCircle.forEach(span => {
481
+ span.classList.remove('selected');
482
+ });
483
+ this.classList.add('selected');
484
+ });
485
+ });
486
+ backgroundColorOptionsCircle.forEach(span => {
487
+ span.addEventListener('click', function(event) {
488
+ event.stopPropagation();
489
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
490
+ const color = this.getAttribute('data-id');
491
+ const oldOptions = {...currentShape.options};
492
+ currentShape.options.fill = color;
493
+ currentShape.draw();
494
+ currentShape.updateSidebar();
495
+ pushOptionsChangeAction(currentShape, oldOptions);
496
+ }
497
+ else
498
+ {
499
+ circleBackgroundColor = this.getAttribute('data-id');
500
+ }
501
+ backgroundColorOptionsCircle.forEach(span => {
502
+ span.classList.remove('selected');
503
+ });
504
+ this.classList.add('selected');
505
+ });
506
+ });
507
+ fillStyleOptionsCircle.forEach(span => {
508
+ span.addEventListener('click', function(event) {
509
+ event.stopPropagation();
510
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
511
+ const style = this.getAttribute('data-id');
512
+ const oldOptions = {...currentShape.options};
513
+ currentShape.options.fillStyle = style;
514
+ currentShape.draw();
515
+ currentShape.updateSidebar();
516
+ pushOptionsChangeAction(currentShape, oldOptions);
517
+ }
518
+ else
519
+ {
520
+ circleFillStyleValue = this.getAttribute('data-id');
521
+ }
522
+ fillStyleOptionsCircle.forEach(span => {
523
+ span.classList.remove('selected');
524
+ });
525
+ this.classList.add('selected');
526
+ });
527
+ });
528
+ strokeThicknessValueCircle.forEach(span => {
529
+ span.addEventListener('click', function(event) {
530
+ event.stopPropagation();
531
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
532
+ const thick = parseInt(this.getAttribute('data-id'), 10);
533
+ const oldOptions = {...currentShape.options};
534
+ currentShape.options.strokeWidth = thick;
535
+ currentShape.draw();
536
+ currentShape.updateSidebar();
537
+ pushOptionsChangeAction(currentShape, oldOptions);
538
+ }
539
+ else
540
+ {
541
+ circleStrokeThicknes = parseInt(this.getAttribute('data-id'), 10);
542
+ }
543
+ strokeThicknessValueCircle.forEach(span => {
544
+ span.classList.remove('selected');
545
+ });
546
+ this.classList.add('selected');
547
+ });
548
+ });
549
+ outlineStyleValueCircle.forEach(span => {
550
+ span.addEventListener('click', function(event) {
551
+ event.stopPropagation();
552
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
553
+ const style = this.getAttribute('data-id');
554
+ const oldOptions = {...currentShape.options};
555
+ if (style === "dashed") {
556
+ currentShape.options.strokeDasharray = "5,5";
557
+ } else if (style === "dotted") {
558
+ currentShape.options.strokeDasharray = "2,8";
559
+ } else {
560
+ currentShape.options.strokeDasharray = "";
561
+ }
562
+ currentShape.draw();
563
+ currentShape.updateSidebar();
564
+ pushOptionsChangeAction(currentShape, oldOptions);
565
+ }
566
+ else
567
+ {
568
+ circleOutlineStyle = this.getAttribute('data-id');
569
+ }
570
+ outlineStyleValueCircle.forEach(span => {
571
+ span.classList.remove('selected');
572
+ });
573
+ this.classList.add('selected');
574
+ });
575
+ });
576
+
577
+ window.Circle = Circle;
578
+
579
+ // Bridge circle tool settings to React sidebar
580
+ window.circleToolSettings = {
581
+ get strokeColor() { return circleStrokecolor; },
582
+ set strokeColor(v) { circleStrokecolor = v; },
583
+ get bgColor() { return circleBackgroundColor; },
584
+ set bgColor(v) { circleBackgroundColor = v; },
585
+ get fillStyle() { return circleFillStyleValue; },
586
+ set fillStyle(v) { circleFillStyleValue = v; },
587
+ get strokeWidth() { return circleStrokeThicknes; },
588
+ set strokeWidth(v) { circleStrokeThicknes = v; },
589
+ get outlineStyle() { return circleOutlineStyle; },
590
+ set outlineStyle(v) { circleOutlineStyle = v; },
591
+ };
592
+ window.updateSelectedCircleStyle = function(changes) {
593
+ if (currentShape && currentShape.shapeName === 'circle' && currentShape.isSelected) {
594
+ pushOptionsChangeAction(currentShape, { ...currentShape.options });
595
+ if (changes.stroke !== undefined) { circleStrokecolor = changes.stroke; currentShape.options.stroke = changes.stroke; }
596
+ if (changes.fill !== undefined) { circleBackgroundColor = changes.fill; currentShape.options.fill = changes.fill; }
597
+ if (changes.fillStyle !== undefined) { circleFillStyleValue = changes.fillStyle; currentShape.options.fillStyle = changes.fillStyle; }
598
+ if (changes.strokeWidth !== undefined) { circleStrokeThicknes = changes.strokeWidth; currentShape.options.strokeWidth = changes.strokeWidth; }
599
+ if (changes.outlineStyle !== undefined) {
600
+ circleOutlineStyle = changes.outlineStyle;
601
+ if (changes.outlineStyle === "dashed") currentShape.options.strokeDasharray = "5,5";
602
+ else if (changes.outlineStyle === "dotted") currentShape.options.strokeDasharray = "2,8";
603
+ else currentShape.options.strokeDasharray = "";
604
+ }
605
+ currentShape.draw();
606
+ } else {
607
+ if (changes.stroke !== undefined) circleStrokecolor = changes.stroke;
608
+ if (changes.fill !== undefined) circleBackgroundColor = changes.fill;
609
+ if (changes.fillStyle !== undefined) circleFillStyleValue = changes.fillStyle;
610
+ if (changes.strokeWidth !== undefined) circleStrokeThicknes = changes.strokeWidth;
611
+ if (changes.outlineStyle !== undefined) circleOutlineStyle = changes.outlineStyle;
612
+ }
613
+ };
614
+
615
+ export {
616
+ handleMouseDown as handleMouseDownCircle,
617
+ handleMouseMove as handleMouseMoveCircle,
618
+ handleMouseUp as handleMouseUpCircle,
619
+ }