@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.
- package/bin/svg-matrix.js +7 -6
- package/bin/svgm.js +109 -40
- package/dist/svg-matrix.min.js +7 -7
- package/dist/svg-toolbox.min.js +148 -228
- package/dist/svgm.min.js +152 -232
- package/dist/version.json +5 -5
- package/package.json +1 -1
- package/scripts/postinstall.js +72 -41
- package/scripts/test-postinstall.js +18 -16
- package/scripts/version-sync.js +78 -60
- package/src/animation-optimization.js +190 -98
- package/src/animation-references.js +11 -3
- package/src/arc-length.js +23 -20
- package/src/bezier-analysis.js +9 -13
- package/src/bezier-intersections.js +18 -4
- package/src/browser-verify.js +35 -8
- package/src/clip-path-resolver.js +285 -114
- package/src/convert-path-data.js +20 -8
- package/src/css-specificity.js +33 -9
- package/src/douglas-peucker.js +272 -141
- package/src/geometry-to-path.js +79 -22
- package/src/gjk-collision.js +287 -126
- package/src/index.js +56 -21
- package/src/inkscape-support.js +122 -101
- package/src/logger.js +43 -27
- package/src/marker-resolver.js +201 -121
- package/src/mask-resolver.js +231 -98
- package/src/matrix.js +9 -5
- package/src/mesh-gradient.js +22 -14
- package/src/off-canvas-detection.js +53 -17
- package/src/path-optimization.js +356 -171
- package/src/path-simplification.js +671 -256
- package/src/pattern-resolver.js +1 -3
- package/src/polygon-clip.js +396 -78
- package/src/svg-boolean-ops.js +90 -23
- package/src/svg-collections.js +1546 -667
- package/src/svg-flatten.js +152 -38
- package/src/svg-matrix-lib.js +2 -2
- package/src/svg-parser.js +5 -1
- package/src/svg-rendering-context.js +3 -1
- package/src/svg-toolbox-lib.js +2 -2
- package/src/svg-toolbox.js +99 -457
- package/src/svg-validation-data.js +513 -345
- package/src/svg2-polyfills.js +156 -93
- package/src/svgm-lib.js +8 -4
- package/src/transform-optimization.js +168 -51
- package/src/transforms2d.js +73 -40
- package/src/transforms3d.js +34 -27
- package/src/use-symbol-resolver.js +175 -76
- package/src/vector.js +80 -44
- package/src/vendor/inkscape-hatch-polyfill.js +143 -108
- package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
- package/src/vendor/inkscape-mesh-polyfill.js +953 -766
- package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
- package/src/verification.js +3 -4
package/src/mesh-gradient.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1035
|
-
|
|
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
|
-
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
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 (
|
|
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 (
|
|
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(
|
|
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 (
|
|
783
|
-
|
|
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(
|
|
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 (
|
|
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
|
|