@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
@@ -134,7 +134,9 @@ export function color(r, g, b, a = 255) {
134
134
  */
135
135
  export function parseColor(colorStr, opacity = 1) {
136
136
  if (!colorStr || typeof colorStr !== "string") {
137
- throw new Error(`parseColor: colorStr must be a non-empty string, got ${colorStr}`);
137
+ throw new Error(
138
+ `parseColor: colorStr must be a non-empty string, got ${colorStr}`,
139
+ );
138
140
  }
139
141
  if (!Number.isFinite(opacity))
140
142
  throw new Error(`parseColor: opacity must be finite, got ${opacity}`);
@@ -397,7 +399,9 @@ export function evalCubicBezier(p0, p1, p2, p3, t) {
397
399
  throw new Error(`evalCubicBezier: t must be finite, got ${t}`);
398
400
  // Warn if t is outside [0,1] - extrapolation beyond curve endpoints
399
401
  if (tDecimal.lt(0) || tDecimal.gt(1)) {
400
- console.warn(`evalCubicBezier: t=${t} is outside [0,1], extrapolating beyond curve`);
402
+ console.warn(
403
+ `evalCubicBezier: t=${t} is outside [0,1], extrapolating beyond curve`,
404
+ );
401
405
  }
402
406
 
403
407
  const mt = D(1).minus(tDecimal);
@@ -605,16 +609,24 @@ export class CoonsPatch {
605
609
  Math.abs(Number(p1.y) - Number(p2.y)) < tolerance;
606
610
 
607
611
  if (!pointsEqual(top[0], left[0])) {
608
- console.warn("CoonsPatch: top-left corner mismatch - top[0] should equal left[0]");
612
+ console.warn(
613
+ "CoonsPatch: top-left corner mismatch - top[0] should equal left[0]",
614
+ );
609
615
  }
610
616
  if (!pointsEqual(top[3], right[0])) {
611
- console.warn("CoonsPatch: top-right corner mismatch - top[3] should equal right[0]");
617
+ console.warn(
618
+ "CoonsPatch: top-right corner mismatch - top[3] should equal right[0]",
619
+ );
612
620
  }
613
621
  if (!pointsEqual(bottom[0], left[3])) {
614
- console.warn("CoonsPatch: bottom-left corner mismatch - bottom[0] should equal left[3]");
622
+ console.warn(
623
+ "CoonsPatch: bottom-left corner mismatch - bottom[0] should equal left[3]",
624
+ );
615
625
  }
616
626
  if (!pointsEqual(bottom[3], right[3])) {
617
- console.warn("CoonsPatch: bottom-right corner mismatch - bottom[3] should equal right[3]");
627
+ console.warn(
628
+ "CoonsPatch: bottom-right corner mismatch - bottom[3] should equal right[3]",
629
+ );
618
630
  }
619
631
 
620
632
  this.top = top;
@@ -1031,8 +1043,8 @@ export function parseMeshGradient(meshGradientDef) {
1031
1043
  if (meshRows.length > 0) {
1032
1044
  throw new Error(
1033
1045
  "parseMeshGradient: Full mesh parsing not yet implemented. " +
1034
- "This stub only handles empty meshGradient definitions. " +
1035
- "To parse actual mesh data, implement path parsing and patch construction logic."
1046
+ "This stub only handles empty meshGradient definitions. " +
1047
+ "To parse actual mesh data, implement path parsing and patch construction logic.",
1036
1048
  );
1037
1049
  }
1038
1050
 
@@ -1305,12 +1317,8 @@ function renderPatchQuad(patch, imageData, width, height) {
1305
1317
  const vDenom = bbox.maxY.minus(bbox.minY);
1306
1318
 
1307
1319
  // For zero-size dimensions, treat as centered at u=0.5 or v=0.5
1308
- const u = uDenom.isZero()
1309
- ? D(0.5)
1310
- : D(x).minus(bbox.minX).div(uDenom);
1311
- const v = vDenom.isZero()
1312
- ? D(0.5)
1313
- : D(y).minus(bbox.minY).div(vDenom);
1320
+ const u = uDenom.isZero() ? D(0.5) : D(x).minus(bbox.minX).div(uDenom);
1321
+ const v = vDenom.isZero() ? D(0.5) : D(y).minus(bbox.minY).div(vDenom);
1314
1322
 
1315
1323
  if (u.gte(0) && u.lte(1) && v.gte(0) && v.lte(1)) {
1316
1324
  const { color: patchColor } = patch.evaluate(u, v);
@@ -221,14 +221,10 @@ function createBBox(minX, minY, maxX, maxY) {
221
221
 
222
222
  // Validate bounds are not inverted (WHY: catch logic errors early)
223
223
  if (dMaxX.lessThan(dMinX)) {
224
- throw new Error(
225
- `createBBox: maxX (${dMaxX}) must be >= minX (${dMinX})`,
226
- );
224
+ throw new Error(`createBBox: maxX (${dMaxX}) must be >= minX (${dMinX})`);
227
225
  }
228
226
  if (dMaxY.lessThan(dMinY)) {
229
- throw new Error(
230
- `createBBox: maxY (${dMaxY}) must be >= minY (${dMinY})`,
231
- );
227
+ throw new Error(`createBBox: maxY (${dMaxY}) must be >= minY (${dMinY})`);
232
228
  }
233
229
 
234
230
  return {
@@ -413,7 +409,9 @@ function sampleQuadraticBezier(x0, y0, x1, y1, x2, y2, samples = 20) {
413
409
  function pointInBBox(pt, bbox, tolerance = DEFAULT_TOLERANCE) {
414
410
  // Validate point parameter (WHY: prevent null dereference)
415
411
  if (!pt || typeof pt !== "object" || pt.x == null || pt.y == null) {
416
- throw new Error("pointInBBox: pt must be an object with x and y properties");
412
+ throw new Error(
413
+ "pointInBBox: pt must be an object with x and y properties",
414
+ );
417
415
  }
418
416
 
419
417
  // Validate bbox parameter (WHY: prevent null dereference)
@@ -479,7 +477,12 @@ export function pathBoundingBox(pathCommands) {
479
477
 
480
478
  for (const cmd of pathCommands) {
481
479
  // Validate command object and type property (WHY: prevent null dereference and type errors)
482
- if (!cmd || typeof cmd !== "object" || !cmd.type || typeof cmd.type !== "string") {
480
+ if (
481
+ !cmd ||
482
+ typeof cmd !== "object" ||
483
+ !cmd.type ||
484
+ typeof cmd.type !== "string"
485
+ ) {
483
486
  throw new Error(
484
487
  "pathBoundingBox: each command must be an object with a string type property",
485
488
  );
@@ -494,7 +497,9 @@ export function pathBoundingBox(pathCommands) {
494
497
  {
495
498
  // Validate required properties (WHY: prevent accessing undefined properties)
496
499
  if (cmd.x == null || cmd.y == null) {
497
- throw new Error("pathBoundingBox: M command requires x and y properties");
500
+ throw new Error(
501
+ "pathBoundingBox: M command requires x and y properties",
502
+ );
498
503
  }
499
504
 
500
505
  // BUG 1 FIX: Handle relative coordinates
@@ -521,7 +526,9 @@ export function pathBoundingBox(pathCommands) {
521
526
  {
522
527
  // Validate required properties (WHY: prevent accessing undefined properties)
523
528
  if (cmd.x == null || cmd.y == null) {
524
- throw new Error("pathBoundingBox: L command requires x and y properties");
529
+ throw new Error(
530
+ "pathBoundingBox: L command requires x and y properties",
531
+ );
525
532
  }
526
533
 
527
534
  // BUG 1 FIX: Handle relative coordinates
@@ -639,7 +646,12 @@ export function pathBoundingBox(pathCommands) {
639
646
  case "S": // Smooth cubic Bezier
640
647
  {
641
648
  // Validate required properties (WHY: prevent accessing undefined properties)
642
- if (cmd.x2 == null || cmd.y2 == null || cmd.x == null || cmd.y == null) {
649
+ if (
650
+ cmd.x2 == null ||
651
+ cmd.y2 == null ||
652
+ cmd.x == null ||
653
+ cmd.y == null
654
+ ) {
643
655
  throw new Error(
644
656
  "pathBoundingBox: S command requires x2, y2, x, y properties",
645
657
  );
@@ -692,7 +704,12 @@ export function pathBoundingBox(pathCommands) {
692
704
  case "Q": // Quadratic Bezier
693
705
  {
694
706
  // Validate required properties (WHY: prevent accessing undefined properties)
695
- if (cmd.x1 == null || cmd.y1 == null || cmd.x == null || cmd.y == null) {
707
+ if (
708
+ cmd.x1 == null ||
709
+ cmd.y1 == null ||
710
+ cmd.x == null ||
711
+ cmd.y == null
712
+ ) {
696
713
  throw new Error(
697
714
  "pathBoundingBox: Q command requires x1, y1, x, y properties",
698
715
  );
@@ -733,7 +750,9 @@ export function pathBoundingBox(pathCommands) {
733
750
  {
734
751
  // Validate required properties (WHY: prevent accessing undefined properties)
735
752
  if (cmd.x == null || cmd.y == null) {
736
- throw new Error("pathBoundingBox: T command requires x and y properties");
753
+ throw new Error(
754
+ "pathBoundingBox: T command requires x and y properties",
755
+ );
737
756
  }
738
757
 
739
758
  // BUG 1 FIX: Handle relative coordinates
@@ -779,8 +798,15 @@ export function pathBoundingBox(pathCommands) {
779
798
  case "A": // Arc (proper extrema calculation)
780
799
  {
781
800
  // Validate required properties (WHY: prevent accessing undefined properties)
782
- if (cmd.x == null || cmd.y == null || cmd.rx == null || cmd.ry == null) {
783
- throw new Error("pathBoundingBox: A command requires x, y, rx, ry properties");
801
+ if (
802
+ cmd.x == null ||
803
+ cmd.y == null ||
804
+ cmd.rx == null ||
805
+ cmd.ry == null
806
+ ) {
807
+ throw new Error(
808
+ "pathBoundingBox: A command requires x, y, rx, ry properties",
809
+ );
784
810
  }
785
811
 
786
812
  // BUG 4 FIX: Proper arc bounding box calculation with extrema points
@@ -1003,7 +1029,12 @@ export function shapeBoundingBox(shape) {
1003
1029
  // Horizontal line
1004
1030
  bbox = createBBox(cx.minus(rx), cy, cx.plus(rx), cy);
1005
1031
  } else {
1006
- bbox = createBBox(cx.minus(rx), cy.minus(ry), cx.plus(rx), cy.plus(ry));
1032
+ bbox = createBBox(
1033
+ cx.minus(rx),
1034
+ cy.minus(ry),
1035
+ cx.plus(rx),
1036
+ cy.plus(ry),
1037
+ );
1007
1038
  }
1008
1039
 
1009
1040
  // Sample points around ellipse
@@ -1522,7 +1553,12 @@ export function clipPathToViewBox(pathCommands, viewBox) {
1522
1553
 
1523
1554
  for (const cmd of pathCommands) {
1524
1555
  // Validate command object and type (WHY: prevent null dereference)
1525
- if (!cmd || typeof cmd !== "object" || !cmd.type || typeof cmd.type !== "string") {
1556
+ if (
1557
+ !cmd ||
1558
+ typeof cmd !== "object" ||
1559
+ !cmd.type ||
1560
+ typeof cmd.type !== "string"
1561
+ ) {
1526
1562
  continue; // Skip invalid commands during clipping (WHY: graceful degradation)
1527
1563
  }
1528
1564