@pixerate/editor 0.107.0 → 0.108.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/THIRD_PARTY_NOTICES.md +4 -0
- package/dist/animation-editor/index.cjs +39 -39
- package/dist/animation-editor/index.d.cts +1 -1
- package/dist/animation-editor/index.d.ts +1 -1
- package/dist/animation-editor/index.js +1 -1
- package/dist/{chunk-63EFQCT5.js → chunk-HUQ7EHVI.js} +1140 -371
- package/dist/chunk-HUQ7EHVI.js.map +1 -0
- package/dist/{chunk-KANRAHTL.cjs → chunk-UTEVPQTS.cjs} +1353 -584
- package/dist/chunk-UTEVPQTS.cjs.map +1 -0
- package/dist/paint-editor/index.cjs +196 -11
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +96 -2
- package/dist/paint-editor/index.d.ts +96 -2
- package/dist/paint-editor/index.js +190 -5
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/{svg-Bj1MQFh6.d.cts → svg-ClVIG4T7.d.cts} +26 -2
- package/dist/{svg-vme0PLNo.d.ts → svg-SseJTIrA.d.ts} +26 -2
- package/dist/vector/index.cjs +977 -948
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +266 -7
- package/dist/vector/index.d.ts +266 -7
- package/dist/vector/index.js +427 -398
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/pixerate-image-editor/SKILL.md +50 -7
- package/skills/pixerate-vector/SKILL.md +35 -5
- package/dist/chunk-63EFQCT5.js.map +0 -1
- package/dist/chunk-KANRAHTL.cjs.map +0 -1
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
bezierPathBounds,
|
|
4
4
|
bezierPathToSvg,
|
|
5
5
|
closeContour,
|
|
6
|
+
contourSignedArea,
|
|
6
7
|
contoursToPath,
|
|
7
8
|
distanceToBezierPath,
|
|
8
9
|
fitCubicRun,
|
|
@@ -10,13 +11,16 @@ import {
|
|
|
10
11
|
flattenChain,
|
|
11
12
|
formatNumber,
|
|
12
13
|
isStraightCubic,
|
|
14
|
+
normalizeBezierPath,
|
|
13
15
|
offsetPath,
|
|
14
16
|
outlineStroke,
|
|
15
17
|
pathBoolean,
|
|
16
18
|
pathToContours,
|
|
17
19
|
pointInBezierPath,
|
|
18
20
|
polygonBoolean,
|
|
21
|
+
segmentBounds,
|
|
19
22
|
segmentDerivative,
|
|
23
|
+
segmentIntersections,
|
|
20
24
|
segmentLength,
|
|
21
25
|
segmentNearest,
|
|
22
26
|
segmentParamAtLength,
|
|
@@ -26,7 +30,8 @@ import {
|
|
|
26
30
|
subSegment,
|
|
27
31
|
toBezierPath,
|
|
28
32
|
transformBezierPath,
|
|
29
|
-
trimSegments
|
|
33
|
+
trimSegments,
|
|
34
|
+
windingNumber
|
|
30
35
|
} from "./chunk-YCSFS3GK.js";
|
|
31
36
|
import {
|
|
32
37
|
IDENTITY_MATRIX,
|
|
@@ -95,6 +100,7 @@ var VECTOR_BLEND_MODES = [
|
|
|
95
100
|
"luminosity"
|
|
96
101
|
];
|
|
97
102
|
var VECTOR_BLEND_SPACINGS = ["steps", "distance", "smoothColor"];
|
|
103
|
+
var VECTOR_MASK_TYPES = ["clip", "alpha", "luminance"];
|
|
98
104
|
var VECTOR_TOOLS = [
|
|
99
105
|
"select",
|
|
100
106
|
"direct",
|
|
@@ -1622,14 +1628,14 @@ function nearestStrokePosition(path, p, only) {
|
|
|
1622
1628
|
if (!(total > 0)) return;
|
|
1623
1629
|
let acc = 0;
|
|
1624
1630
|
c.segments.forEach((seg, si) => {
|
|
1625
|
-
const
|
|
1626
|
-
if (!best ||
|
|
1627
|
-
const s = acc + segmentLength(seg, 0,
|
|
1628
|
-
const tan = segmentTangent(seg,
|
|
1629
|
-
const pt2 = seg.length === 2 ? lerp(seg[0], seg[1],
|
|
1631
|
+
const near2 = segmentNearest(seg, p);
|
|
1632
|
+
if (!best || near2.distance < best.distance) {
|
|
1633
|
+
const s = acc + segmentLength(seg, 0, near2.t);
|
|
1634
|
+
const tan = segmentTangent(seg, near2.t);
|
|
1635
|
+
const pt2 = seg.length === 2 ? lerp(seg[0], seg[1], near2.t) : evalSeg(seg, near2.t);
|
|
1630
1636
|
const n = leftNormal([tan[0], tan[1]]);
|
|
1631
1637
|
const side = (p[0] - pt2[0]) * n[0] + (p[1] - pt2[1]) * n[1] >= 0 ? "left" : "right";
|
|
1632
|
-
best = { contour: ci, t: Math.min(Math.max(s / total, 0), 1), distance:
|
|
1638
|
+
best = { contour: ci, t: Math.min(Math.max(s / total, 0), 1), distance: near2.distance, side, point: pt2, tangent: [tan[0], tan[1]], length: total };
|
|
1633
1639
|
}
|
|
1634
1640
|
acc += lengths[si];
|
|
1635
1641
|
});
|
|
@@ -1814,7 +1820,7 @@ function vectorStrokeParts(path, style) {
|
|
|
1814
1820
|
const cap = capExtent(style, width);
|
|
1815
1821
|
const tipMode = style.arrowAlign === "tip";
|
|
1816
1822
|
const trims = contours.map(() => [0, 0]);
|
|
1817
|
-
const
|
|
1823
|
+
const place2 = (end, contour, ci) => {
|
|
1818
1824
|
const kind = end === "start" ? style.startArrow : style.endArrow;
|
|
1819
1825
|
if (!kind || contour.closed) return;
|
|
1820
1826
|
const hw = arrowheadWeight(style, end);
|
|
@@ -1835,8 +1841,8 @@ function vectorStrokeParts(path, style) {
|
|
|
1835
1841
|
}
|
|
1836
1842
|
heads.push({ end, kind, tip, dir, inset, path: arrowheadPath(kind, tip, dir, hw) });
|
|
1837
1843
|
};
|
|
1838
|
-
|
|
1839
|
-
|
|
1844
|
+
place2("start", first, 0);
|
|
1845
|
+
place2("end", last, contours.length - 1);
|
|
1840
1846
|
if (!tipMode || !heads.length) return { align, line: path, drawWidth, heads };
|
|
1841
1847
|
const trimmed = contours.map((c, i) => {
|
|
1842
1848
|
const [s0, s1] = trims[i];
|
|
@@ -1869,13 +1875,13 @@ function hitTestVectorStroke(path, p, style, tolerance = 0) {
|
|
|
1869
1875
|
let d;
|
|
1870
1876
|
let reach = width / 2;
|
|
1871
1877
|
if (profile) {
|
|
1872
|
-
const
|
|
1873
|
-
if (!
|
|
1874
|
-
d =
|
|
1875
|
-
const w = widthProfileAt(profile,
|
|
1876
|
-
reach = width / 2 * (
|
|
1878
|
+
const near2 = nearestStrokePosition(parts.line, point);
|
|
1879
|
+
if (!near2) return false;
|
|
1880
|
+
d = near2.distance;
|
|
1881
|
+
const w = widthProfileAt(profile, near2.t);
|
|
1882
|
+
reach = width / 2 * (near2.side === "left" ? w.left : w.right);
|
|
1877
1883
|
if (parts.align !== "center") reach *= 2;
|
|
1878
|
-
const atEnd =
|
|
1884
|
+
const atEnd = near2.t <= 1e-9 || near2.t >= 1 - 1e-9;
|
|
1879
1885
|
if (atEnd && (style.strokeLinecap === "round" || style.strokeLinecap === "square") && d > reach) {
|
|
1880
1886
|
reach = Math.max(reach, width / 2 * (w.left + w.right) / 2);
|
|
1881
1887
|
}
|
|
@@ -2318,6 +2324,766 @@ function mapBezierPath(path, f, tolerance = 0.1, options = {}) {
|
|
|
2318
2324
|
return subpathsToBezier(mapVectorSubpaths(bezierToSubpaths(path), f, tolerance, options), { corners: false });
|
|
2319
2325
|
}
|
|
2320
2326
|
|
|
2327
|
+
// src/vector/pathCut.ts
|
|
2328
|
+
var loopArea = (l) => contourSignedArea(l.segs);
|
|
2329
|
+
function loopSample(l) {
|
|
2330
|
+
const k = l.chord.findIndex((c) => !c);
|
|
2331
|
+
return segmentPoint(l.segs[k >= 0 ? k : 0], 0.5);
|
|
2332
|
+
}
|
|
2333
|
+
var contains = (l, p) => windingNumber([l.segs], p) !== 0;
|
|
2334
|
+
function groupFaces(loops) {
|
|
2335
|
+
const usable = loops.filter((l) => l.segs.length && Math.abs(loopArea(l)) > 1e-12);
|
|
2336
|
+
if (!usable.length) return [];
|
|
2337
|
+
const largest = usable.reduce((a, b) => Math.abs(loopArea(b)) > Math.abs(loopArea(a)) ? b : a);
|
|
2338
|
+
const sign = Math.sign(loopArea(largest));
|
|
2339
|
+
const outers = usable.filter((l) => Math.sign(loopArea(l)) === sign).sort((a, b) => Math.abs(loopArea(a)) - Math.abs(loopArea(b)));
|
|
2340
|
+
const faces = new Map(outers.map((o) => [o, { loops: [o] }]));
|
|
2341
|
+
for (const hole of usable.filter((l) => Math.sign(loopArea(l)) !== sign)) {
|
|
2342
|
+
const p = loopSample(hole);
|
|
2343
|
+
const parent = outers.find((o) => Math.abs(loopArea(o)) > Math.abs(loopArea(hole)) && contains(o, p));
|
|
2344
|
+
if (parent) faces.get(parent).loops.push(hole);
|
|
2345
|
+
}
|
|
2346
|
+
return outers.reverse().map((o) => faces.get(o));
|
|
2347
|
+
}
|
|
2348
|
+
function faceToPath(face) {
|
|
2349
|
+
return contoursToPath(face.loops.map((l) => ({ segments: l.segs, closed: true })));
|
|
2350
|
+
}
|
|
2351
|
+
function facesOf(path, fillRule) {
|
|
2352
|
+
const normalized = normalizeBezierPath(path, fillRule);
|
|
2353
|
+
const loops = pathToContours(normalized).map((c) => {
|
|
2354
|
+
const segs = closeContour(c, true).map((s) => s.slice());
|
|
2355
|
+
return { segs, chord: segs.map(() => false) };
|
|
2356
|
+
});
|
|
2357
|
+
return groupFaces(loops);
|
|
2358
|
+
}
|
|
2359
|
+
function splitIntoFaces(path, fillRule = "nonzero") {
|
|
2360
|
+
return facesOf(path, fillRule).map(faceToPath);
|
|
2361
|
+
}
|
|
2362
|
+
function rootsInUnit(a, b, c, d, scale3) {
|
|
2363
|
+
const f = (t) => ((a * t + b) * t + c) * t + d;
|
|
2364
|
+
const tol = 1e-12 * Math.max(1, scale3);
|
|
2365
|
+
const cuts = [0];
|
|
2366
|
+
const qa = 3 * a;
|
|
2367
|
+
const qb = 2 * b;
|
|
2368
|
+
if (Math.abs(qa) > 1e-18) {
|
|
2369
|
+
const disc = qb * qb - 4 * qa * c;
|
|
2370
|
+
if (disc >= 0) {
|
|
2371
|
+
const r = Math.sqrt(disc);
|
|
2372
|
+
for (const t of [(-qb - r) / (2 * qa), (-qb + r) / (2 * qa)].sort((x, y) => x - y)) if (t > 0 && t < 1) cuts.push(t);
|
|
2373
|
+
}
|
|
2374
|
+
} else if (Math.abs(qb) > 1e-18) {
|
|
2375
|
+
const t = -c / qb;
|
|
2376
|
+
if (t > 0 && t < 1) cuts.push(t);
|
|
2377
|
+
}
|
|
2378
|
+
cuts.push(1);
|
|
2379
|
+
const roots = [];
|
|
2380
|
+
const push = (t) => {
|
|
2381
|
+
if (!roots.some((r) => Math.abs(r - t) < 1e-9)) roots.push(t);
|
|
2382
|
+
};
|
|
2383
|
+
for (let i = 0; i < cuts.length - 1; i++) {
|
|
2384
|
+
let lo = cuts[i];
|
|
2385
|
+
let hi = cuts[i + 1];
|
|
2386
|
+
let flo = f(lo);
|
|
2387
|
+
const fhi = f(hi);
|
|
2388
|
+
if (Math.abs(flo) <= tol) push(lo);
|
|
2389
|
+
if (Math.abs(fhi) <= tol) push(hi);
|
|
2390
|
+
if (flo * fhi >= 0) continue;
|
|
2391
|
+
for (let k = 0; k < 80; k++) {
|
|
2392
|
+
const m = (lo + hi) / 2;
|
|
2393
|
+
const fm = f(m);
|
|
2394
|
+
if (fm === 0) {
|
|
2395
|
+
lo = hi = m;
|
|
2396
|
+
break;
|
|
2397
|
+
}
|
|
2398
|
+
if (fm * flo < 0) hi = m;
|
|
2399
|
+
else {
|
|
2400
|
+
lo = m;
|
|
2401
|
+
flo = fm;
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
push((lo + hi) / 2);
|
|
2405
|
+
}
|
|
2406
|
+
return roots.sort((x, y) => x - y);
|
|
2407
|
+
}
|
|
2408
|
+
function lineHits(p, q, seg) {
|
|
2409
|
+
const dx = q[0] - p[0];
|
|
2410
|
+
const dy = q[1] - p[1];
|
|
2411
|
+
const len2 = dx * dx + dy * dy;
|
|
2412
|
+
if (len2 < 1e-24) return [];
|
|
2413
|
+
const h = (pt2) => (pt2[0] - p[0]) * -dy + (pt2[1] - p[1]) * dx;
|
|
2414
|
+
let coeffs;
|
|
2415
|
+
if (seg.length === 2) coeffs = [0, 0, h(seg[1]) - h(seg[0]), h(seg[0])];
|
|
2416
|
+
else {
|
|
2417
|
+
const [h0, h1, h2, h3] = seg.map(h);
|
|
2418
|
+
coeffs = [-h0 + 3 * h1 - 3 * h2 + h3, 3 * h0 - 6 * h1 + 3 * h2, -3 * h0 + 3 * h1, h0];
|
|
2419
|
+
}
|
|
2420
|
+
if (coeffs.every((c) => Math.abs(c) < 1e-12 * Math.max(1, len2))) return [];
|
|
2421
|
+
const scale3 = Math.sqrt(len2) * Math.max(1, ...seg.map((pt2) => Math.abs(pt2[0]) + Math.abs(pt2[1])));
|
|
2422
|
+
const out = [];
|
|
2423
|
+
for (const t of rootsInUnit(...coeffs, scale3)) {
|
|
2424
|
+
const point = segmentPoint(seg, t);
|
|
2425
|
+
const s = ((point[0] - p[0]) * dx + (point[1] - p[1]) * dy) / len2;
|
|
2426
|
+
if (s >= -1e-9 && s <= 1 + 1e-9) out.push({ s: Math.min(1, Math.max(0, s)), t, point });
|
|
2427
|
+
}
|
|
2428
|
+
return out;
|
|
2429
|
+
}
|
|
2430
|
+
var near = (a, b, eps) => Math.abs(a[0] - b[0]) <= eps && Math.abs(a[1] - b[1]) <= eps;
|
|
2431
|
+
var degenerate = (seg, eps) => seg.every((p) => near(p, seg[0], eps));
|
|
2432
|
+
function arc(l, a, b, eps) {
|
|
2433
|
+
const n = l.segs.length;
|
|
2434
|
+
const segs = [];
|
|
2435
|
+
const chord = [];
|
|
2436
|
+
const push = (k, t0, t1) => {
|
|
2437
|
+
const piece = t0 <= 0 && t1 >= 1 ? l.segs[k].slice() : subSegment(l.segs[k], t0, t1);
|
|
2438
|
+
if (!degenerate(piece, eps)) {
|
|
2439
|
+
segs.push(piece);
|
|
2440
|
+
chord.push(l.chord[k]);
|
|
2441
|
+
}
|
|
2442
|
+
};
|
|
2443
|
+
if (a.seg === b.seg && b.t >= a.t + 1e-12) {
|
|
2444
|
+
push(a.seg, a.t, b.t);
|
|
2445
|
+
return { segs, chord };
|
|
2446
|
+
}
|
|
2447
|
+
push(a.seg, a.t, 1);
|
|
2448
|
+
for (let k = (a.seg + 1) % n; k !== b.seg; k = (k + 1) % n) push(k, 0, 1);
|
|
2449
|
+
push(b.seg, 0, b.t);
|
|
2450
|
+
return { segs, chord };
|
|
2451
|
+
}
|
|
2452
|
+
function polySegs(points, eps) {
|
|
2453
|
+
const out = [];
|
|
2454
|
+
for (let i = 1; i < points.length; i++) if (!near(points[i - 1], points[i], eps)) out.push([points[i - 1], points[i]]);
|
|
2455
|
+
return out;
|
|
2456
|
+
}
|
|
2457
|
+
function knifePath(path, fillRule, knife) {
|
|
2458
|
+
const pts = knife.filter((p) => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
2459
|
+
if (pts.length < 2) return null;
|
|
2460
|
+
let faces = facesOf(path, fillRule);
|
|
2461
|
+
if (!faces.length) return null;
|
|
2462
|
+
const b = bezierPathBounds(path);
|
|
2463
|
+
const size = b ? Math.max(b.maxX - b.minX, b.maxY - b.minY, 1) : 1;
|
|
2464
|
+
const eps = size * 1e-9;
|
|
2465
|
+
let cursor = -Infinity;
|
|
2466
|
+
let cuts = 0;
|
|
2467
|
+
for (let guard = 0; guard < 512; guard++) {
|
|
2468
|
+
let best = null;
|
|
2469
|
+
faces.forEach((face2, fi2) => {
|
|
2470
|
+
const hits = [];
|
|
2471
|
+
for (let m = 0; m < pts.length - 1; m++) {
|
|
2472
|
+
if (m + 1 < cursor - 1e-9) continue;
|
|
2473
|
+
const kb = { minX: Math.min(pts[m][0], pts[m + 1][0]), maxX: Math.max(pts[m][0], pts[m + 1][0]), minY: Math.min(pts[m][1], pts[m + 1][1]), maxY: Math.max(pts[m][1], pts[m + 1][1]) };
|
|
2474
|
+
face2.loops.forEach(
|
|
2475
|
+
(l, li) => l.segs.forEach((seg, si) => {
|
|
2476
|
+
const sb = segmentBounds(seg);
|
|
2477
|
+
if (sb.maxX < kb.minX - eps || sb.minX > kb.maxX + eps || sb.maxY < kb.minY - eps || sb.minY > kb.maxY + eps) return;
|
|
2478
|
+
for (const h of lineHits(pts[m], pts[m + 1], seg)) {
|
|
2479
|
+
const s = m + h.s;
|
|
2480
|
+
if (s >= cursor - 1e-9) hits.push({ s, loop: li, seg: si, t: h.t, point: h.point });
|
|
2481
|
+
}
|
|
2482
|
+
})
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
hits.sort((x, y) => x.s - y.s);
|
|
2486
|
+
const unique = hits.filter((h, i) => i === 0 || h.s - hits[i - 1].s > 1e-9 || !near(h.point, hits[i - 1].point, eps * 10));
|
|
2487
|
+
const inside = (s) => {
|
|
2488
|
+
const m = Math.min(pts.length - 2, Math.floor(s));
|
|
2489
|
+
const u = s - m;
|
|
2490
|
+
const q = [pts[m][0] + (pts[m + 1][0] - pts[m][0]) * u, pts[m][1] + (pts[m + 1][1] - pts[m][1]) * u];
|
|
2491
|
+
return windingNumber(face2.loops.map((l) => l.segs), q) !== 0;
|
|
2492
|
+
};
|
|
2493
|
+
for (let i = 0; i < unique.length - 1; i++) {
|
|
2494
|
+
const from2 = unique[i];
|
|
2495
|
+
const to2 = unique[i + 1];
|
|
2496
|
+
if (near(from2.point, to2.point, eps * 10) || !inside((from2.s + to2.s) / 2)) continue;
|
|
2497
|
+
if (!best || from2.s < best.from.s) best = { face: fi2, from: from2, to: to2 };
|
|
2498
|
+
break;
|
|
2499
|
+
}
|
|
2500
|
+
});
|
|
2501
|
+
if (!best) break;
|
|
2502
|
+
const { face: fi, from, to } = best;
|
|
2503
|
+
const face = faces[fi];
|
|
2504
|
+
const corners = [from.point];
|
|
2505
|
+
for (let m = Math.floor(from.s) + 1; m <= to.s - 1e-12 && m < pts.length; m++) if (m > from.s) corners.push(pts[m]);
|
|
2506
|
+
corners.push(to.point);
|
|
2507
|
+
const forward = polySegs(corners, eps);
|
|
2508
|
+
const back = polySegs(corners.slice().reverse(), eps);
|
|
2509
|
+
const la = face.loops[from.loop];
|
|
2510
|
+
const loops = face.loops.filter((_, i) => i !== from.loop && i !== to.loop);
|
|
2511
|
+
if (from.loop === to.loop) {
|
|
2512
|
+
const ab = arc(la, from, to, eps);
|
|
2513
|
+
const ba = arc(la, to, from, eps);
|
|
2514
|
+
loops.push(
|
|
2515
|
+
{ segs: [...ab.segs, ...back], chord: [...ab.chord, ...back.map(() => true)] },
|
|
2516
|
+
{ segs: [...ba.segs, ...forward], chord: [...ba.chord, ...forward.map(() => true)] }
|
|
2517
|
+
);
|
|
2518
|
+
} else {
|
|
2519
|
+
const lb = face.loops[to.loop];
|
|
2520
|
+
const roundA = arc(la, from, from, eps);
|
|
2521
|
+
const roundB = arc(lb, to, to, eps);
|
|
2522
|
+
loops.push({
|
|
2523
|
+
segs: [...roundA.segs, ...forward, ...roundB.segs, ...back],
|
|
2524
|
+
chord: [...roundA.chord, ...forward.map(() => true), ...roundB.chord, ...back.map(() => true)]
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
faces = [...faces.slice(0, fi), ...groupFaces(loops), ...faces.slice(fi + 1)];
|
|
2528
|
+
cursor = to.s;
|
|
2529
|
+
cuts++;
|
|
2530
|
+
}
|
|
2531
|
+
return cuts ? faces.map(faceToPath) : null;
|
|
2532
|
+
}
|
|
2533
|
+
function eraserRegion(points, width) {
|
|
2534
|
+
const pts = points.filter((p) => Number.isFinite(p[0]) && Number.isFinite(p[1]));
|
|
2535
|
+
const r = width / 2;
|
|
2536
|
+
if (!pts.length || !(r > 0)) return [];
|
|
2537
|
+
const moved = pts.some((p) => !near(p, pts[0], 1e-9));
|
|
2538
|
+
if (!moved) {
|
|
2539
|
+
const [cx, cy] = pts[0];
|
|
2540
|
+
const k = r * 0.5522847498307936;
|
|
2541
|
+
return [
|
|
2542
|
+
{ type: "M", x: cx, y: cy - r },
|
|
2543
|
+
{ type: "C", x1: cx + k, y1: cy - r, x2: cx + r, y2: cy - k, x: cx + r, y: cy },
|
|
2544
|
+
{ type: "C", x1: cx + r, y1: cy + k, x2: cx + k, y2: cy + r, x: cx, y: cy + r },
|
|
2545
|
+
{ type: "C", x1: cx - k, y1: cy + r, x2: cx - r, y2: cy + k, x: cx - r, y: cy },
|
|
2546
|
+
{ type: "C", x1: cx - r, y1: cy - k, x2: cx - k, y2: cy - r, x: cx, y: cy - r },
|
|
2547
|
+
{ type: "Z" }
|
|
2548
|
+
];
|
|
2549
|
+
}
|
|
2550
|
+
const line = [{ type: "M", x: pts[0][0], y: pts[0][1] }, ...pts.slice(1).map((p) => ({ type: "L", x: p[0], y: p[1] }))];
|
|
2551
|
+
return outlineStroke(line, { width, cap: "round", join: "round" });
|
|
2552
|
+
}
|
|
2553
|
+
function eraseFromFill(path, fillRule, region) {
|
|
2554
|
+
const overlap = pathBoolean("intersection", [{ path, fillRule }, { path: region }]).path;
|
|
2555
|
+
if (!pathToContours(overlap).some((c) => Math.abs(contourSignedArea(closeContour(c, true))) > 1e-9)) return null;
|
|
2556
|
+
const rest = pathBoolean("difference", [{ path, fillRule }, { path: region }]).path;
|
|
2557
|
+
return splitIntoFaces(rest);
|
|
2558
|
+
}
|
|
2559
|
+
function eraseFromOutline(sp, region, options = {}) {
|
|
2560
|
+
const regionSegs = pathToContours(region).flatMap((c) => closeContour(c, true));
|
|
2561
|
+
if (!regionSegs.length) return null;
|
|
2562
|
+
const rb = bezierPathBounds(region);
|
|
2563
|
+
const count = subpathSegmentCount(sp);
|
|
2564
|
+
if (!rb || count === 0) return null;
|
|
2565
|
+
const inside = options.keep === "inside";
|
|
2566
|
+
const removed = (p) => pointInBezierPath(region, p, options.fillRule ?? "nonzero") !== inside;
|
|
2567
|
+
const runs = [];
|
|
2568
|
+
let cur = [];
|
|
2569
|
+
let any = false;
|
|
2570
|
+
for (let i = 0; i < count; i++) {
|
|
2571
|
+
const seg = subpathSegment(sp, i);
|
|
2572
|
+
const sb = segmentBounds(seg);
|
|
2573
|
+
const ts = [0, 1];
|
|
2574
|
+
if (!(sb.maxX < rb.minX || sb.minX > rb.maxX || sb.maxY < rb.minY || sb.minY > rb.maxY)) {
|
|
2575
|
+
for (const r of regionSegs) {
|
|
2576
|
+
const b = segmentBounds(r);
|
|
2577
|
+
if (b.maxX < sb.minX || b.minX > sb.maxX || b.maxY < sb.minY || b.minY > sb.maxY) continue;
|
|
2578
|
+
for (const hit of segmentIntersections(seg, r)) if (hit.ta > 1e-9 && hit.ta < 1 - 1e-9) ts.push(hit.ta);
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
ts.sort((a, b) => a - b);
|
|
2582
|
+
for (let k = 0; k < ts.length - 1; k++) {
|
|
2583
|
+
const t0 = ts[k];
|
|
2584
|
+
const t1 = ts[k + 1];
|
|
2585
|
+
if (t1 - t0 < 1e-9) continue;
|
|
2586
|
+
if (removed(segmentPoint(seg, (t0 + t1) / 2))) {
|
|
2587
|
+
any = true;
|
|
2588
|
+
if (cur.length) runs.push(cur);
|
|
2589
|
+
cur = [];
|
|
2590
|
+
} else cur.push({ seg: i, t0, t1 });
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
if (cur.length) runs.push(cur);
|
|
2594
|
+
if (!any) return null;
|
|
2595
|
+
if (sp.closed && runs.length >= 2) {
|
|
2596
|
+
const first = runs[0][0];
|
|
2597
|
+
const lastRun = runs[runs.length - 1];
|
|
2598
|
+
const last = lastRun[lastRun.length - 1];
|
|
2599
|
+
if (first.seg === 0 && first.t0 === 0 && last.seg === count - 1 && last.t1 === 1) lastRun.push(...runs.shift());
|
|
2600
|
+
}
|
|
2601
|
+
const out = [];
|
|
2602
|
+
for (const run of runs) {
|
|
2603
|
+
const anchors = [];
|
|
2604
|
+
for (const { seg, t0, t1 } of run) {
|
|
2605
|
+
const c = subSegment(subpathSegment(sp, seg), t0, t1);
|
|
2606
|
+
const line = c.length === 2;
|
|
2607
|
+
const start = c[0];
|
|
2608
|
+
const end = c[c.length - 1];
|
|
2609
|
+
if (!anchors.length) anchors.push({ x: start[0], y: start[1] });
|
|
2610
|
+
if (!line) anchors[anchors.length - 1].out = { x: c[1][0], y: c[1][1] };
|
|
2611
|
+
const next = { x: end[0], y: end[1] };
|
|
2612
|
+
if (!line) next.in = { x: c[2][0], y: c[2][1] };
|
|
2613
|
+
anchors.push(next);
|
|
2614
|
+
}
|
|
2615
|
+
if (anchors.length < 2) continue;
|
|
2616
|
+
for (const a of anchors) {
|
|
2617
|
+
const type = inferAnchorType(a);
|
|
2618
|
+
if (type !== "corner") a.type = type;
|
|
2619
|
+
}
|
|
2620
|
+
out.push({ anchors, closed: false });
|
|
2621
|
+
}
|
|
2622
|
+
return out;
|
|
2623
|
+
}
|
|
2624
|
+
function polylineBounds(points, pad = 0) {
|
|
2625
|
+
if (!points.length) return null;
|
|
2626
|
+
let minX = Infinity;
|
|
2627
|
+
let minY = Infinity;
|
|
2628
|
+
let maxX = -Infinity;
|
|
2629
|
+
let maxY = -Infinity;
|
|
2630
|
+
for (const [x, y] of points) {
|
|
2631
|
+
minX = Math.min(minX, x);
|
|
2632
|
+
minY = Math.min(minY, y);
|
|
2633
|
+
maxX = Math.max(maxX, x);
|
|
2634
|
+
maxY = Math.max(maxY, y);
|
|
2635
|
+
}
|
|
2636
|
+
return { x: minX - pad, y: minY - pad, width: maxX - minX + 2 * pad, height: maxY - minY + 2 * pad };
|
|
2637
|
+
}
|
|
2638
|
+
function simplifyPolyline(points, tolerance) {
|
|
2639
|
+
const n = points.length;
|
|
2640
|
+
if (n < 3) return points.slice();
|
|
2641
|
+
const keep = new Array(n).fill(false);
|
|
2642
|
+
keep[0] = keep[n - 1] = true;
|
|
2643
|
+
const stack = [[0, n - 1]];
|
|
2644
|
+
while (stack.length) {
|
|
2645
|
+
const [a, b] = stack.pop();
|
|
2646
|
+
const [ax, ay] = points[a];
|
|
2647
|
+
const dx = points[b][0] - ax;
|
|
2648
|
+
const dy = points[b][1] - ay;
|
|
2649
|
+
const len2 = Math.hypot(dx, dy);
|
|
2650
|
+
let far = -1;
|
|
2651
|
+
let farD = 0;
|
|
2652
|
+
for (let i = a + 1; i < b; i++) {
|
|
2653
|
+
const [px, py] = points[i];
|
|
2654
|
+
const d = len2 < 1e-12 ? Math.hypot(px - ax, py - ay) : Math.abs((px - ax) * dy - (py - ay) * dx) / len2;
|
|
2655
|
+
if (d > farD) {
|
|
2656
|
+
farD = d;
|
|
2657
|
+
far = i;
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
if (far >= 0 && farD > tolerance) {
|
|
2661
|
+
keep[far] = true;
|
|
2662
|
+
stack.push([a, far], [far, b]);
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
return points.filter((_, i) => keep[i]);
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
// src/vector/filters.ts
|
|
2669
|
+
var VECTOR_FILTER_DEFAULTS = {
|
|
2670
|
+
dropShadow: { color: "#000000", opacity: 0.25, offsetX: 0, offsetY: 4, blur: 4, spread: 0 },
|
|
2671
|
+
innerShadow: { color: "#000000", opacity: 0.25, offsetX: 0, offsetY: 4, blur: 4, spread: 0 },
|
|
2672
|
+
outerGlow: { color: "#ffffbe", opacity: 0.75, blur: 10, spread: 0 },
|
|
2673
|
+
innerGlow: { color: "#ffffbe", opacity: 0.75, blur: 10, spread: 0 },
|
|
2674
|
+
layerBlur: { radius: 4 },
|
|
2675
|
+
feather: { radius: 8 }
|
|
2676
|
+
};
|
|
2677
|
+
var VECTOR_FILTER_LABELS = {
|
|
2678
|
+
dropShadow: "Drop Shadow",
|
|
2679
|
+
innerShadow: "Inner Shadow",
|
|
2680
|
+
outerGlow: "Outer Glow",
|
|
2681
|
+
innerGlow: "Inner Glow",
|
|
2682
|
+
layerBlur: "Layer Blur",
|
|
2683
|
+
feather: "Feather"
|
|
2684
|
+
};
|
|
2685
|
+
var SHADOW_SPECS = [
|
|
2686
|
+
{ key: "color", label: "Color", kind: "color" },
|
|
2687
|
+
{ key: "opacity", label: "Opacity", kind: "number", min: 0, max: 1, step: 0.01, slider: true },
|
|
2688
|
+
{ key: "offsetX", label: "X", kind: "number", min: -1e3, max: 1e3, step: 1 },
|
|
2689
|
+
{ key: "offsetY", label: "Y", kind: "number", min: -1e3, max: 1e3, step: 1 },
|
|
2690
|
+
{ key: "blur", label: "Blur", kind: "number", min: 0, max: 500, step: 1 },
|
|
2691
|
+
{ key: "spread", label: "Spread", kind: "number", min: 0, max: 500, step: 1 }
|
|
2692
|
+
];
|
|
2693
|
+
var GLOW_SPECS = SHADOW_SPECS.filter((s) => s.key !== "offsetX" && s.key !== "offsetY");
|
|
2694
|
+
var VECTOR_FILTER_PARAM_SPECS = {
|
|
2695
|
+
dropShadow: SHADOW_SPECS,
|
|
2696
|
+
innerShadow: SHADOW_SPECS.map((s) => s.key === "spread" ? { ...s, label: "Choke" } : s),
|
|
2697
|
+
outerGlow: GLOW_SPECS,
|
|
2698
|
+
innerGlow: GLOW_SPECS.map((s) => s.key === "spread" ? { ...s, label: "Choke" } : s),
|
|
2699
|
+
layerBlur: [{ key: "radius", label: "Radius", kind: "number", min: 0, max: 500, step: 1, slider: true }],
|
|
2700
|
+
feather: [{ key: "radius", label: "Radius", kind: "number", min: 0, max: 500, step: 1, slider: true }]
|
|
2701
|
+
};
|
|
2702
|
+
function isVectorFilterType(value) {
|
|
2703
|
+
return typeof value === "string" && VECTOR_FILTER_TYPES.includes(value);
|
|
2704
|
+
}
|
|
2705
|
+
function normalizeVectorFilterParams(type, params, base) {
|
|
2706
|
+
if (!isVectorFilterType(type)) return null;
|
|
2707
|
+
const out = { ...VECTOR_FILTER_DEFAULTS[type], ...base ?? {} };
|
|
2708
|
+
for (const spec of VECTOR_FILTER_PARAM_SPECS[type]) {
|
|
2709
|
+
const v2 = params?.[spec.key];
|
|
2710
|
+
if (v2 === void 0) continue;
|
|
2711
|
+
if (spec.kind === "number" && typeof v2 === "number" && Number.isFinite(v2)) out[spec.key] = Math.min(spec.max ?? Infinity, Math.max(spec.min ?? -Infinity, v2));
|
|
2712
|
+
else if (spec.kind === "color" && typeof v2 === "string" && v2.trim()) out[spec.key] = v2.trim();
|
|
2713
|
+
}
|
|
2714
|
+
return out;
|
|
2715
|
+
}
|
|
2716
|
+
function vectorFilterParamKeys(type) {
|
|
2717
|
+
return VECTOR_FILTER_PARAM_SPECS[type].map((s) => s.key);
|
|
2718
|
+
}
|
|
2719
|
+
function createVectorFilter(type, id, params) {
|
|
2720
|
+
const p = normalizeVectorFilterParams(type, params);
|
|
2721
|
+
return p ? { id, type, params: p } : null;
|
|
2722
|
+
}
|
|
2723
|
+
function sanitizeVectorFilters(value) {
|
|
2724
|
+
if (!Array.isArray(value)) return [];
|
|
2725
|
+
const out = [];
|
|
2726
|
+
const used = /* @__PURE__ */ new Set();
|
|
2727
|
+
for (const raw of value) {
|
|
2728
|
+
if (!raw || typeof raw !== "object") continue;
|
|
2729
|
+
const r = raw;
|
|
2730
|
+
if (!isVectorFilterType(r.type)) continue;
|
|
2731
|
+
let id = typeof r.id === "string" && r.id && !used.has(r.id) ? r.id : "";
|
|
2732
|
+
for (let k = out.length + 1; !id; k++) if (!used.has(`filter${k}`)) id = `filter${k}`;
|
|
2733
|
+
used.add(id);
|
|
2734
|
+
const filter = createVectorFilter(r.type, id, r.params ?? {});
|
|
2735
|
+
out.push(r.enabled === false ? { ...filter, enabled: false } : filter);
|
|
2736
|
+
}
|
|
2737
|
+
return out;
|
|
2738
|
+
}
|
|
2739
|
+
function activeVectorFilters(node) {
|
|
2740
|
+
return (node.filters ?? []).filter((f) => {
|
|
2741
|
+
if (f.enabled === false || !isVectorFilterType(f.type)) return false;
|
|
2742
|
+
if (f.type === "layerBlur" || f.type === "feather") return f.params.radius > 0;
|
|
2743
|
+
return f.params.opacity > 0;
|
|
2744
|
+
});
|
|
2745
|
+
}
|
|
2746
|
+
function vectorFilterReach(filters) {
|
|
2747
|
+
let outer = 0;
|
|
2748
|
+
let blur = 0;
|
|
2749
|
+
for (const f of filters) {
|
|
2750
|
+
switch (f.type) {
|
|
2751
|
+
case "dropShadow":
|
|
2752
|
+
case "innerShadow":
|
|
2753
|
+
outer = Math.max(outer, Math.max(Math.abs(f.params.offsetX), Math.abs(f.params.offsetY)) + f.params.blur * 1.5 + f.params.spread);
|
|
2754
|
+
break;
|
|
2755
|
+
case "outerGlow":
|
|
2756
|
+
case "innerGlow":
|
|
2757
|
+
outer = Math.max(outer, f.params.blur * 1.5 + f.params.spread);
|
|
2758
|
+
break;
|
|
2759
|
+
case "layerBlur":
|
|
2760
|
+
blur += f.params.radius * 1.5;
|
|
2761
|
+
break;
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
return outer + blur;
|
|
2765
|
+
}
|
|
2766
|
+
var round = (n) => Math.round(n * 1e3) / 1e3;
|
|
2767
|
+
var fe = (tag, attrs, children) => ({ tag, attrs, ...children ? { children } : {} });
|
|
2768
|
+
function vectorFilterSvg(filters, id, bounds) {
|
|
2769
|
+
const active = filters.filter((f) => activeVectorFilters({ filters: [f] }).length);
|
|
2770
|
+
if (!active.length || !bounds) return null;
|
|
2771
|
+
const primitives = [];
|
|
2772
|
+
let body = "SourceGraphic";
|
|
2773
|
+
let n = 0;
|
|
2774
|
+
const name = (part) => `${part}${n}`;
|
|
2775
|
+
for (const f of active) {
|
|
2776
|
+
if (f.type !== "innerShadow" && f.type !== "innerGlow") continue;
|
|
2777
|
+
n++;
|
|
2778
|
+
const p = f.params;
|
|
2779
|
+
primitives.push(fe("feComponentTransfer", { in: "SourceAlpha", result: name("inv") }, [fe("feFuncA", { type: "table", tableValues: "1 0" })]));
|
|
2780
|
+
let last = name("inv");
|
|
2781
|
+
if (f.type === "innerShadow" && (f.params.offsetX || f.params.offsetY)) {
|
|
2782
|
+
primitives.push(fe("feOffset", { in: last, dx: round(f.params.offsetX), dy: round(f.params.offsetY), result: name("off") }));
|
|
2783
|
+
last = name("off");
|
|
2784
|
+
}
|
|
2785
|
+
if (p.spread > 0) {
|
|
2786
|
+
primitives.push(fe("feMorphology", { in: last, operator: "dilate", radius: round(p.spread), result: name("grow") }));
|
|
2787
|
+
last = name("grow");
|
|
2788
|
+
}
|
|
2789
|
+
if (p.blur > 0) {
|
|
2790
|
+
primitives.push(fe("feGaussianBlur", { in: last, stdDeviation: round(p.blur / 2), result: name("blur") }));
|
|
2791
|
+
last = name("blur");
|
|
2792
|
+
}
|
|
2793
|
+
primitives.push(fe("feFlood", { "flood-color": p.color, "flood-opacity": round(p.opacity), result: name("color") }));
|
|
2794
|
+
primitives.push(fe("feComposite", { in: name("color"), in2: last, operator: "in", result: name("tint") }));
|
|
2795
|
+
primitives.push(fe("feComposite", { in: name("tint"), in2: "SourceAlpha", operator: "in", result: name("inner") }));
|
|
2796
|
+
primitives.push(fe("feComposite", { in: name("inner"), in2: body, operator: "over", result: name("body") }));
|
|
2797
|
+
body = name("body");
|
|
2798
|
+
}
|
|
2799
|
+
for (const f of active) {
|
|
2800
|
+
if (f.type !== "feather") continue;
|
|
2801
|
+
n++;
|
|
2802
|
+
const r = f.params.radius;
|
|
2803
|
+
primitives.push(fe("feMorphology", { in: "SourceAlpha", operator: "erode", radius: round(r / 2), result: name("core") }));
|
|
2804
|
+
primitives.push(fe("feGaussianBlur", { in: name("core"), stdDeviation: round(r / 4), result: name("fade") }));
|
|
2805
|
+
primitives.push(fe("feComposite", { in: body, in2: name("fade"), operator: "in", result: name("body") }));
|
|
2806
|
+
body = name("body");
|
|
2807
|
+
}
|
|
2808
|
+
const under = [];
|
|
2809
|
+
for (const f of active) {
|
|
2810
|
+
if (f.type !== "dropShadow" && f.type !== "outerGlow") continue;
|
|
2811
|
+
n++;
|
|
2812
|
+
const p = f.params;
|
|
2813
|
+
let last = "SourceAlpha";
|
|
2814
|
+
if (p.spread > 0) {
|
|
2815
|
+
primitives.push(fe("feMorphology", { in: last, operator: "dilate", radius: round(p.spread), result: name("grow") }));
|
|
2816
|
+
last = name("grow");
|
|
2817
|
+
}
|
|
2818
|
+
if (p.blur > 0) {
|
|
2819
|
+
primitives.push(fe("feGaussianBlur", { in: last, stdDeviation: round(p.blur / 2), result: name("blur") }));
|
|
2820
|
+
last = name("blur");
|
|
2821
|
+
}
|
|
2822
|
+
if (f.type === "dropShadow" && (f.params.offsetX || f.params.offsetY)) {
|
|
2823
|
+
primitives.push(fe("feOffset", { in: last, dx: round(f.params.offsetX), dy: round(f.params.offsetY), result: name("off") }));
|
|
2824
|
+
last = name("off");
|
|
2825
|
+
}
|
|
2826
|
+
primitives.push(fe("feFlood", { "flood-color": p.color, "flood-opacity": round(p.opacity), result: name("color") }));
|
|
2827
|
+
primitives.push(fe("feComposite", { in: name("color"), in2: last, operator: "in", result: name("shadow") }));
|
|
2828
|
+
under.push(name("shadow"));
|
|
2829
|
+
}
|
|
2830
|
+
if (under.length) {
|
|
2831
|
+
n++;
|
|
2832
|
+
primitives.push(fe("feMerge", { result: name("merged") }, [...under, body].map((i) => fe("feMergeNode", { in: i }))));
|
|
2833
|
+
body = name("merged");
|
|
2834
|
+
}
|
|
2835
|
+
for (const f of active) {
|
|
2836
|
+
if (f.type !== "layerBlur") continue;
|
|
2837
|
+
n++;
|
|
2838
|
+
primitives.push(fe("feGaussianBlur", { in: body, stdDeviation: round(f.params.radius / 2), result: name("body") }));
|
|
2839
|
+
body = name("body");
|
|
2840
|
+
}
|
|
2841
|
+
const lastResult = primitives[primitives.length - 1]?.attrs.result;
|
|
2842
|
+
if (lastResult !== body) primitives.push(fe("feMerge", {}, [fe("feMergeNode", { in: body })]));
|
|
2843
|
+
const pad = vectorFilterReach(active) + 2;
|
|
2844
|
+
return {
|
|
2845
|
+
id,
|
|
2846
|
+
x: round(bounds.x - pad),
|
|
2847
|
+
y: round(bounds.y - pad),
|
|
2848
|
+
width: round(bounds.width + 2 * pad),
|
|
2849
|
+
height: round(bounds.height + 2 * pad),
|
|
2850
|
+
primitives
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
var escapeAttr = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
2854
|
+
function primitiveMarkup(p) {
|
|
2855
|
+
const attrs = Object.entries(p.attrs).map(([k, v2]) => ` ${k}="${escapeAttr(String(v2))}"`).join("");
|
|
2856
|
+
return p.children?.length ? `<${p.tag}${attrs}>${p.children.map(primitiveMarkup).join("")}</${p.tag}>` : `<${p.tag}${attrs}/>`;
|
|
2857
|
+
}
|
|
2858
|
+
function vectorFilterMarkup(filter, extra = "") {
|
|
2859
|
+
return `<filter id="${escapeAttr(filter.id)}" filterUnits="userSpaceOnUse" x="${filter.x}" y="${filter.y}" width="${filter.width}" height="${filter.height}" color-interpolation-filters="sRGB"${extra}>${filter.primitives.map(primitiveMarkup).join("")}</filter>`;
|
|
2860
|
+
}
|
|
2861
|
+
var VECTOR_FILTER_MENU = VECTOR_FILTER_TYPES.map((type) => ({ type, label: VECTOR_FILTER_LABELS[type] }));
|
|
2862
|
+
|
|
2863
|
+
// src/vector/mask.ts
|
|
2864
|
+
function isVectorMaskType(value) {
|
|
2865
|
+
return typeof value === "string" && VECTOR_MASK_TYPES.includes(value);
|
|
2866
|
+
}
|
|
2867
|
+
function sanitizeVectorMask(value) {
|
|
2868
|
+
if (!value || typeof value !== "object") return null;
|
|
2869
|
+
const r = value;
|
|
2870
|
+
if (!isVectorMaskType(r.type)) return null;
|
|
2871
|
+
return r.invert === true ? { type: r.type, invert: true } : { type: r.type };
|
|
2872
|
+
}
|
|
2873
|
+
function isVectorMaskGroup(node) {
|
|
2874
|
+
return node?.type === "group" && !!node.mask && isVectorMaskType(node.mask.type) && !node.blend && !node.liveBoolean && node.children.length > 0;
|
|
2875
|
+
}
|
|
2876
|
+
function isVectorMaskActive(node) {
|
|
2877
|
+
return isVectorMaskGroup(node) && node.children[0].visible !== false;
|
|
2878
|
+
}
|
|
2879
|
+
function vectorMaskSource(node) {
|
|
2880
|
+
return isVectorMaskGroup(node) ? node.children[0] : null;
|
|
2881
|
+
}
|
|
2882
|
+
function vectorMaskContents(group) {
|
|
2883
|
+
return isVectorMaskGroup(group) ? group.children.slice(1) : group.children;
|
|
2884
|
+
}
|
|
2885
|
+
function vectorMaskOwner(nodes, id) {
|
|
2886
|
+
for (const n of nodes) {
|
|
2887
|
+
if (n.type !== "group") continue;
|
|
2888
|
+
if (isVectorMaskGroup(n) && n.children[0].id === id) return n;
|
|
2889
|
+
const inner = vectorMaskOwner(n.children, id);
|
|
2890
|
+
if (inner) return inner;
|
|
2891
|
+
}
|
|
2892
|
+
return null;
|
|
2893
|
+
}
|
|
2894
|
+
function vectorMaskSummary(node) {
|
|
2895
|
+
if (!isVectorMaskGroup(node)) return null;
|
|
2896
|
+
return {
|
|
2897
|
+
type: node.mask.type,
|
|
2898
|
+
invert: !!node.mask.invert,
|
|
2899
|
+
maskId: node.children[0].id,
|
|
2900
|
+
contents: node.children.slice(1).map((c) => c.id),
|
|
2901
|
+
enabled: node.children[0].visible !== false
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
var place = (path, m) => isIdentityMatrix(m) ? path : transformBezierPath(path, m);
|
|
2905
|
+
function vectorMaskRegionShapes(node, type, parent = IDENTITY_MATRIX, self = true) {
|
|
2906
|
+
if (!self && node.visible === false) return [];
|
|
2907
|
+
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
2908
|
+
if (isVectorMaskActive(node) || node.type === "group" && node.effects?.length) {
|
|
2909
|
+
return vectorAppearanceShapes(node).flatMap((s) => regionOfPath(s.path, s.source, type, m));
|
|
2910
|
+
}
|
|
2911
|
+
const drawn = expandVectorAppearance(node);
|
|
2912
|
+
if (drawn.type === "group") {
|
|
2913
|
+
const inner = multiplyMatrices(nodeMatrix(drawn), parent);
|
|
2914
|
+
return drawn.children.flatMap((c) => vectorMaskRegionShapes(c, type, inner, false));
|
|
2915
|
+
}
|
|
2916
|
+
return regionOfPath(subpathsToBezier(drawn.subpaths), drawn, type, m);
|
|
2917
|
+
}
|
|
2918
|
+
function regionOfPath(path, style, type, m) {
|
|
2919
|
+
if (!path.length) return [];
|
|
2920
|
+
const fillRule = style.fillRule ?? "nonzero";
|
|
2921
|
+
if (type === "clip") return [{ path: place(path, m), fillRule }];
|
|
2922
|
+
const out = [];
|
|
2923
|
+
let filled = false;
|
|
2924
|
+
for (const l of vectorPaintLayerNodes(style)) {
|
|
2925
|
+
if (!l.drawn) continue;
|
|
2926
|
+
if (l.kind === "fill") {
|
|
2927
|
+
if (!filled) out.push({ path: place(path, m), fillRule });
|
|
2928
|
+
filled = true;
|
|
2929
|
+
} else if ((l.node.strokeWidth ?? 1) > 0) {
|
|
2930
|
+
const area = vectorStrokeOutlinePath(path, l.node);
|
|
2931
|
+
if (area.length) out.push({ path: place(area, m), fillRule: "nonzero" });
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
return out;
|
|
2935
|
+
}
|
|
2936
|
+
var regionCache = /* @__PURE__ */ new WeakMap();
|
|
2937
|
+
function vectorMaskRegion(group) {
|
|
2938
|
+
let hit = regionCache.get(group);
|
|
2939
|
+
if (!hit) {
|
|
2940
|
+
hit = vectorMaskRegionShapes(group.children[0], group.mask.type);
|
|
2941
|
+
regionCache.set(group, hit);
|
|
2942
|
+
}
|
|
2943
|
+
return hit;
|
|
2944
|
+
}
|
|
2945
|
+
var unionCache = /* @__PURE__ */ new WeakMap();
|
|
2946
|
+
function vectorMaskRegionPath(group) {
|
|
2947
|
+
let hit = unionCache.get(group);
|
|
2948
|
+
if (!hit) {
|
|
2949
|
+
const shapes = vectorMaskRegion(group);
|
|
2950
|
+
hit = !shapes.length ? [] : shapes.length === 1 && shapes[0].fillRule === "nonzero" ? shapes[0].path : pathBoolean("union", shapes.map((s) => ({ path: s.path, fillRule: s.fillRule }))).path;
|
|
2951
|
+
unionCache.set(group, hit);
|
|
2952
|
+
}
|
|
2953
|
+
return hit;
|
|
2954
|
+
}
|
|
2955
|
+
function inRegion(group, p, tolerance) {
|
|
2956
|
+
const pt2 = [p.x, p.y];
|
|
2957
|
+
for (const s of vectorMaskRegion(group)) {
|
|
2958
|
+
if (pointInBezierPath(s.path, pt2, s.fillRule)) return true;
|
|
2959
|
+
if (tolerance > 0 && distanceToBezierPath(s.path, pt2) <= tolerance) return true;
|
|
2960
|
+
}
|
|
2961
|
+
return false;
|
|
2962
|
+
}
|
|
2963
|
+
function vectorMaskContains(group, p, tolerance = 0) {
|
|
2964
|
+
if (!isVectorMaskActive(group)) return true;
|
|
2965
|
+
if (group.mask.type !== "clip") {
|
|
2966
|
+
const source = group.children[0];
|
|
2967
|
+
const hit = hitTestVectorNode(source.visible === false ? { ...source, visible: true } : source, p, group.mask.invert ? 0 : tolerance);
|
|
2968
|
+
return group.mask.invert ? !hit || tolerance > 0 && hitNearEdge(group, p, tolerance) : hit;
|
|
2969
|
+
}
|
|
2970
|
+
if (!group.mask.invert) return inRegion(group, p, tolerance);
|
|
2971
|
+
return !inRegion(group, p, 0) || hitNearEdge(group, p, tolerance);
|
|
2972
|
+
}
|
|
2973
|
+
function hitNearEdge(group, p, tolerance) {
|
|
2974
|
+
if (tolerance <= 0) return false;
|
|
2975
|
+
return vectorMaskRegion(group).some((s) => distanceToBezierPath(s.path, [p.x, p.y]) <= tolerance);
|
|
2976
|
+
}
|
|
2977
|
+
function clipOpen(path, region, invert2) {
|
|
2978
|
+
const out = [];
|
|
2979
|
+
for (const sp of bezierToSubpaths(path)) {
|
|
2980
|
+
const pieces = eraseFromOutline(sp, region, { keep: invert2 ? "outside" : "inside" });
|
|
2981
|
+
if (pieces === null) {
|
|
2982
|
+
const a = sp.anchors[0];
|
|
2983
|
+
const inside = !!a && pointInBezierPath(region, [a.x, a.y], "nonzero");
|
|
2984
|
+
if (inside !== invert2) out.push(...subpathsToBezier([sp]));
|
|
2985
|
+
} else out.push(...subpathsToBezier(pieces));
|
|
2986
|
+
}
|
|
2987
|
+
return out;
|
|
2988
|
+
}
|
|
2989
|
+
function clipShapePath(path, fillRule, region, invert2) {
|
|
2990
|
+
const subpaths = bezierToSubpaths(path);
|
|
2991
|
+
const closed = subpaths.filter((sp) => sp.closed);
|
|
2992
|
+
const open = subpaths.filter((sp) => !sp.closed);
|
|
2993
|
+
const out = [];
|
|
2994
|
+
if (closed.length) {
|
|
2995
|
+
const operands = [{ path: subpathsToBezier(closed), fillRule }, { path: region, fillRule: "nonzero" }];
|
|
2996
|
+
out.push(...region.length ? pathBoolean(invert2 ? "difference" : "intersection", operands).path : invert2 ? operands[0].path : []);
|
|
2997
|
+
}
|
|
2998
|
+
if (open.length) out.push(...region.length ? clipOpen(subpathsToBezier(open), region, invert2) : invert2 ? subpathsToBezier(open) : []);
|
|
2999
|
+
return out;
|
|
3000
|
+
}
|
|
3001
|
+
function vectorMaskedShapes(group) {
|
|
3002
|
+
const contents = group.children.flatMap((c, i) => i === 0 ? [] : vectorChildAppearanceShapes(c, i));
|
|
3003
|
+
const shapes = applyVectorEffects(contents, group.effects);
|
|
3004
|
+
if (!isVectorMaskActive(group)) return shapes;
|
|
3005
|
+
const region = vectorMaskRegionPath(group);
|
|
3006
|
+
const invert2 = !!group.mask.invert;
|
|
3007
|
+
const out = [];
|
|
3008
|
+
for (const s of shapes) {
|
|
3009
|
+
const path = clipShapePath(s.path, s.source.fillRule ?? "nonzero", region, invert2);
|
|
3010
|
+
if (path.length) out.push({ ...s, path, source: s.source.fillRule === "evenodd" ? { ...s.source, fillRule: "nonzero" } : s.source });
|
|
3011
|
+
}
|
|
3012
|
+
return out;
|
|
3013
|
+
}
|
|
3014
|
+
function vectorMaskedGeometry(node) {
|
|
3015
|
+
if (node.type !== "group") return node;
|
|
3016
|
+
if (isVectorMaskActive(node)) {
|
|
3017
|
+
return {
|
|
3018
|
+
id: node.id,
|
|
3019
|
+
type: "group",
|
|
3020
|
+
...node.transform ? { transform: node.transform } : {},
|
|
3021
|
+
...node.opacity !== void 0 ? { opacity: node.opacity } : {},
|
|
3022
|
+
...node.visible === false ? { visible: false } : {},
|
|
3023
|
+
...node.locked ? { locked: true } : {},
|
|
3024
|
+
children: vectorAppearanceNodes(node)
|
|
3025
|
+
};
|
|
3026
|
+
}
|
|
3027
|
+
let changed = false;
|
|
3028
|
+
const children = node.children.map((c) => {
|
|
3029
|
+
const next = vectorMaskedGeometry(c);
|
|
3030
|
+
if (next !== c) changed = true;
|
|
3031
|
+
return next;
|
|
3032
|
+
});
|
|
3033
|
+
return changed ? { ...node, children } : node;
|
|
3034
|
+
}
|
|
3035
|
+
function vectorMaskedLocalBounds(group) {
|
|
3036
|
+
const b = bezierPathBounds(vectorAppearanceShapes(group).flatMap((s) => s.path));
|
|
3037
|
+
return b ? { x: b.minX, y: b.minY, width: b.maxX - b.minX, height: b.maxY - b.minY } : null;
|
|
3038
|
+
}
|
|
3039
|
+
function paintReach(node) {
|
|
3040
|
+
const own = vectorFilterReach(activeVectorFilters(node));
|
|
3041
|
+
if (node.type === "path") return own + vectorStrokeStackReach(node);
|
|
3042
|
+
return own + Math.max(0, ...node.children.map(paintReach));
|
|
3043
|
+
}
|
|
3044
|
+
function vectorMaskContentBounds(group) {
|
|
3045
|
+
const contents = group.children.slice(1);
|
|
3046
|
+
const b = unionBounds(contents.map((c) => vectorNodeBounds(c, IDENTITY_MATRIX)));
|
|
3047
|
+
if (!b) return null;
|
|
3048
|
+
const pad = Math.max(0, ...contents.map(paintReach)) + Math.max(b.width, b.height) * 0.05 + 4;
|
|
3049
|
+
return { x: b.x - pad, y: b.y - pad, width: b.width + 2 * pad, height: b.height + 2 * pad };
|
|
3050
|
+
}
|
|
3051
|
+
var fe2 = (tag, attrs) => ({ tag, attrs });
|
|
3052
|
+
var LUMA = "-0.2125 -0.7154 -0.0721 0 1";
|
|
3053
|
+
function invertFilter(type, id, bounds) {
|
|
3054
|
+
const primitives = type === "alpha" ? [fe2("feColorMatrix", { in: "SourceGraphic", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1" })] : [
|
|
3055
|
+
// Over black first, so a transparent area reads as dark (hidden) before inverting.
|
|
3056
|
+
fe2("feFlood", { "flood-color": "#000000", result: "black" }),
|
|
3057
|
+
fe2("feComposite", { in: "SourceGraphic", in2: "black", operator: "over", result: "flat" }),
|
|
3058
|
+
fe2("feColorMatrix", { in: "flat", type: "matrix", values: `${LUMA} ${LUMA} ${LUMA} 0 0 0 0 1` })
|
|
3059
|
+
];
|
|
3060
|
+
const r = (n) => Math.round(n * 1e3) / 1e3;
|
|
3061
|
+
return { id, x: r(bounds.x), y: r(bounds.y), width: r(bounds.width), height: r(bounds.height), primitives };
|
|
3062
|
+
}
|
|
3063
|
+
var rectPath = (b) => [
|
|
3064
|
+
{ type: "M", x: b.x, y: b.y },
|
|
3065
|
+
{ type: "L", x: b.x + b.width, y: b.y },
|
|
3066
|
+
{ type: "L", x: b.x + b.width, y: b.y + b.height },
|
|
3067
|
+
{ type: "L", x: b.x, y: b.y + b.height },
|
|
3068
|
+
{ type: "Z" }
|
|
3069
|
+
];
|
|
3070
|
+
function vectorMaskRenderData(group, id, filterId, precision = 3) {
|
|
3071
|
+
if (!isVectorMaskActive(group) || group.children.length < 2) return null;
|
|
3072
|
+
const invert2 = !!group.mask.invert;
|
|
3073
|
+
const bounds = vectorMaskContentBounds(group);
|
|
3074
|
+
if (group.mask.type === "clip") {
|
|
3075
|
+
const shapes = vectorMaskRegion(group);
|
|
3076
|
+
if (!invert2) return { type: "clip", invert: invert2, id, clip: shapes.map((s) => ({ d: bezierPathToSvg(s.path, { precision }), clipRule: s.fillRule })) };
|
|
3077
|
+
const box = bounds ?? { x: 0, y: 0, width: 0, height: 0 };
|
|
3078
|
+
const region = vectorMaskRegionPath(group);
|
|
3079
|
+
return { type: "clip", invert: invert2, id, clip: [{ d: bezierPathToSvg([...rectPath(box), ...region], { precision }), clipRule: "evenodd" }] };
|
|
3080
|
+
}
|
|
3081
|
+
if (!bounds) return null;
|
|
3082
|
+
if (!invert2) return { type: group.mask.type, invert: invert2, id, bounds };
|
|
3083
|
+
const filter = invertFilter(group.mask.type, filterId, bounds);
|
|
3084
|
+
return { type: group.mask.type, invert: invert2, id, bounds, filter: `url(#${filterId})`, invertFilter: filter };
|
|
3085
|
+
}
|
|
3086
|
+
|
|
2321
3087
|
// src/vector/warp.ts
|
|
2322
3088
|
function polylineAt(pts) {
|
|
2323
3089
|
const acc = [0];
|
|
@@ -2829,7 +3595,7 @@ function applyVectorEffects(shapes, effects) {
|
|
|
2829
3595
|
}
|
|
2830
3596
|
return list;
|
|
2831
3597
|
}
|
|
2832
|
-
function
|
|
3598
|
+
function vectorChildAppearanceShapes(child, index) {
|
|
2833
3599
|
if (child.visible === false) return [];
|
|
2834
3600
|
const m = child.transform;
|
|
2835
3601
|
const k = child.opacity ?? 1;
|
|
@@ -2844,7 +3610,7 @@ function liveBooleanShapes(group) {
|
|
|
2844
3610
|
const operands = [];
|
|
2845
3611
|
let source = null;
|
|
2846
3612
|
group.children.forEach((child, i) => {
|
|
2847
|
-
const shapes =
|
|
3613
|
+
const shapes = vectorChildAppearanceShapes(child, i);
|
|
2848
3614
|
if (!shapes.length) return;
|
|
2849
3615
|
source ??= shapes[0].source;
|
|
2850
3616
|
const path = shapes.length === 1 ? shapes[0].path : pathBoolean("union", shapes.map((s) => ({ path: s.path, fillRule: s.source.fillRule ?? "nonzero" }))).path;
|
|
@@ -2858,7 +3624,8 @@ var shapeCache = /* @__PURE__ */ new WeakMap();
|
|
|
2858
3624
|
function baseShapes(node) {
|
|
2859
3625
|
if (node.type === "path") return [{ source: node, path: subpathsToBezier(node.subpaths), opacity: 1, order: [] }];
|
|
2860
3626
|
if (node.liveBoolean) return liveBooleanShapes(node);
|
|
2861
|
-
return node.children.flatMap((c, i) =>
|
|
3627
|
+
if (isVectorMaskGroup(node)) return node.children.flatMap((c, i) => i === 0 ? [] : vectorChildAppearanceShapes(c, i));
|
|
3628
|
+
return node.children.flatMap((c, i) => vectorChildAppearanceShapes(c, i));
|
|
2862
3629
|
}
|
|
2863
3630
|
function vectorEffectInputPaths(node, effectId) {
|
|
2864
3631
|
const list = node.effects ?? [];
|
|
@@ -2883,7 +3650,7 @@ function vectorEnvelopeFrame(node, effectId) {
|
|
|
2883
3650
|
function vectorAppearanceShapes(node) {
|
|
2884
3651
|
const hit = shapeCache.get(node);
|
|
2885
3652
|
if (hit) return hit;
|
|
2886
|
-
const out = applyVectorEffects(baseShapes(node), node.effects).sort((a, b) => compareOrder(a.order, b.order));
|
|
3653
|
+
const out = (isVectorMaskGroup(node) ? vectorMaskedShapes(node) : applyVectorEffects(baseShapes(node), node.effects)).sort((a, b) => compareOrder(a.order, b.order));
|
|
2887
3654
|
shapeCache.set(node, out);
|
|
2888
3655
|
return out;
|
|
2889
3656
|
}
|
|
@@ -2939,6 +3706,11 @@ function expandVectorAppearance(node) {
|
|
|
2939
3706
|
if (!hasOwnVectorAppearance(node)) {
|
|
2940
3707
|
const group = node;
|
|
2941
3708
|
out = { ...group, children: group.children.map(expandVectorAppearance) };
|
|
3709
|
+
} else if (isVectorMaskGroup(node)) {
|
|
3710
|
+
const { effects, ...group } = node;
|
|
3711
|
+
const [mask, ...contents] = node.children;
|
|
3712
|
+
const wrapper = { id: `${node.id}~content`, type: "group", effects, children: contents };
|
|
3713
|
+
out = { ...group, children: [expandVectorAppearance(mask), ...contents.length ? [expandVectorAppearance(wrapper)] : []] };
|
|
2942
3714
|
} else {
|
|
2943
3715
|
const shapes = vectorAppearanceShapes(node);
|
|
2944
3716
|
if (node.type === "path" && shapes.length === 1) {
|
|
@@ -3010,10 +3782,10 @@ function vectorEnteredGroups(nodes, ids) {
|
|
|
3010
3782
|
const want = new Set(ids);
|
|
3011
3783
|
const visit = (list, live) => {
|
|
3012
3784
|
for (const n of list) {
|
|
3013
|
-
const own = n.type === "group" && hasOwnVectorAppearance(n);
|
|
3785
|
+
const own = n.type === "group" && (hasOwnVectorAppearance(n) || isVectorMaskGroup(n));
|
|
3014
3786
|
if (want.has(n.id)) {
|
|
3015
3787
|
for (const id of live) out.add(id);
|
|
3016
|
-
if (own) out.add(n.id);
|
|
3788
|
+
if (own && hasOwnVectorAppearance(n)) out.add(n.id);
|
|
3017
3789
|
}
|
|
3018
3790
|
if (n.type === "group") visit(n.children, own ? [...live, n.id] : live);
|
|
3019
3791
|
}
|
|
@@ -3200,6 +3972,11 @@ function vectorPathWorldBezier(node, parent = IDENTITY_MATRIX, options = {}) {
|
|
|
3200
3972
|
return isIdentityMatrix(m) ? path : transformBezierPath(path, m);
|
|
3201
3973
|
}
|
|
3202
3974
|
function vectorNodeBounds(node, parent = IDENTITY_MATRIX) {
|
|
3975
|
+
if (isVectorMaskActive(node)) {
|
|
3976
|
+
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
3977
|
+
const b2 = bezierPathBounds(vectorAppearanceShapes(node).flatMap((s) => isIdentityMatrix(m) ? s.path : transformBezierPath(s.path, m)));
|
|
3978
|
+
return b2 ? { x: b2.minX, y: b2.minY, width: b2.maxX - b2.minX, height: b2.maxY - b2.minY } : null;
|
|
3979
|
+
}
|
|
3203
3980
|
node = expandVectorAppearance(node);
|
|
3204
3981
|
if (node.type === "group") {
|
|
3205
3982
|
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
@@ -3232,6 +4009,14 @@ function boundsFromPoints(a, b) {
|
|
|
3232
4009
|
}
|
|
3233
4010
|
function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX, options = {}) {
|
|
3234
4011
|
if (node.visible === false) return false;
|
|
4012
|
+
if (isVectorMaskGroup(node)) {
|
|
4013
|
+
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
4014
|
+
const entered = !!options.entered?.has(node.id);
|
|
4015
|
+
if (!entered && isVectorMaskActive(node) && !vectorMaskContains(node, applyMatrix(invertMatrix(m), p), tolerance)) return false;
|
|
4016
|
+
const shown = !entered && hasOwnVectorAppearance(node) ? expandVectorAppearance(node).children : node.children;
|
|
4017
|
+
for (let i = shown.length - 1; i >= 1; i--) if (hitTestVectorNode(shown[i], p, tolerance, m, options)) return true;
|
|
4018
|
+
return entered && hitTestVectorMaskSource(node, p, tolerance, m, options);
|
|
4019
|
+
}
|
|
3235
4020
|
if (!(node.type === "group" && (!hasOwnVectorAppearance(node) || options.entered?.has(node.id)))) node = expandVectorAppearance(node);
|
|
3236
4021
|
if (node.type === "group") {
|
|
3237
4022
|
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
@@ -3241,6 +4026,18 @@ function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX, opt
|
|
|
3241
4026
|
if (path.length === 0) return false;
|
|
3242
4027
|
return hitTestVectorPaintStack(node, path, p, tolerance);
|
|
3243
4028
|
}
|
|
4029
|
+
function hitTestVectorMaskSource(group, p, tolerance, m, options) {
|
|
4030
|
+
const source = group.children[0];
|
|
4031
|
+
if (source.visible === false) return false;
|
|
4032
|
+
if (group.mask?.type !== "clip") return hitTestVectorNode(source, p, tolerance, m, options);
|
|
4033
|
+
const paths = collectPathNodes(source).filter((n) => n.visible !== false);
|
|
4034
|
+
const pt2 = [p.x, p.y];
|
|
4035
|
+
return paths.some((n) => {
|
|
4036
|
+
const world = vectorParentMatrix([source], n.id);
|
|
4037
|
+
const path = vectorPathWorldBezier(n, multiplyMatrices(world ?? IDENTITY_MATRIX, m));
|
|
4038
|
+
return pointInBezierPath(path, pt2, n.fillRule ?? "nonzero") || distanceToBezierPath(path, pt2) <= tolerance;
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
3244
4041
|
function vectorStrokeOutline(node, parent = IDENTITY_MATRIX) {
|
|
3245
4042
|
if (!hasPaint(node.stroke) || !((node.strokeWidth ?? 1) > 0)) return [];
|
|
3246
4043
|
return vectorStrokeOutlinePath(vectorPathWorldBezier(node, parent), node);
|
|
@@ -3498,14 +4295,14 @@ function roundSubpaths(subpaths, precision = 3) {
|
|
|
3498
4295
|
|
|
3499
4296
|
// src/vector/pathEffects.ts
|
|
3500
4297
|
var EPS3 = 1e-9;
|
|
3501
|
-
var
|
|
4298
|
+
var degenerate2 = (s) => s.every((p) => Math.abs(p[0] - s[0][0]) < EPS3 && Math.abs(p[1] - s[0][1]) < EPS3);
|
|
3502
4299
|
function raise(seg) {
|
|
3503
4300
|
if (seg.length !== 3) return seg.map((p) => [p[0], p[1]]);
|
|
3504
4301
|
const [p0, p1, p2] = seg;
|
|
3505
4302
|
return [p0, [p0[0] + 2 / 3 * (p1[0] - p0[0]), p0[1] + 2 / 3 * (p1[1] - p0[1])], [p2[0] + 2 / 3 * (p1[0] - p2[0]), p2[1] + 2 / 3 * (p1[1] - p2[1])], p2];
|
|
3506
4303
|
}
|
|
3507
4304
|
function subsOf(path) {
|
|
3508
|
-
return pathToContours(path).map((c) => ({ segs: closeContour(c).filter((s) => !
|
|
4305
|
+
return pathToContours(path).map((c) => ({ segs: closeContour(c).filter((s) => !degenerate2(s)).map(raise), closed: c.closed })).filter((s) => s.segs.length > 0);
|
|
3509
4306
|
}
|
|
3510
4307
|
var subsToPath = (subs) => contoursToPath(subs.map((s) => ({ segments: s.segs, closed: s.closed })));
|
|
3511
4308
|
var unit2 = (x, y) => {
|
|
@@ -3557,7 +4354,7 @@ var Measured = class {
|
|
|
3557
4354
|
*/
|
|
3558
4355
|
append(sa, sb, out) {
|
|
3559
4356
|
for (const piece of trimSegments(this.segs, sa, sb, this.lens)) {
|
|
3560
|
-
if (
|
|
4357
|
+
if (degenerate2(piece)) continue;
|
|
3561
4358
|
const last = out[out.length - 1]?.segs;
|
|
3562
4359
|
const end = last?.[last.length - 1]?.at(-1);
|
|
3563
4360
|
if (!end || Math.hypot(end[0] - piece[0][0], end[1] - piece[0][1]) > 1e-6) out.push({ segs: [piece], closed: false });
|
|
@@ -4329,14 +5126,14 @@ function lerpStops(a, b, t) {
|
|
|
4329
5126
|
function lerpGradient(a, b, t) {
|
|
4330
5127
|
if (a.type !== b.type) return null;
|
|
4331
5128
|
const { stops, resampled } = lerpStops(a, b, t);
|
|
4332
|
-
const
|
|
5129
|
+
const near2 = t < 0.5 ? a : b;
|
|
4333
5130
|
const out = { type: a.type, stops };
|
|
4334
5131
|
if (!resampled) {
|
|
4335
5132
|
if (a.interpolation && a.interpolation !== "srgb") out.interpolation = a.interpolation;
|
|
4336
5133
|
if (a.smoothness) out.smoothness = a.smoothness;
|
|
4337
5134
|
}
|
|
4338
|
-
if (
|
|
4339
|
-
if (
|
|
5135
|
+
if (near2.spread && near2.spread !== "pad") out.spread = near2.spread;
|
|
5136
|
+
if (near2.strokeMode && near2.strokeMode !== "within") out.strokeMode = near2.strokeMode;
|
|
4340
5137
|
const ea = hasExplicitGradientGeometry(a);
|
|
4341
5138
|
const eb = hasExplicitGradientGeometry(b);
|
|
4342
5139
|
if (!ea && !eb) {
|
|
@@ -4354,7 +5151,7 @@ function lerpGradient(a, b, t) {
|
|
|
4354
5151
|
const pa = vectorGradientPoints(a);
|
|
4355
5152
|
const pb = vectorGradientPoints(b);
|
|
4356
5153
|
if (pa.units !== pb.units) {
|
|
4357
|
-
const src = explicitVectorGradient(
|
|
5154
|
+
const src = explicitVectorGradient(near2);
|
|
4358
5155
|
return { ...src, stops: out.stops, ...out.interpolation ? { interpolation: out.interpolation } : {}, ...out.smoothness ? { smoothness: out.smoothness } : {} };
|
|
4359
5156
|
}
|
|
4360
5157
|
out.start = lerpPoint(pa.start, pb.start, t);
|
|
@@ -4414,14 +5211,14 @@ function lerpDashes(a, b, t) {
|
|
|
4414
5211
|
}
|
|
4415
5212
|
var SWITCHED_KEYS = ["strokeLinecap", "strokeLinejoin", "fillRule", "strokeAlign", "startArrow", "endArrow", "arrowAlign"];
|
|
4416
5213
|
function interpolateVectorStyle(a, b, t) {
|
|
4417
|
-
const
|
|
5214
|
+
const near2 = t < 0.5 ? a : b;
|
|
4418
5215
|
const out = {};
|
|
4419
5216
|
const fill = interpolateVectorPaint(a.fill, b.fill, t);
|
|
4420
5217
|
if (fill !== void 0) out.fill = fill;
|
|
4421
5218
|
const stroke = interpolateVectorPaint(a.stroke, b.stroke, t);
|
|
4422
5219
|
if (stroke !== void 0) out.stroke = stroke;
|
|
4423
5220
|
if (a.strokeWidth !== void 0 || b.strokeWidth !== void 0) out.strokeWidth = lerpN(a.strokeWidth ?? 1, b.strokeWidth ?? 1, t);
|
|
4424
|
-
for (const key of SWITCHED_KEYS) if (
|
|
5221
|
+
for (const key of SWITCHED_KEYS) if (near2[key] !== void 0 && near2[key] !== null) out[key] = near2[key];
|
|
4425
5222
|
for (const key of ["startArrowScale", "endArrowScale"])
|
|
4426
5223
|
if (a[key] !== void 0 || b[key] !== void 0) out[key] = lerpN(a[key] ?? 1, b[key] ?? 1, t);
|
|
4427
5224
|
const dash = lerpDashes(a.strokeDasharray, b.strokeDasharray, t);
|
|
@@ -4486,283 +5283,88 @@ function preparePathMorph(a, b, options, ma = nodeMatrix(a), mb = nodeMatrix(b))
|
|
|
4486
5283
|
return node;
|
|
4487
5284
|
};
|
|
4488
5285
|
}
|
|
4489
|
-
function flattenPaths(node, parent = IDENTITY_MATRIX) {
|
|
4490
|
-
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
4491
|
-
if (node.type === "path") return [{ path: node, m, opacity: 1 }];
|
|
4492
|
-
const o = node.opacity ?? 1;
|
|
4493
|
-
return node.children.filter((c) => c.visible !== false).flatMap((c) => flattenPaths(c, m)).map((e) => ({ ...e, opacity: e.opacity * o }));
|
|
4494
|
-
}
|
|
4495
|
-
var placedBounds = (path, m) => boundsOfPoints(contoursOf(path, m).flatMap((c) => c.pts));
|
|
4496
|
-
function collapsedPath(path, m, from, to) {
|
|
4497
|
-
const own = placedBounds(path, m);
|
|
4498
|
-
const c = own ? [own.x + own.width / 2, own.y + own.height / 2] : [0, 0];
|
|
4499
|
-
const fx = from && from.width > 0 ? (c[0] - from.x) / from.width : 0.5;
|
|
4500
|
-
const fy = from && from.height > 0 ? (c[1] - from.y) / from.height : 0.5;
|
|
4501
|
-
const p = to ? { x: to.x + to.width * fx, y: to.y + to.height * fy } : { x: c[0], y: c[1] };
|
|
4502
|
-
const subpaths = path.subpaths.map((sp) => ({ closed: sp.closed, anchors: sp.anchors.map(() => ({ x: p.x, y: p.y })) }));
|
|
4503
|
-
const { transform: _t, ...rest } = path;
|
|
4504
|
-
return { ...rest, subpaths };
|
|
4505
|
-
}
|
|
4506
|
-
function createVectorMorph(a, b, options = {}) {
|
|
4507
|
-
if (a.type === "path" && b.type === "path") {
|
|
4508
|
-
const at2 = preparePathMorph(a, b, options);
|
|
4509
|
-
return { at: at2 };
|
|
4510
|
-
}
|
|
4511
|
-
const pa = flattenPaths(a);
|
|
4512
|
-
const pb = flattenPaths(b);
|
|
4513
|
-
const ba = unionBounds(pa.map((e) => placedBounds(e.path, e.m)));
|
|
4514
|
-
const bb = unionBounds(pb.map((e) => placedBounds(e.path, e.m)));
|
|
4515
|
-
const id = options.id ?? a.id;
|
|
4516
|
-
const parts = [];
|
|
4517
|
-
const opacities = [];
|
|
4518
|
-
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
4519
|
-
const x = pa[i];
|
|
4520
|
-
const y = pb[i];
|
|
4521
|
-
const sub5 = { ...options, id: `${id}-${i}`, starts: void 0 };
|
|
4522
|
-
if (x && y) {
|
|
4523
|
-
parts.push(preparePathMorph(x.path, y.path, sub5, x.m, y.m));
|
|
4524
|
-
opacities.push([x.opacity, y.opacity]);
|
|
4525
|
-
} else if (x) {
|
|
4526
|
-
parts.push(preparePathMorph(x.path, collapsedPath(x.path, x.m, ba, bb), sub5, x.m, IDENTITY_MATRIX));
|
|
4527
|
-
opacities.push([x.opacity, x.opacity]);
|
|
4528
|
-
} else if (y) {
|
|
4529
|
-
parts.push(preparePathMorph(collapsedPath(y.path, y.m, bb, ba), y.path, sub5, IDENTITY_MATRIX, y.m));
|
|
4530
|
-
opacities.push([y.opacity, y.opacity]);
|
|
4531
|
-
}
|
|
4532
|
-
}
|
|
4533
|
-
return {
|
|
4534
|
-
at: (t) => {
|
|
4535
|
-
const children = parts.map((p, i) => {
|
|
4536
|
-
const n = p(t);
|
|
4537
|
-
const o = lerpN(opacities[i][0], opacities[i][1], t) * (n.opacity ?? 1);
|
|
4538
|
-
if (o < 1) n.opacity = o;
|
|
4539
|
-
else delete n.opacity;
|
|
4540
|
-
return n;
|
|
4541
|
-
});
|
|
4542
|
-
const group = { id, type: "group", children };
|
|
4543
|
-
return group;
|
|
4544
|
-
}
|
|
4545
|
-
};
|
|
4546
|
-
}
|
|
4547
|
-
function interpolateVectorPaths(a, b, t, options = {}) {
|
|
4548
|
-
return createVectorMorph(a, b, options).at(t);
|
|
4549
|
-
}
|
|
4550
|
-
var keyframeMorphs = /* @__PURE__ */ new WeakMap();
|
|
4551
|
-
function evaluateVectorPathKeyframes(keyframes, time, options = {}) {
|
|
4552
|
-
const keys = keyframes.filter((k) => Number.isFinite(k.time)).sort((x, y) => x.time - y.time);
|
|
4553
|
-
if (!keys.length) return null;
|
|
4554
|
-
if (!(time > keys[0].time)) return keys[0].value;
|
|
4555
|
-
const last = keys[keys.length - 1];
|
|
4556
|
-
if (time >= last.time) return last.value;
|
|
4557
|
-
let i = 0;
|
|
4558
|
-
while (i + 1 < keys.length && keys[i + 1].time <= time) i++;
|
|
4559
|
-
const a = keys[i];
|
|
4560
|
-
const b = keys[i + 1];
|
|
4561
|
-
if (time === a.time) return a.value;
|
|
4562
|
-
if (a.easing === "hold") return a.value;
|
|
4563
|
-
const span = b.time - a.time;
|
|
4564
|
-
const u = Math.min(1, Math.max(0, evaluateEasing(a.easing, (time - a.time) / span, span)));
|
|
4565
|
-
let inner = keyframeMorphs.get(a.value);
|
|
4566
|
-
if (!inner) keyframeMorphs.set(a.value, inner = /* @__PURE__ */ new WeakMap());
|
|
4567
|
-
let morph = inner.get(b.value);
|
|
4568
|
-
if (!morph) inner.set(b.value, morph = createVectorMorph(a.value, b.value, options));
|
|
4569
|
-
return morph.at(u);
|
|
4570
|
-
}
|
|
4571
|
-
|
|
4572
|
-
// src/vector/filters.ts
|
|
4573
|
-
var VECTOR_FILTER_DEFAULTS = {
|
|
4574
|
-
dropShadow: { color: "#000000", opacity: 0.25, offsetX: 0, offsetY: 4, blur: 4, spread: 0 },
|
|
4575
|
-
innerShadow: { color: "#000000", opacity: 0.25, offsetX: 0, offsetY: 4, blur: 4, spread: 0 },
|
|
4576
|
-
outerGlow: { color: "#ffffbe", opacity: 0.75, blur: 10, spread: 0 },
|
|
4577
|
-
innerGlow: { color: "#ffffbe", opacity: 0.75, blur: 10, spread: 0 },
|
|
4578
|
-
layerBlur: { radius: 4 },
|
|
4579
|
-
feather: { radius: 8 }
|
|
4580
|
-
};
|
|
4581
|
-
var VECTOR_FILTER_LABELS = {
|
|
4582
|
-
dropShadow: "Drop Shadow",
|
|
4583
|
-
innerShadow: "Inner Shadow",
|
|
4584
|
-
outerGlow: "Outer Glow",
|
|
4585
|
-
innerGlow: "Inner Glow",
|
|
4586
|
-
layerBlur: "Layer Blur",
|
|
4587
|
-
feather: "Feather"
|
|
4588
|
-
};
|
|
4589
|
-
var SHADOW_SPECS = [
|
|
4590
|
-
{ key: "color", label: "Color", kind: "color" },
|
|
4591
|
-
{ key: "opacity", label: "Opacity", kind: "number", min: 0, max: 1, step: 0.01, slider: true },
|
|
4592
|
-
{ key: "offsetX", label: "X", kind: "number", min: -1e3, max: 1e3, step: 1 },
|
|
4593
|
-
{ key: "offsetY", label: "Y", kind: "number", min: -1e3, max: 1e3, step: 1 },
|
|
4594
|
-
{ key: "blur", label: "Blur", kind: "number", min: 0, max: 500, step: 1 },
|
|
4595
|
-
{ key: "spread", label: "Spread", kind: "number", min: 0, max: 500, step: 1 }
|
|
4596
|
-
];
|
|
4597
|
-
var GLOW_SPECS = SHADOW_SPECS.filter((s) => s.key !== "offsetX" && s.key !== "offsetY");
|
|
4598
|
-
var VECTOR_FILTER_PARAM_SPECS = {
|
|
4599
|
-
dropShadow: SHADOW_SPECS,
|
|
4600
|
-
innerShadow: SHADOW_SPECS.map((s) => s.key === "spread" ? { ...s, label: "Choke" } : s),
|
|
4601
|
-
outerGlow: GLOW_SPECS,
|
|
4602
|
-
innerGlow: GLOW_SPECS.map((s) => s.key === "spread" ? { ...s, label: "Choke" } : s),
|
|
4603
|
-
layerBlur: [{ key: "radius", label: "Radius", kind: "number", min: 0, max: 500, step: 1, slider: true }],
|
|
4604
|
-
feather: [{ key: "radius", label: "Radius", kind: "number", min: 0, max: 500, step: 1, slider: true }]
|
|
4605
|
-
};
|
|
4606
|
-
function isVectorFilterType(value) {
|
|
4607
|
-
return typeof value === "string" && VECTOR_FILTER_TYPES.includes(value);
|
|
4608
|
-
}
|
|
4609
|
-
function normalizeVectorFilterParams(type, params, base) {
|
|
4610
|
-
if (!isVectorFilterType(type)) return null;
|
|
4611
|
-
const out = { ...VECTOR_FILTER_DEFAULTS[type], ...base ?? {} };
|
|
4612
|
-
for (const spec of VECTOR_FILTER_PARAM_SPECS[type]) {
|
|
4613
|
-
const v2 = params?.[spec.key];
|
|
4614
|
-
if (v2 === void 0) continue;
|
|
4615
|
-
if (spec.kind === "number" && typeof v2 === "number" && Number.isFinite(v2)) out[spec.key] = Math.min(spec.max ?? Infinity, Math.max(spec.min ?? -Infinity, v2));
|
|
4616
|
-
else if (spec.kind === "color" && typeof v2 === "string" && v2.trim()) out[spec.key] = v2.trim();
|
|
4617
|
-
}
|
|
4618
|
-
return out;
|
|
4619
|
-
}
|
|
4620
|
-
function vectorFilterParamKeys(type) {
|
|
4621
|
-
return VECTOR_FILTER_PARAM_SPECS[type].map((s) => s.key);
|
|
4622
|
-
}
|
|
4623
|
-
function createVectorFilter(type, id, params) {
|
|
4624
|
-
const p = normalizeVectorFilterParams(type, params);
|
|
4625
|
-
return p ? { id, type, params: p } : null;
|
|
4626
|
-
}
|
|
4627
|
-
function sanitizeVectorFilters(value) {
|
|
4628
|
-
if (!Array.isArray(value)) return [];
|
|
4629
|
-
const out = [];
|
|
4630
|
-
const used = /* @__PURE__ */ new Set();
|
|
4631
|
-
for (const raw of value) {
|
|
4632
|
-
if (!raw || typeof raw !== "object") continue;
|
|
4633
|
-
const r = raw;
|
|
4634
|
-
if (!isVectorFilterType(r.type)) continue;
|
|
4635
|
-
let id = typeof r.id === "string" && r.id && !used.has(r.id) ? r.id : "";
|
|
4636
|
-
for (let k = out.length + 1; !id; k++) if (!used.has(`filter${k}`)) id = `filter${k}`;
|
|
4637
|
-
used.add(id);
|
|
4638
|
-
const filter = createVectorFilter(r.type, id, r.params ?? {});
|
|
4639
|
-
out.push(r.enabled === false ? { ...filter, enabled: false } : filter);
|
|
4640
|
-
}
|
|
4641
|
-
return out;
|
|
4642
|
-
}
|
|
4643
|
-
function activeVectorFilters(node) {
|
|
4644
|
-
return (node.filters ?? []).filter((f) => {
|
|
4645
|
-
if (f.enabled === false || !isVectorFilterType(f.type)) return false;
|
|
4646
|
-
if (f.type === "layerBlur" || f.type === "feather") return f.params.radius > 0;
|
|
4647
|
-
return f.params.opacity > 0;
|
|
4648
|
-
});
|
|
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 }));
|
|
4649
5291
|
}
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
case "innerGlow":
|
|
4661
|
-
outer = Math.max(outer, f.params.blur * 1.5 + f.params.spread);
|
|
4662
|
-
break;
|
|
4663
|
-
case "layerBlur":
|
|
4664
|
-
blur += f.params.radius * 1.5;
|
|
4665
|
-
break;
|
|
4666
|
-
}
|
|
4667
|
-
}
|
|
4668
|
-
return outer + blur;
|
|
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 };
|
|
4669
5302
|
}
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
if (!active.length || !bounds) return null;
|
|
4675
|
-
const primitives = [];
|
|
4676
|
-
let body = "SourceGraphic";
|
|
4677
|
-
let n = 0;
|
|
4678
|
-
const name = (part) => `${part}${n}`;
|
|
4679
|
-
for (const f of active) {
|
|
4680
|
-
if (f.type !== "innerShadow" && f.type !== "innerGlow") continue;
|
|
4681
|
-
n++;
|
|
4682
|
-
const p = f.params;
|
|
4683
|
-
primitives.push(fe("feComponentTransfer", { in: "SourceAlpha", result: name("inv") }, [fe("feFuncA", { type: "table", tableValues: "1 0" })]));
|
|
4684
|
-
let last = name("inv");
|
|
4685
|
-
if (f.type === "innerShadow" && (f.params.offsetX || f.params.offsetY)) {
|
|
4686
|
-
primitives.push(fe("feOffset", { in: last, dx: round(f.params.offsetX), dy: round(f.params.offsetY), result: name("off") }));
|
|
4687
|
-
last = name("off");
|
|
4688
|
-
}
|
|
4689
|
-
if (p.spread > 0) {
|
|
4690
|
-
primitives.push(fe("feMorphology", { in: last, operator: "dilate", radius: round(p.spread), result: name("grow") }));
|
|
4691
|
-
last = name("grow");
|
|
4692
|
-
}
|
|
4693
|
-
if (p.blur > 0) {
|
|
4694
|
-
primitives.push(fe("feGaussianBlur", { in: last, stdDeviation: round(p.blur / 2), result: name("blur") }));
|
|
4695
|
-
last = name("blur");
|
|
4696
|
-
}
|
|
4697
|
-
primitives.push(fe("feFlood", { "flood-color": p.color, "flood-opacity": round(p.opacity), result: name("color") }));
|
|
4698
|
-
primitives.push(fe("feComposite", { in: name("color"), in2: last, operator: "in", result: name("tint") }));
|
|
4699
|
-
primitives.push(fe("feComposite", { in: name("tint"), in2: "SourceAlpha", operator: "in", result: name("inner") }));
|
|
4700
|
-
primitives.push(fe("feComposite", { in: name("inner"), in2: body, operator: "over", result: name("body") }));
|
|
4701
|
-
body = name("body");
|
|
4702
|
-
}
|
|
4703
|
-
for (const f of active) {
|
|
4704
|
-
if (f.type !== "feather") continue;
|
|
4705
|
-
n++;
|
|
4706
|
-
const r = f.params.radius;
|
|
4707
|
-
primitives.push(fe("feMorphology", { in: "SourceAlpha", operator: "erode", radius: round(r / 2), result: name("core") }));
|
|
4708
|
-
primitives.push(fe("feGaussianBlur", { in: name("core"), stdDeviation: round(r / 4), result: name("fade") }));
|
|
4709
|
-
primitives.push(fe("feComposite", { in: body, in2: name("fade"), operator: "in", result: name("body") }));
|
|
4710
|
-
body = name("body");
|
|
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 };
|
|
4711
5307
|
}
|
|
4712
|
-
const
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
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]);
|
|
4729
5328
|
}
|
|
4730
|
-
primitives.push(fe("feFlood", { "flood-color": p.color, "flood-opacity": round(p.opacity), result: name("color") }));
|
|
4731
|
-
primitives.push(fe("feComposite", { in: name("color"), in2: last, operator: "in", result: name("shadow") }));
|
|
4732
|
-
under.push(name("shadow"));
|
|
4733
|
-
}
|
|
4734
|
-
if (under.length) {
|
|
4735
|
-
n++;
|
|
4736
|
-
primitives.push(fe("feMerge", { result: name("merged") }, [...under, body].map((i) => fe("feMergeNode", { in: i }))));
|
|
4737
|
-
body = name("merged");
|
|
4738
|
-
}
|
|
4739
|
-
for (const f of active) {
|
|
4740
|
-
if (f.type !== "layerBlur") continue;
|
|
4741
|
-
n++;
|
|
4742
|
-
primitives.push(fe("feGaussianBlur", { in: body, stdDeviation: round(f.params.radius / 2), result: name("body") }));
|
|
4743
|
-
body = name("body");
|
|
4744
5329
|
}
|
|
4745
|
-
const lastResult = primitives[primitives.length - 1]?.attrs.result;
|
|
4746
|
-
if (lastResult !== body) primitives.push(fe("feMerge", {}, [fe("feMergeNode", { in: body })]));
|
|
4747
|
-
const pad = vectorFilterReach(active) + 2;
|
|
4748
5330
|
return {
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
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
|
+
}
|
|
4755
5342
|
};
|
|
4756
5343
|
}
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
const attrs = Object.entries(p.attrs).map(([k, v2]) => ` ${k}="${escapeAttr(String(v2))}"`).join("");
|
|
4760
|
-
return p.children?.length ? `<${p.tag}${attrs}>${p.children.map(primitiveMarkup).join("")}</${p.tag}>` : `<${p.tag}${attrs}/>`;
|
|
5344
|
+
function interpolateVectorPaths(a, b, t, options = {}) {
|
|
5345
|
+
return createVectorMorph(a, b, options).at(t);
|
|
4761
5346
|
}
|
|
4762
|
-
|
|
4763
|
-
|
|
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);
|
|
4764
5367
|
}
|
|
4765
|
-
var VECTOR_FILTER_MENU = VECTOR_FILTER_TYPES.map((type) => ({ type, label: VECTOR_FILTER_LABELS[type] }));
|
|
4766
5368
|
|
|
4767
5369
|
// src/vector/gradientStroke.ts
|
|
4768
5370
|
var SHARP = 1.25;
|
|
@@ -5199,7 +5801,45 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
5199
5801
|
emitNode(node, depth + wrappers.length);
|
|
5200
5802
|
for (let i = wrappers.length - 1; i >= 0; i--) lines.push(`${indent(depth + i)}</g>`);
|
|
5201
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
|
+
};
|
|
5202
5838
|
const emitNode = (node, depth) => {
|
|
5839
|
+
if (isVectorMaskGroup(node)) {
|
|
5840
|
+
emitMaskGroup(node, depth);
|
|
5841
|
+
return;
|
|
5842
|
+
}
|
|
5203
5843
|
if (hasOwnVectorAppearance(node)) {
|
|
5204
5844
|
const live2 = {
|
|
5205
5845
|
kind: node.type,
|
|
@@ -5402,6 +6042,26 @@ function collectGradients(el, raw) {
|
|
|
5402
6042
|
if (PAINT_SERVERS.has(el.name) && el.attrs.id) raw.set(el.attrs.id, el);
|
|
5403
6043
|
for (const c of el.children) collectGradients(c, raw);
|
|
5404
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
|
+
}
|
|
5405
6065
|
function collectFilters(el, raw) {
|
|
5406
6066
|
if (el.name === "filter" && el.attrs.id) raw.set(el.attrs.id, el);
|
|
5407
6067
|
for (const c of el.children) collectFilters(c, raw);
|
|
@@ -5540,6 +6200,9 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
5540
6200
|
collectGradients(root, rawGradients);
|
|
5541
6201
|
const rawFilters = /* @__PURE__ */ new Map();
|
|
5542
6202
|
collectFilters(root, rawFilters);
|
|
6203
|
+
const rawMasks = /* @__PURE__ */ new Map();
|
|
6204
|
+
collectMasks(root, rawMasks);
|
|
6205
|
+
const resolving = /* @__PURE__ */ new Set();
|
|
5543
6206
|
const filtersOf = (value) => {
|
|
5544
6207
|
const url = /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec((value ?? "").trim());
|
|
5545
6208
|
const el = url ? rawFilters.get(url[1]) : void 0;
|
|
@@ -5738,68 +6401,148 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
5738
6401
|
const out = [];
|
|
5739
6402
|
for (const child of el.children) {
|
|
5740
6403
|
if (SKIP.has(child.name)) continue;
|
|
5741
|
-
const
|
|
5742
|
-
|
|
5743
|
-
const opacity = child.attrs.opacity !== void 0 ? parseFloat(child.attrs.opacity) : void 0;
|
|
5744
|
-
const hidden = child.attrs.display === "none" || child.attrs.visibility === "hidden";
|
|
5745
|
-
const blendMode = vectorBlendModeFromCss(s.mixBlendMode);
|
|
5746
|
-
const filters = filtersOf(s.filter);
|
|
5747
|
-
const meta = {
|
|
5748
|
-
...child.attrs["inkscape:label"] || child.attrs["data-name"] ? { name: child.attrs["inkscape:label"] ?? child.attrs["data-name"] } : {},
|
|
5749
|
-
...opacity !== void 0 && Number.isFinite(opacity) && opacity < 1 ? { opacity } : {},
|
|
5750
|
-
...hidden ? { visible: false } : {},
|
|
5751
|
-
...blendMode && blendMode !== "normal" ? { blendMode } : {},
|
|
5752
|
-
...filters.length ? { filters } : {}
|
|
5753
|
-
};
|
|
5754
|
-
if (child.attrs["data-vector-blend-step"] !== void 0) continue;
|
|
5755
|
-
const operation = child.attrs["data-vector-boolean-operation"];
|
|
5756
|
-
if (BOOLEAN_OPERATIONS.includes(operation)) meta.booleanOperation = operation;
|
|
5757
|
-
if (child.name === "g" && child.attrs["data-vector-live"] !== void 0) {
|
|
5758
|
-
const node2 = liveNode(child, s, m, meta);
|
|
5759
|
-
if (node2) out.push(node2);
|
|
5760
|
-
continue;
|
|
5761
|
-
}
|
|
5762
|
-
if (child.name === "g" && child.attrs["data-vector-path"] !== void 0 && child.attrs["data-vector-fills"] !== void 0) {
|
|
5763
|
-
const node2 = stackedPath(child, s, m, meta);
|
|
5764
|
-
if (node2) out.push(node2);
|
|
5765
|
-
continue;
|
|
5766
|
-
}
|
|
5767
|
-
if (child.name === "g" && child.attrs["data-vector-path"] !== void 0) {
|
|
5768
|
-
const node2 = mergedPath(child, s, m, meta);
|
|
5769
|
-
if (node2) out.push(node2);
|
|
5770
|
-
continue;
|
|
5771
|
-
}
|
|
5772
|
-
if (child.name === "g" || child.name === "svg" || child.name === "a" || child.name === "switch") {
|
|
5773
|
-
const children = visit(child, s, m);
|
|
5774
|
-
if (!children.length) continue;
|
|
5775
|
-
const group = { id: idFor(child), type: "group", ...meta, children };
|
|
5776
|
-
const blend = child.name === "g" ? blendFromAttribute(child.attrs["data-vector-blend"], m) : null;
|
|
5777
|
-
if (blend) group.blend = blend;
|
|
5778
|
-
out.push(group);
|
|
5779
|
-
continue;
|
|
5780
|
-
}
|
|
5781
|
-
const subpaths = shapeOf(child);
|
|
5782
|
-
if (!subpaths || !subpaths.length) continue;
|
|
5783
|
-
const node = placed(
|
|
5784
|
-
withOpacities(
|
|
5785
|
-
{
|
|
5786
|
-
id: idFor(child),
|
|
5787
|
-
type: "path",
|
|
5788
|
-
...meta,
|
|
5789
|
-
subpaths,
|
|
5790
|
-
fill: child.name === "line" ? null : paint(s.fill),
|
|
5791
|
-
stroke: paint(s.stroke),
|
|
5792
|
-
...strokeStyle(s)
|
|
5793
|
-
},
|
|
5794
|
-
s
|
|
5795
|
-
),
|
|
5796
|
-
m
|
|
5797
|
-
);
|
|
5798
|
-
out.push(node);
|
|
6404
|
+
const nodes2 = visitOne(child, style, matrix);
|
|
6405
|
+
out.push(...nodes2.length ? masked(child, nodes2, multiplyMatrices(parseSvgTransform(child.attrs.transform), matrix)) : nodes2);
|
|
5799
6406
|
}
|
|
5800
6407
|
return options.mergeStackedShapes ? mergeStacked(out) : out;
|
|
5801
6408
|
};
|
|
5802
|
-
|
|
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);
|
|
5803
6546
|
return { width, height, nodes };
|
|
5804
6547
|
}
|
|
5805
6548
|
|
|
@@ -5812,6 +6555,7 @@ export {
|
|
|
5812
6555
|
VECTOR_ARROWHEADS,
|
|
5813
6556
|
VECTOR_BLEND_MODES,
|
|
5814
6557
|
VECTOR_BLEND_SPACINGS,
|
|
6558
|
+
VECTOR_MASK_TYPES,
|
|
5815
6559
|
VECTOR_TOOLS,
|
|
5816
6560
|
VECTOR_TRANSFORM_HANDLES,
|
|
5817
6561
|
VECTOR_PATHFINDER_OPERATIONS,
|
|
@@ -5960,6 +6704,43 @@ export {
|
|
|
5960
6704
|
mapVectorPoints,
|
|
5961
6705
|
mapVectorSubpaths,
|
|
5962
6706
|
mapBezierPath,
|
|
6707
|
+
splitIntoFaces,
|
|
6708
|
+
knifePath,
|
|
6709
|
+
eraserRegion,
|
|
6710
|
+
eraseFromFill,
|
|
6711
|
+
eraseFromOutline,
|
|
6712
|
+
polylineBounds,
|
|
6713
|
+
simplifyPolyline,
|
|
6714
|
+
VECTOR_FILTER_DEFAULTS,
|
|
6715
|
+
VECTOR_FILTER_LABELS,
|
|
6716
|
+
VECTOR_FILTER_PARAM_SPECS,
|
|
6717
|
+
isVectorFilterType,
|
|
6718
|
+
normalizeVectorFilterParams,
|
|
6719
|
+
vectorFilterParamKeys,
|
|
6720
|
+
createVectorFilter,
|
|
6721
|
+
sanitizeVectorFilters,
|
|
6722
|
+
activeVectorFilters,
|
|
6723
|
+
vectorFilterReach,
|
|
6724
|
+
vectorFilterSvg,
|
|
6725
|
+
vectorFilterMarkup,
|
|
6726
|
+
VECTOR_FILTER_MENU,
|
|
6727
|
+
isVectorMaskType,
|
|
6728
|
+
sanitizeVectorMask,
|
|
6729
|
+
isVectorMaskGroup,
|
|
6730
|
+
isVectorMaskActive,
|
|
6731
|
+
vectorMaskSource,
|
|
6732
|
+
vectorMaskContents,
|
|
6733
|
+
vectorMaskOwner,
|
|
6734
|
+
vectorMaskSummary,
|
|
6735
|
+
vectorMaskRegionShapes,
|
|
6736
|
+
vectorMaskRegion,
|
|
6737
|
+
vectorMaskRegionPath,
|
|
6738
|
+
vectorMaskContains,
|
|
6739
|
+
vectorMaskedShapes,
|
|
6740
|
+
vectorMaskedGeometry,
|
|
6741
|
+
vectorMaskedLocalBounds,
|
|
6742
|
+
vectorMaskContentBounds,
|
|
6743
|
+
vectorMaskRenderData,
|
|
5963
6744
|
vectorMeshFromOutline,
|
|
5964
6745
|
vectorMeshOutline,
|
|
5965
6746
|
VECTOR_EFFECT_DEFAULTS,
|
|
@@ -5978,6 +6759,7 @@ export {
|
|
|
5978
6759
|
clearVectorLiveBooleanCache,
|
|
5979
6760
|
foldVectorBooleanOperands,
|
|
5980
6761
|
applyVectorEffects,
|
|
6762
|
+
vectorChildAppearanceShapes,
|
|
5981
6763
|
vectorEffectInputPaths,
|
|
5982
6764
|
vectorEffectInputBounds,
|
|
5983
6765
|
vectorNodeEnvelope,
|
|
@@ -6050,19 +6832,6 @@ export {
|
|
|
6050
6832
|
createVectorMorph,
|
|
6051
6833
|
interpolateVectorPaths,
|
|
6052
6834
|
evaluateVectorPathKeyframes,
|
|
6053
|
-
VECTOR_FILTER_DEFAULTS,
|
|
6054
|
-
VECTOR_FILTER_LABELS,
|
|
6055
|
-
VECTOR_FILTER_PARAM_SPECS,
|
|
6056
|
-
isVectorFilterType,
|
|
6057
|
-
normalizeVectorFilterParams,
|
|
6058
|
-
vectorFilterParamKeys,
|
|
6059
|
-
createVectorFilter,
|
|
6060
|
-
sanitizeVectorFilters,
|
|
6061
|
-
activeVectorFilters,
|
|
6062
|
-
vectorFilterReach,
|
|
6063
|
-
vectorFilterSvg,
|
|
6064
|
-
vectorFilterMarkup,
|
|
6065
|
-
VECTOR_FILTER_MENU,
|
|
6066
6835
|
vectorStrokeGradientDefs,
|
|
6067
6836
|
vectorCornersAttribute,
|
|
6068
6837
|
applyVectorCornersAttribute,
|
|
@@ -6077,4 +6846,4 @@ export {
|
|
|
6077
6846
|
parseSvgTransform,
|
|
6078
6847
|
parseVectorSvg
|
|
6079
6848
|
};
|
|
6080
|
-
//# sourceMappingURL=chunk-
|
|
6849
|
+
//# sourceMappingURL=chunk-HUQ7EHVI.js.map
|