@emasoft/svg-matrix 1.1.0 → 1.2.0

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 (55) hide show
  1. package/bin/svg-matrix.js +7 -6
  2. package/bin/svgm.js +109 -40
  3. package/dist/svg-matrix.min.js +7 -7
  4. package/dist/svg-toolbox.min.js +148 -228
  5. package/dist/svgm.min.js +152 -232
  6. package/dist/version.json +5 -5
  7. package/package.json +1 -1
  8. package/scripts/postinstall.js +72 -41
  9. package/scripts/test-postinstall.js +18 -16
  10. package/scripts/version-sync.js +78 -60
  11. package/src/animation-optimization.js +190 -98
  12. package/src/animation-references.js +11 -3
  13. package/src/arc-length.js +23 -20
  14. package/src/bezier-analysis.js +9 -13
  15. package/src/bezier-intersections.js +18 -4
  16. package/src/browser-verify.js +35 -8
  17. package/src/clip-path-resolver.js +285 -114
  18. package/src/convert-path-data.js +20 -8
  19. package/src/css-specificity.js +33 -9
  20. package/src/douglas-peucker.js +272 -141
  21. package/src/geometry-to-path.js +79 -22
  22. package/src/gjk-collision.js +287 -126
  23. package/src/index.js +56 -21
  24. package/src/inkscape-support.js +122 -101
  25. package/src/logger.js +43 -27
  26. package/src/marker-resolver.js +201 -121
  27. package/src/mask-resolver.js +231 -98
  28. package/src/matrix.js +9 -5
  29. package/src/mesh-gradient.js +22 -14
  30. package/src/off-canvas-detection.js +53 -17
  31. package/src/path-optimization.js +356 -171
  32. package/src/path-simplification.js +671 -256
  33. package/src/pattern-resolver.js +1 -3
  34. package/src/polygon-clip.js +396 -78
  35. package/src/svg-boolean-ops.js +90 -23
  36. package/src/svg-collections.js +1546 -667
  37. package/src/svg-flatten.js +152 -38
  38. package/src/svg-matrix-lib.js +2 -2
  39. package/src/svg-parser.js +5 -1
  40. package/src/svg-rendering-context.js +3 -1
  41. package/src/svg-toolbox-lib.js +2 -2
  42. package/src/svg-toolbox.js +99 -457
  43. package/src/svg-validation-data.js +513 -345
  44. package/src/svg2-polyfills.js +156 -93
  45. package/src/svgm-lib.js +8 -4
  46. package/src/transform-optimization.js +168 -51
  47. package/src/transforms2d.js +73 -40
  48. package/src/transforms3d.js +34 -27
  49. package/src/use-symbol-resolver.js +175 -76
  50. package/src/vector.js +80 -44
  51. package/src/vendor/inkscape-hatch-polyfill.js +143 -108
  52. package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
  53. package/src/vendor/inkscape-mesh-polyfill.js +953 -766
  54. package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
  55. package/src/verification.js +3 -4
@@ -69,26 +69,37 @@ Decimal.set({ precision: 80 });
69
69
  */
70
70
  export function parseMarkerElement(markerElement) {
71
71
  // Validate required parameter
72
- if (!markerElement) throw new Error('parseMarkerElement: markerElement is required');
73
- if (typeof markerElement.getAttribute !== 'function') {
74
- throw new Error('parseMarkerElement: markerElement must be a DOM element');
72
+ if (!markerElement)
73
+ throw new Error("parseMarkerElement: markerElement is required");
74
+ if (typeof markerElement.getAttribute !== "function") {
75
+ throw new Error("parseMarkerElement: markerElement must be a DOM element");
75
76
  }
76
77
 
77
78
  // Parse numeric attributes with validation - NaN check ensures valid numbers
78
- const markerWidth = parseFloat(markerElement.getAttribute("markerWidth") || "3");
79
- const markerHeight = parseFloat(markerElement.getAttribute("markerHeight") || "3");
79
+ const markerWidth = parseFloat(
80
+ markerElement.getAttribute("markerWidth") || "3",
81
+ );
82
+ const markerHeight = parseFloat(
83
+ markerElement.getAttribute("markerHeight") || "3",
84
+ );
80
85
  const refX = parseFloat(markerElement.getAttribute("refX") || "0");
81
86
  const refY = parseFloat(markerElement.getAttribute("refY") || "0");
82
87
 
83
88
  // Validate numeric values to prevent NaN propagation
84
89
  if (isNaN(markerWidth) || markerWidth <= 0) {
85
- throw new Error('parseMarkerElement: markerWidth must be a positive number');
90
+ throw new Error(
91
+ "parseMarkerElement: markerWidth must be a positive number",
92
+ );
86
93
  }
87
94
  if (isNaN(markerHeight) || markerHeight <= 0) {
88
- throw new Error('parseMarkerElement: markerHeight must be a positive number');
95
+ throw new Error(
96
+ "parseMarkerElement: markerHeight must be a positive number",
97
+ );
89
98
  }
90
- if (isNaN(refX)) throw new Error('parseMarkerElement: refX must be a valid number');
91
- if (isNaN(refY)) throw new Error('parseMarkerElement: refY must be a valid number');
99
+ if (isNaN(refX))
100
+ throw new Error("parseMarkerElement: refX must be a valid number");
101
+ if (isNaN(refY))
102
+ throw new Error("parseMarkerElement: refY must be a valid number");
92
103
 
93
104
  const data = {
94
105
  id: markerElement.getAttribute("id") || "",
@@ -112,7 +123,7 @@ export function parseMarkerElement(markerElement) {
112
123
  .split(/[\s,]+/)
113
124
  .map(Number);
114
125
  // Validate viewBox has exactly 4 valid finite numbers
115
- if (parts.length === 4 && parts.every(n => !isNaN(n) && isFinite(n))) {
126
+ if (parts.length === 4 && parts.every((n) => !isNaN(n) && isFinite(n))) {
116
127
  data.viewBox = {
117
128
  x: parts[0],
118
129
  y: parts[1],
@@ -158,8 +169,9 @@ export function parseMarkerElement(markerElement) {
158
169
  */
159
170
  export function parseMarkerChild(element) {
160
171
  // Validate required parameter
161
- if (!element) throw new Error('parseMarkerChild: element is required');
162
- if (!element.tagName) throw new Error('parseMarkerChild: element must have a tagName property');
172
+ if (!element) throw new Error("parseMarkerChild: element is required");
173
+ if (!element.tagName)
174
+ throw new Error("parseMarkerChild: element must have a tagName property");
163
175
 
164
176
  const tagName = element.tagName.toLowerCase();
165
177
  const data = {
@@ -176,7 +188,9 @@ export function parseMarkerChild(element) {
176
188
  const parseValidFloat = (value, defaultVal, name) => {
177
189
  const parsed = parseFloat(value || String(defaultVal));
178
190
  if (isNaN(parsed) || !isFinite(parsed)) {
179
- throw new Error(`parseMarkerChild: ${name} must be a valid finite number`);
191
+ throw new Error(
192
+ `parseMarkerChild: ${name} must be a valid finite number`,
193
+ );
180
194
  }
181
195
  return parsed;
182
196
  };
@@ -190,7 +204,11 @@ export function parseMarkerChild(element) {
190
204
  data.x = parseValidFloat(element.getAttribute("x"), 0, "x");
191
205
  data.y = parseValidFloat(element.getAttribute("y"), 0, "y");
192
206
  data.width = parseValidFloat(element.getAttribute("width"), 0, "width");
193
- data.height = parseValidFloat(element.getAttribute("height"), 0, "height");
207
+ data.height = parseValidFloat(
208
+ element.getAttribute("height"),
209
+ 0,
210
+ "height",
211
+ );
194
212
  break;
195
213
  case "circle":
196
214
  // Validate all circle attributes are valid numbers
@@ -265,15 +283,33 @@ export function getMarkerTransform(
265
283
  isStart = false,
266
284
  ) {
267
285
  // Validate required parameters
268
- if (!markerDef) throw new Error('getMarkerTransform: markerDef is required');
269
- if (!position || typeof position.x !== 'number' || typeof position.y !== 'number') {
270
- throw new Error('getMarkerTransform: position must be an object with x and y numeric properties');
286
+ if (!markerDef) throw new Error("getMarkerTransform: markerDef is required");
287
+ if (
288
+ !position ||
289
+ typeof position.x !== "number" ||
290
+ typeof position.y !== "number"
291
+ ) {
292
+ throw new Error(
293
+ "getMarkerTransform: position must be an object with x and y numeric properties",
294
+ );
271
295
  }
272
- if (typeof tangentAngle !== 'number' || isNaN(tangentAngle) || !isFinite(tangentAngle)) {
273
- throw new Error('getMarkerTransform: tangentAngle must be a valid finite number');
296
+ if (
297
+ typeof tangentAngle !== "number" ||
298
+ isNaN(tangentAngle) ||
299
+ !isFinite(tangentAngle)
300
+ ) {
301
+ throw new Error(
302
+ "getMarkerTransform: tangentAngle must be a valid finite number",
303
+ );
274
304
  }
275
- if (typeof strokeWidth !== 'number' || isNaN(strokeWidth) || strokeWidth <= 0) {
276
- throw new Error('getMarkerTransform: strokeWidth must be a positive number');
305
+ if (
306
+ typeof strokeWidth !== "number" ||
307
+ isNaN(strokeWidth) ||
308
+ strokeWidth <= 0
309
+ ) {
310
+ throw new Error(
311
+ "getMarkerTransform: strokeWidth must be a positive number",
312
+ );
277
313
  }
278
314
 
279
315
  // Extract markerDef properties with validation
@@ -288,17 +324,25 @@ export function getMarkerTransform(
288
324
  } = markerDef;
289
325
 
290
326
  // Validate markerDef has required numeric properties
291
- if (typeof markerWidth !== 'number' || markerWidth <= 0) {
292
- throw new Error('getMarkerTransform: markerDef.markerWidth must be a positive number');
327
+ if (typeof markerWidth !== "number" || markerWidth <= 0) {
328
+ throw new Error(
329
+ "getMarkerTransform: markerDef.markerWidth must be a positive number",
330
+ );
293
331
  }
294
- if (typeof markerHeight !== 'number' || markerHeight <= 0) {
295
- throw new Error('getMarkerTransform: markerDef.markerHeight must be a positive number');
332
+ if (typeof markerHeight !== "number" || markerHeight <= 0) {
333
+ throw new Error(
334
+ "getMarkerTransform: markerDef.markerHeight must be a positive number",
335
+ );
296
336
  }
297
- if (typeof refX !== 'number' || !isFinite(refX)) {
298
- throw new Error('getMarkerTransform: markerDef.refX must be a finite number');
337
+ if (typeof refX !== "number" || !isFinite(refX)) {
338
+ throw new Error(
339
+ "getMarkerTransform: markerDef.refX must be a finite number",
340
+ );
299
341
  }
300
- if (typeof refY !== 'number' || !isFinite(refY)) {
301
- throw new Error('getMarkerTransform: markerDef.refY must be a finite number');
342
+ if (typeof refY !== "number" || !isFinite(refY)) {
343
+ throw new Error(
344
+ "getMarkerTransform: markerDef.refY must be a finite number",
345
+ );
302
346
  }
303
347
 
304
348
  // Start with identity matrix
@@ -340,7 +384,12 @@ export function getMarkerTransform(
340
384
  const vbHeight = viewBox.height;
341
385
 
342
386
  // Prevent division by zero
343
- if (vbWidth > 0 && vbHeight > 0 && isFinite(vbWidth) && isFinite(vbHeight)) {
387
+ if (
388
+ vbWidth > 0 &&
389
+ vbHeight > 0 &&
390
+ isFinite(vbWidth) &&
391
+ isFinite(vbHeight)
392
+ ) {
344
393
  // Calculate uniform scale factor based on preserveAspectRatio
345
394
  const scaleFactorX = markerWidth / vbWidth;
346
395
  const scaleFactorY = markerHeight / vbHeight;
@@ -354,7 +403,10 @@ export function getMarkerTransform(
354
403
  scaleY *= scaleFactor;
355
404
 
356
405
  // Translate to account for viewBox origin
357
- const viewBoxTranslate = Transforms2D.translation(-viewBox.x, -viewBox.y);
406
+ const viewBoxTranslate = Transforms2D.translation(
407
+ -viewBox.x,
408
+ -viewBox.y,
409
+ );
358
410
  transform = transform.mul(viewBoxTranslate);
359
411
  }
360
412
  }
@@ -413,8 +465,8 @@ export function getMarkerTransform(
413
465
  */
414
466
  export function getPathVertices(pathData) {
415
467
  // Validate pathData parameter
416
- if (typeof pathData !== 'string') {
417
- throw new Error('getPathVertices: pathData must be a string');
468
+ if (typeof pathData !== "string") {
469
+ throw new Error("getPathVertices: pathData must be a string");
418
470
  }
419
471
 
420
472
  const vertices = [];
@@ -463,9 +515,12 @@ export function getPathVertices(pathData) {
463
515
  // Calculate tangent angle (handle zero-length segments)
464
516
  const dx = currentX - prevX;
465
517
  const dy = currentY - prevY;
466
- const lineAngle = (dx === 0 && dy === 0)
467
- ? (vertices.length > 0 ? vertices[vertices.length - 1].tangentOut : 0)
468
- : Math.atan2(dy, dx);
518
+ const lineAngle =
519
+ dx === 0 && dy === 0
520
+ ? vertices.length > 0
521
+ ? vertices[vertices.length - 1].tangentOut
522
+ : 0
523
+ : Math.atan2(dy, dx);
469
524
 
470
525
  // Update previous vertex's outgoing tangent
471
526
  if (vertices.length > 0) {
@@ -492,17 +547,19 @@ export function getPathVertices(pathData) {
492
547
  // Handle degenerate case: if first control point coincides with start
493
548
  const dx1 = cmd.x1 - prevX;
494
549
  const dy1 = cmd.y1 - prevY;
495
- const startTangent = (dx1 === 0 && dy1 === 0)
496
- ? Math.atan2(cmd.y2 - prevY, cmd.x2 - prevX) // Use second control point
497
- : Math.atan2(dy1, dx1);
550
+ const startTangent =
551
+ dx1 === 0 && dy1 === 0
552
+ ? Math.atan2(cmd.y2 - prevY, cmd.x2 - prevX) // Use second control point
553
+ : Math.atan2(dy1, dx1);
498
554
 
499
555
  // Calculate tangent at end (direction from last control point)
500
556
  // Handle degenerate case: if last control point coincides with end
501
557
  const dx2 = currentX - cmd.x2;
502
558
  const dy2 = currentY - cmd.y2;
503
- const endTangent = (dx2 === 0 && dy2 === 0)
504
- ? Math.atan2(currentY - cmd.y1, currentX - cmd.x1) // Use first control point
505
- : Math.atan2(dy2, dx2);
559
+ const endTangent =
560
+ dx2 === 0 && dy2 === 0
561
+ ? Math.atan2(currentY - cmd.y1, currentX - cmd.x1) // Use first control point
562
+ : Math.atan2(dy2, dx2);
506
563
 
507
564
  // Update previous vertex's outgoing tangent
508
565
  if (vertices.length > 0) {
@@ -528,16 +585,18 @@ export function getPathVertices(pathData) {
528
585
  // Calculate tangent at start (handle degenerate case)
529
586
  const dxq1 = cmd.x1 - prevX;
530
587
  const dyq1 = cmd.y1 - prevY;
531
- const qStartTangent = (dxq1 === 0 && dyq1 === 0)
532
- ? Math.atan2(currentY - prevY, currentX - prevX) // Use endpoint
533
- : Math.atan2(dyq1, dxq1);
588
+ const qStartTangent =
589
+ dxq1 === 0 && dyq1 === 0
590
+ ? Math.atan2(currentY - prevY, currentX - prevX) // Use endpoint
591
+ : Math.atan2(dyq1, dxq1);
534
592
 
535
593
  // Calculate tangent at end (handle degenerate case)
536
594
  const dxq2 = currentX - cmd.x1;
537
595
  const dyq2 = currentY - cmd.y1;
538
- const qEndTangent = (dxq2 === 0 && dyq2 === 0)
539
- ? Math.atan2(currentY - prevY, currentX - prevX) // Use startpoint
540
- : Math.atan2(dyq2, dxq2);
596
+ const qEndTangent =
597
+ dxq2 === 0 && dyq2 === 0
598
+ ? Math.atan2(currentY - prevY, currentX - prevX) // Use startpoint
599
+ : Math.atan2(dyq2, dxq2);
541
600
 
542
601
  // Update previous vertex's outgoing tangent
543
602
  if (vertices.length > 0) {
@@ -563,9 +622,12 @@ export function getPathVertices(pathData) {
563
622
  // Simplified tangent calculation (handle zero-length arc)
564
623
  const dxa = currentX - prevX;
565
624
  const dya = currentY - prevY;
566
- const arcAngle = (dxa === 0 && dya === 0)
567
- ? (vertices.length > 0 ? vertices[vertices.length - 1].tangentOut : 0)
568
- : Math.atan2(dya, dxa);
625
+ const arcAngle =
626
+ dxa === 0 && dya === 0
627
+ ? vertices.length > 0
628
+ ? vertices[vertices.length - 1].tangentOut
629
+ : 0
630
+ : Math.atan2(dya, dxa);
569
631
 
570
632
  // Update previous vertex's outgoing tangent
571
633
  if (vertices.length > 0) {
@@ -591,9 +653,12 @@ export function getPathVertices(pathData) {
591
653
  // Calculate tangent from last point to start (handle zero-length close)
592
654
  const dxz = currentX - prevX;
593
655
  const dyz = currentY - prevY;
594
- const closeAngle = (dxz === 0 && dyz === 0)
595
- ? (vertices.length > 0 ? vertices[vertices.length - 1].tangentOut : 0)
596
- : Math.atan2(dyz, dxz);
656
+ const closeAngle =
657
+ dxz === 0 && dyz === 0
658
+ ? vertices.length > 0
659
+ ? vertices[vertices.length - 1].tangentOut
660
+ : 0
661
+ : Math.atan2(dyz, dxz);
597
662
 
598
663
  // Update previous vertex's outgoing tangent
599
664
  if (vertices.length > 0) {
@@ -622,14 +687,14 @@ export function getPathVertices(pathData) {
622
687
  */
623
688
  export function parsePathCommands(pathData) {
624
689
  // Validate pathData parameter
625
- if (typeof pathData !== 'string') {
626
- throw new Error('parsePathCommands: pathData must be a string');
690
+ if (typeof pathData !== "string") {
691
+ throw new Error("parsePathCommands: pathData must be a string");
627
692
  }
628
693
 
629
694
  const commands = [];
630
695
 
631
696
  // Handle empty path data
632
- if (pathData.trim() === '') {
697
+ if (pathData.trim() === "") {
633
698
  return commands;
634
699
  }
635
700
 
@@ -675,11 +740,15 @@ export function parsePathCommands(pathData) {
675
740
  // Helper to safely parse token with bounds checking
676
741
  const parseToken = (index, name) => {
677
742
  if (index >= tokens.length) {
678
- throw new Error(`parsePathCommands: missing ${name} parameter at token ${index}`);
743
+ throw new Error(
744
+ `parsePathCommands: missing ${name} parameter at token ${index}`,
745
+ );
679
746
  }
680
747
  const value = parseFloat(tokens[index]);
681
748
  if (isNaN(value) || !isFinite(value)) {
682
- throw new Error(`parsePathCommands: invalid ${name} value "${tokens[index]}" at token ${index}`);
749
+ throw new Error(
750
+ `parsePathCommands: invalid ${name} value "${tokens[index]}" at token ${index}`,
751
+ );
683
752
  }
684
753
  return value;
685
754
  };
@@ -690,8 +759,8 @@ export function parsePathCommands(pathData) {
690
759
  switch (cmdType.toUpperCase()) {
691
760
  case "M": {
692
761
  // moveto - requires 2 parameters (x, y)
693
- const mx = parseToken(i + 1, 'M.x');
694
- const my = parseToken(i + 2, 'M.y');
762
+ const mx = parseToken(i + 1, "M.x");
763
+ const my = parseToken(i + 2, "M.y");
695
764
  commands.push({
696
765
  type: "M",
697
766
  x: cmdType === "M" ? mx : currentX + mx,
@@ -705,8 +774,8 @@ export function parsePathCommands(pathData) {
705
774
 
706
775
  case "L": {
707
776
  // lineto - requires 2 parameters (x, y)
708
- const lx = parseToken(i + 1, 'L.x');
709
- const ly = parseToken(i + 2, 'L.y');
777
+ const lx = parseToken(i + 1, "L.x");
778
+ const ly = parseToken(i + 2, "L.y");
710
779
  commands.push({
711
780
  type: "L",
712
781
  x: cmdType === "L" ? lx : currentX + lx,
@@ -720,7 +789,7 @@ export function parsePathCommands(pathData) {
720
789
 
721
790
  case "H": {
722
791
  // horizontal lineto - requires 1 parameter (x)
723
- const hx = parseToken(i + 1, 'H.x');
792
+ const hx = parseToken(i + 1, "H.x");
724
793
  commands.push({
725
794
  type: "L",
726
795
  x: cmdType === "H" ? hx : currentX + hx,
@@ -733,7 +802,7 @@ export function parsePathCommands(pathData) {
733
802
 
734
803
  case "V": {
735
804
  // vertical lineto - requires 1 parameter (y)
736
- const vy = parseToken(i + 1, 'V.y');
805
+ const vy = parseToken(i + 1, "V.y");
737
806
  commands.push({
738
807
  type: "L",
739
808
  x: currentX,
@@ -746,12 +815,12 @@ export function parsePathCommands(pathData) {
746
815
 
747
816
  case "C": {
748
817
  // cubic bezier - requires 6 parameters (x1, y1, x2, y2, x, y)
749
- const c1x = parseToken(i + 1, 'C.x1');
750
- const c1y = parseToken(i + 2, 'C.y1');
751
- const c2x = parseToken(i + 3, 'C.x2');
752
- const c2y = parseToken(i + 4, 'C.y2');
753
- const cx = parseToken(i + 5, 'C.x');
754
- const cy = parseToken(i + 6, 'C.y');
818
+ const c1x = parseToken(i + 1, "C.x1");
819
+ const c1y = parseToken(i + 2, "C.y1");
820
+ const c2x = parseToken(i + 3, "C.x2");
821
+ const c2y = parseToken(i + 4, "C.y2");
822
+ const cx = parseToken(i + 5, "C.x");
823
+ const cy = parseToken(i + 6, "C.y");
755
824
  commands.push({
756
825
  type: "C",
757
826
  x1: cmdType === "C" ? c1x : currentX + c1x,
@@ -769,10 +838,10 @@ export function parsePathCommands(pathData) {
769
838
 
770
839
  case "Q": {
771
840
  // quadratic bezier - requires 4 parameters (x1, y1, x, y)
772
- const q1x = parseToken(i + 1, 'Q.x1');
773
- const q1y = parseToken(i + 2, 'Q.y1');
774
- const qx = parseToken(i + 3, 'Q.x');
775
- const qy = parseToken(i + 4, 'Q.y');
841
+ const q1x = parseToken(i + 1, "Q.x1");
842
+ const q1y = parseToken(i + 2, "Q.y1");
843
+ const qx = parseToken(i + 3, "Q.x");
844
+ const qy = parseToken(i + 4, "Q.y");
776
845
  commands.push({
777
846
  type: "Q",
778
847
  x1: cmdType === "Q" ? q1x : currentX + q1x,
@@ -788,9 +857,9 @@ export function parsePathCommands(pathData) {
788
857
 
789
858
  case "A": {
790
859
  // arc - requires 7 parameters (rx, ry, rotation, largeArc, sweep, x, y)
791
- const rx = parseToken(i + 1, 'A.rx');
792
- const ry = parseToken(i + 2, 'A.ry');
793
- const xAxisRotation = parseToken(i + 3, 'A.rotation');
860
+ const rx = parseToken(i + 1, "A.rx");
861
+ const ry = parseToken(i + 2, "A.ry");
862
+ const xAxisRotation = parseToken(i + 3, "A.rotation");
794
863
  // Flags must be 0 or 1
795
864
  if (i + 4 >= tokens.length || i + 5 >= tokens.length) {
796
865
  throw new Error(`parsePathCommands: missing arc flag parameters`);
@@ -800,8 +869,8 @@ export function parsePathCommands(pathData) {
800
869
  if (isNaN(largeArcFlag) || isNaN(sweepFlag)) {
801
870
  throw new Error(`parsePathCommands: invalid arc flag values`);
802
871
  }
803
- const ax = parseToken(i + 6, 'A.x');
804
- const ay = parseToken(i + 7, 'A.y');
872
+ const ax = parseToken(i + 6, "A.x");
873
+ const ay = parseToken(i + 7, "A.y");
805
874
  commands.push({
806
875
  type: "A",
807
876
  rx,
@@ -864,9 +933,9 @@ export function parsePathCommands(pathData) {
864
933
  */
865
934
  export function resolveMarkers(pathElement, defsMap) {
866
935
  // Validate required parameters
867
- if (!pathElement) throw new Error('resolveMarkers: pathElement is required');
868
- if (!defsMap || typeof defsMap !== 'object') {
869
- throw new Error('resolveMarkers: defsMap must be an object');
936
+ if (!pathElement) throw new Error("resolveMarkers: pathElement is required");
937
+ if (!defsMap || typeof defsMap !== "object") {
938
+ throw new Error("resolveMarkers: defsMap must be an object");
870
939
  }
871
940
 
872
941
  const instances = [];
@@ -881,7 +950,7 @@ export function resolveMarkers(pathElement, defsMap) {
881
950
  const strokeWidth = parseFloat(strokeWidthStr);
882
951
  // Validate strokeWidth is a positive number
883
952
  if (isNaN(strokeWidth) || strokeWidth <= 0) {
884
- throw new Error('resolveMarkers: stroke-width must be a positive number');
953
+ throw new Error("resolveMarkers: stroke-width must be a positive number");
885
954
  }
886
955
 
887
956
  // Get path data and extract vertices
@@ -1012,18 +1081,25 @@ export function resolveMarkers(pathElement, defsMap) {
1012
1081
  */
1013
1082
  export function markerToPolygons(markerInstance, options = {}) {
1014
1083
  // Validate markerInstance parameter
1015
- if (!markerInstance) throw new Error('markerToPolygons: markerInstance is required');
1016
- if (!markerInstance.markerDef) throw new Error('markerToPolygons: markerInstance.markerDef is required');
1017
- if (!markerInstance.transform) throw new Error('markerToPolygons: markerInstance.transform is required');
1084
+ if (!markerInstance)
1085
+ throw new Error("markerToPolygons: markerInstance is required");
1086
+ if (!markerInstance.markerDef)
1087
+ throw new Error("markerToPolygons: markerInstance.markerDef is required");
1088
+ if (!markerInstance.transform)
1089
+ throw new Error("markerToPolygons: markerInstance.transform is required");
1018
1090
 
1019
1091
  const { precision = 2, curveSegments = 10 } = options;
1020
1092
 
1021
1093
  // Validate options
1022
- if (typeof precision !== 'number' || precision < 0) {
1023
- throw new Error('markerToPolygons: precision must be a non-negative number');
1094
+ if (typeof precision !== "number" || precision < 0) {
1095
+ throw new Error(
1096
+ "markerToPolygons: precision must be a non-negative number",
1097
+ );
1024
1098
  }
1025
- if (typeof curveSegments !== 'number' || curveSegments <= 0) {
1026
- throw new Error('markerToPolygons: curveSegments must be a positive number');
1099
+ if (typeof curveSegments !== "number" || curveSegments <= 0) {
1100
+ throw new Error(
1101
+ "markerToPolygons: curveSegments must be a positive number",
1102
+ );
1027
1103
  }
1028
1104
 
1029
1105
  const polygons = [];
@@ -1031,7 +1107,7 @@ export function markerToPolygons(markerInstance, options = {}) {
1031
1107
 
1032
1108
  // Validate markerDef has children array
1033
1109
  if (!Array.isArray(markerDef.children)) {
1034
- throw new Error('markerToPolygons: markerDef.children must be an array');
1110
+ throw new Error("markerToPolygons: markerDef.children must be an array");
1035
1111
  }
1036
1112
 
1037
1113
  // Process each child element
@@ -1112,11 +1188,11 @@ export function markerToPolygons(markerInstance, options = {}) {
1112
1188
  */
1113
1189
  export function pathToPoints(pathData, segments = 10) {
1114
1190
  // Validate parameters
1115
- if (typeof pathData !== 'string') {
1116
- throw new Error('pathToPoints: pathData must be a string');
1191
+ if (typeof pathData !== "string") {
1192
+ throw new Error("pathToPoints: pathData must be a string");
1117
1193
  }
1118
- if (typeof segments !== 'number' || segments <= 0) {
1119
- throw new Error('pathToPoints: segments must be a positive number');
1194
+ if (typeof segments !== "number" || segments <= 0) {
1195
+ throw new Error("pathToPoints: segments must be a positive number");
1120
1196
  }
1121
1197
 
1122
1198
  const points = [];
@@ -1197,17 +1273,17 @@ export function pathToPoints(pathData, segments = 10) {
1197
1273
  */
1198
1274
  export function circleToPoints(cx, cy, r, segments = 32) {
1199
1275
  // Validate parameters
1200
- if (typeof cx !== 'number' || !isFinite(cx)) {
1201
- throw new Error('circleToPoints: cx must be a finite number');
1276
+ if (typeof cx !== "number" || !isFinite(cx)) {
1277
+ throw new Error("circleToPoints: cx must be a finite number");
1202
1278
  }
1203
- if (typeof cy !== 'number' || !isFinite(cy)) {
1204
- throw new Error('circleToPoints: cy must be a finite number');
1279
+ if (typeof cy !== "number" || !isFinite(cy)) {
1280
+ throw new Error("circleToPoints: cy must be a finite number");
1205
1281
  }
1206
- if (typeof r !== 'number' || !isFinite(r) || r < 0) {
1207
- throw new Error('circleToPoints: r must be a non-negative finite number');
1282
+ if (typeof r !== "number" || !isFinite(r) || r < 0) {
1283
+ throw new Error("circleToPoints: r must be a non-negative finite number");
1208
1284
  }
1209
- if (typeof segments !== 'number' || segments <= 0) {
1210
- throw new Error('circleToPoints: segments must be a positive number');
1285
+ if (typeof segments !== "number" || segments <= 0) {
1286
+ throw new Error("circleToPoints: segments must be a positive number");
1211
1287
  }
1212
1288
 
1213
1289
  const points = [];
@@ -1233,20 +1309,20 @@ export function circleToPoints(cx, cy, r, segments = 32) {
1233
1309
  */
1234
1310
  export function ellipseToPoints(cx, cy, rx, ry, segments = 32) {
1235
1311
  // Validate parameters
1236
- if (typeof cx !== 'number' || !isFinite(cx)) {
1237
- throw new Error('ellipseToPoints: cx must be a finite number');
1312
+ if (typeof cx !== "number" || !isFinite(cx)) {
1313
+ throw new Error("ellipseToPoints: cx must be a finite number");
1238
1314
  }
1239
- if (typeof cy !== 'number' || !isFinite(cy)) {
1240
- throw new Error('ellipseToPoints: cy must be a finite number');
1315
+ if (typeof cy !== "number" || !isFinite(cy)) {
1316
+ throw new Error("ellipseToPoints: cy must be a finite number");
1241
1317
  }
1242
- if (typeof rx !== 'number' || !isFinite(rx) || rx < 0) {
1243
- throw new Error('ellipseToPoints: rx must be a non-negative finite number');
1318
+ if (typeof rx !== "number" || !isFinite(rx) || rx < 0) {
1319
+ throw new Error("ellipseToPoints: rx must be a non-negative finite number");
1244
1320
  }
1245
- if (typeof ry !== 'number' || !isFinite(ry) || ry < 0) {
1246
- throw new Error('ellipseToPoints: ry must be a non-negative finite number');
1321
+ if (typeof ry !== "number" || !isFinite(ry) || ry < 0) {
1322
+ throw new Error("ellipseToPoints: ry must be a non-negative finite number");
1247
1323
  }
1248
- if (typeof segments !== 'number' || segments <= 0) {
1249
- throw new Error('ellipseToPoints: segments must be a positive number');
1324
+ if (typeof segments !== "number" || segments <= 0) {
1325
+ throw new Error("ellipseToPoints: segments must be a positive number");
1250
1326
  }
1251
1327
 
1252
1328
  const points = [];
@@ -1268,8 +1344,8 @@ export function ellipseToPoints(cx, cy, rx, ry, segments = 32) {
1268
1344
  */
1269
1345
  export function parsePoints(pointsStr) {
1270
1346
  // Validate parameter
1271
- if (typeof pointsStr !== 'string') {
1272
- throw new Error('parsePoints: pointsStr must be a string');
1347
+ if (typeof pointsStr !== "string") {
1348
+ throw new Error("parsePoints: pointsStr must be a string");
1273
1349
  }
1274
1350
 
1275
1351
  const points = [];
@@ -1277,11 +1353,13 @@ export function parsePoints(pointsStr) {
1277
1353
  .trim()
1278
1354
  .split(/[\s,]+/)
1279
1355
  .map(Number)
1280
- .filter(n => !isNaN(n) && isFinite(n)); // Filter out invalid numbers
1356
+ .filter((n) => !isNaN(n) && isFinite(n)); // Filter out invalid numbers
1281
1357
 
1282
1358
  // Ensure we have an even number of coordinates
1283
1359
  if (coords.length % 2 !== 0) {
1284
- throw new Error('parsePoints: pointsStr must contain an even number of valid coordinates');
1360
+ throw new Error(
1361
+ "parsePoints: pointsStr must contain an even number of valid coordinates",
1362
+ );
1285
1363
  }
1286
1364
 
1287
1365
  for (let i = 0; i < coords.length; i += 2) {
@@ -1310,10 +1388,12 @@ export function parsePoints(pointsStr) {
1310
1388
  export function markersToPathData(markerInstances, precision = 2) {
1311
1389
  // Validate parameters
1312
1390
  if (!Array.isArray(markerInstances)) {
1313
- throw new Error('markersToPathData: markerInstances must be an array');
1391
+ throw new Error("markersToPathData: markerInstances must be an array");
1314
1392
  }
1315
- if (typeof precision !== 'number' || precision < 0) {
1316
- throw new Error('markersToPathData: precision must be a non-negative number');
1393
+ if (typeof precision !== "number" || precision < 0) {
1394
+ throw new Error(
1395
+ "markersToPathData: precision must be a non-negative number",
1396
+ );
1317
1397
  }
1318
1398
 
1319
1399
  const pathParts = [];