@pixerate/editor 0.108.0 → 0.110.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/dist/animation/index.cjs +5 -5
- package/dist/animation/index.cjs.map +1 -1
- package/dist/animation/index.js +9 -9
- package/dist/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +2 -1
- package/dist/animation-editor/index.d.ts +2 -1
- package/dist/animation-editor/index.js +29 -29
- package/dist/blending-DXl06NSx.d.ts +486 -0
- package/dist/blending-aOE6Y3UE.d.cts +486 -0
- package/dist/canvas/index.cjs +27 -27
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.js +11 -11
- package/dist/{chunk-2FGRTYJN.cjs → chunk-477UVMNR.cjs} +3 -3
- package/dist/{chunk-2FGRTYJN.cjs.map → chunk-477UVMNR.cjs.map} +1 -1
- package/dist/chunk-7VOHOPLW.cjs +1136 -0
- package/dist/chunk-7VOHOPLW.cjs.map +1 -0
- package/dist/{chunk-HUQ7EHVI.js → chunk-BLWCAQCW.js} +723 -1975
- package/dist/chunk-BLWCAQCW.js.map +1 -0
- package/dist/{chunk-SOROZ2BF.js → chunk-DMRSJBJF.js} +1939 -318
- package/dist/chunk-DMRSJBJF.js.map +1 -0
- package/dist/chunk-FTBZPI77.cjs +1 -0
- package/dist/chunk-FTBZPI77.cjs.map +1 -0
- package/dist/{chunk-WMBIJCHA.js → chunk-HNS7UHCM.js} +5 -1
- package/dist/{chunk-WMBIJCHA.js.map → chunk-HNS7UHCM.js.map} +1 -1
- package/dist/chunk-JLYX4V57.cjs +2001 -0
- package/dist/chunk-JLYX4V57.cjs.map +1 -0
- package/dist/chunk-KB2YBCVS.js +2001 -0
- package/dist/chunk-KB2YBCVS.js.map +1 -0
- package/dist/{chunk-G4BIYE6R.js → chunk-LQEEDHOP.js} +40 -2
- package/dist/chunk-LQEEDHOP.js.map +1 -0
- package/dist/{chunk-FRD3FUXI.cjs → chunk-MGL4U5WA.cjs} +2144 -523
- package/dist/chunk-MGL4U5WA.cjs.map +1 -0
- package/dist/{chunk-T3QZ6S47.cjs → chunk-POGBUYWE.cjs} +131 -93
- package/dist/chunk-POGBUYWE.cjs.map +1 -0
- package/dist/chunk-VKK5VS2T.js +1 -0
- package/dist/{chunk-UTEVPQTS.cjs → chunk-W3GXSUSQ.cjs} +746 -1998
- package/dist/chunk-W3GXSUSQ.cjs.map +1 -0
- package/dist/{chunk-SZ6KMZNM.cjs → chunk-XIOMMGPD.cjs} +6 -2
- package/dist/chunk-XIOMMGPD.cjs.map +1 -0
- package/dist/{chunk-JK6M6V7G.js → chunk-Z3YWVUWT.js} +4 -4
- package/dist/{chunk-3PHA3UKI.js → chunk-Z4BC6M74.js} +523 -121
- package/dist/chunk-Z4BC6M74.js.map +1 -0
- package/dist/{export-a9bnF7Cl.d.ts → export-CO2ryu3I.d.ts} +419 -18
- package/dist/{export-JGWQEPJn.d.cts → export-DRiLzP_j.d.cts} +419 -18
- package/dist/image-editor/index.cjs +1665 -1113
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +78 -14
- package/dist/image-editor/index.d.ts +78 -14
- package/dist/image-editor/index.js +843 -291
- package/dist/image-editor/index.js.map +1 -1
- package/dist/paint/index.cjs +28 -4
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +3 -89
- package/dist/paint/index.d.ts +3 -89
- package/dist/paint/index.js +27 -3
- package/dist/paint-editor/index.cjs +1056 -287
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +304 -22
- package/dist/paint-editor/index.d.ts +304 -22
- package/dist/paint-editor/index.js +852 -83
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +7 -3
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.d.cts +3 -129
- package/dist/raster/index.d.ts +3 -129
- package/dist/raster/index.js +6 -2
- package/dist/{compositor-D92URMlm.d.cts → render-BEriFuqK.d.cts} +136 -2
- package/dist/{compositor-Kt_M4ruo.d.ts → render-tjzKaik-.d.ts} +136 -2
- package/dist/{surface-CkKOHGPm.d.cts → surface-C8RRg_Bh.d.cts} +109 -1
- package/dist/{surface-CkKOHGPm.d.ts → surface-C8RRg_Bh.d.ts} +109 -1
- package/dist/{svg-SseJTIrA.d.ts → svg-D_cfkhlB.d.cts} +3 -629
- package/dist/{svg-ClVIG4T7.d.cts → svg-wIaKLrU0.d.ts} +3 -629
- package/dist/types-DtL_qLFz.d.ts +630 -0
- package/dist/types-DyQq-WPY.d.cts +630 -0
- package/dist/vector/index.cjs +563 -563
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +4 -2
- package/dist/vector/index.d.ts +4 -2
- package/dist/vector/index.js +69 -69
- package/dist/video-editor/index.cjs +3 -3
- package/dist/video-editor/index.js +2 -2
- package/package.json +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +49 -13
- package/dist/chunk-3PHA3UKI.js.map +0 -1
- package/dist/chunk-6BU5WU4R.cjs +0 -1
- package/dist/chunk-6BU5WU4R.cjs.map +0 -1
- package/dist/chunk-DWGZUSES.cjs +0 -694
- package/dist/chunk-DWGZUSES.cjs.map +0 -1
- package/dist/chunk-FRD3FUXI.cjs.map +0 -1
- package/dist/chunk-G4BIYE6R.js.map +0 -1
- package/dist/chunk-HUFQD4CB.cjs +0 -734
- package/dist/chunk-HUFQD4CB.cjs.map +0 -1
- package/dist/chunk-HUQ7EHVI.js.map +0 -1
- package/dist/chunk-KKREERP2.js +0 -694
- package/dist/chunk-KKREERP2.js.map +0 -1
- package/dist/chunk-SOROZ2BF.js.map +0 -1
- package/dist/chunk-SZ6KMZNM.cjs.map +0 -1
- package/dist/chunk-T3QZ6S47.cjs.map +0 -1
- package/dist/chunk-UTEVPQTS.cjs.map +0 -1
- package/dist/chunk-XYBJKUAU.js +0 -1
- package/dist/mixer-5ziHU8OS.d.cts +0 -282
- package/dist/mixer-DNqiYXYQ.d.ts +0 -282
- /package/dist/{chunk-XYBJKUAU.js.map → chunk-VKK5VS2T.js.map} +0 -0
- /package/dist/{chunk-JK6M6V7G.js.map → chunk-Z3YWVUWT.js.map} +0 -0
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
fitCubicRun,
|
|
10
10
|
fitCubics,
|
|
11
11
|
flattenChain,
|
|
12
|
-
formatNumber,
|
|
13
12
|
isStraightCubic,
|
|
14
13
|
normalizeBezierPath,
|
|
15
14
|
offsetPath,
|
|
@@ -34,33 +33,6 @@ import {
|
|
|
34
33
|
windingNumber
|
|
35
34
|
} from "./chunk-YCSFS3GK.js";
|
|
36
35
|
import {
|
|
37
|
-
IDENTITY_MATRIX,
|
|
38
|
-
WARP_STYLES,
|
|
39
|
-
WARP_STYLE_LABELS,
|
|
40
|
-
applyMatrix,
|
|
41
|
-
clampMeshCount,
|
|
42
|
-
decomposeRigid,
|
|
43
|
-
evalWarpMesh,
|
|
44
|
-
evenKnots,
|
|
45
|
-
fitWarpMesh,
|
|
46
|
-
identityWarpMesh,
|
|
47
|
-
invertMatrix,
|
|
48
|
-
isIdentityMatrix,
|
|
49
|
-
isValidWarpMesh,
|
|
50
|
-
lerpVec2,
|
|
51
|
-
mapWarpMeshPoints,
|
|
52
|
-
matrixRotation,
|
|
53
|
-
multiplyMatrices,
|
|
54
|
-
resizeWarpMesh,
|
|
55
|
-
rotateMatrix,
|
|
56
|
-
scaleMatrix,
|
|
57
|
-
translateMatrix,
|
|
58
|
-
warpMeshColumns,
|
|
59
|
-
warpMeshRows,
|
|
60
|
-
warpPresetMesh
|
|
61
|
-
} from "./chunk-KKREERP2.js";
|
|
62
|
-
import {
|
|
63
|
-
mixColorsOklab,
|
|
64
36
|
oklabToRgb,
|
|
65
37
|
rgbToOklab
|
|
66
38
|
} from "./chunk-ZRJMJIQU.js";
|
|
@@ -69,9 +41,6 @@ import {
|
|
|
69
41
|
normalizeTokenColor,
|
|
70
42
|
rgbaToHex
|
|
71
43
|
} from "./chunk-TGD52FEZ.js";
|
|
72
|
-
import {
|
|
73
|
-
evaluateEasing
|
|
74
|
-
} from "./chunk-AGR4P4UZ.js";
|
|
75
44
|
|
|
76
45
|
// src/vector/types.ts
|
|
77
46
|
var VECTOR_CORNER_KINDS = ["round", "inverted", "chamfer"];
|
|
@@ -539,12 +508,12 @@ function vectorGradientHandles(g, bounds, toWorld = IDENTITY) {
|
|
|
539
508
|
const p = vectorGradientPoints(g);
|
|
540
509
|
const m = mul(vectorGradientUnitsMatrix(g, bounds), toWorld);
|
|
541
510
|
const f = g.type === "radial" ? unitFocal(g) : null;
|
|
542
|
-
const
|
|
511
|
+
const frame = mul(framePointsMatrix(p), m);
|
|
543
512
|
return {
|
|
544
513
|
start: apply(m, p.start),
|
|
545
514
|
end: apply(m, p.end),
|
|
546
515
|
aspect: isCentredVectorGradient(g.type) ? apply(m, p.width) : null,
|
|
547
|
-
focal: g.type === "radial" ? apply(
|
|
516
|
+
focal: g.type === "radial" ? apply(frame, f?.f ?? { x: 0, y: 0 }) : null
|
|
548
517
|
};
|
|
549
518
|
}
|
|
550
519
|
function withMainAxis(p, start, end) {
|
|
@@ -590,15 +559,15 @@ function moveVectorGradientHandle(g, bounds, handle, to, from = to) {
|
|
|
590
559
|
return set({ width, focal });
|
|
591
560
|
}
|
|
592
561
|
case "focal": {
|
|
593
|
-
const
|
|
594
|
-
const inv = invert(
|
|
562
|
+
const frame = framePointsMatrix(p);
|
|
563
|
+
const inv = invert(frame);
|
|
595
564
|
if (!inv) return pinned;
|
|
596
565
|
let q = apply(inv, to);
|
|
597
566
|
const r = Math.hypot(q.x, q.y);
|
|
598
567
|
if (r < 1e-6) return set({ focal: null });
|
|
599
568
|
const reach = FOCAL_MAX * (1 - p.focalRadius);
|
|
600
569
|
if (r > reach) q = scale(q, reach / r);
|
|
601
|
-
return set({ focal: apply(
|
|
570
|
+
return set({ focal: apply(frame, q) });
|
|
602
571
|
}
|
|
603
572
|
}
|
|
604
573
|
}
|
|
@@ -938,6 +907,65 @@ function applyVectorGradientPatch(g, patch) {
|
|
|
938
907
|
return clean2;
|
|
939
908
|
}
|
|
940
909
|
|
|
910
|
+
// src/geom/affine.ts
|
|
911
|
+
var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
|
|
912
|
+
function multiplyMatrices(a, b) {
|
|
913
|
+
const [a0, a1, a2, a3, a4, a5] = a;
|
|
914
|
+
const [b0, b1, b2, b3, b4, b5] = b;
|
|
915
|
+
return [b0 * a0 + b2 * a1, b1 * a0 + b3 * a1, b0 * a2 + b2 * a3, b1 * a2 + b3 * a3, b0 * a4 + b2 * a5 + b4, b1 * a4 + b3 * a5 + b5];
|
|
916
|
+
}
|
|
917
|
+
var translateMatrix = (dx, dy) => [1, 0, 0, 1, dx, dy];
|
|
918
|
+
function scaleMatrix(sx, sy, origin = { x: 0, y: 0 }) {
|
|
919
|
+
return [sx, 0, 0, sy, origin.x - sx * origin.x, origin.y - sy * origin.y];
|
|
920
|
+
}
|
|
921
|
+
function rotateMatrix(degrees, origin = { x: 0, y: 0 }) {
|
|
922
|
+
const r = degrees * Math.PI / 180;
|
|
923
|
+
const cos = Math.cos(r);
|
|
924
|
+
const sin = Math.sin(r);
|
|
925
|
+
return [cos, sin, -sin, cos, origin.x - cos * origin.x + sin * origin.y, origin.y - sin * origin.x - cos * origin.y];
|
|
926
|
+
}
|
|
927
|
+
function matrixAbout(m, origin) {
|
|
928
|
+
return multiplyMatrices(multiplyMatrices(translateMatrix(-origin.x, -origin.y), m), translateMatrix(origin.x, origin.y));
|
|
929
|
+
}
|
|
930
|
+
function skewMatrix(ax, ay, origin = { x: 0, y: 0 }) {
|
|
931
|
+
const tx = Math.tan(ax * Math.PI / 180);
|
|
932
|
+
const ty = Math.tan(ay * Math.PI / 180);
|
|
933
|
+
return matrixAbout([1, ty, tx, 1, 0, 0], origin);
|
|
934
|
+
}
|
|
935
|
+
function applyMatrix(m, p) {
|
|
936
|
+
return { x: m[0] * p.x + m[2] * p.y + m[4], y: m[1] * p.x + m[3] * p.y + m[5] };
|
|
937
|
+
}
|
|
938
|
+
function isIdentityMatrix(m, eps = 1e-12) {
|
|
939
|
+
return Math.abs(m[0] - 1) < eps && Math.abs(m[1]) < eps && Math.abs(m[2]) < eps && Math.abs(m[3] - 1) < eps && Math.abs(m[4]) < eps && Math.abs(m[5]) < eps;
|
|
940
|
+
}
|
|
941
|
+
function invertMatrix(m) {
|
|
942
|
+
const [a, b, c, d, e, f] = m;
|
|
943
|
+
const det = a * d - b * c;
|
|
944
|
+
if (!det || !Number.isFinite(det)) return IDENTITY_MATRIX;
|
|
945
|
+
return [d / det, -b / det, -c / det, a / det, (c * f - d * e) / det, (b * e - a * f) / det];
|
|
946
|
+
}
|
|
947
|
+
function applyMatrixLinear(m, v2) {
|
|
948
|
+
return { x: m[0] * v2.x + m[2] * v2.y, y: m[1] * v2.x + m[3] * v2.y };
|
|
949
|
+
}
|
|
950
|
+
function matrixRotation(m) {
|
|
951
|
+
const [a, b, c, d] = m;
|
|
952
|
+
const mirrored = a * d - b * c < 0;
|
|
953
|
+
const deg = (mirrored ? Math.atan2(-b - c, d - a) : Math.atan2(b - c, a + d)) * 180 / Math.PI;
|
|
954
|
+
return Math.abs(deg) < 1e-9 ? 0 : deg;
|
|
955
|
+
}
|
|
956
|
+
function decomposeRigid(m) {
|
|
957
|
+
const [a, b, c, d, e, f] = m;
|
|
958
|
+
const deg = matrixRotation(m);
|
|
959
|
+
if (deg === 0) return { rigid: IDENTITY_MATRIX, residual: m };
|
|
960
|
+
const r = deg * Math.PI / 180;
|
|
961
|
+
const cos = Math.cos(r);
|
|
962
|
+
const sin = Math.sin(r);
|
|
963
|
+
return {
|
|
964
|
+
rigid: [cos, sin, -sin, cos, e, f],
|
|
965
|
+
residual: [cos * a + sin * b, -sin * a + cos * b, cos * c + sin * d, -sin * c + cos * d, 0, 0]
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
|
|
941
969
|
// src/vector/corners.ts
|
|
942
970
|
var EPS = 1e-9;
|
|
943
971
|
var MIN_SINE = 1e-6;
|
|
@@ -1281,8 +1309,8 @@ function removeWidthPoints(points, indices) {
|
|
|
1281
1309
|
}
|
|
1282
1310
|
function ease(u, e) {
|
|
1283
1311
|
const x = Math.min(Math.max(u, 0), 1);
|
|
1284
|
-
const
|
|
1285
|
-
return x + (
|
|
1312
|
+
const round2 = Math.sqrt(Math.max(0, 1 - (1 - x) * (1 - x)));
|
|
1313
|
+
return x + (round2 - x) * Math.min(Math.max(e, 0), 1);
|
|
1286
1314
|
}
|
|
1287
1315
|
function taperWaveFactor(t, taper, wave) {
|
|
1288
1316
|
let k = 1;
|
|
@@ -1561,10 +1589,10 @@ function variableStrokeRings(path, options) {
|
|
|
1561
1589
|
if (closed && out.length > 1 && dist(out[0], out[out.length - 1]) <= 1e-12) out.pop();
|
|
1562
1590
|
return out;
|
|
1563
1591
|
};
|
|
1564
|
-
const
|
|
1592
|
+
const left = side(1);
|
|
1565
1593
|
const right = side(-1);
|
|
1566
1594
|
if (closed) {
|
|
1567
|
-
rings.push(
|
|
1595
|
+
rings.push(left, right.reverse());
|
|
1568
1596
|
continue;
|
|
1569
1597
|
}
|
|
1570
1598
|
const capPoints = (atStart) => {
|
|
@@ -1586,7 +1614,7 @@ function variableStrokeRings(path, options) {
|
|
|
1586
1614
|
return atStart ? [along(R, o, ext), along(L, o, ext)] : [along(L, o, ext), along(R, o, ext)];
|
|
1587
1615
|
};
|
|
1588
1616
|
const ring = [];
|
|
1589
|
-
for (const q of [...
|
|
1617
|
+
for (const q of [...left, ...capPoints(false), ...right.reverse(), ...capPoints(true)]) push(ring, q);
|
|
1590
1618
|
if (ring.length > 2) rings.push(ring);
|
|
1591
1619
|
}
|
|
1592
1620
|
}
|
|
@@ -1702,8 +1730,8 @@ function vectorStrokeLineArea(parts, style, tolerance) {
|
|
|
1702
1730
|
}
|
|
1703
1731
|
var capExtent = (style, width) => style.strokeLinecap === "round" || style.strokeLinecap === "square" ? width / 2 : 0;
|
|
1704
1732
|
function arrowheadWeight(style, end) {
|
|
1705
|
-
const
|
|
1706
|
-
const s = typeof
|
|
1733
|
+
const scale2 = end === "start" ? style.startArrowScale : style.endArrowScale;
|
|
1734
|
+
const s = typeof scale2 === "number" && scale2 > 0 && Number.isFinite(scale2) ? scale2 : 1;
|
|
1707
1735
|
const width = style.strokeWidth ?? 1;
|
|
1708
1736
|
const profile = strokeWidthProfileOf(style);
|
|
1709
1737
|
const at2 = profile ? widthProfileAt(profile, end === "start" ? 0 : 1) : null;
|
|
@@ -2359,9 +2387,9 @@ function facesOf(path, fillRule) {
|
|
|
2359
2387
|
function splitIntoFaces(path, fillRule = "nonzero") {
|
|
2360
2388
|
return facesOf(path, fillRule).map(faceToPath);
|
|
2361
2389
|
}
|
|
2362
|
-
function rootsInUnit(a, b, c, d,
|
|
2390
|
+
function rootsInUnit(a, b, c, d, scale2) {
|
|
2363
2391
|
const f = (t) => ((a * t + b) * t + c) * t + d;
|
|
2364
|
-
const tol = 1e-12 * Math.max(1,
|
|
2392
|
+
const tol = 1e-12 * Math.max(1, scale2);
|
|
2365
2393
|
const cuts = [0];
|
|
2366
2394
|
const qa = 3 * a;
|
|
2367
2395
|
const qb = 2 * b;
|
|
@@ -2418,9 +2446,9 @@ function lineHits(p, q, seg) {
|
|
|
2418
2446
|
coeffs = [-h0 + 3 * h1 - 3 * h2 + h3, 3 * h0 - 6 * h1 + 3 * h2, -3 * h0 + 3 * h1, h0];
|
|
2419
2447
|
}
|
|
2420
2448
|
if (coeffs.every((c) => Math.abs(c) < 1e-12 * Math.max(1, len2))) return [];
|
|
2421
|
-
const
|
|
2449
|
+
const scale2 = Math.sqrt(len2) * Math.max(1, ...seg.map((pt2) => Math.abs(pt2[0]) + Math.abs(pt2[1])));
|
|
2422
2450
|
const out = [];
|
|
2423
|
-
for (const t of rootsInUnit(...coeffs,
|
|
2451
|
+
for (const t of rootsInUnit(...coeffs, scale2)) {
|
|
2424
2452
|
const point = segmentPoint(seg, t);
|
|
2425
2453
|
const s = ((point[0] - p[0]) * dx + (point[1] - p[1]) * dy) / len2;
|
|
2426
2454
|
if (s >= -1e-9 && s <= 1 + 1e-9) out.push({ s: Math.min(1, Math.max(0, s)), t, point });
|
|
@@ -3084,6 +3112,600 @@ function vectorMaskRenderData(group, id, filterId, precision = 3) {
|
|
|
3084
3112
|
return { type: group.mask.type, invert: invert2, id, bounds, filter: `url(#${filterId})`, invertFilter: filter };
|
|
3085
3113
|
}
|
|
3086
3114
|
|
|
3115
|
+
// src/geom/warp.ts
|
|
3116
|
+
var WARP_STYLES = [
|
|
3117
|
+
"arc",
|
|
3118
|
+
"arcLower",
|
|
3119
|
+
"arcUpper",
|
|
3120
|
+
"arch",
|
|
3121
|
+
"bulge",
|
|
3122
|
+
"shellLower",
|
|
3123
|
+
"shellUpper",
|
|
3124
|
+
"flag",
|
|
3125
|
+
"wave",
|
|
3126
|
+
"fish",
|
|
3127
|
+
"rise",
|
|
3128
|
+
"fisheye",
|
|
3129
|
+
"inflate",
|
|
3130
|
+
"squeeze",
|
|
3131
|
+
"twist"
|
|
3132
|
+
];
|
|
3133
|
+
var WARP_STYLE_LABELS = {
|
|
3134
|
+
arc: "Arc",
|
|
3135
|
+
arcLower: "Arc Lower",
|
|
3136
|
+
arcUpper: "Arc Upper",
|
|
3137
|
+
arch: "Arch",
|
|
3138
|
+
bulge: "Bulge",
|
|
3139
|
+
shellLower: "Shell Lower",
|
|
3140
|
+
shellUpper: "Shell Upper",
|
|
3141
|
+
flag: "Flag",
|
|
3142
|
+
wave: "Wave",
|
|
3143
|
+
fish: "Fish",
|
|
3144
|
+
rise: "Rise",
|
|
3145
|
+
fisheye: "Fisheye",
|
|
3146
|
+
inflate: "Inflate",
|
|
3147
|
+
squeeze: "Squeeze",
|
|
3148
|
+
twist: "Twist"
|
|
3149
|
+
};
|
|
3150
|
+
function restGrid() {
|
|
3151
|
+
return [0, 1, 2, 3].map((j) => [0, 1, 2, 3].map((i) => [i / 3, j / 3]));
|
|
3152
|
+
}
|
|
3153
|
+
function edgeArc(y, b, up, h) {
|
|
3154
|
+
if (Math.abs(b) < 1e-9) return [0, 1, 2, 3].map((i) => [i / 3, y]);
|
|
3155
|
+
const th = Math.abs(b) * Math.PI;
|
|
3156
|
+
const k = 4 / 3 * Math.tan(th / 4) * 0.5 / Math.sin(th / 2);
|
|
3157
|
+
const s = b > 0 === up ? -1 : 1;
|
|
3158
|
+
const c = Math.cos(th / 2);
|
|
3159
|
+
const n = Math.sin(th / 2);
|
|
3160
|
+
const dy = s * k * n / h;
|
|
3161
|
+
return [
|
|
3162
|
+
[0, y],
|
|
3163
|
+
[k * c, y + dy],
|
|
3164
|
+
[1 - k * c, y + dy],
|
|
3165
|
+
[1, y]
|
|
3166
|
+
];
|
|
3167
|
+
}
|
|
3168
|
+
function arcGrid(b, h) {
|
|
3169
|
+
if (Math.abs(b) < 1e-9) return restGrid();
|
|
3170
|
+
const up = b > 0;
|
|
3171
|
+
const th = Math.abs(b) * Math.PI;
|
|
3172
|
+
const r = 0.5 / Math.sin(th / 2);
|
|
3173
|
+
const k = 4 / 3 * Math.tan(th / 4);
|
|
3174
|
+
const s = up ? -1 : 1;
|
|
3175
|
+
const cy = up ? h + r * Math.cos(th / 2) : -r * Math.cos(th / 2);
|
|
3176
|
+
return [0, 1, 2, 3].map((j) => {
|
|
3177
|
+
const v2 = j / 3;
|
|
3178
|
+
const big = r + h * (up ? 1 - v2 : v2);
|
|
3179
|
+
const at2 = (a) => [0.5 + big * Math.sin(a), cy + s * big * Math.cos(a)];
|
|
3180
|
+
const tangent2 = (a) => [Math.cos(a), -s * Math.sin(a)];
|
|
3181
|
+
const p0 = at2(-th / 2);
|
|
3182
|
+
const p3 = at2(th / 2);
|
|
3183
|
+
const t0 = tangent2(-th / 2);
|
|
3184
|
+
const t1 = tangent2(th / 2);
|
|
3185
|
+
const l = k * big;
|
|
3186
|
+
const pts = [p0, [p0[0] + l * t0[0], p0[1] + l * t0[1]], [p3[0] - l * t1[0], p3[1] - l * t1[1]], p3];
|
|
3187
|
+
return pts.map((p) => [p[0], p[1] / h]);
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
function blendRows(top, bottom) {
|
|
3191
|
+
return [0, 1, 2, 3].map((j) => {
|
|
3192
|
+
const t = j / 3;
|
|
3193
|
+
return [0, 1, 2, 3].map((i) => [top[i][0] + (bottom[i][0] - top[i][0]) * t, top[i][1] + (bottom[i][1] - top[i][1]) * t]);
|
|
3194
|
+
});
|
|
3195
|
+
}
|
|
3196
|
+
var INNER = [
|
|
3197
|
+
[1, 1, -1, -1],
|
|
3198
|
+
[1, 2, 1, -1],
|
|
3199
|
+
[2, 1, -1, 1],
|
|
3200
|
+
[2, 2, 1, 1]
|
|
3201
|
+
];
|
|
3202
|
+
function warpPresetGrid(style, b, hd, vd, vertical, aspect) {
|
|
3203
|
+
const h = vertical ? 1 / aspect : aspect;
|
|
3204
|
+
if (vertical) [hd, vd] = [vd, hd];
|
|
3205
|
+
let g = restGrid();
|
|
3206
|
+
switch (style) {
|
|
3207
|
+
case "arc":
|
|
3208
|
+
g = arcGrid(b, h);
|
|
3209
|
+
break;
|
|
3210
|
+
case "arch":
|
|
3211
|
+
g = [0, 1, 2, 3].map((j) => edgeArc(j / 3, b, true, h));
|
|
3212
|
+
break;
|
|
3213
|
+
case "bulge":
|
|
3214
|
+
g = blendRows(edgeArc(0, b, true, h), edgeArc(1, b, false, h));
|
|
3215
|
+
break;
|
|
3216
|
+
case "arcLower":
|
|
3217
|
+
g = blendRows(g[0], edgeArc(1, b, false, h));
|
|
3218
|
+
break;
|
|
3219
|
+
case "arcUpper":
|
|
3220
|
+
g = blendRows(edgeArc(0, b, true, h), g[3]);
|
|
3221
|
+
break;
|
|
3222
|
+
// The bulging edge and the outer points of the row next to it come from Arc (bent the other
|
|
3223
|
+
// way for Shell Lower); the rest stays put.
|
|
3224
|
+
case "shellLower": {
|
|
3225
|
+
const a = arcGrid(-b, h);
|
|
3226
|
+
g[3] = a[3];
|
|
3227
|
+
g[2][0] = a[2][0];
|
|
3228
|
+
g[2][3] = a[2][3];
|
|
3229
|
+
break;
|
|
3230
|
+
}
|
|
3231
|
+
case "shellUpper": {
|
|
3232
|
+
const a = arcGrid(b, h);
|
|
3233
|
+
g[0] = a[0];
|
|
3234
|
+
g[1][0] = a[1][0];
|
|
3235
|
+
g[1][3] = a[1][3];
|
|
3236
|
+
break;
|
|
3237
|
+
}
|
|
3238
|
+
case "flag":
|
|
3239
|
+
for (const row of g) {
|
|
3240
|
+
row[1][1] -= 2 * b;
|
|
3241
|
+
row[2][1] += 2 * b;
|
|
3242
|
+
}
|
|
3243
|
+
break;
|
|
3244
|
+
case "wave":
|
|
3245
|
+
for (const row of g.slice(1, 3)) {
|
|
3246
|
+
row[1][1] += 4 / 3 * b;
|
|
3247
|
+
row[2][1] -= 4 / 3 * b;
|
|
3248
|
+
}
|
|
3249
|
+
break;
|
|
3250
|
+
case "fish":
|
|
3251
|
+
[-2, -2 / 3, 2 / 3, 2].forEach((f, j) => {
|
|
3252
|
+
g[j][1][1] += f * b;
|
|
3253
|
+
g[j][2][1] -= f * b;
|
|
3254
|
+
});
|
|
3255
|
+
break;
|
|
3256
|
+
case "rise":
|
|
3257
|
+
for (const row of g) {
|
|
3258
|
+
row[0][1] += 2 * b;
|
|
3259
|
+
row[1][1] += 2 * b;
|
|
3260
|
+
}
|
|
3261
|
+
break;
|
|
3262
|
+
case "fisheye":
|
|
3263
|
+
for (const [j, i, dx, dy] of INNER) {
|
|
3264
|
+
g[j][i][0] += dx * 2 * b / 3;
|
|
3265
|
+
g[j][i][1] += dy * 2 * b / 3;
|
|
3266
|
+
}
|
|
3267
|
+
break;
|
|
3268
|
+
// Edge midpoints move out (Inflate) or the sides in (Squeeze) by b/3, the inner points by b/9.
|
|
3269
|
+
case "inflate":
|
|
3270
|
+
case "squeeze": {
|
|
3271
|
+
const s = style === "inflate" ? 1 : -1;
|
|
3272
|
+
for (const p of g[0].slice(1, 3)) p[1] -= b / 3;
|
|
3273
|
+
for (const p of g[3].slice(1, 3)) p[1] += b / 3;
|
|
3274
|
+
for (const row of g.slice(1, 3)) {
|
|
3275
|
+
row[0][0] -= s * b / 3;
|
|
3276
|
+
row[3][0] += s * b / 3;
|
|
3277
|
+
}
|
|
3278
|
+
for (const [j, i, dx, dy] of INNER) {
|
|
3279
|
+
g[j][i][0] += s * dx * b / 9;
|
|
3280
|
+
g[j][i][1] += dy * b / 9;
|
|
3281
|
+
}
|
|
3282
|
+
break;
|
|
3283
|
+
}
|
|
3284
|
+
// The inner points turn round the centre (the other way for a negative bend).
|
|
3285
|
+
case "twist": {
|
|
3286
|
+
const a = Math.abs(b);
|
|
3287
|
+
if (b >= 0) {
|
|
3288
|
+
g[1][1][0] += a;
|
|
3289
|
+
g[1][2][1] += a;
|
|
3290
|
+
g[2][1][1] -= a;
|
|
3291
|
+
g[2][2][0] -= a;
|
|
3292
|
+
} else {
|
|
3293
|
+
g[1][1][1] += a;
|
|
3294
|
+
g[1][2][0] -= a;
|
|
3295
|
+
g[2][1][0] += a;
|
|
3296
|
+
g[2][2][1] -= a;
|
|
3297
|
+
}
|
|
3298
|
+
break;
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
if (vd !== 0) {
|
|
3302
|
+
const moved = (row, s) => {
|
|
3303
|
+
const m = [(row[0][0] + row[3][0]) / 2, (row[0][1] + row[3][1]) / 2];
|
|
3304
|
+
return row.map((p) => [m[0] + (p[0] - m[0]) * s - p[0], m[1] + (p[1] - m[1]) * s - p[1]]);
|
|
3305
|
+
};
|
|
3306
|
+
const d0 = moved(g[0], 1 - vd);
|
|
3307
|
+
const d3 = moved(g[3], 1 + vd);
|
|
3308
|
+
g.forEach((row, j) => {
|
|
3309
|
+
const t = j / 3;
|
|
3310
|
+
row.forEach((p, i) => {
|
|
3311
|
+
p[0] += d0[i][0] + (d3[i][0] - d0[i][0]) * t;
|
|
3312
|
+
p[1] += d0[i][1] + (d3[i][1] - d0[i][1]) * t;
|
|
3313
|
+
});
|
|
3314
|
+
});
|
|
3315
|
+
}
|
|
3316
|
+
if (hd !== 0) {
|
|
3317
|
+
for (let i = 0; i < 4; i++) {
|
|
3318
|
+
const s = 1 + hd * (2 * i / 3 - 1);
|
|
3319
|
+
const m = [(g[0][i][0] + g[3][i][0]) / 2, (g[0][i][1] + g[3][i][1]) / 2];
|
|
3320
|
+
for (const row of g) row[i] = [m[0] + (row[i][0] - m[0]) * s, m[1] + (row[i][1] - m[1]) * s];
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
if (vertical) g = [0, 1, 2, 3].map((j) => [0, 1, 2, 3].map((i) => [g[i][j][1], g[i][j][0]]));
|
|
3324
|
+
return g;
|
|
3325
|
+
}
|
|
3326
|
+
function bernstein(t) {
|
|
3327
|
+
const s = 1 - t;
|
|
3328
|
+
return [s * s * s, 3 * s * s * t, 3 * s * t * t, t * t * t];
|
|
3329
|
+
}
|
|
3330
|
+
var lerpVec2 = (a, b, t) => ({ x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t });
|
|
3331
|
+
function splitCubic(p, t) {
|
|
3332
|
+
const a = lerpVec2(p[0], p[1], t);
|
|
3333
|
+
const b = lerpVec2(p[1], p[2], t);
|
|
3334
|
+
const c = lerpVec2(p[2], p[3], t);
|
|
3335
|
+
const d = lerpVec2(a, b, t);
|
|
3336
|
+
const e = lerpVec2(b, c, t);
|
|
3337
|
+
return [p[0], a, d, lerpVec2(d, e, t), e, c, p[3]];
|
|
3338
|
+
}
|
|
3339
|
+
var BERN_INV = [
|
|
3340
|
+
[1, 0, 0, 0],
|
|
3341
|
+
[-5 / 6, 3, -1.5, 1 / 3],
|
|
3342
|
+
[1 / 3, -1.5, 3, -5 / 6],
|
|
3343
|
+
[0, 0, 0, 1]
|
|
3344
|
+
];
|
|
3345
|
+
var pct = (v2) => typeof v2 === "number" && Number.isFinite(v2) ? Math.min(1, Math.max(-1, v2 / 100)) : 0;
|
|
3346
|
+
function warpPresetMesh(preset, bounds) {
|
|
3347
|
+
if (!WARP_STYLES.includes(preset.style)) return null;
|
|
3348
|
+
const { x, y, width: w, height: h } = bounds;
|
|
3349
|
+
if (!(w > 0 && h > 0)) return null;
|
|
3350
|
+
const b = pct(preset.bend);
|
|
3351
|
+
const hd = pct(preset.horizontal);
|
|
3352
|
+
const vd = pct(preset.vertical);
|
|
3353
|
+
if (b === 0 && hd === 0 && vd === 0) return null;
|
|
3354
|
+
const grid = warpPresetGrid(preset.style, b, hd, vd, preset.orientation === "vertical", h / w);
|
|
3355
|
+
return { us: [0, 1], vs: [0, 1], points: grid.flat().map((p) => ({ x: x + p[0] * w, y: y + p[1] * h })) };
|
|
3356
|
+
}
|
|
3357
|
+
var warpMeshColumns = (m) => 3 * (m.us.length - 1) + 1;
|
|
3358
|
+
var warpMeshRows = (m) => 3 * (m.vs.length - 1) + 1;
|
|
3359
|
+
function isValidWarpMesh(m) {
|
|
3360
|
+
if (!m || typeof m !== "object") return false;
|
|
3361
|
+
const { us, vs, points } = m;
|
|
3362
|
+
const knots = (k) => Array.isArray(k) && k.length >= 2 && k.length <= 65 && k[0] === 0 && k[k.length - 1] === 1 && k.every((v2, i) => typeof v2 === "number" && (i === 0 || v2 > k[i - 1]));
|
|
3363
|
+
if (!knots(us) || !knots(vs) || !Array.isArray(points)) return false;
|
|
3364
|
+
return points.length === (3 * (us.length - 1) + 1) * (3 * (vs.length - 1) + 1) && points.every((p) => !!p && Number.isFinite(p.x) && Number.isFinite(p.y));
|
|
3365
|
+
}
|
|
3366
|
+
function fitWarpMesh(f, us, vs) {
|
|
3367
|
+
const pc = us.length - 1;
|
|
3368
|
+
const pr = vs.length - 1;
|
|
3369
|
+
const nx = 3 * pc + 1;
|
|
3370
|
+
const points = new Array((3 * pr + 1) * nx);
|
|
3371
|
+
for (let pj = 0; pj < pr; pj++) {
|
|
3372
|
+
for (let pi = 0; pi < pc; pi++) {
|
|
3373
|
+
const s = [0, 1, 2, 3].map(
|
|
3374
|
+
(j) => [0, 1, 2, 3].map((i) => f(us[pi] + (us[pi + 1] - us[pi]) * i / 3, vs[pj] + (vs[pj + 1] - vs[pj]) * j / 3))
|
|
3375
|
+
);
|
|
3376
|
+
for (let j = 0; j < 4; j++) {
|
|
3377
|
+
for (let i = 0; i < 4; i++) {
|
|
3378
|
+
let x = 0;
|
|
3379
|
+
let y = 0;
|
|
3380
|
+
for (let a = 0; a < 4; a++) {
|
|
3381
|
+
for (let b = 0; b < 4; b++) {
|
|
3382
|
+
const k = BERN_INV[j][a] * BERN_INV[i][b];
|
|
3383
|
+
x += k * s[a][b].x;
|
|
3384
|
+
y += k * s[a][b].y;
|
|
3385
|
+
}
|
|
3386
|
+
}
|
|
3387
|
+
points[(3 * pj + j) * nx + 3 * pi + i] = { x, y };
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
return { us: us.slice(), vs: vs.slice(), points };
|
|
3393
|
+
}
|
|
3394
|
+
var evenKnots = (n) => Array.from({ length: n + 1 }, (_, i) => i / n);
|
|
3395
|
+
var clampMeshCount = (n) => Math.min(64, Math.max(1, Math.round(Number.isFinite(n) ? n : 1)));
|
|
3396
|
+
function identityWarpMesh(bounds, columns = 1, rows = 1) {
|
|
3397
|
+
return fitWarpMesh((s, t) => ({ x: bounds.x + s * bounds.width, y: bounds.y + t * bounds.height }), evenKnots(clampMeshCount(columns)), evenKnots(clampMeshCount(rows)));
|
|
3398
|
+
}
|
|
3399
|
+
function locate(knots, s) {
|
|
3400
|
+
const n = knots.length - 1;
|
|
3401
|
+
let i = 0;
|
|
3402
|
+
while (i + 1 < n && s > knots[i + 1]) i++;
|
|
3403
|
+
const w = knots[i + 1] - knots[i];
|
|
3404
|
+
return [i, w > 0 ? (s - knots[i]) / w : 0];
|
|
3405
|
+
}
|
|
3406
|
+
function evalWarpMesh(m, s, t) {
|
|
3407
|
+
const [pi, a] = locate(m.us, s);
|
|
3408
|
+
const [pj, b] = locate(m.vs, t);
|
|
3409
|
+
const ba = bernstein(a);
|
|
3410
|
+
const bb = bernstein(b);
|
|
3411
|
+
const nx = warpMeshColumns(m);
|
|
3412
|
+
let x = 0;
|
|
3413
|
+
let y = 0;
|
|
3414
|
+
for (let j = 0; j < 4; j++) {
|
|
3415
|
+
for (let i = 0; i < 4; i++) {
|
|
3416
|
+
const p = m.points[(3 * pj + j) * nx + 3 * pi + i];
|
|
3417
|
+
const k = ba[i] * bb[j];
|
|
3418
|
+
x += p.x * k;
|
|
3419
|
+
y += p.y * k;
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
return { x, y };
|
|
3423
|
+
}
|
|
3424
|
+
function transposeMesh(m) {
|
|
3425
|
+
const nx = warpMeshColumns(m);
|
|
3426
|
+
const ny = warpMeshRows(m);
|
|
3427
|
+
const points = new Array(nx * ny);
|
|
3428
|
+
for (let j = 0; j < ny; j++) for (let i = 0; i < nx; i++) points[i * ny + j] = m.points[j * nx + i];
|
|
3429
|
+
return { us: m.vs.slice(), vs: m.us.slice(), points };
|
|
3430
|
+
}
|
|
3431
|
+
function splitWarpMeshU(m, s) {
|
|
3432
|
+
const [pi, a] = locate(m.us, s);
|
|
3433
|
+
if (!(a >= 0.01 && a <= 0.99)) return null;
|
|
3434
|
+
const nx = warpMeshColumns(m);
|
|
3435
|
+
const ny = warpMeshRows(m);
|
|
3436
|
+
const points = [];
|
|
3437
|
+
for (let j = 0; j < ny; j++) {
|
|
3438
|
+
const row = m.points.slice(j * nx, (j + 1) * nx);
|
|
3439
|
+
points.push(...row.slice(0, 3 * pi), ...splitCubic(row.slice(3 * pi, 3 * pi + 4), a), ...row.slice(3 * pi + 4));
|
|
3440
|
+
}
|
|
3441
|
+
const us = m.us.slice();
|
|
3442
|
+
us.splice(pi + 1, 0, Math.min(1, Math.max(0, s)));
|
|
3443
|
+
return { us, vs: m.vs.slice(), points };
|
|
3444
|
+
}
|
|
3445
|
+
function splitWarpMeshV(m, t) {
|
|
3446
|
+
const out = splitWarpMeshU(transposeMesh(m), t);
|
|
3447
|
+
return out && transposeMesh(out);
|
|
3448
|
+
}
|
|
3449
|
+
function removeWarpMeshSplitU(m, k) {
|
|
3450
|
+
if (k <= 0 || k + 1 >= m.us.length) return null;
|
|
3451
|
+
const a = (m.us[k] - m.us[k - 1]) / (m.us[k + 1] - m.us[k - 1]);
|
|
3452
|
+
const nx = warpMeshColumns(m);
|
|
3453
|
+
const ny = warpMeshRows(m);
|
|
3454
|
+
const c0 = 3 * (k - 1);
|
|
3455
|
+
const points = [];
|
|
3456
|
+
for (let j = 0; j < ny; j++) {
|
|
3457
|
+
const row = m.points.slice(j * nx, (j + 1) * nx);
|
|
3458
|
+
const [p0, q1, r2, p3] = [row[c0], row[c0 + 1], row[c0 + 5], row[c0 + 6]];
|
|
3459
|
+
const p1 = { x: (q1.x - (1 - a) * p0.x) / a, y: (q1.y - (1 - a) * p0.y) / a };
|
|
3460
|
+
const p2 = { x: (r2.x - a * p3.x) / (1 - a), y: (r2.y - a * p3.y) / (1 - a) };
|
|
3461
|
+
points.push(...row.slice(0, c0), p0, p1, p2, p3, ...row.slice(c0 + 7));
|
|
3462
|
+
}
|
|
3463
|
+
const us = m.us.slice();
|
|
3464
|
+
us.splice(k, 1);
|
|
3465
|
+
return { us, vs: m.vs.slice(), points };
|
|
3466
|
+
}
|
|
3467
|
+
function removeWarpMeshSplitV(m, k) {
|
|
3468
|
+
const out = removeWarpMeshSplitU(transposeMesh(m), k);
|
|
3469
|
+
return out && transposeMesh(out);
|
|
3470
|
+
}
|
|
3471
|
+
function mapWarpMeshPoints(m, f) {
|
|
3472
|
+
return { us: m.us.slice(), vs: m.vs.slice(), points: m.points.map((p) => f(p)) };
|
|
3473
|
+
}
|
|
3474
|
+
function resizeWarpMesh(m, columns, rows) {
|
|
3475
|
+
const cols = clampMeshCount(columns);
|
|
3476
|
+
const rws = clampMeshCount(rows);
|
|
3477
|
+
if (m.us.length - 1 === cols && m.vs.length - 1 === rws) return m;
|
|
3478
|
+
const us = evenKnots(cols);
|
|
3479
|
+
const vs = evenKnots(rws);
|
|
3480
|
+
const has = (list, v2) => list.some((k) => Math.abs(k - v2) < 1e-12);
|
|
3481
|
+
if (m.us.every((u) => has(us, u)) && m.vs.every((v2) => has(vs, v2))) {
|
|
3482
|
+
let out = m;
|
|
3483
|
+
for (const u of us) if (!has(out.us, u)) out = splitWarpMeshU(out, u) ?? out;
|
|
3484
|
+
for (const v2 of vs) if (!has(out.vs, v2)) out = splitWarpMeshV(out, v2) ?? out;
|
|
3485
|
+
return out;
|
|
3486
|
+
}
|
|
3487
|
+
return fitWarpMesh((s, t) => evalWarpMesh(m, s, t), us, vs);
|
|
3488
|
+
}
|
|
3489
|
+
function warpMeshControlBounds(m) {
|
|
3490
|
+
let minX = Infinity;
|
|
3491
|
+
let minY = Infinity;
|
|
3492
|
+
let maxX = -Infinity;
|
|
3493
|
+
let maxY = -Infinity;
|
|
3494
|
+
for (const p of m.points) {
|
|
3495
|
+
minX = Math.min(minX, p.x);
|
|
3496
|
+
minY = Math.min(minY, p.y);
|
|
3497
|
+
maxX = Math.max(maxX, p.x);
|
|
3498
|
+
maxY = Math.max(maxY, p.y);
|
|
3499
|
+
}
|
|
3500
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
3501
|
+
}
|
|
3502
|
+
function warpMeshParamAt(m, p) {
|
|
3503
|
+
const n = 48;
|
|
3504
|
+
let best = { s: 0.5, t: 0.5, d: Infinity };
|
|
3505
|
+
for (let j = 0; j <= n; j++) {
|
|
3506
|
+
for (let i = 0; i <= n; i++) {
|
|
3507
|
+
const q2 = evalWarpMesh(m, i / n, j / n);
|
|
3508
|
+
const d = (q2.x - p.x) ** 2 + (q2.y - p.y) ** 2;
|
|
3509
|
+
if (d < best.d) best = { s: i / n, t: j / n, d };
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
let { s, t } = best;
|
|
3513
|
+
for (let k = 0; k < 12; k++) {
|
|
3514
|
+
const h = 1e-5;
|
|
3515
|
+
const q2 = evalWarpMesh(m, s, t);
|
|
3516
|
+
const qs = evalWarpMesh(m, s + h, t);
|
|
3517
|
+
const qt = evalWarpMesh(m, s, t + h);
|
|
3518
|
+
const a = (qs.x - q2.x) / h;
|
|
3519
|
+
const b = (qt.x - q2.x) / h;
|
|
3520
|
+
const c = (qs.y - q2.y) / h;
|
|
3521
|
+
const d = (qt.y - q2.y) / h;
|
|
3522
|
+
const det = a * d - b * c;
|
|
3523
|
+
if (Math.abs(det) < 1e-12) break;
|
|
3524
|
+
const ex = p.x - q2.x;
|
|
3525
|
+
const ey = p.y - q2.y;
|
|
3526
|
+
s = Math.min(1, Math.max(0, s + (d * ex - b * ey) / det));
|
|
3527
|
+
t = Math.min(1, Math.max(0, t + (a * ey - c * ex) / det));
|
|
3528
|
+
}
|
|
3529
|
+
const q = evalWarpMesh(m, s, t);
|
|
3530
|
+
return { s, t, distance: Math.hypot(q.x - p.x, q.y - p.y) };
|
|
3531
|
+
}
|
|
3532
|
+
function smoothLines(m, i0, i1, j0, j1) {
|
|
3533
|
+
const nx = warpMeshColumns(m);
|
|
3534
|
+
i1 = Math.min(i1, nx);
|
|
3535
|
+
j1 = Math.min(j1, warpMeshRows(m));
|
|
3536
|
+
const triples = [];
|
|
3537
|
+
for (let a = 1; a < m.us.length - 1; a++) {
|
|
3538
|
+
if (3 * a >= i0 && 3 * a < i1)
|
|
3539
|
+
for (let j = j0; j < j1; j++) triples.push([j * nx + 3 * a - 1, j * nx + 3 * a, j * nx + 3 * a + 1, m.us[a] - m.us[a - 1], m.us[a + 1] - m.us[a]]);
|
|
3540
|
+
}
|
|
3541
|
+
for (let b = 1; b < m.vs.length - 1; b++) {
|
|
3542
|
+
if (3 * b >= j0 && 3 * b < j1)
|
|
3543
|
+
for (let i = i0; i < i1; i++) triples.push([(3 * b - 1) * nx + i, 3 * b * nx + i, (3 * b + 1) * nx + i, m.vs[b] - m.vs[b - 1], m.vs[b + 1] - m.vs[b]]);
|
|
3544
|
+
}
|
|
3545
|
+
for (const [l, c, r, hl, hr] of triples) {
|
|
3546
|
+
const pl = m.points[l];
|
|
3547
|
+
const pc = m.points[c];
|
|
3548
|
+
const pr = m.points[r];
|
|
3549
|
+
const tx = ((pc.x - pl.x) / hl + (pr.x - pc.x) / hr) / 2;
|
|
3550
|
+
const ty = ((pc.y - pl.y) / hl + (pr.y - pc.y) / hr) / 2;
|
|
3551
|
+
m.points[l] = { x: pc.x - tx * hl, y: pc.y - ty * hl };
|
|
3552
|
+
m.points[r] = { x: pc.x + tx * hr, y: pc.y + ty * hr };
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
function dragWarpMeshPoint(base, index, d) {
|
|
3556
|
+
if (index < 0 || index >= base.points.length || !Number.isFinite(d.x) || !Number.isFinite(d.y)) return base;
|
|
3557
|
+
const out = { us: base.us.slice(), vs: base.vs.slice(), points: base.points.slice() };
|
|
3558
|
+
const nx = warpMeshColumns(base);
|
|
3559
|
+
const ny = warpMeshRows(base);
|
|
3560
|
+
const i = index % nx;
|
|
3561
|
+
const j = Math.floor(index / nx);
|
|
3562
|
+
const shift = (ii, jj, v2) => {
|
|
3563
|
+
if (ii < 0 || jj < 0 || ii >= nx || jj >= ny) return;
|
|
3564
|
+
const p = out.points[jj * nx + ii];
|
|
3565
|
+
out.points[jj * nx + ii] = { x: p.x + v2.x, y: p.y + v2.y };
|
|
3566
|
+
};
|
|
3567
|
+
const span = (knots, k) => k > 0 && k + 1 < knots.length ? [knots[k] - knots[k - 1], knots[k + 1] - knots[k]] : null;
|
|
3568
|
+
const ri = i % 3;
|
|
3569
|
+
const rj = j % 3;
|
|
3570
|
+
if (ri === 0 && rj === 0) {
|
|
3571
|
+
for (let dj = -1; dj <= 1; dj++) for (let di = -1; di <= 1; di++) shift(i + di, j + dj, d);
|
|
3572
|
+
} else if (ri === 0) {
|
|
3573
|
+
for (let di = -1; di <= 1; di++) shift(i + di, j, d);
|
|
3574
|
+
const sp = span(base.vs, Math.floor(j / 3) + (rj === 2 ? 1 : 0));
|
|
3575
|
+
if (sp) {
|
|
3576
|
+
const [other, k] = rj === 1 ? [j - 2, sp[0] / sp[1]] : [j + 2, sp[1] / sp[0]];
|
|
3577
|
+
for (let di = -1; di <= 1; di++) shift(i + di, other, { x: -d.x * k, y: -d.y * k });
|
|
3578
|
+
}
|
|
3579
|
+
} else if (rj === 0) {
|
|
3580
|
+
for (let dj = -1; dj <= 1; dj++) shift(i, j + dj, d);
|
|
3581
|
+
const sp = span(base.us, Math.floor(i / 3) + (ri === 2 ? 1 : 0));
|
|
3582
|
+
if (sp) {
|
|
3583
|
+
const [other, k] = ri === 1 ? [i - 2, sp[0] / sp[1]] : [i + 2, sp[1] / sp[0]];
|
|
3584
|
+
for (let dj = -1; dj <= 1; dj++) shift(other, j + dj, { x: -d.x * k, y: -d.y * k });
|
|
3585
|
+
}
|
|
3586
|
+
} else shift(i, j, d);
|
|
3587
|
+
return out;
|
|
3588
|
+
}
|
|
3589
|
+
function pullWarpMesh(base, s, t, d) {
|
|
3590
|
+
const BORDER_ZONE = 0.12;
|
|
3591
|
+
const REACH = 1.8;
|
|
3592
|
+
if (!Number.isFinite(d.x) || !Number.isFinite(d.y)) return base;
|
|
3593
|
+
const m = { us: base.us.slice(), vs: base.vs.slice(), points: base.points.slice() };
|
|
3594
|
+
const cols = m.us.length - 1;
|
|
3595
|
+
const rows = m.vs.length - 1;
|
|
3596
|
+
const [pi, a] = locate(m.us, s);
|
|
3597
|
+
const [pj, b] = locate(m.vs, t);
|
|
3598
|
+
const ba = bernstein(a);
|
|
3599
|
+
const bb = bernstein(b);
|
|
3600
|
+
const nx = warpMeshColumns(m);
|
|
3601
|
+
const ny = warpMeshRows(m);
|
|
3602
|
+
const anchor = (ai, aj) => base.points[3 * aj * nx + 3 * ai] ?? { x: 0, y: 0 };
|
|
3603
|
+
const at0 = evalWarpMesh(base, s, t);
|
|
3604
|
+
const target = { x: at0.x + d.x, y: at0.y + d.y };
|
|
3605
|
+
let size = 1;
|
|
3606
|
+
for (const k of ["x", "y"]) {
|
|
3607
|
+
const vals = [anchor(pi, pj)[k], anchor(pi + 1, pj)[k], anchor(pi, pj + 1)[k], anchor(pi + 1, pj + 1)[k]];
|
|
3608
|
+
size = Math.max(size, Math.max(...vals) - Math.min(...vals));
|
|
3609
|
+
}
|
|
3610
|
+
const radius = REACH * size;
|
|
3611
|
+
const innerW = (ba[1] + ba[2]) * (bb[1] + bb[2]);
|
|
3612
|
+
const interior = Math.min(1, Math.max(0, innerW / 0.5625));
|
|
3613
|
+
const toBorder = Math.min(s, 1 - s, t, 1 - t);
|
|
3614
|
+
const nearBorder = Math.min(1, Math.max(0, 1 - toBorder / BORDER_ZONE));
|
|
3615
|
+
const meshCorner = (ai, aj) => (ai === 0 || ai === cols) && (aj === 0 || aj === rows);
|
|
3616
|
+
const onBorder = (ai, aj) => ai === 0 || ai === cols || aj === 0 || aj === rows;
|
|
3617
|
+
const reach = (ai, aj, wa, wb) => meshCorner(ai, aj) ? 0 : wa * wb * (onBorder(ai, aj) ? nearBorder : 1);
|
|
3618
|
+
const corner = [
|
|
3619
|
+
[pi, pj, reach(pi, pj, ba[0] + ba[1], bb[0] + bb[1])],
|
|
3620
|
+
[pi + 1, pj, reach(pi + 1, pj, ba[2] + ba[3], bb[0] + bb[1])],
|
|
3621
|
+
[pi, pj + 1, reach(pi, pj + 1, ba[0] + ba[1], bb[2] + bb[3])],
|
|
3622
|
+
[pi + 1, pj + 1, reach(pi + 1, pj + 1, ba[2] + ba[3], bb[2] + bb[3])]
|
|
3623
|
+
];
|
|
3624
|
+
const share = new Array((cols + 1) * (rows + 1)).fill(0);
|
|
3625
|
+
for (let aj = 0; aj <= rows; aj++) {
|
|
3626
|
+
for (let ai = 0; ai <= cols; ai++) {
|
|
3627
|
+
const p = anchor(ai, aj);
|
|
3628
|
+
const x = Math.min(1, Math.max(0, Math.hypot(p.x - at0.x, p.y - at0.y) / radius));
|
|
3629
|
+
const fall = 0.5 * (1 + Math.cos(Math.PI * x));
|
|
3630
|
+
const edge = meshCorner(ai, aj) ? 0 : onBorder(ai, aj) ? nearBorder : 1;
|
|
3631
|
+
share[aj * (cols + 1) + ai] = fall * edge;
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
for (const [ai, aj, w] of corner) share[aj * (cols + 1) + ai] = Math.max(share[aj * (cols + 1) + ai], (1 - interior) * w);
|
|
3635
|
+
const move = (idx, k, v2) => {
|
|
3636
|
+
const p = m.points[idx];
|
|
3637
|
+
m.points[idx] = { x: p.x + v2.x * k, y: p.y + v2.y * k };
|
|
3638
|
+
};
|
|
3639
|
+
for (let j = 0; j < ny; j++) {
|
|
3640
|
+
for (let i = 0; i < nx; i++) {
|
|
3641
|
+
const ai = Math.min(cols, Math.floor((i + 1) / 3));
|
|
3642
|
+
const aj = Math.min(rows, Math.floor((j + 1) / 3));
|
|
3643
|
+
move(j * nx + i, share[aj * (cols + 1) + ai], d);
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
let norm = 0;
|
|
3647
|
+
for (const j of [1, 2]) for (const i of [1, 2]) norm += (ba[i] * bb[j]) ** 2;
|
|
3648
|
+
const cornerNorm = corner.reduce((acc, c) => acc + c[2] * c[2], 0);
|
|
3649
|
+
const innerPart = cornerNorm > 1e-12 ? Math.min(1, innerW / 0.15) : 1;
|
|
3650
|
+
const edgeHandles = [];
|
|
3651
|
+
for (const k of [1, 2]) {
|
|
3652
|
+
if (pi === 0) edgeHandles.push([(3 * pj + k) * nx + 3 * pi, ba[0] * bb[k]]);
|
|
3653
|
+
if (pi + 1 === cols) edgeHandles.push([(3 * pj + k) * nx + 3 * pi + 3, ba[3] * bb[k]]);
|
|
3654
|
+
if (pj === 0) edgeHandles.push([3 * pj * nx + 3 * pi + k, ba[k] * bb[0]]);
|
|
3655
|
+
if (pj + 1 === rows) edgeHandles.push([(3 * pj + 3) * nx + 3 * pi + k, ba[k] * bb[3]]);
|
|
3656
|
+
}
|
|
3657
|
+
const edgeNorm = edgeHandles.reduce((acc, e) => acc + e[1] * e[1], 0);
|
|
3658
|
+
const edgePart = edgeNorm > 1e-12 ? nearBorder : 0;
|
|
3659
|
+
const innerShare = (1 - edgePart) * innerPart;
|
|
3660
|
+
const cornerShare = (1 - edgePart) * (1 - innerPart);
|
|
3661
|
+
for (let iter = 0; iter < 60; iter++) {
|
|
3662
|
+
const now = evalWarpMesh(m, s, t);
|
|
3663
|
+
const rem = { x: target.x - now.x, y: target.y - now.y };
|
|
3664
|
+
if (Math.hypot(rem.x, rem.y) < 1e-9) break;
|
|
3665
|
+
if (innerShare > 0 && norm > 0) for (const j of [1, 2]) for (const i of [1, 2]) move((3 * pj + j) * nx + 3 * pi + i, ba[i] * bb[j] / norm * innerShare, rem);
|
|
3666
|
+
if (edgePart > 0) for (const [idx, w] of edgeHandles) move(idx, w / edgeNorm * edgePart, rem);
|
|
3667
|
+
if (cornerShare > 0 && cornerNorm > 0) {
|
|
3668
|
+
for (const [ai, aj, w] of corner) {
|
|
3669
|
+
const k = w / cornerNorm * cornerShare;
|
|
3670
|
+
for (let dj = -1; dj <= 1; dj++) {
|
|
3671
|
+
for (let di = -1; di <= 1; di++) {
|
|
3672
|
+
const i = 3 * ai + di;
|
|
3673
|
+
const j = 3 * aj + dj;
|
|
3674
|
+
if (i >= 0 && j >= 0 && i < nx && j < ny) move(j * nx + i, k, rem);
|
|
3675
|
+
}
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
for (let k = 0; k < 3; k++) smoothLines(m, Math.max(0, 3 * pi - 3), 3 * pi + 7, Math.max(0, 3 * pj - 3), 3 * pj + 7);
|
|
3680
|
+
}
|
|
3681
|
+
return m;
|
|
3682
|
+
}
|
|
3683
|
+
function warpMeshEditPoints(m) {
|
|
3684
|
+
const nx = warpMeshColumns(m);
|
|
3685
|
+
const ny = warpMeshRows(m);
|
|
3686
|
+
const anchors = [];
|
|
3687
|
+
const handles = [];
|
|
3688
|
+
for (let j = 0; j < ny; j++) {
|
|
3689
|
+
for (let i = 0; i < nx; i++) {
|
|
3690
|
+
const ri = i % 3;
|
|
3691
|
+
const rj = j % 3;
|
|
3692
|
+
if (ri === 0 && rj === 0) anchors.push(j * nx + i);
|
|
3693
|
+
else if (ri === 0) handles.push({ index: j * nx + i, anchor: (rj === 1 ? j - 1 : j + 1) * nx + i });
|
|
3694
|
+
else if (rj === 0) handles.push({ index: j * nx + i, anchor: j * nx + (ri === 1 ? i - 1 : i + 1) });
|
|
3695
|
+
}
|
|
3696
|
+
}
|
|
3697
|
+
return { anchors, handles };
|
|
3698
|
+
}
|
|
3699
|
+
function warpMeshGridCurves(m) {
|
|
3700
|
+
const nx = warpMeshColumns(m);
|
|
3701
|
+
const ny = warpMeshRows(m);
|
|
3702
|
+
const pt2 = (i, j) => m.points[j * nx + i];
|
|
3703
|
+
const out = [];
|
|
3704
|
+
for (let j = 0; j < ny; j += 3) for (let i = 0; i + 3 < nx; i += 3) out.push([pt2(i, j), pt2(i + 1, j), pt2(i + 2, j), pt2(i + 3, j)]);
|
|
3705
|
+
for (let i = 0; i < nx; i += 3) for (let j = 0; j + 3 < ny; j += 3) out.push([pt2(i, j), pt2(i, j + 1), pt2(i, j + 2), pt2(i, j + 3)]);
|
|
3706
|
+
return out;
|
|
3707
|
+
}
|
|
3708
|
+
|
|
3087
3709
|
// src/vector/warp.ts
|
|
3088
3710
|
function polylineAt(pts) {
|
|
3089
3711
|
const acc = [0];
|
|
@@ -4203,12 +4825,12 @@ function insertAnchor(sp, segment, t) {
|
|
|
4203
4825
|
const ia = segment;
|
|
4204
4826
|
const ib = (segment + 1) % n;
|
|
4205
4827
|
const seg = subpathSegment(sp, segment);
|
|
4206
|
-
const [
|
|
4207
|
-
const mid =
|
|
4828
|
+
const [left, right] = splitSegment(seg, t);
|
|
4829
|
+
const mid = left[left.length - 1];
|
|
4208
4830
|
const anchor = { x: mid[0], y: mid[1] };
|
|
4209
4831
|
if (seg.length === 4) {
|
|
4210
|
-
anchors[ia].out = { x:
|
|
4211
|
-
anchor.in = { x:
|
|
4832
|
+
anchors[ia].out = { x: left[1][0], y: left[1][1] };
|
|
4833
|
+
anchor.in = { x: left[2][0], y: left[2][1] };
|
|
4212
4834
|
anchor.out = { x: right[1][0], y: right[1][1] };
|
|
4213
4835
|
anchor.type = "smooth";
|
|
4214
4836
|
anchors[ib].in = { x: right[2][0], y: right[2][1] };
|
|
@@ -4500,9 +5122,9 @@ function twistPaths(paths, angle, center) {
|
|
|
4500
5122
|
};
|
|
4501
5123
|
return paths.map((p) => {
|
|
4502
5124
|
const out = [];
|
|
4503
|
-
for (const
|
|
5125
|
+
for (const sub4 of subsOf(p)) {
|
|
4504
5126
|
const segs = [];
|
|
4505
|
-
for (const seg of
|
|
5127
|
+
for (const seg of sub4.segs) {
|
|
4506
5128
|
const cubic = seg.length === 2 ? [seg[0], seg[0], seg[1], seg[1]] : seg;
|
|
4507
5129
|
const len2 = segmentLength(seg);
|
|
4508
5130
|
const m = Math.min(64, Math.max(1, Math.ceil(Math.abs(a) * len2 / rmax / 0.15 + len2 / 50)));
|
|
@@ -4515,13 +5137,13 @@ function twistPaths(paths, angle, center) {
|
|
|
4515
5137
|
segs.push([p0, [p0[0] + h1[0], p0[1] + h1[1]], [p3[0] + h2[0], p3[1] + h2[1]], p3]);
|
|
4516
5138
|
}
|
|
4517
5139
|
}
|
|
4518
|
-
out.push({ segs, closed:
|
|
5140
|
+
out.push({ segs, closed: sub4.closed });
|
|
4519
5141
|
}
|
|
4520
5142
|
return subsToPath(out);
|
|
4521
5143
|
});
|
|
4522
5144
|
}
|
|
4523
|
-
function resample(
|
|
4524
|
-
const segs =
|
|
5145
|
+
function resample(sub4, m) {
|
|
5146
|
+
const segs = sub4.segs;
|
|
4525
5147
|
const n = segs.length;
|
|
4526
5148
|
const lens = segs.map((s) => segmentLength(s));
|
|
4527
5149
|
const out = [];
|
|
@@ -4530,7 +5152,7 @@ function resample(sub5, m) {
|
|
|
4530
5152
|
for (let k = 0; k < m; k++) {
|
|
4531
5153
|
if (k === 0) {
|
|
4532
5154
|
const tout = startTangent(segs[j]);
|
|
4533
|
-
const prev =
|
|
5155
|
+
const prev = sub4.closed || j > 0 ? (j + n - 1) % n : null;
|
|
4534
5156
|
let tan = tout;
|
|
4535
5157
|
if (prev !== null) {
|
|
4536
5158
|
const tin = endTangent(segs[prev]);
|
|
@@ -4543,7 +5165,7 @@ function resample(sub5, m) {
|
|
|
4543
5165
|
}
|
|
4544
5166
|
}
|
|
4545
5167
|
}
|
|
4546
|
-
if (!
|
|
5168
|
+
if (!sub4.closed) {
|
|
4547
5169
|
const last = segs[n - 1];
|
|
4548
5170
|
out.push({ p: last[last.length - 1], tan: endTangent(last), lenPrev: lens[n - 1] / m, lenNext: 0 });
|
|
4549
5171
|
}
|
|
@@ -4571,14 +5193,14 @@ function zigzagPaths(paths, size, ridges, smooth = false) {
|
|
|
4571
5193
|
const m = Math.min(1e3, Math.max(0, Math.round(Number.isFinite(ridges) ? ridges : 0))) + 1;
|
|
4572
5194
|
return paths.map((p) => {
|
|
4573
5195
|
const out = [];
|
|
4574
|
-
for (const
|
|
4575
|
-
const s = resample(
|
|
5196
|
+
for (const sub4 of subsOf(p)) {
|
|
5197
|
+
const s = resample(sub4, m);
|
|
4576
5198
|
const disp = s.map((x, i) => {
|
|
4577
5199
|
const n = perp2(x.tan);
|
|
4578
5200
|
const d = i % 2 === 0 ? size : -size;
|
|
4579
5201
|
return [n[0] * d, n[1] * d];
|
|
4580
5202
|
});
|
|
4581
|
-
const e = emit(s, disp,
|
|
5203
|
+
const e = emit(s, disp, sub4.closed, smooth, 0.36);
|
|
4582
5204
|
if (e) out.push(e);
|
|
4583
5205
|
}
|
|
4584
5206
|
return subsToPath(out);
|
|
@@ -4617,8 +5239,8 @@ function wigglePaths(paths, w) {
|
|
|
4617
5239
|
let idx = 0;
|
|
4618
5240
|
return paths.map((p) => {
|
|
4619
5241
|
const out = [];
|
|
4620
|
-
for (const
|
|
4621
|
-
const s = resample(
|
|
5242
|
+
for (const sub4 of subsOf(p)) {
|
|
5243
|
+
const s = resample(sub4, m);
|
|
4622
5244
|
const disp = s.map(() => {
|
|
4623
5245
|
const i = BigInt(idx);
|
|
4624
5246
|
const ox = noise(seed, i * 2n, t + idx * 0.37);
|
|
@@ -4626,7 +5248,7 @@ function wigglePaths(paths, w) {
|
|
|
4626
5248
|
idx++;
|
|
4627
5249
|
return [(sx * corr + ox * (1 - corr)) * w.size, (sy * corr + oy * (1 - corr)) * w.size];
|
|
4628
5250
|
});
|
|
4629
|
-
const e = emit(s, disp,
|
|
5251
|
+
const e = emit(s, disp, sub4.closed, w.smooth, 1 / 3);
|
|
4630
5252
|
if (e) out.push(e);
|
|
4631
5253
|
}
|
|
4632
5254
|
return subsToPath(out);
|
|
@@ -4667,1885 +5289,6 @@ function pathsCenter(paths) {
|
|
|
4667
5289
|
return b ? { x: (b.minX + b.maxX) / 2, y: (b.minY + b.maxY) / 2 } : { x: 0, y: 0 };
|
|
4668
5290
|
}
|
|
4669
5291
|
|
|
4670
|
-
// src/vector/blend.ts
|
|
4671
|
-
var lerpN = (a, b, t) => a + (b - a) * t;
|
|
4672
|
-
var lerpP = (a, b, t) => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
|
|
4673
|
-
var toP = (v2) => [v2.x, v2.y];
|
|
4674
|
-
var mapP = (m, p) => [m[0] * p[0] + m[2] * p[1] + m[4], m[1] * p[0] + m[3] * p[1] + m[5]];
|
|
4675
|
-
var curvesOf = (c) => Math.max(0, (c.pts.length - 1) / 3) | 0;
|
|
4676
|
-
function subpathToMorphContour(sp, m = IDENTITY_MATRIX) {
|
|
4677
|
-
const n = sp.anchors.length;
|
|
4678
|
-
if (!n) return null;
|
|
4679
|
-
const first = mapP(m, toP(sp.anchors[0]));
|
|
4680
|
-
const pts = [first];
|
|
4681
|
-
const count = n < 2 ? 0 : sp.closed ? n : n - 1;
|
|
4682
|
-
for (let i = 0; i < count; i++) {
|
|
4683
|
-
const a = sp.anchors[i];
|
|
4684
|
-
const b = sp.anchors[(i + 1) % n];
|
|
4685
|
-
const pa = toP(a);
|
|
4686
|
-
const pb = toP(b);
|
|
4687
|
-
const straight = (!a.out || a.out.x === a.x && a.out.y === a.y) && (!b.in || b.in.x === b.x && b.in.y === b.y);
|
|
4688
|
-
const c1 = straight ? lerpP(pa, pb, 1 / 3) : toP(a.out ?? a);
|
|
4689
|
-
const c2 = straight ? lerpP(pa, pb, 2 / 3) : toP(b.in ?? b);
|
|
4690
|
-
pts.push(mapP(m, c1), mapP(m, c2), i === count - 1 && sp.closed ? first : mapP(m, pb));
|
|
4691
|
-
}
|
|
4692
|
-
return { closed: sp.closed && count > 0, pts };
|
|
4693
|
-
}
|
|
4694
|
-
function isStraight(p0, p1, p2, p3) {
|
|
4695
|
-
const dx = p3[0] - p0[0];
|
|
4696
|
-
const dy = p3[1] - p0[1];
|
|
4697
|
-
const len2 = Math.hypot(dx, dy);
|
|
4698
|
-
const tol = Math.max(1e-7, len2 * 1e-7);
|
|
4699
|
-
if (len2 < 1e-12) return Math.hypot(p1[0] - p0[0], p1[1] - p0[1]) < tol && Math.hypot(p2[0] - p0[0], p2[1] - p0[1]) < tol;
|
|
4700
|
-
const off = (p) => Math.abs((p[0] - p0[0]) * dy - (p[1] - p0[1]) * dx) / len2;
|
|
4701
|
-
const along2 = (p) => ((p[0] - p0[0]) * dx + (p[1] - p0[1]) * dy) / (len2 * len2);
|
|
4702
|
-
const u1 = along2(p1);
|
|
4703
|
-
const u2 = along2(p2);
|
|
4704
|
-
return off(p1) < tol && off(p2) < tol && u1 >= -1e-9 && u1 <= 1 + 1e-9 && u2 >= -1e-9 && u2 <= 1 + 1e-9;
|
|
4705
|
-
}
|
|
4706
|
-
function morphContourToSubpath(c, m = IDENTITY_MATRIX, closed = c.closed) {
|
|
4707
|
-
const pts = isIdentityMatrix(m) ? c.pts : c.pts.map((p) => mapP(m, p));
|
|
4708
|
-
const curves = curvesOf(c);
|
|
4709
|
-
const dropLast = closed && c.closed && curves > 0;
|
|
4710
|
-
const count = dropLast ? curves : curves + 1;
|
|
4711
|
-
const anchors = [];
|
|
4712
|
-
for (let k = 0; k < count; k++) anchors.push({ x: pts[3 * k][0], y: pts[3 * k][1] });
|
|
4713
|
-
for (let k = 0; k < curves; k++) {
|
|
4714
|
-
const p0 = pts[3 * k];
|
|
4715
|
-
const p1 = pts[3 * k + 1];
|
|
4716
|
-
const p2 = pts[3 * k + 2];
|
|
4717
|
-
const p3 = pts[3 * k + 3];
|
|
4718
|
-
if (isStraight(p0, p1, p2, p3)) continue;
|
|
4719
|
-
anchors[k].out = { x: p1[0], y: p1[1] };
|
|
4720
|
-
anchors[(k + 1) % count].in = { x: p2[0], y: p2[1] };
|
|
4721
|
-
}
|
|
4722
|
-
for (const a of anchors) {
|
|
4723
|
-
const type = inferAnchorType(a);
|
|
4724
|
-
if (type !== "corner") a.type = type;
|
|
4725
|
-
}
|
|
4726
|
-
const isClosed = closed && curves > 0;
|
|
4727
|
-
return { anchors: dropCollinear(anchors, isClosed), closed: isClosed };
|
|
4728
|
-
}
|
|
4729
|
-
function dropCollinear(anchors, closed) {
|
|
4730
|
-
const out = anchors.slice();
|
|
4731
|
-
const min = closed ? 3 : 2;
|
|
4732
|
-
let i = closed ? 0 : 1;
|
|
4733
|
-
while (out.length > min && i < out.length - (closed ? 0 : 1)) {
|
|
4734
|
-
const n = out.length;
|
|
4735
|
-
const a = out[(i - 1 + n) % n];
|
|
4736
|
-
const b = out[i];
|
|
4737
|
-
const c = out[(i + 1) % n];
|
|
4738
|
-
const plain2 = !b.in && !b.out && !a.out && !c.in;
|
|
4739
|
-
const ux = b.x - a.x;
|
|
4740
|
-
const uy = b.y - a.y;
|
|
4741
|
-
const vx = c.x - b.x;
|
|
4742
|
-
const vy = c.y - b.y;
|
|
4743
|
-
const len2 = Math.hypot(ux, uy) + Math.hypot(vx, vy);
|
|
4744
|
-
if (plain2 && Math.abs(ux * vy - uy * vx) <= 1e-9 * Math.max(1, len2 * len2) && ux * vx + uy * vy >= 0) out.splice(i, 1);
|
|
4745
|
-
else i++;
|
|
4746
|
-
}
|
|
4747
|
-
return out;
|
|
4748
|
-
}
|
|
4749
|
-
var segOf = (c, k) => c.pts.slice(3 * k, 3 * k + 4);
|
|
4750
|
-
function refineMorphContour(c, segments) {
|
|
4751
|
-
const have = curvesOf(c);
|
|
4752
|
-
if (have === 0) return { contour: { closed: c.closed, pts: Array.from({ length: 1 + 3 * segments }, () => [c.pts[0][0], c.pts[0][1]]) }, anchors: [0] };
|
|
4753
|
-
const identity = Array.from({ length: c.closed ? have : have + 1 }, (_, i) => i);
|
|
4754
|
-
if (have >= segments) return { contour: c, anchors: identity };
|
|
4755
|
-
const segs = Array.from({ length: have }, (_, k) => segOf(c, k));
|
|
4756
|
-
const lens = segs.map((s) => segmentLength(s));
|
|
4757
|
-
const sum = lens.reduce((a, b) => a + b, 0);
|
|
4758
|
-
const extra = segments - have;
|
|
4759
|
-
const want = lens.map((l) => sum > 1e-12 ? l / sum * extra : extra / have);
|
|
4760
|
-
const parts = want.map((w) => 1 + Math.floor(w));
|
|
4761
|
-
let left2 = segments - parts.reduce((a, b) => a + b, 0);
|
|
4762
|
-
const frac = want.map((w) => w - Math.floor(w));
|
|
4763
|
-
const order = parts.map((_, i) => i).sort((a, b) => Math.abs(frac[b] - frac[a]) > 1e-9 ? frac[b] - frac[a] : a - b);
|
|
4764
|
-
for (let i = 0; left2 > 0; i = (i + 1) % order.length, left2--) parts[order[i]]++;
|
|
4765
|
-
const pts = [c.pts[0]];
|
|
4766
|
-
const anchors = [0];
|
|
4767
|
-
let at2 = 0;
|
|
4768
|
-
segs.forEach((seg, k) => {
|
|
4769
|
-
const pieces = parts[k];
|
|
4770
|
-
let rest = seg.slice();
|
|
4771
|
-
let t0 = 0;
|
|
4772
|
-
for (let j = 1; j < pieces; j++) {
|
|
4773
|
-
const t = segmentParamAtLength(seg, lens[k] * j / pieces, lens[k]);
|
|
4774
|
-
const u = Math.min(1, Math.max(0, (t - t0) / (1 - t0 || 1)));
|
|
4775
|
-
const [l, r] = splitSegment(rest, u);
|
|
4776
|
-
pts.push(l[1], l[2], l[3]);
|
|
4777
|
-
rest = r;
|
|
4778
|
-
t0 = t;
|
|
4779
|
-
}
|
|
4780
|
-
pts.push(rest[1], rest[2], k === have - 1 && c.closed ? c.pts[0] : rest[3]);
|
|
4781
|
-
at2 += pieces;
|
|
4782
|
-
if (k < have - 1 || !c.closed) anchors.push(at2);
|
|
4783
|
-
});
|
|
4784
|
-
return { contour: { closed: c.closed, pts }, anchors };
|
|
4785
|
-
}
|
|
4786
|
-
function reverseMorphContour(c) {
|
|
4787
|
-
return { closed: c.closed, pts: c.pts.slice().reverse() };
|
|
4788
|
-
}
|
|
4789
|
-
function turnMorphContour(c, s) {
|
|
4790
|
-
const n = curvesOf(c);
|
|
4791
|
-
if (!c.closed || n === 0) return c;
|
|
4792
|
-
const k = (s % n + n) % n;
|
|
4793
|
-
if (k === 0) return c;
|
|
4794
|
-
const body = c.pts.slice(1);
|
|
4795
|
-
return { closed: true, pts: [c.pts[3 * k], ...body.slice(3 * k), ...body.slice(0, 3 * k)] };
|
|
4796
|
-
}
|
|
4797
|
-
function anchorPoints(c) {
|
|
4798
|
-
const n = curvesOf(c);
|
|
4799
|
-
const count = c.closed ? n : n + 1;
|
|
4800
|
-
return Array.from({ length: Math.max(1, count) }, (_, k) => c.pts[3 * k]);
|
|
4801
|
-
}
|
|
4802
|
-
function polygonArea(pts) {
|
|
4803
|
-
let s = 0;
|
|
4804
|
-
for (let i = 0; i < pts.length; i++) {
|
|
4805
|
-
const a = pts[i];
|
|
4806
|
-
const b = pts[(i + 1) % pts.length];
|
|
4807
|
-
s += a[0] * b[1] - b[0] * a[1];
|
|
4808
|
-
}
|
|
4809
|
-
return s / 2;
|
|
4810
|
-
}
|
|
4811
|
-
function frame(v2) {
|
|
4812
|
-
const n = Math.max(1, v2.length);
|
|
4813
|
-
let cx = 0;
|
|
4814
|
-
let cy = 0;
|
|
4815
|
-
for (const p of v2) {
|
|
4816
|
-
cx += p[0];
|
|
4817
|
-
cy += p[1];
|
|
4818
|
-
}
|
|
4819
|
-
cx /= n;
|
|
4820
|
-
cy /= n;
|
|
4821
|
-
let s = 0;
|
|
4822
|
-
for (const p of v2) s += (p[0] - cx) ** 2 + (p[1] - cy) ** 2;
|
|
4823
|
-
return { c: [cx, cy], r: Math.max(1e-9, Math.sqrt(s / n)) };
|
|
4824
|
-
}
|
|
4825
|
-
var RBINS = 5;
|
|
4826
|
-
var ABINS = 12;
|
|
4827
|
-
var TURN_WEIGHT = 0.1;
|
|
4828
|
-
function shapeContexts(v2, closed) {
|
|
4829
|
-
const { r } = frame(v2);
|
|
4830
|
-
const n = v2.length;
|
|
4831
|
-
return v2.map((p, i) => {
|
|
4832
|
-
const prev = v2[closed ? (i - 1 + n) % n : Math.max(0, i - 1)];
|
|
4833
|
-
const next = v2[closed ? (i + 1) % n : Math.min(n - 1, i + 1)];
|
|
4834
|
-
const dir = Math.atan2(next[1] - prev[1], next[0] - prev[0]);
|
|
4835
|
-
const h = new Float64Array(RBINS * ABINS);
|
|
4836
|
-
let total = 0;
|
|
4837
|
-
for (let j = 0; j < n; j++) {
|
|
4838
|
-
if (i === j) continue;
|
|
4839
|
-
const dx = v2[j][0] - p[0];
|
|
4840
|
-
const dy = v2[j][1] - p[1];
|
|
4841
|
-
const d = Math.hypot(dx, dy) / r;
|
|
4842
|
-
const lr = (Math.log2(Math.max(d, 1e-6)) + 3) / 4 * RBINS;
|
|
4843
|
-
if (!(lr >= 0 && lr < RBINS)) continue;
|
|
4844
|
-
let ang = Math.atan2(dy, dx) - dir;
|
|
4845
|
-
ang = (ang % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
4846
|
-
h[Math.floor(lr) * ABINS + Math.min(ABINS - 1, Math.floor(ang / (2 * Math.PI) * ABINS))] += 1;
|
|
4847
|
-
total++;
|
|
4848
|
-
}
|
|
4849
|
-
if (total > 0) for (let k = 0; k < h.length; k++) h[k] /= total;
|
|
4850
|
-
return h;
|
|
4851
|
-
});
|
|
4852
|
-
}
|
|
4853
|
-
function chi2(a, b) {
|
|
4854
|
-
let s = 0;
|
|
4855
|
-
for (let k = 0; k < a.length; k++) {
|
|
4856
|
-
const t = a[k] + b[k];
|
|
4857
|
-
if (t > 1e-12) s += (a[k] - b[k]) * (a[k] - b[k]) / t;
|
|
4858
|
-
}
|
|
4859
|
-
return s / 2;
|
|
4860
|
-
}
|
|
4861
|
-
function bestStart(fixed, free, useShapeContext) {
|
|
4862
|
-
const fa = anchorPoints(fixed);
|
|
4863
|
-
const ga = anchorPoints(free);
|
|
4864
|
-
const n = ga.length;
|
|
4865
|
-
const ff = frame(fa);
|
|
4866
|
-
const gf = frame(ga);
|
|
4867
|
-
const fn = fa.map((p) => [(p[0] - ff.c[0]) / ff.r, (p[1] - ff.c[1]) / ff.r]);
|
|
4868
|
-
const gn = ga.map((p) => [(p[0] - gf.c[0]) / gf.r, (p[1] - gf.c[1]) / gf.r]);
|
|
4869
|
-
const fsc = useShapeContext ? shapeContexts(fa, fixed.closed) : null;
|
|
4870
|
-
const gsc = useShapeContext ? shapeContexts(ga, free.closed) : null;
|
|
4871
|
-
const m = Math.max(1, fn.length);
|
|
4872
|
-
const cost = (s) => {
|
|
4873
|
-
let dot3 = 0;
|
|
4874
|
-
let cross2 = 0;
|
|
4875
|
-
let sc = 0;
|
|
4876
|
-
for (let i = 0; i < fn.length; i++) {
|
|
4877
|
-
const j = free.closed ? (i + s) % n : i;
|
|
4878
|
-
const p = fn[i];
|
|
4879
|
-
const q = gn[j];
|
|
4880
|
-
dot3 += p[0] * q[0] + p[1] * q[1];
|
|
4881
|
-
cross2 += p[0] * q[1] - p[1] * q[0];
|
|
4882
|
-
if (fsc && gsc) sc += chi2(fsc[i], gsc[j]);
|
|
4883
|
-
}
|
|
4884
|
-
const residual = Math.max(0, 1 - (dot3 * dot3 + cross2 * cross2) / (m * m));
|
|
4885
|
-
const turn = 1 - Math.cos(Math.atan2(cross2, dot3));
|
|
4886
|
-
return residual + TURN_WEIGHT * turn + sc / m;
|
|
4887
|
-
};
|
|
4888
|
-
if (!free.closed) return { start: 0, cost: cost(0) };
|
|
4889
|
-
const stride = n > 96 ? Math.ceil(n / 48) : 1;
|
|
4890
|
-
let best = { start: 0, cost: Infinity };
|
|
4891
|
-
for (let s = 0; s < n; s += stride) {
|
|
4892
|
-
const c = cost(s);
|
|
4893
|
-
if (c < best.cost - 1e-12) best = { start: s, cost: c };
|
|
4894
|
-
}
|
|
4895
|
-
if (stride > 1) {
|
|
4896
|
-
const s0 = best.start;
|
|
4897
|
-
for (let d = 1; d < stride; d++)
|
|
4898
|
-
for (const s of [(s0 + d) % n, (s0 - d + n) % n]) {
|
|
4899
|
-
const c = cost(s);
|
|
4900
|
-
if (c < best.cost - 1e-12) best = { start: s, cost: c };
|
|
4901
|
-
}
|
|
4902
|
-
}
|
|
4903
|
-
return best;
|
|
4904
|
-
}
|
|
4905
|
-
function placeIn(c, from, to) {
|
|
4906
|
-
const b = unionBounds([boundsOfPoints(c.pts)]);
|
|
4907
|
-
const p = b ? [b.x + b.width / 2, b.y + b.height / 2] : c.pts[0];
|
|
4908
|
-
if (!from || !to) return p;
|
|
4909
|
-
const fx = from.width > 0 ? (p[0] - from.x) / from.width : 0.5;
|
|
4910
|
-
const fy = from.height > 0 ? (p[1] - from.y) / from.height : 0.5;
|
|
4911
|
-
return [to.x + to.width * fx, to.y + to.height * fy];
|
|
4912
|
-
}
|
|
4913
|
-
function boundsOfPoints(pts) {
|
|
4914
|
-
if (!pts.length) return null;
|
|
4915
|
-
let x0 = Infinity;
|
|
4916
|
-
let y0 = Infinity;
|
|
4917
|
-
let x1 = -Infinity;
|
|
4918
|
-
let y1 = -Infinity;
|
|
4919
|
-
for (const p of pts) {
|
|
4920
|
-
x0 = Math.min(x0, p[0]);
|
|
4921
|
-
y0 = Math.min(y0, p[1]);
|
|
4922
|
-
x1 = Math.max(x1, p[0]);
|
|
4923
|
-
y1 = Math.max(y1, p[1]);
|
|
4924
|
-
}
|
|
4925
|
-
return { x: x0, y: y0, width: x1 - x0, height: y1 - y0 };
|
|
4926
|
-
}
|
|
4927
|
-
function correspondMorphContours(a, b, options = {}) {
|
|
4928
|
-
const minSeg = Math.max(1, Math.round(options.minSegments ?? 16));
|
|
4929
|
-
const maxSeg = Math.max(minSeg, Math.round(options.maxSegments ?? 400));
|
|
4930
|
-
const spacing = options.spacing && options.spacing > 0 ? options.spacing : null;
|
|
4931
|
-
const useSC = options.shapeContext !== false;
|
|
4932
|
-
const match = options.matchStart !== false;
|
|
4933
|
-
const ba = boundsOfPoints(a.flatMap((c) => c.pts));
|
|
4934
|
-
const bb = boundsOfPoints(b.flatMap((c) => c.pts));
|
|
4935
|
-
const contourLength = (c) => {
|
|
4936
|
-
let l = 0;
|
|
4937
|
-
for (let k = 0; k < curvesOf(c); k++) l += segmentLength(segOf(c, k));
|
|
4938
|
-
return l;
|
|
4939
|
-
};
|
|
4940
|
-
const pairs = [];
|
|
4941
|
-
const [sa, sb] = options.starts ?? [];
|
|
4942
|
-
for (let k = 0; k < Math.max(a.length, b.length); k++) {
|
|
4943
|
-
const ca = a[k];
|
|
4944
|
-
const cb = b[k];
|
|
4945
|
-
const explicitA = k === 0 && sa !== null && sa !== void 0 ? sa : null;
|
|
4946
|
-
const explicitB = k === 0 && sb !== null && sb !== void 0 ? sb : null;
|
|
4947
|
-
const counts = [ca ? curvesOf(ca) : 0, cb ? curvesOf(cb) : 0];
|
|
4948
|
-
const longest = Math.max(ca ? contourLength(ca) : 0, cb ? contourLength(cb) : 0);
|
|
4949
|
-
let n = Math.max(counts[0], counts[1], minSeg, spacing ? Math.ceil(longest / spacing) : 0);
|
|
4950
|
-
n = Math.max(counts[0], counts[1], Math.min(n, maxSeg));
|
|
4951
|
-
const point = (c, from, to) => {
|
|
4952
|
-
const p = placeIn(c, from, to);
|
|
4953
|
-
return { closed: c.closed, pts: Array.from({ length: 1 + 3 * n }, () => [p[0], p[1]]) };
|
|
4954
|
-
};
|
|
4955
|
-
if (ca && cb) {
|
|
4956
|
-
const ra = refineMorphContour(ca, n);
|
|
4957
|
-
const rb = refineMorphContour(cb, n);
|
|
4958
|
-
pairs.push({
|
|
4959
|
-
x: ra.contour,
|
|
4960
|
-
y: rb.contour,
|
|
4961
|
-
point: false,
|
|
4962
|
-
startX: explicitA === null ? null : ra.anchors[explicitA] ?? null,
|
|
4963
|
-
startY: explicitB === null ? null : explicitB === rb.anchors.length - 1 && !cb.closed ? -1 : rb.anchors[explicitB] ?? null
|
|
4964
|
-
});
|
|
4965
|
-
if (explicitA !== null && !ca.closed && explicitA === ra.anchors.length - 1 && explicitA > 0) pairs[pairs.length - 1].startX = -1;
|
|
4966
|
-
} else if (ca) pairs.push({ x: refineMorphContour(ca, n).contour, y: point(ca, ba, bb), point: true, startX: null, startY: null });
|
|
4967
|
-
else if (cb) pairs.push({ x: point(cb, bb, ba), y: refineMorphContour(cb, n).contour, point: true, startX: null, startY: null });
|
|
4968
|
-
}
|
|
4969
|
-
const startAt = (c, s) => {
|
|
4970
|
-
if (s === null) return c;
|
|
4971
|
-
if (s === -1) return reverseMorphContour(c);
|
|
4972
|
-
return c.closed ? turnMorphContour(c, s) : c;
|
|
4973
|
-
};
|
|
4974
|
-
const explicit = pairs.length > 0 && (pairs[0].startX !== null || pairs[0].startY !== null);
|
|
4975
|
-
const ref = pairs.find((p) => !p.point && p.x.closed && p.y.closed);
|
|
4976
|
-
const fixedBack = ref ? Math.sign(polygonArea(anchorPoints(ref.x))) !== Math.sign(polygonArea(anchorPoints(ref.y))) && Math.abs(polygonArea(anchorPoints(ref.y))) > 1e-12 : explicit ? false : null;
|
|
4977
|
-
let best = null;
|
|
4978
|
-
for (const back of fixedBack === null ? [false, true] : [fixedBack]) {
|
|
4979
|
-
const xs = [];
|
|
4980
|
-
const ys = [];
|
|
4981
|
-
let cost = 0;
|
|
4982
|
-
pairs.forEach((p, k) => {
|
|
4983
|
-
let x = k === 0 ? startAt(p.x, p.startX) : p.x;
|
|
4984
|
-
let y = k === 0 ? startAt(p.y, p.startY) : p.y;
|
|
4985
|
-
if (back) y = reverseMorphContour(y);
|
|
4986
|
-
if (p.point) {
|
|
4987
|
-
xs.push(x);
|
|
4988
|
-
ys.push(y);
|
|
4989
|
-
return;
|
|
4990
|
-
}
|
|
4991
|
-
const pinned = k === 0 && explicit;
|
|
4992
|
-
const turnX = !y.closed && x.closed;
|
|
4993
|
-
if (match && !pinned && (y.closed || turnX)) {
|
|
4994
|
-
const r = turnX ? bestStart(y, x, useSC) : bestStart(x, y, useSC);
|
|
4995
|
-
if (turnX) x = turnMorphContour(x, r.start);
|
|
4996
|
-
else y = turnMorphContour(y, r.start);
|
|
4997
|
-
cost += r.cost;
|
|
4998
|
-
} else cost += bestStart(x, { ...y, closed: false }, useSC).cost;
|
|
4999
|
-
xs.push(x);
|
|
5000
|
-
ys.push(y);
|
|
5001
|
-
});
|
|
5002
|
-
if (!best || cost < best.cost - 1e-9) best = { xs, ys, cost, back };
|
|
5003
|
-
}
|
|
5004
|
-
return best ? { a: best.xs, b: best.ys, reversed: best.back } : { a: [], b: [], reversed: false };
|
|
5005
|
-
}
|
|
5006
|
-
function morphPathsCross(a, b) {
|
|
5007
|
-
let count = 0;
|
|
5008
|
-
const d = (p, q, r) => (q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0]);
|
|
5009
|
-
for (let k = 0; k < Math.min(a.length, b.length); k++) {
|
|
5010
|
-
const pa = anchorPoints(a[k]);
|
|
5011
|
-
const pb = anchorPoints(b[k]);
|
|
5012
|
-
const n = Math.min(pa.length, pb.length);
|
|
5013
|
-
for (let i = 0; i < n; i++)
|
|
5014
|
-
for (let j = i + 1; j < n; j++) {
|
|
5015
|
-
const d1 = d(pa[j], pb[j], pa[i]);
|
|
5016
|
-
const d2 = d(pa[j], pb[j], pb[i]);
|
|
5017
|
-
const d3 = d(pa[i], pb[i], pa[j]);
|
|
5018
|
-
const d4 = d(pa[i], pb[i], pb[j]);
|
|
5019
|
-
if (d1 * d2 < 0 && d3 * d4 < 0) count++;
|
|
5020
|
-
}
|
|
5021
|
-
}
|
|
5022
|
-
return count;
|
|
5023
|
-
}
|
|
5024
|
-
function procrustes(a, b) {
|
|
5025
|
-
const pa = a.flatMap(anchorPoints);
|
|
5026
|
-
const pb = b.flatMap(anchorPoints);
|
|
5027
|
-
const ca = frame(pa).c;
|
|
5028
|
-
const cb = frame(pb).c;
|
|
5029
|
-
let ss = 0;
|
|
5030
|
-
let dot3 = 0;
|
|
5031
|
-
let cross2 = 0;
|
|
5032
|
-
for (let i = 0; i < Math.min(pa.length, pb.length); i++) {
|
|
5033
|
-
const p = [pa[i][0] - ca[0], pa[i][1] - ca[1]];
|
|
5034
|
-
const q = [pb[i][0] - cb[0], pb[i][1] - cb[1]];
|
|
5035
|
-
ss += p[0] * p[0] + p[1] * p[1];
|
|
5036
|
-
dot3 += p[0] * q[0] + p[1] * q[1];
|
|
5037
|
-
cross2 += p[0] * q[1] - p[1] * q[0];
|
|
5038
|
-
}
|
|
5039
|
-
return { ca, cb, theta: Math.atan2(cross2, dot3), s: ss > 1e-12 ? Math.hypot(dot3, cross2) / ss : 1 };
|
|
5040
|
-
}
|
|
5041
|
-
function interpolateMorphContours(a, b, u, options = {}) {
|
|
5042
|
-
const w = options.linear ? 0 : Math.min(1, Math.max(0, options.rigidity ?? 1));
|
|
5043
|
-
const sim = w > 0 ? options.similarity ?? procrustes(a, b) : null;
|
|
5044
|
-
const rot = (p, ang, k) => {
|
|
5045
|
-
const c = Math.cos(ang);
|
|
5046
|
-
const s = Math.sin(ang);
|
|
5047
|
-
return [k * (c * p[0] - s * p[1]), k * (s * p[0] + c * p[1])];
|
|
5048
|
-
};
|
|
5049
|
-
const thetaU = sim ? sim.theta * u : 0;
|
|
5050
|
-
const sU = sim ? Math.max(1e-9, sim.s) ** u : 1;
|
|
5051
|
-
const cU = sim ? lerpP(sim.ca, sim.cb, u) : [0, 0];
|
|
5052
|
-
return a.map((ca, k) => {
|
|
5053
|
-
const cb = b[k];
|
|
5054
|
-
const pts = ca.pts.map((p, i) => {
|
|
5055
|
-
const q = cb.pts[i] ?? p;
|
|
5056
|
-
const linear = lerpP(p, q, u);
|
|
5057
|
-
if (!sim) return linear;
|
|
5058
|
-
const d = [p[0] - sim.ca[0], p[1] - sim.ca[1]];
|
|
5059
|
-
const full = rot(d, sim.theta, sim.s);
|
|
5060
|
-
const resid = [q[0] - (full[0] + sim.cb[0]), q[1] - (full[1] + sim.cb[1])];
|
|
5061
|
-
const part = rot(d, thetaU, sU);
|
|
5062
|
-
const rigid = [part[0] + cU[0] + resid[0] * u, part[1] + cU[1] + resid[1] * u];
|
|
5063
|
-
return lerpP(linear, rigid, w);
|
|
5064
|
-
});
|
|
5065
|
-
return { closed: ca.closed && cb.closed, pts };
|
|
5066
|
-
});
|
|
5067
|
-
}
|
|
5068
|
-
function interpolateRigidMatrix(a, b, t) {
|
|
5069
|
-
const decompose = (m) => {
|
|
5070
|
-
const sx2 = Math.hypot(m[0], m[1]);
|
|
5071
|
-
const ang2 = sx2 > 1e-12 ? Math.atan2(m[1], m[0]) : 0;
|
|
5072
|
-
const c2 = Math.cos(ang2);
|
|
5073
|
-
const s2 = Math.sin(ang2);
|
|
5074
|
-
return { e: m[4], f: m[5], ang: ang2, sx: sx2, sh: c2 * m[2] + s2 * m[3], sy: -s2 * m[2] + c2 * m[3] };
|
|
5075
|
-
};
|
|
5076
|
-
const p = decompose(a);
|
|
5077
|
-
const q = decompose(b);
|
|
5078
|
-
let turn = q.ang - p.ang;
|
|
5079
|
-
turn = ((turn + Math.PI) % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI) - Math.PI;
|
|
5080
|
-
const ang = p.ang + turn * t;
|
|
5081
|
-
const sx = lerpN(p.sx, q.sx, t);
|
|
5082
|
-
const sh = lerpN(p.sh, q.sh, t);
|
|
5083
|
-
const sy = lerpN(p.sy, q.sy, t);
|
|
5084
|
-
const c = Math.cos(ang);
|
|
5085
|
-
const s = Math.sin(ang);
|
|
5086
|
-
return [c * sx, s * sx, c * sh - s * sy, s * sh + c * sy, lerpN(p.e, q.e, t), lerpN(p.f, q.f, t)];
|
|
5087
|
-
}
|
|
5088
|
-
function interpolateVectorColor(a, b, t) {
|
|
5089
|
-
if (t <= 0) return a;
|
|
5090
|
-
if (t >= 1) return b;
|
|
5091
|
-
return mixColorsOklab(a, b, t) ?? (t < 0.5 ? a : b);
|
|
5092
|
-
}
|
|
5093
|
-
function resampleGradientStops(g, offsets) {
|
|
5094
|
-
return offsets.map((offset) => {
|
|
5095
|
-
const s = sampleVectorGradient(g, offset);
|
|
5096
|
-
return s.opacity < 1 ? { offset, color: s.color, opacity: Math.round(s.opacity * 1e4) / 1e4 } : { offset, color: s.color };
|
|
5097
|
-
});
|
|
5098
|
-
}
|
|
5099
|
-
function lerpAngle(a, b, t) {
|
|
5100
|
-
const d = ((b - a + 180) % 360 + 360) % 360 - 180;
|
|
5101
|
-
return a + d * t;
|
|
5102
|
-
}
|
|
5103
|
-
var lerpPoint = (a, b, t) => ({ x: lerpN(a.x, b.x, t), y: lerpN(a.y, b.y, t) });
|
|
5104
|
-
var sameColourModel = (a, b) => (a.interpolation ?? "srgb") === (b.interpolation ?? "srgb") && (a.smoothness ?? 0) === (b.smoothness ?? 0);
|
|
5105
|
-
function lerpStops(a, b, t) {
|
|
5106
|
-
let stopsA = sortedVectorGradientStops(a);
|
|
5107
|
-
let stopsB = sortedVectorGradientStops(b);
|
|
5108
|
-
const resampled = stopsA.length !== stopsB.length || !sameColourModel(a, b);
|
|
5109
|
-
if (resampled) {
|
|
5110
|
-
const offs = [...expandVectorGradientStops(a), ...expandVectorGradientStops(b), ...stopsA, ...stopsB].map((s) => s.offset).filter(Number.isFinite).sort((x, y) => x - y);
|
|
5111
|
-
const common = offs.filter((o, i) => i === 0 || o - offs[i - 1] > 1e-4);
|
|
5112
|
-
stopsA = resampleGradientStops(a, common);
|
|
5113
|
-
stopsB = resampleGradientStops(b, common);
|
|
5114
|
-
}
|
|
5115
|
-
const stops = stopsA.map((x, i) => {
|
|
5116
|
-
const y = stopsB[i];
|
|
5117
|
-
const opacity = lerpN(x.opacity ?? 1, y.opacity ?? 1, t);
|
|
5118
|
-
const stop = { offset: lerpN(x.offset, y.offset, t), color: interpolateVectorColor(x.color, y.color, t) };
|
|
5119
|
-
if (opacity < 1) stop.opacity = opacity;
|
|
5120
|
-
const mid = lerpN(x.midpoint ?? 0.5, y.midpoint ?? 0.5, t);
|
|
5121
|
-
if (Math.abs(mid - 0.5) > 1e-6) stop.midpoint = mid;
|
|
5122
|
-
return stop;
|
|
5123
|
-
});
|
|
5124
|
-
return { stops, resampled };
|
|
5125
|
-
}
|
|
5126
|
-
function lerpGradient(a, b, t) {
|
|
5127
|
-
if (a.type !== b.type) return null;
|
|
5128
|
-
const { stops, resampled } = lerpStops(a, b, t);
|
|
5129
|
-
const near2 = t < 0.5 ? a : b;
|
|
5130
|
-
const out = { type: a.type, stops };
|
|
5131
|
-
if (!resampled) {
|
|
5132
|
-
if (a.interpolation && a.interpolation !== "srgb") out.interpolation = a.interpolation;
|
|
5133
|
-
if (a.smoothness) out.smoothness = a.smoothness;
|
|
5134
|
-
}
|
|
5135
|
-
if (near2.spread && near2.spread !== "pad") out.spread = near2.spread;
|
|
5136
|
-
if (near2.strokeMode && near2.strokeMode !== "within") out.strokeMode = near2.strokeMode;
|
|
5137
|
-
const ea = hasExplicitGradientGeometry(a);
|
|
5138
|
-
const eb = hasExplicitGradientGeometry(b);
|
|
5139
|
-
if (!ea && !eb) {
|
|
5140
|
-
if (a.angle !== void 0 || b.angle !== void 0 || a.type === "linear" || a.type === "reflected") {
|
|
5141
|
-
const fallback = a.type === "linear" || a.type === "reflected" ? 180 : 90;
|
|
5142
|
-
out.angle = lerpAngle(a.angle ?? fallback, b.angle ?? fallback, t);
|
|
5143
|
-
}
|
|
5144
|
-
if (a.type !== "linear" && a.type !== "reflected") {
|
|
5145
|
-
out.cx = lerpN(a.cx ?? 0.5, b.cx ?? 0.5, t);
|
|
5146
|
-
out.cy = lerpN(a.cy ?? 0.5, b.cy ?? 0.5, t);
|
|
5147
|
-
out.r = lerpN(a.r ?? 0.5, b.r ?? 0.5, t);
|
|
5148
|
-
}
|
|
5149
|
-
return out;
|
|
5150
|
-
}
|
|
5151
|
-
const pa = vectorGradientPoints(a);
|
|
5152
|
-
const pb = vectorGradientPoints(b);
|
|
5153
|
-
if (pa.units !== pb.units) {
|
|
5154
|
-
const src = explicitVectorGradient(near2);
|
|
5155
|
-
return { ...src, stops: out.stops, ...out.interpolation ? { interpolation: out.interpolation } : {}, ...out.smoothness ? { smoothness: out.smoothness } : {} };
|
|
5156
|
-
}
|
|
5157
|
-
out.start = lerpPoint(pa.start, pb.start, t);
|
|
5158
|
-
out.end = lerpPoint(pa.end, pb.end, t);
|
|
5159
|
-
out.width = lerpPoint(pa.width, pb.width, t);
|
|
5160
|
-
out.units = pa.units;
|
|
5161
|
-
if (a.type === "radial") {
|
|
5162
|
-
if (pa.focal || pb.focal) out.focal = lerpPoint(pa.focal ?? pa.start, pb.focal ?? pb.start, t);
|
|
5163
|
-
const fr = lerpN(pa.focalRadius, pb.focalRadius, t);
|
|
5164
|
-
if (fr > 0) out.focalRadius = fr;
|
|
5165
|
-
}
|
|
5166
|
-
return out;
|
|
5167
|
-
}
|
|
5168
|
-
function solidLike(color, like) {
|
|
5169
|
-
return { ...like, stops: like.stops.map((s) => color === null ? { offset: s.offset, color: s.color, opacity: 0 } : { offset: s.offset, color }) };
|
|
5170
|
-
}
|
|
5171
|
-
function interpolateVectorPaint(a, b, t) {
|
|
5172
|
-
if (t <= 0) return a;
|
|
5173
|
-
if (t >= 1) return b;
|
|
5174
|
-
const pa = hasPaint(a);
|
|
5175
|
-
const pb = hasPaint(b);
|
|
5176
|
-
if (!pa && !pb) return t < 0.5 ? a : b;
|
|
5177
|
-
if (typeof a === "string" && pa && typeof b === "string" && pb) return interpolateVectorColor(a, b, t);
|
|
5178
|
-
if (!pa && typeof b === "string") return interpolateVectorColor("transparent", b, t);
|
|
5179
|
-
if (!pb && typeof a === "string") return interpolateVectorColor(a, "transparent", t);
|
|
5180
|
-
const ga = pa && isVectorGradient(a) ? a : null;
|
|
5181
|
-
const gb = pb && isVectorGradient(b) ? b : null;
|
|
5182
|
-
if (ga && gb) return lerpGradient(ga, gb, t) ?? (t < 0.5 ? a : b);
|
|
5183
|
-
if (gb) return lerpGradient(solidLike(pa ? a : null, gb), gb, t) ?? b;
|
|
5184
|
-
if (ga) return lerpGradient(ga, solidLike(pb ? b : null, ga), t) ?? a;
|
|
5185
|
-
return t < 0.5 ? a : b;
|
|
5186
|
-
}
|
|
5187
|
-
function interpolateWidthProfiles(a, b, t) {
|
|
5188
|
-
if (!a?.length && !b?.length) return null;
|
|
5189
|
-
const at2 = [...a ?? [], ...b ?? [], { t: 0 }, { t: 1 }].map((p) => p.t).sort((x, y) => x - y);
|
|
5190
|
-
const ts = at2.filter((v2, i) => i === 0 || v2 - at2[i - 1] > 1e-6);
|
|
5191
|
-
return ts.map((pos) => {
|
|
5192
|
-
const x = widthProfileAt(a, pos);
|
|
5193
|
-
const y = widthProfileAt(b, pos);
|
|
5194
|
-
return { t: pos, left: lerpN(x.left, y.left, t), right: lerpN(x.right, y.right, t) };
|
|
5195
|
-
});
|
|
5196
|
-
}
|
|
5197
|
-
function lerpDashes(a, b, t) {
|
|
5198
|
-
const dashed = (d) => !!d?.length && d.some((v2) => v2 > 0);
|
|
5199
|
-
if (!dashed(a) && !dashed(b)) return t < 0.5 ? a : b;
|
|
5200
|
-
const even = (p) => p.length % 2 ? [...p, ...p] : p;
|
|
5201
|
-
const solid = (p) => {
|
|
5202
|
-
const e = even(p);
|
|
5203
|
-
const out = [];
|
|
5204
|
-
for (let i = 0; i < e.length; i += 2) out.push(e[i] + e[i + 1], 0);
|
|
5205
|
-
return out;
|
|
5206
|
-
};
|
|
5207
|
-
const x = dashed(a) ? even(a) : solid(b);
|
|
5208
|
-
const y = dashed(b) ? even(b) : solid(a);
|
|
5209
|
-
if (x.length !== y.length) return t < 0.5 ? a : b;
|
|
5210
|
-
return x.map((v2, i) => lerpN(v2, y[i], t));
|
|
5211
|
-
}
|
|
5212
|
-
var SWITCHED_KEYS = ["strokeLinecap", "strokeLinejoin", "fillRule", "strokeAlign", "startArrow", "endArrow", "arrowAlign"];
|
|
5213
|
-
function interpolateVectorStyle(a, b, t) {
|
|
5214
|
-
const near2 = t < 0.5 ? a : b;
|
|
5215
|
-
const out = {};
|
|
5216
|
-
const fill = interpolateVectorPaint(a.fill, b.fill, t);
|
|
5217
|
-
if (fill !== void 0) out.fill = fill;
|
|
5218
|
-
const stroke = interpolateVectorPaint(a.stroke, b.stroke, t);
|
|
5219
|
-
if (stroke !== void 0) out.stroke = stroke;
|
|
5220
|
-
if (a.strokeWidth !== void 0 || b.strokeWidth !== void 0) out.strokeWidth = lerpN(a.strokeWidth ?? 1, b.strokeWidth ?? 1, t);
|
|
5221
|
-
for (const key of SWITCHED_KEYS) if (near2[key] !== void 0 && near2[key] !== null) out[key] = near2[key];
|
|
5222
|
-
for (const key of ["startArrowScale", "endArrowScale"])
|
|
5223
|
-
if (a[key] !== void 0 || b[key] !== void 0) out[key] = lerpN(a[key] ?? 1, b[key] ?? 1, t);
|
|
5224
|
-
const dash = lerpDashes(a.strokeDasharray, b.strokeDasharray, t);
|
|
5225
|
-
if (dash?.length) out.strokeDasharray = dash;
|
|
5226
|
-
const profile = interpolateWidthProfiles(a.strokeWidthProfile, b.strokeWidthProfile, t);
|
|
5227
|
-
if (profile) out.strokeWidthProfile = profile;
|
|
5228
|
-
return out;
|
|
5229
|
-
}
|
|
5230
|
-
function reversedStyle(s) {
|
|
5231
|
-
const out = { ...s };
|
|
5232
|
-
out.startArrow = s.endArrow;
|
|
5233
|
-
out.endArrow = s.startArrow;
|
|
5234
|
-
out.startArrowScale = s.endArrowScale;
|
|
5235
|
-
out.endArrowScale = s.startArrowScale;
|
|
5236
|
-
if (s.strokeWidthProfile?.length) out.strokeWidthProfile = reverseWidthProfile(s.strokeWidthProfile);
|
|
5237
|
-
for (const k of ["startArrow", "endArrow", "startArrowScale", "endArrowScale"]) if (out[k] === void 0) delete out[k];
|
|
5238
|
-
return out;
|
|
5239
|
-
}
|
|
5240
|
-
var STYLE_KEYS = [
|
|
5241
|
-
"fill",
|
|
5242
|
-
"stroke",
|
|
5243
|
-
"strokeWidth",
|
|
5244
|
-
"strokeLinecap",
|
|
5245
|
-
"strokeLinejoin",
|
|
5246
|
-
"strokeDasharray",
|
|
5247
|
-
"fillRule",
|
|
5248
|
-
"strokeAlign",
|
|
5249
|
-
"startArrow",
|
|
5250
|
-
"endArrow",
|
|
5251
|
-
"arrowAlign",
|
|
5252
|
-
"startArrowScale",
|
|
5253
|
-
"endArrowScale",
|
|
5254
|
-
"strokeWidthProfile"
|
|
5255
|
-
];
|
|
5256
|
-
function styleOf(n) {
|
|
5257
|
-
const out = {};
|
|
5258
|
-
for (const k of STYLE_KEYS) if (n[k] !== void 0) out[k] = n[k];
|
|
5259
|
-
return out;
|
|
5260
|
-
}
|
|
5261
|
-
function contoursOf(node, m) {
|
|
5262
|
-
return expandVectorCorners(node.subpaths).map((sp) => subpathToMorphContour(sp, m)).filter((c) => !!c);
|
|
5263
|
-
}
|
|
5264
|
-
function preparePathMorph(a, b, options, ma = nodeMatrix(a), mb = nodeMatrix(b)) {
|
|
5265
|
-
const corr = correspondMorphContours(contoursOf(a, ma), contoursOf(b, mb), options);
|
|
5266
|
-
const sim = procrustes(corr.a, corr.b);
|
|
5267
|
-
const styleA = styleOf(a);
|
|
5268
|
-
const styleB = corr.reversed ? reversedStyle(styleOf(b)) : styleOf(b);
|
|
5269
|
-
const rigid = !isIdentityMatrix(ma) || !isIdentityMatrix(mb);
|
|
5270
|
-
const id = options.id ?? a.id;
|
|
5271
|
-
return (t) => {
|
|
5272
|
-
const contours = interpolateMorphContours(corr.a, corr.b, t, { linear: options.linear, rigidity: options.rigidity, similarity: sim });
|
|
5273
|
-
const m = rigid ? interpolateRigidMatrix(ma, mb, t) : IDENTITY_MATRIX;
|
|
5274
|
-
const back = rigid ? invertMatrix(m) : IDENTITY_MATRIX;
|
|
5275
|
-
const subpaths = contours.map((c, k) => {
|
|
5276
|
-
const closed = t <= 0 ? corr.a[k].closed : t >= 1 ? corr.b[k].closed : corr.a[k].closed && corr.b[k].closed;
|
|
5277
|
-
return morphContourToSubpath({ closed: corr.a[k].closed && corr.b[k].closed, pts: c.pts }, back, closed);
|
|
5278
|
-
});
|
|
5279
|
-
const node = { id, type: "path", subpaths, ...interpolateVectorStyle(styleA, styleB, t) };
|
|
5280
|
-
const opacity = lerpN(a.opacity ?? 1, b.opacity ?? 1, t);
|
|
5281
|
-
if (opacity < 1) node.opacity = opacity;
|
|
5282
|
-
if (rigid && !isIdentityMatrix(m)) node.transform = m;
|
|
5283
|
-
return node;
|
|
5284
|
-
};
|
|
5285
|
-
}
|
|
5286
|
-
function flattenPaths(node, parent = IDENTITY_MATRIX) {
|
|
5287
|
-
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
5288
|
-
if (node.type === "path") return [{ path: node, m, opacity: 1 }];
|
|
5289
|
-
const o = node.opacity ?? 1;
|
|
5290
|
-
return node.children.filter((c) => c.visible !== false).flatMap((c) => flattenPaths(c, m)).map((e) => ({ ...e, opacity: e.opacity * o }));
|
|
5291
|
-
}
|
|
5292
|
-
var placedBounds = (path, m) => boundsOfPoints(contoursOf(path, m).flatMap((c) => c.pts));
|
|
5293
|
-
function collapsedPath(path, m, from, to) {
|
|
5294
|
-
const own = placedBounds(path, m);
|
|
5295
|
-
const c = own ? [own.x + own.width / 2, own.y + own.height / 2] : [0, 0];
|
|
5296
|
-
const fx = from && from.width > 0 ? (c[0] - from.x) / from.width : 0.5;
|
|
5297
|
-
const fy = from && from.height > 0 ? (c[1] - from.y) / from.height : 0.5;
|
|
5298
|
-
const p = to ? { x: to.x + to.width * fx, y: to.y + to.height * fy } : { x: c[0], y: c[1] };
|
|
5299
|
-
const subpaths = path.subpaths.map((sp) => ({ closed: sp.closed, anchors: sp.anchors.map(() => ({ x: p.x, y: p.y })) }));
|
|
5300
|
-
const { transform: _t, ...rest } = path;
|
|
5301
|
-
return { ...rest, subpaths };
|
|
5302
|
-
}
|
|
5303
|
-
function createVectorMorph(a, b, options = {}) {
|
|
5304
|
-
if (a.type === "path" && b.type === "path") {
|
|
5305
|
-
const at2 = preparePathMorph(a, b, options);
|
|
5306
|
-
return { at: at2 };
|
|
5307
|
-
}
|
|
5308
|
-
const pa = flattenPaths(a);
|
|
5309
|
-
const pb = flattenPaths(b);
|
|
5310
|
-
const ba = unionBounds(pa.map((e) => placedBounds(e.path, e.m)));
|
|
5311
|
-
const bb = unionBounds(pb.map((e) => placedBounds(e.path, e.m)));
|
|
5312
|
-
const id = options.id ?? a.id;
|
|
5313
|
-
const parts = [];
|
|
5314
|
-
const opacities = [];
|
|
5315
|
-
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
5316
|
-
const x = pa[i];
|
|
5317
|
-
const y = pb[i];
|
|
5318
|
-
const sub5 = { ...options, id: `${id}-${i}`, starts: void 0 };
|
|
5319
|
-
if (x && y) {
|
|
5320
|
-
parts.push(preparePathMorph(x.path, y.path, sub5, x.m, y.m));
|
|
5321
|
-
opacities.push([x.opacity, y.opacity]);
|
|
5322
|
-
} else if (x) {
|
|
5323
|
-
parts.push(preparePathMorph(x.path, collapsedPath(x.path, x.m, ba, bb), sub5, x.m, IDENTITY_MATRIX));
|
|
5324
|
-
opacities.push([x.opacity, x.opacity]);
|
|
5325
|
-
} else if (y) {
|
|
5326
|
-
parts.push(preparePathMorph(collapsedPath(y.path, y.m, bb, ba), y.path, sub5, IDENTITY_MATRIX, y.m));
|
|
5327
|
-
opacities.push([y.opacity, y.opacity]);
|
|
5328
|
-
}
|
|
5329
|
-
}
|
|
5330
|
-
return {
|
|
5331
|
-
at: (t) => {
|
|
5332
|
-
const children = parts.map((p, i) => {
|
|
5333
|
-
const n = p(t);
|
|
5334
|
-
const o = lerpN(opacities[i][0], opacities[i][1], t) * (n.opacity ?? 1);
|
|
5335
|
-
if (o < 1) n.opacity = o;
|
|
5336
|
-
else delete n.opacity;
|
|
5337
|
-
return n;
|
|
5338
|
-
});
|
|
5339
|
-
const group = { id, type: "group", children };
|
|
5340
|
-
return group;
|
|
5341
|
-
}
|
|
5342
|
-
};
|
|
5343
|
-
}
|
|
5344
|
-
function interpolateVectorPaths(a, b, t, options = {}) {
|
|
5345
|
-
return createVectorMorph(a, b, options).at(t);
|
|
5346
|
-
}
|
|
5347
|
-
var keyframeMorphs = /* @__PURE__ */ new WeakMap();
|
|
5348
|
-
function evaluateVectorPathKeyframes(keyframes, time, options = {}) {
|
|
5349
|
-
const keys = keyframes.filter((k) => Number.isFinite(k.time)).sort((x, y) => x.time - y.time);
|
|
5350
|
-
if (!keys.length) return null;
|
|
5351
|
-
if (!(time > keys[0].time)) return keys[0].value;
|
|
5352
|
-
const last = keys[keys.length - 1];
|
|
5353
|
-
if (time >= last.time) return last.value;
|
|
5354
|
-
let i = 0;
|
|
5355
|
-
while (i + 1 < keys.length && keys[i + 1].time <= time) i++;
|
|
5356
|
-
const a = keys[i];
|
|
5357
|
-
const b = keys[i + 1];
|
|
5358
|
-
if (time === a.time) return a.value;
|
|
5359
|
-
if (a.easing === "hold") return a.value;
|
|
5360
|
-
const span = b.time - a.time;
|
|
5361
|
-
const u = Math.min(1, Math.max(0, evaluateEasing(a.easing, (time - a.time) / span, span)));
|
|
5362
|
-
let inner = keyframeMorphs.get(a.value);
|
|
5363
|
-
if (!inner) keyframeMorphs.set(a.value, inner = /* @__PURE__ */ new WeakMap());
|
|
5364
|
-
let morph = inner.get(b.value);
|
|
5365
|
-
if (!morph) inner.set(b.value, morph = createVectorMorph(a.value, b.value, options));
|
|
5366
|
-
return morph.at(u);
|
|
5367
|
-
}
|
|
5368
|
-
|
|
5369
|
-
// src/vector/gradientStroke.ts
|
|
5370
|
-
var SHARP = 1.25;
|
|
5371
|
-
var TOLERANCE = 0.2;
|
|
5372
|
-
var OVERLAP = 0.5;
|
|
5373
|
-
var fmt2 = (n, digits = 3) => {
|
|
5374
|
-
const k = 10 ** digits;
|
|
5375
|
-
const v2 = Math.round(n * k) / k;
|
|
5376
|
-
return Object.is(v2, -0) ? "0" : String(v2);
|
|
5377
|
-
};
|
|
5378
|
-
var toSvgStops2 = (stops) => stops.map((s) => ({ offset: `${fmt2(s.offset * 100)}%`, stopColor: s.color, ...s.opacity !== void 0 && s.opacity !== 1 ? { stopOpacity: Math.round(s.opacity * 1e4) / 1e4 } : {} }));
|
|
5379
|
-
var polygonD2 = (pts, precision) => `M${pts.map((p) => `${fmt2(p.x, precision)} ${fmt2(p.y, precision)}`).join("L")}Z`;
|
|
5380
|
-
var add4 = (a, b) => ({ x: a.x + b.x, y: a.y + b.y });
|
|
5381
|
-
var sub4 = (a, b) => ({ x: a.x - b.x, y: a.y - b.y });
|
|
5382
|
-
var scale2 = (a, k) => ({ x: a.x * k, y: a.y * k });
|
|
5383
|
-
var left = (d) => ({ x: d.y, y: -d.x });
|
|
5384
|
-
var unit3 = (v2) => {
|
|
5385
|
-
const l = Math.hypot(v2.x, v2.y);
|
|
5386
|
-
return l > 1e-12 ? { x: v2.x / l, y: v2.y / l } : { x: 1, y: 0 };
|
|
5387
|
-
};
|
|
5388
|
-
function flattenedSubpaths(node) {
|
|
5389
|
-
const out = [];
|
|
5390
|
-
for (const contour of pathToContours(subpathsToBezier(node.subpaths))) {
|
|
5391
|
-
const segs = closeContour(contour);
|
|
5392
|
-
if (!segs.length) continue;
|
|
5393
|
-
const ring = flattenChain(segs, TOLERANCE);
|
|
5394
|
-
const pts = ring.map(([x, y]) => ({ x, y })).filter((p, i, a) => i === 0 || Math.hypot(p.x - a[i - 1].x, p.y - a[i - 1].y) > 1e-9);
|
|
5395
|
-
if (contour.closed && pts.length > 2 && Math.hypot(pts[0].x - pts[pts.length - 1].x, pts[0].y - pts[pts.length - 1].y) < 1e-9) pts.pop();
|
|
5396
|
-
if (pts.length >= 2) out.push({ pts, closed: contour.closed && pts.length > 2 });
|
|
5397
|
-
}
|
|
5398
|
-
return out;
|
|
5399
|
-
}
|
|
5400
|
-
var signedArea = (pts) => {
|
|
5401
|
-
let a = 0;
|
|
5402
|
-
for (let i = 0; i < pts.length; i++) {
|
|
5403
|
-
const p = pts[i];
|
|
5404
|
-
const q = pts[(i + 1) % pts.length];
|
|
5405
|
-
a += p.x * q.y - q.x * p.y;
|
|
5406
|
-
}
|
|
5407
|
-
return a / 2;
|
|
5408
|
-
};
|
|
5409
|
-
function vectorStrokeGradientDefs(g, id, node, options = {}) {
|
|
5410
|
-
const precision = options.precision ?? 3;
|
|
5411
|
-
const mode = g.strokeMode === "across" ? "across" : "along";
|
|
5412
|
-
const expanded = expandVectorGradientStops(g);
|
|
5413
|
-
const reach = vectorStrokeReach(node) + 1;
|
|
5414
|
-
const area = options.area ?? vectorGradientArea(options.bounds && { x: options.bounds.x - reach, y: options.bounds.y - reach, width: options.bounds.width + 2 * reach, height: options.bounds.height + 2 * reach });
|
|
5415
|
-
const width = node.strokeWidth ?? 1;
|
|
5416
|
-
const align = node.strokeAlign ?? "center";
|
|
5417
|
-
const profile = strokeWidthProfileOf(node);
|
|
5418
|
-
const gradients = [];
|
|
5419
|
-
const patches = [];
|
|
5420
|
-
const slices = [];
|
|
5421
|
-
const colourAt = (t) => {
|
|
5422
|
-
const s = spanVectorGradientStops(g, t, t, expanded)[0];
|
|
5423
|
-
return s;
|
|
5424
|
-
};
|
|
5425
|
-
let counter = 0;
|
|
5426
|
-
const solid = (pts, t) => {
|
|
5427
|
-
const s = colourAt(t);
|
|
5428
|
-
const gid = `${id}-p${counter++}`;
|
|
5429
|
-
gradients.push({ id: gid, type: "linear", attrs: { gradientUnits: "userSpaceOnUse", x1: 0, y1: 0, x2: 1, y2: 0 }, stops: toSvgStops2([{ ...s, offset: 0 }]) });
|
|
5430
|
-
patches.push({ d: polygonD2(pts, precision), fill: `url(#${gid})` });
|
|
5431
|
-
};
|
|
5432
|
-
const disc = (c, r) => Array.from({ length: 16 }, (_, k) => add4(c, scale2({ x: Math.cos(k * Math.PI / 8), y: Math.sin(k * Math.PI / 8) }, r)));
|
|
5433
|
-
for (const { pts, closed } of flattenedSubpaths(node)) {
|
|
5434
|
-
const n = pts.length;
|
|
5435
|
-
const segCount = closed ? n : n - 1;
|
|
5436
|
-
const dirs = [];
|
|
5437
|
-
const lengths = [0];
|
|
5438
|
-
for (let i = 0; i < segCount; i++) {
|
|
5439
|
-
const a = pts[i];
|
|
5440
|
-
const b = pts[(i + 1) % n];
|
|
5441
|
-
dirs.push(unit3(sub4(b, a)));
|
|
5442
|
-
lengths.push(lengths[i] + Math.hypot(b.x - a.x, b.y - a.y));
|
|
5443
|
-
}
|
|
5444
|
-
const total = lengths[segCount];
|
|
5445
|
-
if (!(total > 1e-9)) continue;
|
|
5446
|
-
const tAt = (i) => lengths[i] / total;
|
|
5447
|
-
const clockwise = closed && signedArea(pts) > 0;
|
|
5448
|
-
const visibleLeft = align === "center" || !closed ? null : align === "inside" ? !clockwise : clockwise;
|
|
5449
|
-
const ribs = [];
|
|
5450
|
-
for (let i = 0; i < n; i++) {
|
|
5451
|
-
const p = pts[i];
|
|
5452
|
-
const din = i > 0 || closed ? dirs[(i - 1 + segCount) % segCount] : null;
|
|
5453
|
-
const dout = i < segCount ? dirs[i] : null;
|
|
5454
|
-
const square = (d) => ({ l: add4(p, scale2(left(d), reach)), r: sub4(p, scale2(left(d), reach)) });
|
|
5455
|
-
if (!din || !dout) {
|
|
5456
|
-
const rib = square(din ?? dout);
|
|
5457
|
-
ribs.push({ before: rib, after: rib });
|
|
5458
|
-
continue;
|
|
5459
|
-
}
|
|
5460
|
-
const nin = left(din);
|
|
5461
|
-
const nout = left(dout);
|
|
5462
|
-
const den = 1 + nin.x * nout.x + nin.y * nout.y;
|
|
5463
|
-
const stretch = den > 1e-12 ? Math.sqrt(2 / den) : Infinity;
|
|
5464
|
-
if (stretch <= SHARP) {
|
|
5465
|
-
const m = scale2(add4(nin, nout), reach / den);
|
|
5466
|
-
const rib = { l: add4(p, m), r: sub4(p, m) };
|
|
5467
|
-
ribs.push({ before: rib, after: rib });
|
|
5468
|
-
} else {
|
|
5469
|
-
ribs.push({ before: square(din), after: square(dout) });
|
|
5470
|
-
solid(disc(p, reach * 1.5), tAt(i));
|
|
5471
|
-
}
|
|
5472
|
-
}
|
|
5473
|
-
if (!closed) {
|
|
5474
|
-
const d0 = dirs[0];
|
|
5475
|
-
const d1 = dirs[segCount - 1];
|
|
5476
|
-
const a = pts[0];
|
|
5477
|
-
const b = pts[n - 1];
|
|
5478
|
-
const cap = (p, d) => [add4(p, scale2(left(d), reach)), add4(add4(p, scale2(d, reach)), scale2(left(d), reach)), sub4(add4(p, scale2(d, reach)), scale2(left(d), reach)), sub4(p, scale2(left(d), reach))];
|
|
5479
|
-
solid(cap(a, scale2(d0, -1)), 0);
|
|
5480
|
-
solid(cap(b, d1), 1);
|
|
5481
|
-
}
|
|
5482
|
-
for (let i = 0; i < segCount; i++) {
|
|
5483
|
-
const j = (i + 1) % n;
|
|
5484
|
-
const a = pts[i];
|
|
5485
|
-
const b = pts[j];
|
|
5486
|
-
const d = dirs[i];
|
|
5487
|
-
const from = ribs[i].after;
|
|
5488
|
-
const to = ribs[j].before;
|
|
5489
|
-
const ext = scale2(d, OVERLAP);
|
|
5490
|
-
const quad = [from.l, add4(to.l, ext), add4(to.r, ext), from.r];
|
|
5491
|
-
const gid = `${id}-s${counter++}`;
|
|
5492
|
-
const t0 = tAt(i);
|
|
5493
|
-
const t1 = closed && i === segCount - 1 ? 1 : tAt(i + 1);
|
|
5494
|
-
if (mode === "along") {
|
|
5495
|
-
gradients.push({
|
|
5496
|
-
id: gid,
|
|
5497
|
-
type: "linear",
|
|
5498
|
-
attrs: { gradientUnits: "userSpaceOnUse", x1: fmt2(a.x, 4), y1: fmt2(a.y, 4), x2: fmt2(b.x, 4), y2: fmt2(b.y, 4) },
|
|
5499
|
-
stops: toSvgStops2(spanVectorGradientStops(g, t0, t1, expanded))
|
|
5500
|
-
});
|
|
5501
|
-
} else {
|
|
5502
|
-
const mid = scale2(add4(a, b), 0.5);
|
|
5503
|
-
const side = widthProfileAt(profile, (t0 + t1) / 2);
|
|
5504
|
-
const nrm = left(d);
|
|
5505
|
-
const reachL = visibleLeft === null ? width / 2 * side.left : visibleLeft ? width * side.left : 0;
|
|
5506
|
-
const reachR = visibleLeft === null ? width / 2 * side.right : visibleLeft ? 0 : width * side.right;
|
|
5507
|
-
const p0 = add4(mid, scale2(nrm, reachL));
|
|
5508
|
-
const p1 = sub4(mid, scale2(nrm, reachR));
|
|
5509
|
-
gradients.push({
|
|
5510
|
-
id: gid,
|
|
5511
|
-
type: "linear",
|
|
5512
|
-
attrs: { gradientUnits: "userSpaceOnUse", x1: fmt2(p0.x, 4), y1: fmt2(p0.y, 4), x2: fmt2(p1.x, 4), y2: fmt2(p1.y, 4) },
|
|
5513
|
-
stops: toSvgStops2(expanded)
|
|
5514
|
-
});
|
|
5515
|
-
}
|
|
5516
|
-
slices.push({ d: polygonD2(quad, precision), fill: `url(#${gid})` });
|
|
5517
|
-
}
|
|
5518
|
-
}
|
|
5519
|
-
const def = {
|
|
5520
|
-
id,
|
|
5521
|
-
type: "pattern",
|
|
5522
|
-
attrs: patternAttrs(area),
|
|
5523
|
-
gradients,
|
|
5524
|
-
tiles: [...patches, ...slices]
|
|
5525
|
-
};
|
|
5526
|
-
return [def];
|
|
5527
|
-
}
|
|
5528
|
-
|
|
5529
|
-
// src/vector/svg.ts
|
|
5530
|
-
function vectorCornersAttribute(subpaths, precision = 3) {
|
|
5531
|
-
const out = [];
|
|
5532
|
-
subpaths.forEach(
|
|
5533
|
-
(sp, s) => sp.anchors.forEach((a, i) => {
|
|
5534
|
-
if (!a.corner || !(a.corner.radius > 0)) return;
|
|
5535
|
-
out.push(`${s}.${i}:${formatNumber(a.corner.radius, precision)}${a.corner.kind && a.corner.kind !== "round" ? `:${a.corner.kind}` : ""}`);
|
|
5536
|
-
})
|
|
5537
|
-
);
|
|
5538
|
-
return out.join(" ");
|
|
5539
|
-
}
|
|
5540
|
-
function applyVectorCornersAttribute(subpaths, value) {
|
|
5541
|
-
for (const item of value.trim().split(/\s+/)) {
|
|
5542
|
-
const m = /^(\d+)\.(\d+):([\d.eE+-]+)(?::([a-z]+))?$/.exec(item);
|
|
5543
|
-
if (!m) continue;
|
|
5544
|
-
const a = subpaths[+m[1]]?.anchors[+m[2]];
|
|
5545
|
-
const radius = parseFloat(m[3]);
|
|
5546
|
-
if (!a || !(radius > 0)) continue;
|
|
5547
|
-
const kind = VECTOR_CORNER_KINDS.includes(m[4]) ? m[4] : void 0;
|
|
5548
|
-
a.corner = { radius, ...kind && kind !== "round" ? { kind } : {} };
|
|
5549
|
-
}
|
|
5550
|
-
return subpaths;
|
|
5551
|
-
}
|
|
5552
|
-
var escapeAttr2 = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
5553
|
-
function vectorPathLocalBounds(node) {
|
|
5554
|
-
const b = bezierPathBounds(subpathsToBezier(node.subpaths));
|
|
5555
|
-
return b ? { x: b.minX, y: b.minY, width: b.maxX - b.minX, height: b.maxY - b.minY } : null;
|
|
5556
|
-
}
|
|
5557
|
-
var paintCache = /* @__PURE__ */ new WeakMap();
|
|
5558
|
-
function vectorPaintToSvg(paint, gradientId, options = {}) {
|
|
5559
|
-
if (!hasPaint(paint)) return { value: "none", defs: [] };
|
|
5560
|
-
if (typeof paint === "string") return { value: paint, defs: [] };
|
|
5561
|
-
if (!isVectorGradient(paint)) return { value: "none", defs: [] };
|
|
5562
|
-
const role = options.role ?? "fill";
|
|
5563
|
-
const precision = options.precision ?? 3;
|
|
5564
|
-
const key = `${gradientId}|${role}|${precision}`;
|
|
5565
|
-
const owner = options.node ?? paint;
|
|
5566
|
-
const cached = paintCache.get(owner)?.get(key);
|
|
5567
|
-
if (cached && (!options.node || (role === "fill" ? options.node.fill : options.node.stroke) === paint)) return { value: `url(#${gradientId})`, defs: cached };
|
|
5568
|
-
const node = options.node;
|
|
5569
|
-
const bounds = node ? vectorPathLocalBounds(node) : null;
|
|
5570
|
-
const reach = node && role === "stroke" ? vectorStrokeReach(node) + 1 : 1;
|
|
5571
|
-
const area = bounds ? { x: bounds.x - reach, y: bounds.y - reach, width: bounds.width + 2 * reach, height: bounds.height + 2 * reach } : null;
|
|
5572
|
-
const defs = node && role === "stroke" && (paint.strokeMode === "along" || paint.strokeMode === "across") ? vectorStrokeGradientDefs(paint, gradientId, node, { bounds, area, precision }) : vectorGradientSvgDefs(paint, gradientId, { bounds, area, precision });
|
|
5573
|
-
let byKey = paintCache.get(owner);
|
|
5574
|
-
if (!byKey) paintCache.set(owner, byKey = /* @__PURE__ */ new Map());
|
|
5575
|
-
byKey.set(key, defs);
|
|
5576
|
-
return { value: `url(#${gradientId})`, defs };
|
|
5577
|
-
}
|
|
5578
|
-
var partsCache = /* @__PURE__ */ new WeakMap();
|
|
5579
|
-
function vectorStrokeSvgParts(node, clipId, precision = 3) {
|
|
5580
|
-
if (!hasPaint(node.stroke) || !hasStrokeExtras(node)) return void 0;
|
|
5581
|
-
const hit = partsCache.get(node);
|
|
5582
|
-
if (hit && hit.clipId === clipId && hit.precision === precision) return hit.parts;
|
|
5583
|
-
const parts = computeStrokeSvgParts(node, clipId, precision);
|
|
5584
|
-
partsCache.set(node, { clipId, precision, parts });
|
|
5585
|
-
return parts;
|
|
5586
|
-
}
|
|
5587
|
-
function computeStrokeSvgParts(node, clipId, precision) {
|
|
5588
|
-
const path = subpathsToBezier(node.subpaths);
|
|
5589
|
-
const parts = vectorStrokeParts(path, node);
|
|
5590
|
-
const profiled = !!strokeWidthProfileOf(node);
|
|
5591
|
-
if (parts.align === "center" && !parts.heads.length && !profiled) return void 0;
|
|
5592
|
-
let clip = null;
|
|
5593
|
-
if (parts.align !== "center") {
|
|
5594
|
-
const b = bezierPathBounds(path);
|
|
5595
|
-
const pad = vectorStrokeReach(node) + 1;
|
|
5596
|
-
const bounds = b ? { x: round2(b.minX - pad), y: round2(b.minY - pad), width: round2(b.maxX - b.minX + 2 * pad), height: round2(b.maxY - b.minY + 2 * pad) } : { x: 0, y: 0, width: 0, height: 0 };
|
|
5597
|
-
clip = { kind: parts.align === "inside" ? "clip" : "mask", id: clipId, bounds };
|
|
5598
|
-
}
|
|
5599
|
-
return {
|
|
5600
|
-
align: parts.align,
|
|
5601
|
-
d: bezierPathToSvg(parts.line, { precision }),
|
|
5602
|
-
width: parts.drawWidth,
|
|
5603
|
-
...profiled && (node.strokeWidth ?? 1) > 0 ? { outline: bezierPathToSvg(vectorStrokeLineArea(parts, node), { precision }) } : {},
|
|
5604
|
-
clip,
|
|
5605
|
-
heads: parts.heads.map((h) => bezierPathToSvg(h.path, { precision }))
|
|
5606
|
-
};
|
|
5607
|
-
}
|
|
5608
|
-
function vectorNodeLocalPaintBounds(node) {
|
|
5609
|
-
const drawn = expandVectorAppearance(node);
|
|
5610
|
-
const reach = (n) => n.type === "path" ? vectorStrokeStackReach(n) : Math.max(0, ...n.children.map(reach));
|
|
5611
|
-
let b;
|
|
5612
|
-
if (drawn.type === "path") b = vectorPathLocalBounds(drawn);
|
|
5613
|
-
else b = unionBounds(drawn.children.filter((c) => c.visible !== false).map((c) => vectorNodeBounds(c, IDENTITY_MATRIX)));
|
|
5614
|
-
if (!b) return null;
|
|
5615
|
-
const pad = reach(drawn);
|
|
5616
|
-
return { x: b.x - pad, y: b.y - pad, width: b.width + 2 * pad, height: b.height + 2 * pad };
|
|
5617
|
-
}
|
|
5618
|
-
var filterCache = /* @__PURE__ */ new WeakMap();
|
|
5619
|
-
function vectorNodeFilterSvg(node, id) {
|
|
5620
|
-
if (!node.filters?.length) return null;
|
|
5621
|
-
const hit = filterCache.get(node);
|
|
5622
|
-
if (hit && hit.id === id) return hit.filter;
|
|
5623
|
-
const active = activeVectorFilters(node);
|
|
5624
|
-
const filter = active.length ? vectorFilterSvg(active, id, vectorNodeLocalPaintBounds(node)) : null;
|
|
5625
|
-
filterCache.set(node, { id, filter });
|
|
5626
|
-
return filter;
|
|
5627
|
-
}
|
|
5628
|
-
function widthProfileToAttribute(points, precision = 4) {
|
|
5629
|
-
return points.map((p) => [p.t, p.left, p.right].map((n) => formatNumber(n, precision)).join(",")).join(";");
|
|
5630
|
-
}
|
|
5631
|
-
function widthProfileFromAttribute(value) {
|
|
5632
|
-
if (!value) return [];
|
|
5633
|
-
return sanitizeWidthProfile(
|
|
5634
|
-
value.split(";").map((part) => {
|
|
5635
|
-
const [t, left2, right] = part.split(",").map((n) => parseFloat(n));
|
|
5636
|
-
return { t, left: left2, right: Number.isFinite(right) ? right : left2 };
|
|
5637
|
-
})
|
|
5638
|
-
);
|
|
5639
|
-
}
|
|
5640
|
-
var round2 = (n) => Math.round(n * 100) / 100;
|
|
5641
|
-
function gradientMarkup(def, extra = "") {
|
|
5642
|
-
const tag = def.type === "radial" ? "radialGradient" : "linearGradient";
|
|
5643
|
-
const attrs = Object.entries(def.attrs).map(([k, v2]) => ` ${k}="${escapeAttr2(String(v2))}"`).join("");
|
|
5644
|
-
const stops = def.stops.map((s) => `<stop offset="${s.offset}" stop-color="${escapeAttr2(s.stopColor)}"${s.stopOpacity !== void 0 ? ` stop-opacity="${s.stopOpacity}"` : ""}/>`).join("");
|
|
5645
|
-
return `<${tag} id="${escapeAttr2(def.id)}"${attrs}${extra}>${stops}</${tag}>`;
|
|
5646
|
-
}
|
|
5647
|
-
function paintDefMarkup(def, gradient) {
|
|
5648
|
-
const extra = gradient ? ` data-vector-gradient="${escapeAttr2(JSON.stringify(gradient))}"` : "";
|
|
5649
|
-
if (def.type !== "pattern") return gradientMarkup(def, extra);
|
|
5650
|
-
const attrs = Object.entries(def.attrs).map(([k, v2]) => ` ${k}="${escapeAttr2(String(v2))}"`).join("");
|
|
5651
|
-
const inner = def.gradients.map((g) => gradientMarkup(g)).join("") + def.tiles.map((t) => `<path d="${t.d}" fill="${escapeAttr2(t.fill)}"/>`).join("");
|
|
5652
|
-
return `<pattern id="${escapeAttr2(def.id)}"${attrs}${extra}>${inner}</pattern>`;
|
|
5653
|
-
}
|
|
5654
|
-
var paintMarkup = (paint, defs) => defs.map((d, i) => paintDefMarkup(d, i === 0 && isVectorGradient(paint) ? paint : void 0));
|
|
5655
|
-
function blendFromAttribute(value, m) {
|
|
5656
|
-
if (!value) return null;
|
|
5657
|
-
let raw;
|
|
5658
|
-
try {
|
|
5659
|
-
raw = JSON.parse(value);
|
|
5660
|
-
} catch {
|
|
5661
|
-
return null;
|
|
5662
|
-
}
|
|
5663
|
-
if (!raw || typeof raw !== "object") return null;
|
|
5664
|
-
const r = raw;
|
|
5665
|
-
const out = {};
|
|
5666
|
-
if (r.spacing === "steps" || r.spacing === "distance" || r.spacing === "smoothColor") out.spacing = r.spacing;
|
|
5667
|
-
if (typeof r.steps === "number" && Number.isFinite(r.steps)) out.steps = Math.min(1e3, Math.max(1, Math.round(r.steps)));
|
|
5668
|
-
if (typeof r.distance === "number" && r.distance > 0) out.distance = r.distance;
|
|
5669
|
-
if (typeof r.orientToSpine === "boolean") out.orientToSpine = r.orientToSpine;
|
|
5670
|
-
if (typeof r.linear === "boolean") out.linear = r.linear;
|
|
5671
|
-
if (r.starts && typeof r.starts === "object") {
|
|
5672
|
-
const starts = Object.fromEntries(Object.entries(r.starts).filter((e) => Number.isInteger(e[1]) && e[1] >= 0));
|
|
5673
|
-
if (Object.keys(starts).length) out.starts = starts;
|
|
5674
|
-
}
|
|
5675
|
-
const spine = r.spine;
|
|
5676
|
-
if (spine && Array.isArray(spine.anchors) && spine.anchors.every((a) => a && Number.isFinite(a.x) && Number.isFinite(a.y))) {
|
|
5677
|
-
const sp = { closed: !!spine.closed, anchors: spine.anchors.map((a) => ({ x: a.x, y: a.y, ...a.in ? { in: { x: a.in.x, y: a.in.y } } : {}, ...a.out ? { out: { x: a.out.x, y: a.out.y } } : {} })) };
|
|
5678
|
-
out.spine = m === IDENTITY_MATRIX ? sp : transformVectorNode({ id: "", type: "path", subpaths: [sp] }, m).subpaths[0];
|
|
5679
|
-
}
|
|
5680
|
-
return out;
|
|
5681
|
-
}
|
|
5682
|
-
function vectorDocumentToSvg(doc, options = {}) {
|
|
5683
|
-
const precision = options.precision ?? 3;
|
|
5684
|
-
const prefix = options.idPrefix ?? "vg-";
|
|
5685
|
-
const pretty = options.pretty !== false;
|
|
5686
|
-
const defs = [];
|
|
5687
|
-
const lines = [];
|
|
5688
|
-
const num2 = (n) => formatNumber(n, precision);
|
|
5689
|
-
const indent = (depth) => pretty ? " ".repeat(depth) : "";
|
|
5690
|
-
const common = (node) => {
|
|
5691
|
-
let out2 = ` id="${escapeAttr2(node.id)}"`;
|
|
5692
|
-
if (node.transform) out2 += ` transform="matrix(${node.transform.map((n) => formatNumber(n, 6)).join(" ")})"`;
|
|
5693
|
-
if (node.opacity !== void 0 && node.opacity < 1) out2 += ` opacity="${num2(node.opacity)}"`;
|
|
5694
|
-
if (node.visible === false) out2 += ` display="none"`;
|
|
5695
|
-
if (node.blendStep) out2 += ` data-vector-blend-step=""`;
|
|
5696
|
-
if (node.type === "group" && node.blend) out2 += ` data-vector-blend="${escapeAttr2(JSON.stringify(node.blend))}"`;
|
|
5697
|
-
if (node.booleanOperation) out2 += ` data-vector-boolean-operation="${node.booleanOperation}"`;
|
|
5698
|
-
const blend = vectorBlendModeCss(node.blendMode);
|
|
5699
|
-
if (blend) out2 += ` style="mix-blend-mode:${blend}"`;
|
|
5700
|
-
if (node.filters?.length) {
|
|
5701
|
-
const filter = vectorNodeFilterSvg(node, `${prefix}filter-${node.id}`);
|
|
5702
|
-
const data = ` data-vector-filters="${escapeAttr2(JSON.stringify(node.filters))}"`;
|
|
5703
|
-
if (filter) {
|
|
5704
|
-
defs.push(vectorFilterMarkup(filter, data));
|
|
5705
|
-
out2 += ` filter="url(#${escapeAttr2(filter.id)})"`;
|
|
5706
|
-
} else out2 += data;
|
|
5707
|
-
}
|
|
5708
|
-
return out2;
|
|
5709
|
-
};
|
|
5710
|
-
const layerAttrs = (layer) => {
|
|
5711
|
-
let out2 = "";
|
|
5712
|
-
if (layer.opacity !== void 0 && layer.opacity < 1) out2 += ` opacity="${num2(layer.opacity)}"`;
|
|
5713
|
-
const blend = vectorBlendModeCss(layer.blendMode);
|
|
5714
|
-
if (blend) out2 += ` style="mix-blend-mode:${blend}"`;
|
|
5715
|
-
return out2;
|
|
5716
|
-
};
|
|
5717
|
-
const strokePartLines = (node, parts, strokeValue, d, lineAttrs, depth) => {
|
|
5718
|
-
const out2 = [];
|
|
5719
|
-
if (options.strokes === "outline") {
|
|
5720
|
-
const area = bezierPathToSvg(vectorStrokeOutlinePath(subpathsToBezier(node.subpaths), node), { precision });
|
|
5721
|
-
out2.push(`${indent(depth)}<path data-vector-part="stroke-outline" d="${area}" fill="${escapeAttr2(strokeValue)}"/>`);
|
|
5722
|
-
return out2;
|
|
5723
|
-
}
|
|
5724
|
-
let clip = "";
|
|
5725
|
-
if (parts.clip) {
|
|
5726
|
-
const rule = node.fillRule === "evenodd" ? "evenodd" : "nonzero";
|
|
5727
|
-
const id = escapeAttr2(parts.clip.id);
|
|
5728
|
-
if (parts.clip.kind === "clip") {
|
|
5729
|
-
defs.push(`<clipPath id="${id}"><path d="${d}" clip-rule="${rule}"/></clipPath>`);
|
|
5730
|
-
clip = ` clip-path="url(#${id})"`;
|
|
5731
|
-
} else {
|
|
5732
|
-
const b = parts.clip.bounds;
|
|
5733
|
-
const box = `x="${num2(b.x)}" y="${num2(b.y)}" width="${num2(b.width)}" height="${num2(b.height)}"`;
|
|
5734
|
-
defs.push(`<mask id="${id}" maskUnits="userSpaceOnUse" ${box}><rect ${box} fill="#fff"/><path d="${d}" fill="#000" fill-rule="${rule}"/></mask>`);
|
|
5735
|
-
clip = ` mask="url(#${id})"`;
|
|
5736
|
-
}
|
|
5737
|
-
}
|
|
5738
|
-
if (parts.outline !== void 0) out2.push(`${indent(depth)}<path data-vector-part="stroke-outline" d="${parts.outline}" fill="${escapeAttr2(strokeValue)}"${clip}/>`);
|
|
5739
|
-
else out2.push(`${indent(depth)}<path data-vector-part="stroke" d="${parts.d}" fill="none"${lineAttrs(parts.width)}${clip}/>`);
|
|
5740
|
-
for (const h2 of parts.heads) out2.push(`${indent(depth)}<path data-vector-part="head" d="${h2}" fill="${escapeAttr2(strokeValue)}"/>`);
|
|
5741
|
-
return out2;
|
|
5742
|
-
};
|
|
5743
|
-
const lineAttrsOf = (node, strokeValue) => (width) => {
|
|
5744
|
-
let out2 = ` stroke="${escapeAttr2(strokeValue)}" stroke-width="${num2(width)}"`;
|
|
5745
|
-
if (node.strokeLinecap && node.strokeLinecap !== "butt") out2 += ` stroke-linecap="${node.strokeLinecap}"`;
|
|
5746
|
-
if (node.strokeLinejoin && node.strokeLinejoin !== "miter") out2 += ` stroke-linejoin="${node.strokeLinejoin}"`;
|
|
5747
|
-
if (node.strokeDasharray?.length) out2 += ` stroke-dasharray="${node.strokeDasharray.map(num2).join(" ")}"`;
|
|
5748
|
-
return out2;
|
|
5749
|
-
};
|
|
5750
|
-
const liveCorners = (node) => {
|
|
5751
|
-
const corners = vectorCornersAttribute(node.subpaths, precision);
|
|
5752
|
-
return corners ? ` data-vector-d="${bezierPathToSvg(subpathsToBezier(node.subpaths, { corners: false }), { precision })}" data-vector-corners="${corners}"` : "";
|
|
5753
|
-
};
|
|
5754
|
-
const emitStacked = (node, depth) => {
|
|
5755
|
-
const d = vectorPathData(node, precision);
|
|
5756
|
-
const rule = node.fillRule === "evenodd" ? ` fill-rule="evenodd"` : "";
|
|
5757
|
-
let data = ` data-vector-path="" data-vector-fills="${escapeAttr2(JSON.stringify(vectorFills(node)))}" data-vector-strokes="${escapeAttr2(JSON.stringify(vectorStrokes(node)))}"`;
|
|
5758
|
-
if (node.fillRule === "evenodd") data += ` data-vector-fill-rule="evenodd"`;
|
|
5759
|
-
lines.push(`${indent(depth)}<g${common(node)}${data}>`);
|
|
5760
|
-
const layers = vectorPaintLayerNodes(node).filter((l) => l.drawn);
|
|
5761
|
-
let geometry = liveCorners(node);
|
|
5762
|
-
if (!layers.some((l) => l.kind === "fill")) {
|
|
5763
|
-
lines.push(`${indent(depth + 1)}<path data-vector-part="fill" d="${d}" fill="none"${rule}${geometry}/>`);
|
|
5764
|
-
geometry = "";
|
|
5765
|
-
}
|
|
5766
|
-
for (const l of layers) {
|
|
5767
|
-
const id = `${prefix}${l.kind}-${node.id}-${l.index}`;
|
|
5768
|
-
const paint = vectorPaintToSvg(l.layer.paint, id, { node: l.node, precision, ...l.kind === "stroke" ? { role: "stroke" } : {} });
|
|
5769
|
-
defs.push(...paintMarkup(l.layer.paint, paint.defs));
|
|
5770
|
-
const attrs = ` data-vector-layer="${l.index}"${layerAttrs(l.layer)}`;
|
|
5771
|
-
if (l.kind === "fill") {
|
|
5772
|
-
lines.push(`${indent(depth + 1)}<path data-vector-part="fill"${attrs} d="${d}" fill="${escapeAttr2(paint.value)}"${rule}${geometry}/>`);
|
|
5773
|
-
geometry = "";
|
|
5774
|
-
continue;
|
|
5775
|
-
}
|
|
5776
|
-
const lineAttrs = lineAttrsOf(l.node, paint.value);
|
|
5777
|
-
const parts = vectorStrokeSvgParts(l.node, `${prefix}clip-${node.id}-${l.index}`, precision);
|
|
5778
|
-
if (!parts) {
|
|
5779
|
-
lines.push(`${indent(depth + 1)}<path data-vector-part="stroke"${attrs} d="${d}" fill="none"${lineAttrs(l.node.strokeWidth ?? 1)}/>`);
|
|
5780
|
-
continue;
|
|
5781
|
-
}
|
|
5782
|
-
lines.push(`${indent(depth + 1)}<g data-vector-part="stroke-layer"${attrs}>`);
|
|
5783
|
-
lines.push(...strokePartLines(l.node, parts, paint.value, d, lineAttrs, depth + 2));
|
|
5784
|
-
lines.push(`${indent(depth + 1)}</g>`);
|
|
5785
|
-
}
|
|
5786
|
-
lines.push(`${indent(depth)}</g>`);
|
|
5787
|
-
};
|
|
5788
|
-
const emit2 = (node, depth) => {
|
|
5789
|
-
if (node.visible === false && !options.includeHidden) return;
|
|
5790
|
-
const wrappers = options.wrap?.[node.id] ?? [];
|
|
5791
|
-
wrappers.forEach((w2, i) => {
|
|
5792
|
-
let attrs = w2.id !== void 0 ? ` id="${escapeAttr2(w2.id)}"` : "";
|
|
5793
|
-
if (w2.transform) attrs += ` transform="${escapeAttr2(w2.transform)}"`;
|
|
5794
|
-
if (w2.clip) {
|
|
5795
|
-
const shape = Object.entries(w2.clip.attrs).map(([k, v2]) => ` ${k}="${formatNumber(v2, 4)}"`).join("");
|
|
5796
|
-
defs.push(`<clipPath id="${escapeAttr2(w2.clip.id)}" clipPathUnits="objectBoundingBox"><${w2.clip.shape}${w2.clip.shapeId !== void 0 ? ` id="${escapeAttr2(w2.clip.shapeId)}"` : ""}${shape}/></clipPath>`);
|
|
5797
|
-
attrs += ` clip-path="url(#${escapeAttr2(w2.clip.id)})"`;
|
|
5798
|
-
}
|
|
5799
|
-
lines.push(`${indent(depth + i)}<g${attrs}>`);
|
|
5800
|
-
});
|
|
5801
|
-
emitNode(node, depth + wrappers.length);
|
|
5802
|
-
for (let i = wrappers.length - 1; i >= 0; i--) lines.push(`${indent(depth + i)}</g>`);
|
|
5803
|
-
};
|
|
5804
|
-
const capture = (fn) => {
|
|
5805
|
-
const at2 = lines.length;
|
|
5806
|
-
fn();
|
|
5807
|
-
return lines.splice(at2).map((l) => l.trim()).join("");
|
|
5808
|
-
};
|
|
5809
|
-
const emitMaskGroup = (node, depth) => {
|
|
5810
|
-
const [source, ...contents] = node.children;
|
|
5811
|
-
const body = node.effects?.length && contents.length ? [{ id: `${node.id}~content`, type: "group", effects: node.effects, children: contents }] : contents;
|
|
5812
|
-
const settings = { type: node.mask.type, ...node.mask.invert ? { invert: true } : {} };
|
|
5813
|
-
lines.push(`${indent(depth)}<g${common(node)} data-vector-mask="${escapeAttr2(JSON.stringify(settings))}">`);
|
|
5814
|
-
const mask = vectorMaskRenderData(node, `${prefix}mask-${node.id}`, `${prefix}mask-filter-${node.id}`, precision);
|
|
5815
|
-
let ref = "";
|
|
5816
|
-
if (mask && mask.type !== "clip") {
|
|
5817
|
-
const b = mask.bounds;
|
|
5818
|
-
const box = `x="${num2(b.x)}" y="${num2(b.y)}" width="${num2(b.width)}" height="${num2(b.height)}"`;
|
|
5819
|
-
if (mask.invertFilter) defs.push(vectorFilterMarkup(mask.invertFilter));
|
|
5820
|
-
const inner = capture(() => emitNode(source, depth + 1));
|
|
5821
|
-
const drawn = mask.filter ? `<g data-vector-part="mask-invert" filter="${escapeAttr2(mask.filter)}">${inner}</g>` : inner;
|
|
5822
|
-
defs.push(`<mask id="${escapeAttr2(mask.id)}" data-vector-part="mask-source" maskUnits="userSpaceOnUse" ${box}${mask.type === "alpha" ? ' mask-type="alpha"' : ""}>${drawn}</mask>`);
|
|
5823
|
-
ref = ` mask="url(#${escapeAttr2(mask.id)})"`;
|
|
5824
|
-
} else {
|
|
5825
|
-
lines.push(`${indent(depth + 1)}<g data-vector-part="mask-source" display="none">`);
|
|
5826
|
-
emitNode(source, depth + 2);
|
|
5827
|
-
lines.push(`${indent(depth + 1)}</g>`);
|
|
5828
|
-
if (mask?.clip) {
|
|
5829
|
-
defs.push(`<clipPath id="${escapeAttr2(mask.id)}">${mask.clip.map((c) => `<path d="${c.d}" clip-rule="${c.clipRule}"/>`).join("")}</clipPath>`);
|
|
5830
|
-
ref = ` clip-path="url(#${escapeAttr2(mask.id)})"`;
|
|
5831
|
-
}
|
|
5832
|
-
}
|
|
5833
|
-
lines.push(`${indent(depth + 1)}<g data-vector-part="masked"${ref}>`);
|
|
5834
|
-
for (const child of body) emit2(child, depth + 2);
|
|
5835
|
-
lines.push(`${indent(depth + 1)}</g>`);
|
|
5836
|
-
lines.push(`${indent(depth)}</g>`);
|
|
5837
|
-
};
|
|
5838
|
-
const emitNode = (node, depth) => {
|
|
5839
|
-
if (isVectorMaskGroup(node)) {
|
|
5840
|
-
emitMaskGroup(node, depth);
|
|
5841
|
-
return;
|
|
5842
|
-
}
|
|
5843
|
-
if (hasOwnVectorAppearance(node)) {
|
|
5844
|
-
const live2 = {
|
|
5845
|
-
kind: node.type,
|
|
5846
|
-
...node.effects?.length ? { effects: node.effects } : {},
|
|
5847
|
-
...node.type === "group" && node.liveBoolean ? { liveBoolean: node.liveBoolean } : {}
|
|
5848
|
-
};
|
|
5849
|
-
lines.push(`${indent(depth)}<g${common(node)} data-vector-live="${escapeAttr2(JSON.stringify(live2))}">`);
|
|
5850
|
-
lines.push(`${indent(depth + 1)}<g data-vector-part="appearance">`);
|
|
5851
|
-
for (const shape of vectorAppearanceNodes(node)) emit2(shape, depth + 2);
|
|
5852
|
-
lines.push(`${indent(depth + 1)}</g>`);
|
|
5853
|
-
lines.push(`${indent(depth + 1)}<g data-vector-part="source" display="none">`);
|
|
5854
|
-
if (node.type === "path") {
|
|
5855
|
-
const { effects: _e, transform: _t, opacity: _o, visible: _v, booleanOperation: _b, blendStep: _s, blendMode: _bm, filters: _f, ...source } = node;
|
|
5856
|
-
emit2({ ...source, id: `${node.id}~src` }, depth + 2);
|
|
5857
|
-
} else for (const child of node.children) emit2(child, depth + 2);
|
|
5858
|
-
lines.push(`${indent(depth + 1)}</g>`);
|
|
5859
|
-
lines.push(`${indent(depth)}</g>`);
|
|
5860
|
-
return;
|
|
5861
|
-
}
|
|
5862
|
-
if (node.type === "group") {
|
|
5863
|
-
lines.push(`${indent(depth)}<g${common(node)}>`);
|
|
5864
|
-
for (const child of node.children) emit2(child, depth + 1);
|
|
5865
|
-
lines.push(`${indent(depth)}</g>`);
|
|
5866
|
-
return;
|
|
5867
|
-
}
|
|
5868
|
-
if (needsVectorPaintLayers(node)) {
|
|
5869
|
-
emitStacked(node, depth);
|
|
5870
|
-
return;
|
|
5871
|
-
}
|
|
5872
|
-
const fill = vectorPaintToSvg(node.fill, `${prefix}fill-${node.id}`, { node, precision });
|
|
5873
|
-
const stroke = vectorPaintToSvg(node.stroke, `${prefix}stroke-${node.id}`, { node, role: "stroke", precision });
|
|
5874
|
-
defs.push(...paintMarkup(node.fill, fill.defs), ...paintMarkup(node.stroke, stroke.defs));
|
|
5875
|
-
const d = vectorPathData(node, precision);
|
|
5876
|
-
const live = liveCorners(node);
|
|
5877
|
-
const fillAttrs = ` fill="${escapeAttr2(fill.value)}"${node.fillRule === "evenodd" ? ` fill-rule="evenodd"` : ""}`;
|
|
5878
|
-
const lineAttrs = lineAttrsOf(node, stroke.value);
|
|
5879
|
-
const parts = stroke.value !== "none" ? vectorStrokeSvgParts(node, `${prefix}clip-${node.id}`, precision) : void 0;
|
|
5880
|
-
if (!parts) {
|
|
5881
|
-
lines.push(`${indent(depth)}<path${common(node)} d="${d}"${fillAttrs}${stroke.value !== "none" ? lineAttrs(node.strokeWidth ?? 1) : ""}${live}/>`);
|
|
5882
|
-
return;
|
|
5883
|
-
}
|
|
5884
|
-
let data = ` data-vector-path="" data-vector-stroke-width="${num2(node.strokeWidth ?? 1)}"`;
|
|
5885
|
-
if (parts.align !== "center") data += ` data-vector-stroke-align="${parts.align}"`;
|
|
5886
|
-
if (node.startArrow) data += ` data-vector-start-arrow="${node.startArrow}"`;
|
|
5887
|
-
if (node.endArrow) data += ` data-vector-end-arrow="${node.endArrow}"`;
|
|
5888
|
-
if (node.arrowAlign && node.arrowAlign !== "extend") data += ` data-vector-arrow-align="${node.arrowAlign}"`;
|
|
5889
|
-
if (node.startArrowScale !== void 0 && node.startArrowScale !== 1) data += ` data-vector-start-arrow-scale="${num2(node.startArrowScale)}"`;
|
|
5890
|
-
if (node.endArrowScale !== void 0 && node.endArrowScale !== 1) data += ` data-vector-end-arrow-scale="${num2(node.endArrowScale)}"`;
|
|
5891
|
-
const profile = strokeWidthProfileOf(node);
|
|
5892
|
-
if (profile) {
|
|
5893
|
-
data += ` data-vector-width-profile="${widthProfileToAttribute(profile)}"`;
|
|
5894
|
-
if (node.strokeLinecap && node.strokeLinecap !== "butt") data += ` data-vector-stroke-linecap="${node.strokeLinecap}"`;
|
|
5895
|
-
if (node.strokeLinejoin && node.strokeLinejoin !== "miter") data += ` data-vector-stroke-linejoin="${node.strokeLinejoin}"`;
|
|
5896
|
-
if (node.strokeDasharray?.length) data += ` data-vector-stroke-dasharray="${node.strokeDasharray.map(num2).join(" ")}"`;
|
|
5897
|
-
}
|
|
5898
|
-
lines.push(`${indent(depth)}<g${common(node)}${data}>`);
|
|
5899
|
-
lines.push(`${indent(depth + 1)}<path data-vector-part="fill" d="${d}"${fillAttrs}${live}/>`);
|
|
5900
|
-
lines.push(...strokePartLines(node, parts, stroke.value, d, lineAttrs, depth + 1));
|
|
5901
|
-
lines.push(`${indent(depth)}</g>`);
|
|
5902
|
-
};
|
|
5903
|
-
for (const node of doc.nodes) emit2(node, 1);
|
|
5904
|
-
const w = num2(doc.width);
|
|
5905
|
-
const h = num2(doc.height);
|
|
5906
|
-
const nl = pretty ? "\n" : "";
|
|
5907
|
-
const out = [`<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">`];
|
|
5908
|
-
if (defs.length) out.push(`${indent(1)}<defs>${defs.join("")}</defs>`);
|
|
5909
|
-
if (doc.background && options.background !== false && hasPaint(doc.background)) {
|
|
5910
|
-
out.push(`${indent(1)}<rect width="${w}" height="${h}" fill="${escapeAttr2(doc.background)}"/>`);
|
|
5911
|
-
}
|
|
5912
|
-
out.push(...lines, "</svg>");
|
|
5913
|
-
return out.join(nl);
|
|
5914
|
-
}
|
|
5915
|
-
var BOOLEAN_OPERATIONS = ["union", "subtract", "intersect", "exclude"];
|
|
5916
|
-
function parseXml(source) {
|
|
5917
|
-
const text = source.replace(/<!--[\s\S]*?-->/g, "").replace(/<\?[\s\S]*?\?>/g, "").replace(/<!\[CDATA\[[\s\S]*?\]\]>/g, "").replace(/<!DOCTYPE[^>[]*(\[[\s\S]*?\])?\s*>/gi, "");
|
|
5918
|
-
const root = { name: "#root", attrs: {}, children: [] };
|
|
5919
|
-
const stack = [root];
|
|
5920
|
-
const tag = /<(\/?)([A-Za-z_][\w:.-]*)((?:\s+[^\s=/>]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+))?)*)\s*(\/?)>/g;
|
|
5921
|
-
const attr = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
|
|
5922
|
-
let m;
|
|
5923
|
-
while (m = tag.exec(text)) {
|
|
5924
|
-
const [, closing, rawName, rawAttrs, selfClosing] = m;
|
|
5925
|
-
const name = rawName.replace(/^svg:/, "");
|
|
5926
|
-
if (closing) {
|
|
5927
|
-
for (let i = stack.length - 1; i > 0; i--) {
|
|
5928
|
-
if (stack[i].name === name) {
|
|
5929
|
-
stack.length = i;
|
|
5930
|
-
break;
|
|
5931
|
-
}
|
|
5932
|
-
}
|
|
5933
|
-
continue;
|
|
5934
|
-
}
|
|
5935
|
-
const attrs = {};
|
|
5936
|
-
let a;
|
|
5937
|
-
attr.lastIndex = 0;
|
|
5938
|
-
while (a = attr.exec(rawAttrs)) attrs[a[1]] = decodeEntities(a[2] ?? a[3] ?? a[4] ?? "");
|
|
5939
|
-
const el = { name, attrs, children: [] };
|
|
5940
|
-
stack[stack.length - 1].children.push(el);
|
|
5941
|
-
if (!selfClosing) stack.push(el);
|
|
5942
|
-
}
|
|
5943
|
-
const find = (el) => {
|
|
5944
|
-
if (el.name === "svg") return el;
|
|
5945
|
-
for (const c of el.children) {
|
|
5946
|
-
const f = find(c);
|
|
5947
|
-
if (f) return f;
|
|
5948
|
-
}
|
|
5949
|
-
return null;
|
|
5950
|
-
};
|
|
5951
|
-
return find(root);
|
|
5952
|
-
}
|
|
5953
|
-
function decodeEntities(s) {
|
|
5954
|
-
return s.replace(/&#x([0-9a-f]+);/gi, (_, h) => String.fromCodePoint(parseInt(h, 16))).replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(parseInt(d, 10))).replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
5955
|
-
}
|
|
5956
|
-
var numberList = (s) => (s ?? "").trim().split(/[\s,]+|(?=-)(?<![eE])/).filter(Boolean).map(Number).filter((n) => Number.isFinite(n));
|
|
5957
|
-
var length = (s, fallback = 0) => {
|
|
5958
|
-
if (s === void 0) return fallback;
|
|
5959
|
-
const n = parseFloat(s);
|
|
5960
|
-
return Number.isFinite(n) ? n : fallback;
|
|
5961
|
-
};
|
|
5962
|
-
function parseSvgTransform(value) {
|
|
5963
|
-
let m = IDENTITY_MATRIX;
|
|
5964
|
-
if (!value) return m;
|
|
5965
|
-
const re = /(matrix|translate|scale|rotate|skewX|skewY)\s*\(([^)]*)\)/g;
|
|
5966
|
-
let t;
|
|
5967
|
-
while (t = re.exec(value)) {
|
|
5968
|
-
const n = numberList(t[2]);
|
|
5969
|
-
let step = IDENTITY_MATRIX;
|
|
5970
|
-
switch (t[1]) {
|
|
5971
|
-
case "matrix":
|
|
5972
|
-
if (n.length >= 6) step = [n[0], n[1], n[2], n[3], n[4], n[5]];
|
|
5973
|
-
break;
|
|
5974
|
-
case "translate":
|
|
5975
|
-
step = translateMatrix(n[0] ?? 0, n[1] ?? 0);
|
|
5976
|
-
break;
|
|
5977
|
-
case "scale":
|
|
5978
|
-
step = scaleMatrix(n[0] ?? 1, n[1] ?? n[0] ?? 1);
|
|
5979
|
-
break;
|
|
5980
|
-
case "rotate":
|
|
5981
|
-
step = rotateMatrix(n[0] ?? 0, { x: n[1] ?? 0, y: n[2] ?? 0 });
|
|
5982
|
-
break;
|
|
5983
|
-
case "skewX":
|
|
5984
|
-
step = [1, 0, Math.tan((n[0] ?? 0) * Math.PI / 180), 1, 0, 0];
|
|
5985
|
-
break;
|
|
5986
|
-
case "skewY":
|
|
5987
|
-
step = [1, Math.tan((n[0] ?? 0) * Math.PI / 180), 0, 1, 0, 0];
|
|
5988
|
-
break;
|
|
5989
|
-
}
|
|
5990
|
-
m = multiplyMatrices(step, m);
|
|
5991
|
-
}
|
|
5992
|
-
return m;
|
|
5993
|
-
}
|
|
5994
|
-
var STYLE_KEYS2 = {
|
|
5995
|
-
fill: "fill",
|
|
5996
|
-
stroke: "stroke",
|
|
5997
|
-
"stroke-width": "strokeWidth",
|
|
5998
|
-
"stroke-linecap": "strokeLinecap",
|
|
5999
|
-
"stroke-linejoin": "strokeLinejoin",
|
|
6000
|
-
"stroke-dasharray": "strokeDasharray",
|
|
6001
|
-
"fill-rule": "fillRule",
|
|
6002
|
-
"fill-opacity": "fillOpacity",
|
|
6003
|
-
"stroke-opacity": "strokeOpacity",
|
|
6004
|
-
"mix-blend-mode": "mixBlendMode",
|
|
6005
|
-
filter: "filter"
|
|
6006
|
-
};
|
|
6007
|
-
function readStyle(el, parent) {
|
|
6008
|
-
const { mixBlendMode: _m, filter: _f, ...inherited } = parent;
|
|
6009
|
-
const out = { ...inherited };
|
|
6010
|
-
for (const [attr, key] of Object.entries(STYLE_KEYS2)) if (el.attrs[attr] !== void 0) out[key] = el.attrs[attr].trim();
|
|
6011
|
-
for (const decl of (el.attrs.style ?? "").split(";")) {
|
|
6012
|
-
const i = decl.indexOf(":");
|
|
6013
|
-
if (i < 0) continue;
|
|
6014
|
-
const key = STYLE_KEYS2[decl.slice(0, i).trim()];
|
|
6015
|
-
if (key) out[key] = decl.slice(i + 1).replace(/!important/, "").trim();
|
|
6016
|
-
}
|
|
6017
|
-
return out;
|
|
6018
|
-
}
|
|
6019
|
-
function readStops(el) {
|
|
6020
|
-
return el.children.filter((c) => c.name === "stop").map((c) => {
|
|
6021
|
-
const style = Object.fromEntries(
|
|
6022
|
-
(c.attrs.style ?? "").split(";").map((d) => d.split(":").map((s) => s.trim())).filter((d) => d.length === 2)
|
|
6023
|
-
);
|
|
6024
|
-
const raw = c.attrs.offset ?? "0";
|
|
6025
|
-
const offset = raw.endsWith("%") ? parseFloat(raw) / 100 : parseFloat(raw);
|
|
6026
|
-
const opacity = style["stop-opacity"] ?? c.attrs["stop-opacity"];
|
|
6027
|
-
return {
|
|
6028
|
-
offset: Number.isFinite(offset) ? Math.max(0, Math.min(1, offset)) : 0,
|
|
6029
|
-
color: style["stop-color"] ?? c.attrs["stop-color"] ?? "#000",
|
|
6030
|
-
...opacity !== void 0 ? { opacity: parseFloat(opacity) } : {}
|
|
6031
|
-
};
|
|
6032
|
-
});
|
|
6033
|
-
}
|
|
6034
|
-
var fraction = (s, fallback) => {
|
|
6035
|
-
if (s === void 0) return fallback;
|
|
6036
|
-
const n = parseFloat(s);
|
|
6037
|
-
if (!Number.isFinite(n)) return fallback;
|
|
6038
|
-
return s.trim().endsWith("%") ? n / 100 : n;
|
|
6039
|
-
};
|
|
6040
|
-
var PAINT_SERVERS = /* @__PURE__ */ new Set(["linearGradient", "radialGradient", "pattern"]);
|
|
6041
|
-
function collectGradients(el, raw) {
|
|
6042
|
-
if (PAINT_SERVERS.has(el.name) && el.attrs.id) raw.set(el.attrs.id, el);
|
|
6043
|
-
for (const c of el.children) collectGradients(c, raw);
|
|
6044
|
-
}
|
|
6045
|
-
function collectMasks(el, raw) {
|
|
6046
|
-
if ((el.name === "clipPath" || el.name === "mask") && el.attrs.id) raw.set(el.attrs.id, el);
|
|
6047
|
-
for (const c of el.children) collectMasks(c, raw);
|
|
6048
|
-
}
|
|
6049
|
-
function attrOrStyle(el, name) {
|
|
6050
|
-
for (const decl of (el.attrs.style ?? "").split(";")) {
|
|
6051
|
-
const i = decl.indexOf(":");
|
|
6052
|
-
if (i >= 0 && decl.slice(0, i).trim() === name) return decl.slice(i + 1).replace(/!important/, "").trim();
|
|
6053
|
-
}
|
|
6054
|
-
return el.attrs[name];
|
|
6055
|
-
}
|
|
6056
|
-
function urlId(value) {
|
|
6057
|
-
return /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec((value ?? "").trim())?.[1] ?? null;
|
|
6058
|
-
}
|
|
6059
|
-
function clipRulesAsFillRules(el) {
|
|
6060
|
-
const attrs = { ...el.attrs };
|
|
6061
|
-
const rule = attrOrStyle(el, "clip-rule");
|
|
6062
|
-
if (rule) attrs["fill-rule"] = rule;
|
|
6063
|
-
return { ...el, attrs, children: el.children.map(clipRulesAsFillRules) };
|
|
6064
|
-
}
|
|
6065
|
-
function collectFilters(el, raw) {
|
|
6066
|
-
if (el.name === "filter" && el.attrs.id) raw.set(el.attrs.id, el);
|
|
6067
|
-
for (const c of el.children) collectFilters(c, raw);
|
|
6068
|
-
}
|
|
6069
|
-
function filtersFromElement(el) {
|
|
6070
|
-
const own = el.attrs["data-vector-filters"];
|
|
6071
|
-
if (own !== void 0) {
|
|
6072
|
-
try {
|
|
6073
|
-
return sanitizeVectorFilters(JSON.parse(own));
|
|
6074
|
-
} catch {
|
|
6075
|
-
return [];
|
|
6076
|
-
}
|
|
6077
|
-
}
|
|
6078
|
-
const prims = el.children.filter((c) => c.name.startsWith("fe"));
|
|
6079
|
-
const out = [];
|
|
6080
|
-
for (const p of prims) {
|
|
6081
|
-
const std = numberList(p.attrs.stdDeviation)[0] ?? 0;
|
|
6082
|
-
if (p.name === "feDropShadow") {
|
|
6083
|
-
const style = Object.fromEntries(
|
|
6084
|
-
(p.attrs.style ?? "").split(";").map((d) => d.split(":").map((x) => x.trim())).filter((d) => d.length === 2)
|
|
6085
|
-
);
|
|
6086
|
-
const opacity = parseFloat(style["flood-opacity"] ?? p.attrs["flood-opacity"] ?? "1");
|
|
6087
|
-
out.push({
|
|
6088
|
-
type: "dropShadow",
|
|
6089
|
-
params: {
|
|
6090
|
-
color: style["flood-color"] ?? p.attrs["flood-color"] ?? "#000000",
|
|
6091
|
-
opacity: Number.isFinite(opacity) ? opacity : 1,
|
|
6092
|
-
offsetX: length(p.attrs.dx, 2),
|
|
6093
|
-
offsetY: length(p.attrs.dy, 2),
|
|
6094
|
-
blur: std * 2,
|
|
6095
|
-
spread: 0
|
|
6096
|
-
}
|
|
6097
|
-
});
|
|
6098
|
-
} else if (p.name === "feGaussianBlur" && prims.length === 1 && (p.attrs.in === void 0 || p.attrs.in === "SourceGraphic")) {
|
|
6099
|
-
out.push({ type: "layerBlur", params: { radius: std * 2 } });
|
|
6100
|
-
} else return [];
|
|
6101
|
-
}
|
|
6102
|
-
return sanitizeVectorFilters(out);
|
|
6103
|
-
}
|
|
6104
|
-
function gradientFromAttribute(value) {
|
|
6105
|
-
if (!value) return null;
|
|
6106
|
-
try {
|
|
6107
|
-
return sanitizeVectorGradient(JSON.parse(value));
|
|
6108
|
-
} catch {
|
|
6109
|
-
return null;
|
|
6110
|
-
}
|
|
6111
|
-
}
|
|
6112
|
-
function resolveGradient(id, raw) {
|
|
6113
|
-
const first = raw.get(id);
|
|
6114
|
-
if (!first) return null;
|
|
6115
|
-
const own = gradientFromAttribute(first.attrs["data-vector-gradient"]);
|
|
6116
|
-
if (own) return own;
|
|
6117
|
-
if (first.name === "pattern") return null;
|
|
6118
|
-
const chain = [];
|
|
6119
|
-
for (let el = first; el && !chain.includes(el) && chain.length < 32; ) {
|
|
6120
|
-
chain.push(el);
|
|
6121
|
-
const href = el.attrs.href ?? el.attrs["xlink:href"];
|
|
6122
|
-
el = href?.startsWith("#") ? raw.get(href.slice(1)) : void 0;
|
|
6123
|
-
}
|
|
6124
|
-
const attr = (name) => chain.find((el) => el.attrs[name] !== void 0)?.attrs[name];
|
|
6125
|
-
const stops = chain.map(readStops).find((s) => s.length) ?? [];
|
|
6126
|
-
if (!stops.length) return null;
|
|
6127
|
-
const user = attr("gradientUnits") === "userSpaceOnUse";
|
|
6128
|
-
const t = parseSvgTransform(attr("gradientTransform"));
|
|
6129
|
-
const plain2 = t === IDENTITY_MATRIX || t[0] === 1 && t[1] === 0 && t[2] === 0 && t[3] === 1 && t[4] === 0 && t[5] === 0;
|
|
6130
|
-
const at2 = (name, fallback) => user ? length(attr(name), fallback) : fraction(attr(name), fallback);
|
|
6131
|
-
const spreadAttr = attr("spreadMethod");
|
|
6132
|
-
const spread = spreadAttr === "reflect" || spreadAttr === "repeat" ? { spread: spreadAttr } : {};
|
|
6133
|
-
const map = (p) => applySvgMatrix(t, p);
|
|
6134
|
-
if (first.name === "radialGradient") {
|
|
6135
|
-
const cx = at2("cx", user ? 0 : 0.5);
|
|
6136
|
-
const cy = at2("cy", user ? 0 : 0.5);
|
|
6137
|
-
const r = at2("r", user ? 0 : 0.5);
|
|
6138
|
-
const fx = attr("fx") !== void 0 ? at2("fx", cx) : cx;
|
|
6139
|
-
const fy = attr("fy") !== void 0 ? at2("fy", cy) : cy;
|
|
6140
|
-
const fr = attr("fr") !== void 0 ? at2("fr", 0) : 0;
|
|
6141
|
-
const focal = Math.abs(fx - cx) > 1e-9 || Math.abs(fy - cy) > 1e-9;
|
|
6142
|
-
if (!user && plain2 && !focal && !(fr > 0)) return { type: "radial", cx, cy, r, stops, ...spread };
|
|
6143
|
-
const g = {
|
|
6144
|
-
type: "radial",
|
|
6145
|
-
stops,
|
|
6146
|
-
start: map({ x: cx, y: cy }),
|
|
6147
|
-
end: map({ x: cx + r, y: cy }),
|
|
6148
|
-
width: map({ x: cx, y: cy + r }),
|
|
6149
|
-
units: user ? "userSpaceOnUse" : "objectBoundingBox",
|
|
6150
|
-
...spread
|
|
6151
|
-
};
|
|
6152
|
-
if (focal) g.focal = map({ x: fx, y: fy });
|
|
6153
|
-
if (fr > 0 && r > 0) g.focalRadius = Math.min(0.99, fr / r);
|
|
6154
|
-
return g;
|
|
6155
|
-
}
|
|
6156
|
-
const x1 = at2("x1", 0);
|
|
6157
|
-
const y1 = at2("y1", 0);
|
|
6158
|
-
const x2 = attr("x2") !== void 0 ? at2("x2", 1) : user ? 0 : 1;
|
|
6159
|
-
const y2 = at2("y2", 0);
|
|
6160
|
-
if (!user && plain2) {
|
|
6161
|
-
const angle = Math.round((Math.atan2(x2 - x1, -(y2 - y1)) * 180 / Math.PI + 360) % 360);
|
|
6162
|
-
const c = angleToSvgLinearCoords(angle);
|
|
6163
|
-
const len2 = Math.hypot(x2 - x1, y2 - y1);
|
|
6164
|
-
const d = len2 > 0 ? { x: (x2 - x1) / len2, y: (y2 - y1) / len2 } : { x: 0, y: 1 };
|
|
6165
|
-
const along2 = (x, y) => x * d.x + y * d.y;
|
|
6166
|
-
const same2 = len2 > 0 && Math.abs((c.x2 - c.x1) * d.y - (c.y2 - c.y1) * d.x) < 1e-3 && Math.abs(along2(c.x1, c.y1) - along2(x1, y1)) < 1e-3 && Math.abs(along2(c.x2, c.y2) - along2(x2, y2)) < 1e-3;
|
|
6167
|
-
if (same2) return { type: "linear", angle, stops, ...spread };
|
|
6168
|
-
}
|
|
6169
|
-
const start = { x: x1, y: y1 };
|
|
6170
|
-
const end = { x: x2, y: y2 };
|
|
6171
|
-
return {
|
|
6172
|
-
type: "linear",
|
|
6173
|
-
stops,
|
|
6174
|
-
start: map(start),
|
|
6175
|
-
end: map(end),
|
|
6176
|
-
width: map({ x: x1 - (y2 - y1), y: y1 + (x2 - x1) }),
|
|
6177
|
-
units: user ? "userSpaceOnUse" : "objectBoundingBox",
|
|
6178
|
-
...spread
|
|
6179
|
-
};
|
|
6180
|
-
}
|
|
6181
|
-
var applySvgMatrix = (m, p) => ({ x: m[0] * p.x + m[2] * p.y + m[4], y: m[1] * p.x + m[3] * p.y + m[5] });
|
|
6182
|
-
function parseVectorSvg(svg, options = {}) {
|
|
6183
|
-
const root = parseXml(svg);
|
|
6184
|
-
if (!root) throw new Error("The markup has no <svg> element.");
|
|
6185
|
-
let counter = 0;
|
|
6186
|
-
const usedIds = /* @__PURE__ */ new Set();
|
|
6187
|
-
const createId = options.createId ?? (() => `node-${++counter}`);
|
|
6188
|
-
const idFor = (el) => {
|
|
6189
|
-
const id = el.attrs.id;
|
|
6190
|
-
if (id && !usedIds.has(id)) {
|
|
6191
|
-
usedIds.add(id);
|
|
6192
|
-
return id;
|
|
6193
|
-
}
|
|
6194
|
-
let next = createId();
|
|
6195
|
-
while (usedIds.has(next)) next = createId();
|
|
6196
|
-
usedIds.add(next);
|
|
6197
|
-
return next;
|
|
6198
|
-
};
|
|
6199
|
-
const rawGradients = /* @__PURE__ */ new Map();
|
|
6200
|
-
collectGradients(root, rawGradients);
|
|
6201
|
-
const rawFilters = /* @__PURE__ */ new Map();
|
|
6202
|
-
collectFilters(root, rawFilters);
|
|
6203
|
-
const rawMasks = /* @__PURE__ */ new Map();
|
|
6204
|
-
collectMasks(root, rawMasks);
|
|
6205
|
-
const resolving = /* @__PURE__ */ new Set();
|
|
6206
|
-
const filtersOf = (value) => {
|
|
6207
|
-
const url = /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec((value ?? "").trim());
|
|
6208
|
-
const el = url ? rawFilters.get(url[1]) : void 0;
|
|
6209
|
-
return el ? filtersFromElement(el) : [];
|
|
6210
|
-
};
|
|
6211
|
-
const paint = (value) => {
|
|
6212
|
-
const v2 = value.trim();
|
|
6213
|
-
const url = /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec(v2);
|
|
6214
|
-
if (url) return resolveGradient(url[1], rawGradients) ?? null;
|
|
6215
|
-
if (v2 === "none" || v2 === "") return null;
|
|
6216
|
-
return v2;
|
|
6217
|
-
};
|
|
6218
|
-
const viewBox = numberList(root.attrs.viewBox);
|
|
6219
|
-
const width = viewBox.length === 4 ? viewBox[2] : length(root.attrs.width, 300);
|
|
6220
|
-
const height = viewBox.length === 4 ? viewBox[3] : length(root.attrs.height, 150);
|
|
6221
|
-
const rootMatrix = viewBox.length === 4 ? translateMatrix(-viewBox[0], -viewBox[1]) : IDENTITY_MATRIX;
|
|
6222
|
-
const SKIP = /* @__PURE__ */ new Set(["defs", "clipPath", "mask", "symbol", "style", "title", "desc", "metadata", "pattern", "marker", "filter", "text", "image", "use", "linearGradient", "radialGradient", "script", "foreignObject"]);
|
|
6223
|
-
const shapeOf = (el) => {
|
|
6224
|
-
const a = el.attrs;
|
|
6225
|
-
switch (el.name) {
|
|
6226
|
-
case "path": {
|
|
6227
|
-
if (a["data-vector-d"] && a["data-vector-corners"]) {
|
|
6228
|
-
const sharp = bezierToSubpaths(a["data-vector-d"]);
|
|
6229
|
-
if (sharp.length) return applyVectorCornersAttribute(sharp, a["data-vector-corners"]);
|
|
6230
|
-
}
|
|
6231
|
-
return a.d ? bezierToSubpaths(a.d) : null;
|
|
6232
|
-
}
|
|
6233
|
-
case "rect": {
|
|
6234
|
-
const w = length(a.width);
|
|
6235
|
-
const h = length(a.height);
|
|
6236
|
-
if (w <= 0 || h <= 0) return null;
|
|
6237
|
-
const r = length(a.rx ?? a.ry, 0);
|
|
6238
|
-
return [rectSubpath({ x: length(a.x), y: length(a.y), width: w, height: h }, r)];
|
|
6239
|
-
}
|
|
6240
|
-
case "circle": {
|
|
6241
|
-
const r = length(a.r);
|
|
6242
|
-
if (r <= 0) return null;
|
|
6243
|
-
const cx = length(a.cx);
|
|
6244
|
-
const cy = length(a.cy);
|
|
6245
|
-
return [ellipseSubpath({ x: cx - r, y: cy - r, width: 2 * r, height: 2 * r })];
|
|
6246
|
-
}
|
|
6247
|
-
case "ellipse": {
|
|
6248
|
-
const rx = length(a.rx);
|
|
6249
|
-
const ry = length(a.ry);
|
|
6250
|
-
if (rx <= 0 || ry <= 0) return null;
|
|
6251
|
-
return [ellipseSubpath({ x: length(a.cx) - rx, y: length(a.cy) - ry, width: 2 * rx, height: 2 * ry })];
|
|
6252
|
-
}
|
|
6253
|
-
case "line":
|
|
6254
|
-
return [lineSubpath({ x: length(a.x1), y: length(a.y1) }, { x: length(a.x2), y: length(a.y2) })];
|
|
6255
|
-
case "polyline":
|
|
6256
|
-
case "polygon": {
|
|
6257
|
-
const n = numberList(a.points);
|
|
6258
|
-
if (n.length < 4) return null;
|
|
6259
|
-
const anchors = [];
|
|
6260
|
-
for (let i = 0; i + 1 < n.length; i += 2) anchors.push({ x: n[i], y: n[i + 1] });
|
|
6261
|
-
return [{ anchors, closed: el.name === "polygon" }];
|
|
6262
|
-
}
|
|
6263
|
-
}
|
|
6264
|
-
return null;
|
|
6265
|
-
};
|
|
6266
|
-
const strokeStyle = (s) => ({
|
|
6267
|
-
...s.strokeWidth ? { strokeWidth: length(s.strokeWidth, 1) } : {},
|
|
6268
|
-
...s.strokeLinecap ? { strokeLinecap: s.strokeLinecap } : {},
|
|
6269
|
-
...s.strokeLinejoin ? { strokeLinejoin: s.strokeLinejoin } : {},
|
|
6270
|
-
...s.strokeDasharray && s.strokeDasharray !== "none" ? { strokeDasharray: numberList(s.strokeDasharray) } : {},
|
|
6271
|
-
...s.fillRule === "evenodd" ? { fillRule: "evenodd" } : {}
|
|
6272
|
-
});
|
|
6273
|
-
const placed = (node, m) => {
|
|
6274
|
-
if (m === IDENTITY_MATRIX) return node;
|
|
6275
|
-
const next = transformVectorNode(node, m);
|
|
6276
|
-
const strokeScale = Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
6277
|
-
if (strokeScale > 0 && Math.abs(strokeScale - 1) > 1e-9) {
|
|
6278
|
-
if (hasPaint(next.stroke)) next.strokeWidth = (next.strokeWidth ?? 1) * strokeScale;
|
|
6279
|
-
if (Array.isArray(next.strokes)) next.strokes = next.strokes.map((l) => (l.kind ?? "paint") === "paint" ? { ...l, strokeWidth: (l.strokeWidth ?? 1) * strokeScale } : l);
|
|
6280
|
-
}
|
|
6281
|
-
return normalizeVectorPaintStacks(next, "stack");
|
|
6282
|
-
};
|
|
6283
|
-
const withOpacities = (node, s) => {
|
|
6284
|
-
let out = node;
|
|
6285
|
-
const fo = s.fillOpacity !== void 0 ? fraction(s.fillOpacity, 1) : 1;
|
|
6286
|
-
const so = s.strokeOpacity !== void 0 ? fraction(s.strokeOpacity, 1) : 1;
|
|
6287
|
-
if (fo < 1 && hasPaint(out.fill)) out = withVectorFills(out, [{ paint: out.fill, opacity: Math.max(0, fo) }]);
|
|
6288
|
-
if (so < 1 && hasPaint(out.stroke)) out = withVectorStrokes(out, vectorStrokes(out).map((l) => ({ ...l, opacity: Math.max(0, so) })));
|
|
6289
|
-
return out;
|
|
6290
|
-
};
|
|
6291
|
-
const stackedPath = (g, _style, m, meta) => {
|
|
6292
|
-
const fillEl = g.children.find((c) => c.name === "path" && c.attrs["data-vector-part"] === "fill");
|
|
6293
|
-
const subpaths = fillEl ? shapeOf(fillEl) : null;
|
|
6294
|
-
if (!subpaths?.length) return null;
|
|
6295
|
-
const parse = (v2) => {
|
|
6296
|
-
try {
|
|
6297
|
-
return v2 ? JSON.parse(v2) : [];
|
|
6298
|
-
} catch {
|
|
6299
|
-
return [];
|
|
6300
|
-
}
|
|
6301
|
-
};
|
|
6302
|
-
let node = { id: idFor(g), type: "path", ...meta, subpaths, fill: null, stroke: null };
|
|
6303
|
-
if (g.attrs["data-vector-fill-rule"] === "evenodd") node.fillRule = "evenodd";
|
|
6304
|
-
node = withVectorFills(node, sanitizeVectorFills(parse(g.attrs["data-vector-fills"])));
|
|
6305
|
-
node = withVectorStrokes(node, sanitizeVectorStrokes(parse(g.attrs["data-vector-strokes"])));
|
|
6306
|
-
return placed(node, m);
|
|
6307
|
-
};
|
|
6308
|
-
const mergeStacked = (nodes2) => {
|
|
6309
|
-
const out = [];
|
|
6310
|
-
const key = (n) => JSON.stringify([n.subpaths, n.transform ?? null, n.opacity ?? 1, n.visible !== false, n.filters ?? null, n.blendMode ?? "normal", n.fillRule ?? "nonzero", n.booleanOperation ?? null]);
|
|
6311
|
-
for (const n of nodes2) {
|
|
6312
|
-
const prev = out[out.length - 1];
|
|
6313
|
-
if (prev?.type === "path" && n.type === "path" && key(prev) === key(n)) {
|
|
6314
|
-
const fills = vectorFills(n);
|
|
6315
|
-
const strokesBefore = vectorStrokes(prev);
|
|
6316
|
-
if (!(fills.length && strokesBefore.length)) {
|
|
6317
|
-
let merged = withVectorFills(prev, [...vectorFills(prev), ...fills]);
|
|
6318
|
-
merged = withVectorStrokes(merged, [...strokesBefore, ...vectorStrokes(n)]);
|
|
6319
|
-
out[out.length - 1] = merged;
|
|
6320
|
-
continue;
|
|
6321
|
-
}
|
|
6322
|
-
}
|
|
6323
|
-
out.push(n);
|
|
6324
|
-
}
|
|
6325
|
-
return out;
|
|
6326
|
-
};
|
|
6327
|
-
const mergedPath = (g, style, m, meta) => {
|
|
6328
|
-
const part = (name) => g.children.find((c) => c.name === "path" && c.attrs["data-vector-part"] === name);
|
|
6329
|
-
const fillEl = part("fill");
|
|
6330
|
-
const subpaths = fillEl ? shapeOf(fillEl) : null;
|
|
6331
|
-
if (!fillEl || !subpaths?.length) return null;
|
|
6332
|
-
const a = g.attrs;
|
|
6333
|
-
const fs = readStyle(fillEl, style);
|
|
6334
|
-
const strokeEl = part("stroke");
|
|
6335
|
-
const outlineEl = part("stroke-outline");
|
|
6336
|
-
const ss = strokeEl ? readStyle(strokeEl, style) : null;
|
|
6337
|
-
const width2 = length(a["data-vector-stroke-width"], ss ? length(ss.strokeWidth, 1) : 1);
|
|
6338
|
-
const arrow = (v2) => VECTOR_ARROWHEADS.includes(v2) ? v2 : void 0;
|
|
6339
|
-
const scale3 = (v2) => {
|
|
6340
|
-
const n = v2 === void 0 ? NaN : parseFloat(v2);
|
|
6341
|
-
return n > 0 ? n : void 0;
|
|
6342
|
-
};
|
|
6343
|
-
const align = a["data-vector-stroke-align"];
|
|
6344
|
-
const profile = widthProfileFromAttribute(a["data-vector-width-profile"]);
|
|
6345
|
-
const kept = (key, values) => values.includes(a[key]) ? a[key] : void 0;
|
|
6346
|
-
const keptCap = kept("data-vector-stroke-linecap", ["round", "square"]);
|
|
6347
|
-
const keptJoin = kept("data-vector-stroke-linejoin", ["round", "bevel"]);
|
|
6348
|
-
const keptDash = a["data-vector-stroke-dasharray"] ? numberList(a["data-vector-stroke-dasharray"]) : void 0;
|
|
6349
|
-
const node = {
|
|
6350
|
-
id: idFor(g),
|
|
6351
|
-
type: "path",
|
|
6352
|
-
...meta,
|
|
6353
|
-
subpaths,
|
|
6354
|
-
fill: paint(fs.fill),
|
|
6355
|
-
stroke: ss ? paint(ss.stroke) : outlineEl ? paint(readStyle(outlineEl, style).fill) : null,
|
|
6356
|
-
...ss ? strokeStyle(ss) : {},
|
|
6357
|
-
...fs.fillRule === "evenodd" ? { fillRule: "evenodd" } : {},
|
|
6358
|
-
strokeWidth: width2,
|
|
6359
|
-
...align === "inside" || align === "outside" ? { strokeAlign: align } : {},
|
|
6360
|
-
...arrow(a["data-vector-start-arrow"]) ? { startArrow: arrow(a["data-vector-start-arrow"]) } : {},
|
|
6361
|
-
...arrow(a["data-vector-end-arrow"]) ? { endArrow: arrow(a["data-vector-end-arrow"]) } : {},
|
|
6362
|
-
...a["data-vector-arrow-align"] === "tip" ? { arrowAlign: "tip" } : {},
|
|
6363
|
-
...scale3(a["data-vector-start-arrow-scale"]) ? { startArrowScale: scale3(a["data-vector-start-arrow-scale"]) } : {},
|
|
6364
|
-
...scale3(a["data-vector-end-arrow-scale"]) ? { endArrowScale: scale3(a["data-vector-end-arrow-scale"]) } : {},
|
|
6365
|
-
...profile.length ? { strokeWidthProfile: profile } : {},
|
|
6366
|
-
...keptCap ? { strokeLinecap: keptCap } : {},
|
|
6367
|
-
...keptJoin ? { strokeLinejoin: keptJoin } : {},
|
|
6368
|
-
...keptDash?.length ? { strokeDasharray: keptDash } : {}
|
|
6369
|
-
};
|
|
6370
|
-
return placed(node, m);
|
|
6371
|
-
};
|
|
6372
|
-
const liveNode = (g, style, m, meta) => {
|
|
6373
|
-
let raw = {};
|
|
6374
|
-
try {
|
|
6375
|
-
raw = JSON.parse(g.attrs["data-vector-live"]) ?? {};
|
|
6376
|
-
} catch {
|
|
6377
|
-
raw = {};
|
|
6378
|
-
}
|
|
6379
|
-
const sourceEl = g.children.find((c) => c.name === "g" && c.attrs["data-vector-part"] === "source");
|
|
6380
|
-
if (!sourceEl) return null;
|
|
6381
|
-
const inner = visit(sourceEl, style, m);
|
|
6382
|
-
const effects = sanitizeVectorEffects(raw.effects);
|
|
6383
|
-
const liveBoolean = BOOLEAN_OPERATIONS.includes(raw.liveBoolean) ? raw.liveBoolean : null;
|
|
6384
|
-
const id = idFor(g);
|
|
6385
|
-
if (raw.kind === "path") {
|
|
6386
|
-
const path = inner.find((n) => n.type === "path");
|
|
6387
|
-
if (!path) return null;
|
|
6388
|
-
const { residual } = decomposeRigid(m);
|
|
6389
|
-
const { visible: _v, ...rest } = path;
|
|
6390
|
-
return { ...rest, id, ...meta, ...effects.length ? { effects: transformVectorEffects(effects, residual) } : {} };
|
|
6391
|
-
}
|
|
6392
|
-
if (!inner.length) return null;
|
|
6393
|
-
const group = { id, type: "group", ...meta, children: inner };
|
|
6394
|
-
if (effects.length) group.effects = transformVectorEffects(effects, m);
|
|
6395
|
-
if (liveBoolean) group.liveBoolean = liveBoolean;
|
|
6396
|
-
const blend = blendFromAttribute(g.attrs["data-vector-blend"], m);
|
|
6397
|
-
if (blend) group.blend = blend;
|
|
6398
|
-
return group;
|
|
6399
|
-
};
|
|
6400
|
-
const visit = (el, style, matrix) => {
|
|
6401
|
-
const out = [];
|
|
6402
|
-
for (const child of el.children) {
|
|
6403
|
-
if (SKIP.has(child.name)) continue;
|
|
6404
|
-
const nodes2 = visitOne(child, style, matrix);
|
|
6405
|
-
out.push(...nodes2.length ? masked(child, nodes2, multiplyMatrices(parseSvgTransform(child.attrs.transform), matrix)) : nodes2);
|
|
6406
|
-
}
|
|
6407
|
-
return options.mergeStackedShapes ? mergeStacked(out) : out;
|
|
6408
|
-
};
|
|
6409
|
-
let rootStyle = { fill: "#000", stroke: "none", strokeWidth: "" };
|
|
6410
|
-
const bboxMatrix = (nodes2) => {
|
|
6411
|
-
const b = unionBounds(nodes2.map((n) => vectorNodeBounds(n)));
|
|
6412
|
-
return b && b.width > 0 && b.height > 0 ? [b.width, 0, 0, b.height, b.x, b.y] : null;
|
|
6413
|
-
};
|
|
6414
|
-
const maskNode = (el, m, nodes2, units) => {
|
|
6415
|
-
const id = el.attrs.id;
|
|
6416
|
-
if (!id || resolving.has(id)) return null;
|
|
6417
|
-
let space = m;
|
|
6418
|
-
if (units === "objectBoundingBox") {
|
|
6419
|
-
const box = bboxMatrix(nodes2);
|
|
6420
|
-
if (!box) return null;
|
|
6421
|
-
space = box;
|
|
6422
|
-
}
|
|
6423
|
-
resolving.add(id);
|
|
6424
|
-
const isClip = el.name === "clipPath";
|
|
6425
|
-
const content = isClip ? clipRulesAsFillRules(el) : el;
|
|
6426
|
-
const inner = visit(content, readStyle(content, rootStyle), multiplyMatrices(parseSvgTransform(el.attrs.transform), space));
|
|
6427
|
-
resolving.delete(id);
|
|
6428
|
-
const strip2 = (n) => n.type === "path" ? withVectorStrokes(withVectorFills({ ...n, fill: null, stroke: null }, []), []) : { ...n, children: n.children.map(strip2) };
|
|
6429
|
-
const list = isClip ? inner.map(strip2) : inner;
|
|
6430
|
-
if (!list.length) return null;
|
|
6431
|
-
return list.length === 1 ? list[0] : { id: idFor({ name: "g", attrs: {}, children: [] }), type: "group", name: isClip ? "Clip" : "Mask", children: list };
|
|
6432
|
-
};
|
|
6433
|
-
const masked = (el, nodes2, m) => {
|
|
6434
|
-
let out = nodes2;
|
|
6435
|
-
const clipEl = rawMasks.get(urlId(attrOrStyle(el, "clip-path")) ?? "");
|
|
6436
|
-
if (clipEl?.name === "clipPath") {
|
|
6437
|
-
const source = maskNode(clipEl, m, out, clipEl.attrs.clipPathUnits);
|
|
6438
|
-
if (source) out = [{ id: idFor({ name: "g", attrs: {}, children: [] }), type: "group", name: "Clip Group", mask: { type: "clip" }, children: [source, ...out] }];
|
|
6439
|
-
}
|
|
6440
|
-
const maskEl = rawMasks.get(urlId(attrOrStyle(el, "mask")) ?? "");
|
|
6441
|
-
if (maskEl?.name === "mask") {
|
|
6442
|
-
const source = maskNode(maskEl, m, out, maskEl.attrs.maskContentUnits);
|
|
6443
|
-
const type = attrOrStyle(maskEl, "mask-type") === "alpha" ? "alpha" : "luminance";
|
|
6444
|
-
if (source) out = [{ id: idFor({ name: "g", attrs: {}, children: [] }), type: "group", name: "Opacity Mask", mask: { type }, children: [source, ...out] }];
|
|
6445
|
-
}
|
|
6446
|
-
return out;
|
|
6447
|
-
};
|
|
6448
|
-
const maskGroup = (g, style, m, meta) => {
|
|
6449
|
-
let raw = null;
|
|
6450
|
-
try {
|
|
6451
|
-
raw = JSON.parse(g.attrs["data-vector-mask"]);
|
|
6452
|
-
} catch {
|
|
6453
|
-
raw = null;
|
|
6454
|
-
}
|
|
6455
|
-
const mask = sanitizeVectorMask(raw);
|
|
6456
|
-
const part = (name) => g.children.find((c) => c.name === "g" && c.attrs["data-vector-part"] === name);
|
|
6457
|
-
const maskedEl = part("masked");
|
|
6458
|
-
if (!mask || !maskedEl) return null;
|
|
6459
|
-
const id = idFor(g);
|
|
6460
|
-
let sourceEl = part("mask-source");
|
|
6461
|
-
if (!sourceEl) {
|
|
6462
|
-
const el = rawMasks.get(urlId(maskedEl.attrs.mask) ?? "");
|
|
6463
|
-
const invert2 = el?.children.find((c) => c.name === "g" && c.attrs["data-vector-part"] === "mask-invert");
|
|
6464
|
-
sourceEl = invert2 ?? el;
|
|
6465
|
-
}
|
|
6466
|
-
const source = sourceEl ? visit(sourceEl, style, m)[0] : void 0;
|
|
6467
|
-
let contents = visit(maskedEl, style, m);
|
|
6468
|
-
let effects;
|
|
6469
|
-
const wrapper = contents.length === 1 && contents[0].type === "group" && contents[0].id === `${id}~content` ? contents[0] : null;
|
|
6470
|
-
if (wrapper?.type === "group") {
|
|
6471
|
-
effects = wrapper.effects ?? void 0;
|
|
6472
|
-
contents = wrapper.children;
|
|
6473
|
-
}
|
|
6474
|
-
if (!source) return contents.length ? { id, type: "group", ...meta, children: contents } : null;
|
|
6475
|
-
return { id, type: "group", ...meta, mask, ...effects?.length ? { effects } : {}, children: [source, ...contents] };
|
|
6476
|
-
};
|
|
6477
|
-
const visitOne = (child, style, matrix) => {
|
|
6478
|
-
const out = [];
|
|
6479
|
-
const m = multiplyMatrices(parseSvgTransform(child.attrs.transform), matrix);
|
|
6480
|
-
const s = readStyle(child, style);
|
|
6481
|
-
const opacity = child.attrs.opacity !== void 0 ? parseFloat(child.attrs.opacity) : void 0;
|
|
6482
|
-
const hidden = child.attrs.display === "none" || child.attrs.visibility === "hidden";
|
|
6483
|
-
const blendMode = vectorBlendModeFromCss(s.mixBlendMode);
|
|
6484
|
-
const filters = filtersOf(s.filter);
|
|
6485
|
-
const meta = {
|
|
6486
|
-
...child.attrs["inkscape:label"] || child.attrs["data-name"] ? { name: child.attrs["inkscape:label"] ?? child.attrs["data-name"] } : {},
|
|
6487
|
-
...opacity !== void 0 && Number.isFinite(opacity) && opacity < 1 ? { opacity } : {},
|
|
6488
|
-
...hidden ? { visible: false } : {},
|
|
6489
|
-
...blendMode && blendMode !== "normal" ? { blendMode } : {},
|
|
6490
|
-
...filters.length ? { filters } : {}
|
|
6491
|
-
};
|
|
6492
|
-
if (child.attrs["data-vector-blend-step"] !== void 0) return out;
|
|
6493
|
-
const operation = child.attrs["data-vector-boolean-operation"];
|
|
6494
|
-
if (BOOLEAN_OPERATIONS.includes(operation)) meta.booleanOperation = operation;
|
|
6495
|
-
if (child.name === "g" && child.attrs["data-vector-mask"] !== void 0) {
|
|
6496
|
-
const node2 = maskGroup(child, s, m, meta);
|
|
6497
|
-
if (node2) out.push(node2);
|
|
6498
|
-
return out;
|
|
6499
|
-
}
|
|
6500
|
-
if (child.name === "g" && child.attrs["data-vector-live"] !== void 0) {
|
|
6501
|
-
const node2 = liveNode(child, s, m, meta);
|
|
6502
|
-
if (node2) out.push(node2);
|
|
6503
|
-
return out;
|
|
6504
|
-
}
|
|
6505
|
-
if (child.name === "g" && child.attrs["data-vector-path"] !== void 0 && child.attrs["data-vector-fills"] !== void 0) {
|
|
6506
|
-
const node2 = stackedPath(child, s, m, meta);
|
|
6507
|
-
if (node2) out.push(node2);
|
|
6508
|
-
return out;
|
|
6509
|
-
}
|
|
6510
|
-
if (child.name === "g" && child.attrs["data-vector-path"] !== void 0) {
|
|
6511
|
-
const node2 = mergedPath(child, s, m, meta);
|
|
6512
|
-
if (node2) out.push(node2);
|
|
6513
|
-
return out;
|
|
6514
|
-
}
|
|
6515
|
-
if (child.name === "g" || child.name === "svg" || child.name === "a" || child.name === "switch") {
|
|
6516
|
-
const children = visit(child, s, m);
|
|
6517
|
-
if (!children.length) return out;
|
|
6518
|
-
const group = { id: idFor(child), type: "group", ...meta, children };
|
|
6519
|
-
const blend = child.name === "g" ? blendFromAttribute(child.attrs["data-vector-blend"], m) : null;
|
|
6520
|
-
if (blend) group.blend = blend;
|
|
6521
|
-
out.push(group);
|
|
6522
|
-
return out;
|
|
6523
|
-
}
|
|
6524
|
-
const subpaths = shapeOf(child);
|
|
6525
|
-
if (!subpaths || !subpaths.length) return out;
|
|
6526
|
-
const node = placed(
|
|
6527
|
-
withOpacities(
|
|
6528
|
-
{
|
|
6529
|
-
id: idFor(child),
|
|
6530
|
-
type: "path",
|
|
6531
|
-
...meta,
|
|
6532
|
-
subpaths,
|
|
6533
|
-
fill: child.name === "line" ? null : paint(s.fill),
|
|
6534
|
-
stroke: paint(s.stroke),
|
|
6535
|
-
...strokeStyle(s)
|
|
6536
|
-
},
|
|
6537
|
-
s
|
|
6538
|
-
),
|
|
6539
|
-
m
|
|
6540
|
-
);
|
|
6541
|
-
out.push(node);
|
|
6542
|
-
return out;
|
|
6543
|
-
};
|
|
6544
|
-
rootStyle = readStyle(root, rootStyle);
|
|
6545
|
-
const nodes = visit(root, rootStyle, rootMatrix);
|
|
6546
|
-
return { width, height, nodes };
|
|
6547
|
-
}
|
|
6548
|
-
|
|
6549
5292
|
export {
|
|
6550
5293
|
VECTOR_CORNER_KINDS,
|
|
6551
5294
|
VECTOR_GRADIENT_TYPES,
|
|
@@ -6611,6 +5354,19 @@ export {
|
|
|
6611
5354
|
convertVectorGradient,
|
|
6612
5355
|
defaultVectorGradient,
|
|
6613
5356
|
applyVectorGradientPatch,
|
|
5357
|
+
IDENTITY_MATRIX,
|
|
5358
|
+
multiplyMatrices,
|
|
5359
|
+
translateMatrix,
|
|
5360
|
+
scaleMatrix,
|
|
5361
|
+
rotateMatrix,
|
|
5362
|
+
matrixAbout,
|
|
5363
|
+
skewMatrix,
|
|
5364
|
+
applyMatrix,
|
|
5365
|
+
isIdentityMatrix,
|
|
5366
|
+
invertMatrix,
|
|
5367
|
+
applyMatrixLinear,
|
|
5368
|
+
matrixRotation,
|
|
5369
|
+
decomposeRigid,
|
|
6614
5370
|
vectorCornerAt,
|
|
6615
5371
|
vectorCorners,
|
|
6616
5372
|
cornerSetback,
|
|
@@ -6741,6 +5497,28 @@ export {
|
|
|
6741
5497
|
vectorMaskedLocalBounds,
|
|
6742
5498
|
vectorMaskContentBounds,
|
|
6743
5499
|
vectorMaskRenderData,
|
|
5500
|
+
WARP_STYLES,
|
|
5501
|
+
WARP_STYLE_LABELS,
|
|
5502
|
+
warpPresetGrid,
|
|
5503
|
+
warpPresetMesh,
|
|
5504
|
+
warpMeshColumns,
|
|
5505
|
+
warpMeshRows,
|
|
5506
|
+
isValidWarpMesh,
|
|
5507
|
+
fitWarpMesh,
|
|
5508
|
+
identityWarpMesh,
|
|
5509
|
+
evalWarpMesh,
|
|
5510
|
+
splitWarpMeshU,
|
|
5511
|
+
splitWarpMeshV,
|
|
5512
|
+
removeWarpMeshSplitU,
|
|
5513
|
+
removeWarpMeshSplitV,
|
|
5514
|
+
mapWarpMeshPoints,
|
|
5515
|
+
resizeWarpMesh,
|
|
5516
|
+
warpMeshControlBounds,
|
|
5517
|
+
warpMeshParamAt,
|
|
5518
|
+
dragWarpMeshPoint,
|
|
5519
|
+
pullWarpMesh,
|
|
5520
|
+
warpMeshEditPoints,
|
|
5521
|
+
warpMeshGridCurves,
|
|
6744
5522
|
vectorMeshFromOutline,
|
|
6745
5523
|
vectorMeshOutline,
|
|
6746
5524
|
VECTOR_EFFECT_DEFAULTS,
|
|
@@ -6814,36 +5592,6 @@ export {
|
|
|
6814
5592
|
polygonSubpath,
|
|
6815
5593
|
starSubpath,
|
|
6816
5594
|
lineSubpath,
|
|
6817
|
-
roundSubpaths
|
|
6818
|
-
subpathToMorphContour,
|
|
6819
|
-
morphContourToSubpath,
|
|
6820
|
-
refineMorphContour,
|
|
6821
|
-
reverseMorphContour,
|
|
6822
|
-
turnMorphContour,
|
|
6823
|
-
correspondMorphContours,
|
|
6824
|
-
morphPathsCross,
|
|
6825
|
-
interpolateMorphContours,
|
|
6826
|
-
interpolateRigidMatrix,
|
|
6827
|
-
interpolateVectorColor,
|
|
6828
|
-
resampleGradientStops,
|
|
6829
|
-
interpolateVectorPaint,
|
|
6830
|
-
interpolateWidthProfiles,
|
|
6831
|
-
interpolateVectorStyle,
|
|
6832
|
-
createVectorMorph,
|
|
6833
|
-
interpolateVectorPaths,
|
|
6834
|
-
evaluateVectorPathKeyframes,
|
|
6835
|
-
vectorStrokeGradientDefs,
|
|
6836
|
-
vectorCornersAttribute,
|
|
6837
|
-
applyVectorCornersAttribute,
|
|
6838
|
-
vectorPathLocalBounds,
|
|
6839
|
-
vectorPaintToSvg,
|
|
6840
|
-
vectorStrokeSvgParts,
|
|
6841
|
-
vectorNodeLocalPaintBounds,
|
|
6842
|
-
vectorNodeFilterSvg,
|
|
6843
|
-
widthProfileToAttribute,
|
|
6844
|
-
widthProfileFromAttribute,
|
|
6845
|
-
vectorDocumentToSvg,
|
|
6846
|
-
parseSvgTransform,
|
|
6847
|
-
parseVectorSvg
|
|
5595
|
+
roundSubpaths
|
|
6848
5596
|
};
|
|
6849
|
-
//# sourceMappingURL=chunk-
|
|
5597
|
+
//# sourceMappingURL=chunk-BLWCAQCW.js.map
|