@pixerate/editor 0.34.0 → 0.35.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 +7 -0
- package/dist/canvas/index.cjs +178 -623
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +10 -1
- package/dist/canvas/index.d.ts +10 -1
- package/dist/canvas/index.js +35 -480
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-UG5DVXJK.cjs → chunk-BGNPT5PE.cjs} +446 -6
- package/dist/chunk-BGNPT5PE.cjs.map +1 -0
- package/dist/{chunk-RK6HUKDI.js → chunk-EGPIVUEF.js} +451 -11
- package/dist/chunk-EGPIVUEF.js.map +1 -0
- package/dist/vector/index.cjs +1801 -116
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +373 -7
- package/dist/vector/index.d.ts +373 -7
- package/dist/vector/index.js +1721 -36
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-RK6HUKDI.js.map +0 -1
- package/dist/chunk-UG5DVXJK.cjs.map +0 -1
package/dist/canvas/index.js
CHANGED
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
CANVAS_GRADIENT_PRESETS,
|
|
3
3
|
PathOpsError,
|
|
4
4
|
SHAPE_KINDS,
|
|
5
|
-
add,
|
|
6
5
|
angleToSvgLinearCoords,
|
|
7
6
|
arcToCubics,
|
|
8
7
|
bezierPathArea,
|
|
@@ -15,20 +14,18 @@ import {
|
|
|
15
14
|
contourSignedArea,
|
|
16
15
|
contoursToPath,
|
|
17
16
|
countPathSegments,
|
|
18
|
-
cross,
|
|
19
17
|
cubicPointAt,
|
|
20
18
|
cubicsToPathData,
|
|
21
|
-
|
|
19
|
+
dashContours,
|
|
22
20
|
distanceToBezierPath,
|
|
23
21
|
dividePaths,
|
|
24
22
|
dividePolygons,
|
|
25
|
-
dot,
|
|
26
23
|
excludePaths,
|
|
27
24
|
fitCubicRun,
|
|
25
|
+
fitCubicWithTangents,
|
|
28
26
|
fitCubics,
|
|
29
27
|
fitFreehandPath,
|
|
30
28
|
fitPathData,
|
|
31
|
-
flattenChain,
|
|
32
29
|
flattenSvgPath,
|
|
33
30
|
formatNumber,
|
|
34
31
|
getShapeRenderData,
|
|
@@ -41,12 +38,12 @@ import {
|
|
|
41
38
|
isStraightCubic,
|
|
42
39
|
multiPolygonArea,
|
|
43
40
|
multiPolygonBounds,
|
|
44
|
-
nestedRingsToPath,
|
|
45
41
|
normalizeBezierPath,
|
|
42
|
+
offsetPath,
|
|
43
|
+
outlineStroke,
|
|
46
44
|
parseCssGradient,
|
|
47
45
|
parseSvgPath,
|
|
48
46
|
pathBoolean,
|
|
49
|
-
pathBooleanRings,
|
|
50
47
|
pathToContours,
|
|
51
48
|
pointInBezierPath,
|
|
52
49
|
pointInMultiPolygon,
|
|
@@ -56,8 +53,6 @@ import {
|
|
|
56
53
|
polygonToSvgPath,
|
|
57
54
|
resolveCanvasGradient,
|
|
58
55
|
ringSignedArea,
|
|
59
|
-
samePoint,
|
|
60
|
-
scale,
|
|
61
56
|
segmentBounds,
|
|
62
57
|
segmentCurvature,
|
|
63
58
|
segmentDerivative,
|
|
@@ -71,7 +66,7 @@ import {
|
|
|
71
66
|
shapeToPolygon,
|
|
72
67
|
simplifyRing,
|
|
73
68
|
splitSegment,
|
|
74
|
-
|
|
69
|
+
strokeOutlineRings,
|
|
75
70
|
subSegment,
|
|
76
71
|
subtractPaths,
|
|
77
72
|
subtractPolygons,
|
|
@@ -82,7 +77,7 @@ import {
|
|
|
82
77
|
unitePaths,
|
|
83
78
|
windingNumber,
|
|
84
79
|
xorPolygons
|
|
85
|
-
} from "../chunk-
|
|
80
|
+
} from "../chunk-EGPIVUEF.js";
|
|
86
81
|
import {
|
|
87
82
|
DEFAULT_NODE_HEIGHT,
|
|
88
83
|
DEFAULT_NODE_WIDTH,
|
|
@@ -184,11 +179,11 @@ function createFanOutTrajectory(options = {}) {
|
|
|
184
179
|
const oneMinusT = 1 - t;
|
|
185
180
|
const x = oneMinusT * oneMinusT * origin.x + 2 * oneMinusT * t * midX + t * t * target.x;
|
|
186
181
|
const y = oneMinusT * oneMinusT * origin.y + 2 * oneMinusT * t * midY + t * t * target.y;
|
|
187
|
-
const
|
|
182
|
+
const scale = startScale + (endScale - startScale) * progress;
|
|
188
183
|
const opacity = startOpacity + (endOpacity - startOpacity) * progress;
|
|
189
184
|
return {
|
|
190
185
|
position: { x, y },
|
|
191
|
-
scale
|
|
186
|
+
scale,
|
|
192
187
|
opacity
|
|
193
188
|
};
|
|
194
189
|
};
|
|
@@ -1215,7 +1210,7 @@ function spacingCandidate(rects, moving, horizontal, tolerance) {
|
|
|
1215
1210
|
return best2;
|
|
1216
1211
|
};
|
|
1217
1212
|
const crossMid = (a, b) => (Math.max(crossStart(a), crossStart(b)) + Math.min(crossEnd(a), crossEnd(b))) / 2;
|
|
1218
|
-
const segment = (from, to,
|
|
1213
|
+
const segment = (from, to, cross) => horizontal ? { orientation: "horizontal", kind: "spacing", x1: from, y1: cross, x2: to, y2: cross } : { orientation: "vertical", kind: "spacing", x1: cross, y1: from, x2: cross, y2: to };
|
|
1219
1214
|
const candidates = [];
|
|
1220
1215
|
if (before && after) {
|
|
1221
1216
|
const b = before;
|
|
@@ -1727,447 +1722,6 @@ function fitViewportToNodes(nodes, size, ids, options = {}) {
|
|
|
1727
1722
|
return bounds ? fitViewportToRect(bounds, size, options) : null;
|
|
1728
1723
|
}
|
|
1729
1724
|
|
|
1730
|
-
// src/canvas/pathops/stroke.ts
|
|
1731
|
-
var DEFAULT_TOLERANCE = 0.01;
|
|
1732
|
-
var normal = (t) => [-t[1], t[0]];
|
|
1733
|
-
function raise(seg) {
|
|
1734
|
-
if (seg.length !== 3) return [...seg];
|
|
1735
|
-
const [p0, p1, p2] = seg;
|
|
1736
|
-
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];
|
|
1737
|
-
}
|
|
1738
|
-
function isDegenerate(seg, tol) {
|
|
1739
|
-
return seg.every((p) => dist(p, seg[0]) <= tol);
|
|
1740
|
-
}
|
|
1741
|
-
function offsetSegment(seg, d, tol, out, depth = 0) {
|
|
1742
|
-
if (seg.length === 2) {
|
|
1743
|
-
const n = normal(segmentTangent(seg, 0));
|
|
1744
|
-
out.push([add(seg[0], scale(n, d)), add(seg[1], scale(n, d))]);
|
|
1745
|
-
return;
|
|
1746
|
-
}
|
|
1747
|
-
const c = raise(seg);
|
|
1748
|
-
const t0 = segmentTangent(c, 0);
|
|
1749
|
-
const t1 = segmentTangent(c, 1);
|
|
1750
|
-
const q0 = add(c[0], scale(normal(t0), d));
|
|
1751
|
-
const q3 = add(c[3], scale(normal(t1), d));
|
|
1752
|
-
const k0 = segmentCurvature(c, 0);
|
|
1753
|
-
const k1 = segmentCurvature(c, 1);
|
|
1754
|
-
const f0 = Number.isFinite(k0) ? 1 - d * k0 : 1;
|
|
1755
|
-
const f1 = Number.isFinite(k1) ? 1 - d * k1 : 1;
|
|
1756
|
-
const q1 = add(q0, scale(sub(c[1], c[0]), f0));
|
|
1757
|
-
const q2 = add(q3, scale(sub(c[2], c[3]), f1));
|
|
1758
|
-
const approx = [q0, q1, q2, q3];
|
|
1759
|
-
if (depth < 10) {
|
|
1760
|
-
let err = 0;
|
|
1761
|
-
for (const t of [0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875]) {
|
|
1762
|
-
const target = add(segmentPoint(c, t), scale(normal(segmentTangent(c, t)), d));
|
|
1763
|
-
err = Math.max(err, segmentNearest(approx, target).distance);
|
|
1764
|
-
if (err > tol) break;
|
|
1765
|
-
}
|
|
1766
|
-
if (err <= tol) {
|
|
1767
|
-
const m = segmentPoint(approx, 0.5);
|
|
1768
|
-
const back = segmentNearest(c, m).distance;
|
|
1769
|
-
err = Math.max(err, Math.abs(back - Math.abs(d)));
|
|
1770
|
-
}
|
|
1771
|
-
if (err > tol) {
|
|
1772
|
-
const [a, b] = splitSegment(c, 0.5);
|
|
1773
|
-
offsetSegment(a, d, tol, out, depth + 1);
|
|
1774
|
-
offsetSegment(b, d, tol, out, depth + 1);
|
|
1775
|
-
return;
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
out.push(approx);
|
|
1779
|
-
}
|
|
1780
|
-
function pushArc(out, center, radius, start, sweep, from, to) {
|
|
1781
|
-
const n = Math.max(1, Math.ceil(Math.abs(sweep) / (Math.PI / 2) - 1e-9));
|
|
1782
|
-
const step = sweep / n;
|
|
1783
|
-
const k = 4 / 3 * Math.tan(step / 4);
|
|
1784
|
-
let prev = from;
|
|
1785
|
-
for (let i = 0; i < n; i++) {
|
|
1786
|
-
const a0 = start + step * i;
|
|
1787
|
-
const a1 = a0 + step;
|
|
1788
|
-
const c0 = Math.cos(a0);
|
|
1789
|
-
const s0 = Math.sin(a0);
|
|
1790
|
-
const c1 = Math.cos(a1);
|
|
1791
|
-
const s1 = Math.sin(a1);
|
|
1792
|
-
const end = i === n - 1 ? to : [center[0] + radius * c1, center[1] + radius * s1];
|
|
1793
|
-
out.push([
|
|
1794
|
-
prev,
|
|
1795
|
-
[center[0] + radius * (c0 - k * s0), center[1] + radius * (s0 + k * c0)],
|
|
1796
|
-
[center[0] + radius * (c1 + k * s1), center[1] + radius * (s1 - k * c1)],
|
|
1797
|
-
end
|
|
1798
|
-
]);
|
|
1799
|
-
prev = end;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
function lineTo(out, from, to) {
|
|
1803
|
-
if (!samePoint(from, to)) out.push([from, to]);
|
|
1804
|
-
}
|
|
1805
|
-
function addJoin(out, p, tin, tout, d, style) {
|
|
1806
|
-
const from = add(p, scale(normal(tin), d));
|
|
1807
|
-
const to = add(p, scale(normal(tout), d));
|
|
1808
|
-
const turn = cross(tin, tout);
|
|
1809
|
-
const cos = dot(tin, tout);
|
|
1810
|
-
if (Math.abs(turn) < 1e-9 && cos > 0) {
|
|
1811
|
-
lineTo(out, from, to);
|
|
1812
|
-
return;
|
|
1813
|
-
}
|
|
1814
|
-
const reversal = Math.abs(turn) < 1e-9 && cos < 0;
|
|
1815
|
-
const inner = !reversal && turn > 0 === d > 0;
|
|
1816
|
-
if (inner) {
|
|
1817
|
-
lineTo(out, from, p);
|
|
1818
|
-
lineTo(out, p, to);
|
|
1819
|
-
return;
|
|
1820
|
-
}
|
|
1821
|
-
const theta = reversal ? d > 0 ? -Math.PI : Math.PI : Math.atan2(turn, cos);
|
|
1822
|
-
if (style.join === "round") {
|
|
1823
|
-
const v = sub(from, p);
|
|
1824
|
-
pushArc(out, p, Math.abs(d), Math.atan2(v[1], v[0]), theta, from, to);
|
|
1825
|
-
return;
|
|
1826
|
-
}
|
|
1827
|
-
if (style.join === "miter" && !reversal) {
|
|
1828
|
-
const phi = Math.PI - Math.abs(theta);
|
|
1829
|
-
const ratio = 1 / Math.max(Math.sin(phi / 2), 1e-12);
|
|
1830
|
-
if (ratio <= style.miterLimit) {
|
|
1831
|
-
const nin = normal(tin);
|
|
1832
|
-
const nout = normal(tout);
|
|
1833
|
-
const s = d / (1 + dot(nin, nout));
|
|
1834
|
-
const miter = add(p, scale(add(nin, nout), s));
|
|
1835
|
-
lineTo(out, from, miter);
|
|
1836
|
-
lineTo(out, miter, to);
|
|
1837
|
-
return;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
lineTo(out, from, to);
|
|
1841
|
-
}
|
|
1842
|
-
function offsetChain(segs, d, closed, style, tol) {
|
|
1843
|
-
const out = [];
|
|
1844
|
-
const pen = () => out.length > 0 ? out[out.length - 1][out[out.length - 1].length - 1] : null;
|
|
1845
|
-
for (let i = 0; i < segs.length; i++) {
|
|
1846
|
-
if (i > 0) addJoin(out, segs[i][0], segmentTangent(segs[i - 1], 1), segmentTangent(segs[i], 0), d, style);
|
|
1847
|
-
const pieces = [];
|
|
1848
|
-
offsetSegment(segs[i], d, tol, pieces);
|
|
1849
|
-
for (const piece of pieces) {
|
|
1850
|
-
const at = pen();
|
|
1851
|
-
if (at && !samePoint(at, piece[0])) lineTo(out, at, piece[0]);
|
|
1852
|
-
out.push(piece);
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
if (closed && segs.length > 0) {
|
|
1856
|
-
const last = segs[segs.length - 1];
|
|
1857
|
-
addJoin(out, segs[0][0], segmentTangent(last, 1), segmentTangent(segs[0], 0), d, style);
|
|
1858
|
-
const at = pen();
|
|
1859
|
-
if (at && out.length > 0 && !samePoint(at, out[0][0])) lineTo(out, at, out[0][0]);
|
|
1860
|
-
}
|
|
1861
|
-
return out;
|
|
1862
|
-
}
|
|
1863
|
-
function reverseChain(chain) {
|
|
1864
|
-
return chain.map((s) => [...s].reverse()).reverse();
|
|
1865
|
-
}
|
|
1866
|
-
function addCap(out, p, t, h, cap) {
|
|
1867
|
-
const n = normal(t);
|
|
1868
|
-
const from = add(p, scale(n, h));
|
|
1869
|
-
const to = add(p, scale(n, -h));
|
|
1870
|
-
if (cap === "round") {
|
|
1871
|
-
pushArc(out, p, h, Math.atan2(n[1], n[0]), -Math.PI, from, to);
|
|
1872
|
-
} else if (cap === "square") {
|
|
1873
|
-
const a = add(from, scale(t, h));
|
|
1874
|
-
const b = add(to, scale(t, h));
|
|
1875
|
-
lineTo(out, from, a);
|
|
1876
|
-
lineTo(out, a, b);
|
|
1877
|
-
lineTo(out, b, to);
|
|
1878
|
-
} else {
|
|
1879
|
-
lineTo(out, from, to);
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
|
-
function dotRings(p, t, h, cap) {
|
|
1883
|
-
if (cap === "butt") return [];
|
|
1884
|
-
const ring = [];
|
|
1885
|
-
addCap(ring, p, t, h, cap);
|
|
1886
|
-
addCap(ring, p, [-t[0], -t[1]], h, cap);
|
|
1887
|
-
return [ring];
|
|
1888
|
-
}
|
|
1889
|
-
function strokeContour(contour, h, style, tol) {
|
|
1890
|
-
const tiny = Math.max(1e-12, tol * 1e-6);
|
|
1891
|
-
const all = contour.closed ? closeContour(contour) : contour.segments;
|
|
1892
|
-
const segs = all.filter((s) => !isDegenerate(s, tiny));
|
|
1893
|
-
if (segs.length === 0) {
|
|
1894
|
-
const p = contour.segments[0]?.[0];
|
|
1895
|
-
return p ? dotRings(p, [1, 0], h, style.cap) : [];
|
|
1896
|
-
}
|
|
1897
|
-
if (contour.closed) {
|
|
1898
|
-
const left2 = offsetChain(segs, h, true, style, tol);
|
|
1899
|
-
const right2 = offsetChain(segs, -h, true, style, tol);
|
|
1900
|
-
return [left2, reverseChain(right2)];
|
|
1901
|
-
}
|
|
1902
|
-
const left = offsetChain(segs, h, false, style, tol);
|
|
1903
|
-
const right = reverseChain(offsetChain(segs, -h, false, style, tol));
|
|
1904
|
-
const ring = [...left];
|
|
1905
|
-
const last = segs[segs.length - 1];
|
|
1906
|
-
addCap(ring, last[last.length - 1], segmentTangent(last, 1), h, style.cap);
|
|
1907
|
-
const joinTo = (p) => {
|
|
1908
|
-
const at = ring[ring.length - 1][ring[ring.length - 1].length - 1];
|
|
1909
|
-
lineTo(ring, at, p);
|
|
1910
|
-
};
|
|
1911
|
-
if (right.length > 0) joinTo(right[0][0]);
|
|
1912
|
-
ring.push(...right);
|
|
1913
|
-
const first = segs[0];
|
|
1914
|
-
const t0 = segmentTangent(first, 0);
|
|
1915
|
-
addCap(ring, first[0], [-t0[0], -t0[1]], h, style.cap);
|
|
1916
|
-
if (ring.length > 0) joinTo(ring[0][0]);
|
|
1917
|
-
return [ring];
|
|
1918
|
-
}
|
|
1919
|
-
function ringsToPath(rings) {
|
|
1920
|
-
return contoursToPath(rings.filter((r) => r.length > 0).map((segments) => ({ segments, closed: true })));
|
|
1921
|
-
}
|
|
1922
|
-
var MAX_DASHES = 2e5;
|
|
1923
|
-
var MIN_ENTRY = 1e-6;
|
|
1924
|
-
function dashContours(contours, pattern, offset = 0) {
|
|
1925
|
-
if (pattern.length === 0 || pattern.some((v) => !Number.isFinite(v) || v < 0) || !Number.isFinite(offset)) return null;
|
|
1926
|
-
if (!pattern.some((v) => v > MIN_ENTRY)) return null;
|
|
1927
|
-
const pat = pattern.length % 2 === 1 ? [...pattern, ...pattern] : [...pattern];
|
|
1928
|
-
const period = pat.reduce((s, v) => s + v, 0);
|
|
1929
|
-
const chains = contours.map((c) => {
|
|
1930
|
-
const segs = closeContour(c);
|
|
1931
|
-
const lengths = segs.map((s) => segmentLength(s));
|
|
1932
|
-
return { segs, lengths, total: lengths.reduce((s, v) => s + v, 0), closed: c.closed };
|
|
1933
|
-
});
|
|
1934
|
-
const totalLength = chains.reduce((s, c) => s + c.total, 0);
|
|
1935
|
-
if (totalLength / period * pat.length > MAX_DASHES) return null;
|
|
1936
|
-
let off = (offset % period + period) % period;
|
|
1937
|
-
let ix0 = 0;
|
|
1938
|
-
while (off > pat[ix0]) {
|
|
1939
|
-
off -= pat[ix0];
|
|
1940
|
-
ix0 = (ix0 + 1) % pat.length;
|
|
1941
|
-
}
|
|
1942
|
-
const out = { contours: [], dots: [] };
|
|
1943
|
-
for (const chain of chains) {
|
|
1944
|
-
if (chain.segs.length === 0 || !(chain.total > 0)) continue;
|
|
1945
|
-
let ix = ix0;
|
|
1946
|
-
let rem = pat[ix0] - off;
|
|
1947
|
-
let pos = 0;
|
|
1948
|
-
const dashes = [];
|
|
1949
|
-
let guard = 0;
|
|
1950
|
-
while (pos < chain.total && guard++ < MAX_DASHES * 2) {
|
|
1951
|
-
const step = Math.min(rem, chain.total - pos);
|
|
1952
|
-
const on = ix % 2 === 0;
|
|
1953
|
-
if (on) dashes.push({ from: pos, to: pos + step });
|
|
1954
|
-
pos += step;
|
|
1955
|
-
rem -= step;
|
|
1956
|
-
if (rem <= 1e-12) {
|
|
1957
|
-
ix = (ix + 1) % pat.length;
|
|
1958
|
-
rem = pat[ix];
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
if (chain.closed && dashes.length > 1) {
|
|
1962
|
-
const first = dashes[0];
|
|
1963
|
-
const last = dashes[dashes.length - 1];
|
|
1964
|
-
if (first.from <= 1e-9 && last.to >= chain.total - 1e-9 && first.to > first.from && last.to > last.from) {
|
|
1965
|
-
dashes.pop();
|
|
1966
|
-
const tail = trimSegments(chain.segs, last.from, chain.total, chain.lengths);
|
|
1967
|
-
const head = trimSegments(chain.segs, 0, first.to, chain.lengths);
|
|
1968
|
-
dashes.shift();
|
|
1969
|
-
out.contours.push({ segments: [...tail, ...head], closed: false });
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
for (const dash of dashes) {
|
|
1973
|
-
if (dash.to - dash.from <= 1e-12) {
|
|
1974
|
-
const at = locate(chain.segs, chain.lengths, dash.from);
|
|
1975
|
-
out.dots.push(at);
|
|
1976
|
-
continue;
|
|
1977
|
-
}
|
|
1978
|
-
const segments = trimSegments(chain.segs, dash.from, dash.to, chain.lengths);
|
|
1979
|
-
if (segments.length > 0) out.contours.push({ segments, closed: false });
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
return out;
|
|
1983
|
-
}
|
|
1984
|
-
function locate(segs, lengths, at) {
|
|
1985
|
-
let acc = 0;
|
|
1986
|
-
for (let i = 0; i < segs.length; i++) {
|
|
1987
|
-
if (at <= acc + lengths[i] || i === segs.length - 1) {
|
|
1988
|
-
const piece = trimSegments([segs[i]], 0, Math.max(0, at - acc), [lengths[i]]);
|
|
1989
|
-
const t = piece.length > 0 ? 1 : 0;
|
|
1990
|
-
const point = piece.length > 0 ? piece[piece.length - 1][piece[piece.length - 1].length - 1] : segs[i][0];
|
|
1991
|
-
const tangent = segmentTangent(piece.length > 0 ? piece[piece.length - 1] : segs[i], t);
|
|
1992
|
-
return { point, tangent };
|
|
1993
|
-
}
|
|
1994
|
-
acc += lengths[i];
|
|
1995
|
-
}
|
|
1996
|
-
return { point: segs[0][0], tangent: segmentTangent(segs[0], 0) };
|
|
1997
|
-
}
|
|
1998
|
-
function deepPoint(rings) {
|
|
1999
|
-
let minX = Infinity;
|
|
2000
|
-
let minY = Infinity;
|
|
2001
|
-
let maxX = -Infinity;
|
|
2002
|
-
let maxY = -Infinity;
|
|
2003
|
-
for (const p of rings[0].flat()) {
|
|
2004
|
-
minX = Math.min(minX, p[0]);
|
|
2005
|
-
maxX = Math.max(maxX, p[0]);
|
|
2006
|
-
minY = Math.min(minY, p[1]);
|
|
2007
|
-
maxY = Math.max(maxY, p[1]);
|
|
2008
|
-
}
|
|
2009
|
-
const w = maxX - minX;
|
|
2010
|
-
const h = maxY - minY;
|
|
2011
|
-
if (!(w > 0 && h > 0)) return null;
|
|
2012
|
-
const tolerance = Math.max(1e-6, 2e-3 * Math.min(w, h));
|
|
2013
|
-
const polys = rings.map((r) => flattenChain(r, tolerance));
|
|
2014
|
-
let best = null;
|
|
2015
|
-
for (const f of [0.5, 0.3, 0.7, 0.15, 0.85]) {
|
|
2016
|
-
const y = minY + h * f;
|
|
2017
|
-
const xs = [];
|
|
2018
|
-
for (const poly of polys) {
|
|
2019
|
-
for (let i = 0; i < poly.length; i++) {
|
|
2020
|
-
const a = poly[i];
|
|
2021
|
-
const b = poly[(i + 1) % poly.length];
|
|
2022
|
-
if (a[1] <= y !== b[1] <= y) xs.push(a[0] + (y - a[1]) / (b[1] - a[1]) * (b[0] - a[0]));
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
xs.sort((p, q) => p - q);
|
|
2026
|
-
for (let i = 0; i + 1 < xs.length; i += 2) {
|
|
2027
|
-
const span = xs[i + 1] - xs[i];
|
|
2028
|
-
if (!best || span > best.span) best = { span, p: [(xs[i] + xs[i + 1]) / 2, y] };
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
return best?.p ?? null;
|
|
2032
|
-
}
|
|
2033
|
-
function dropSpurious(rings, spurious) {
|
|
2034
|
-
const children = rings.map(() => []);
|
|
2035
|
-
rings.forEach((r, i) => {
|
|
2036
|
-
if (r.parent >= 0) children[r.parent].push(i);
|
|
2037
|
-
});
|
|
2038
|
-
const marked = rings.map((r, i) => spurious([r.segments, ...children[i].map((c) => rings[c].segments)], r));
|
|
2039
|
-
const hasMarkedAncestor = (i) => {
|
|
2040
|
-
for (let k = i; k >= 0; k = rings[k].parent) if (marked[k]) return true;
|
|
2041
|
-
return false;
|
|
2042
|
-
};
|
|
2043
|
-
return nestedRingsToPath(rings, (i) => !hasMarkedAncestor(i));
|
|
2044
|
-
}
|
|
2045
|
-
function mergeSmoothRuns(path, tolerance) {
|
|
2046
|
-
const contours = pathToContours(path).map((contour) => {
|
|
2047
|
-
const segs = closeContour(contour, true).map((s) => s.length === 3 ? raise(s) : [...s]);
|
|
2048
|
-
const n = segs.length;
|
|
2049
|
-
if (n < 2) return { segments: segs, closed: true };
|
|
2050
|
-
const smooth = (a, b) => {
|
|
2051
|
-
if (a.length !== 4 || b.length !== 4) return false;
|
|
2052
|
-
const ta = segmentTangent(a, 1);
|
|
2053
|
-
const tb = segmentTangent(b, 0);
|
|
2054
|
-
return dot(ta, tb) > 0.9998 && Math.abs(cross(ta, tb)) < 0.02;
|
|
2055
|
-
};
|
|
2056
|
-
let start = 0;
|
|
2057
|
-
for (let k = 0; k < n; k++) {
|
|
2058
|
-
if (!smooth(segs[(k + n - 1) % n], segs[k])) {
|
|
2059
|
-
start = k;
|
|
2060
|
-
break;
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
const ordered = [...segs.slice(start), ...segs.slice(0, start)];
|
|
2064
|
-
const out = [];
|
|
2065
|
-
let i = 0;
|
|
2066
|
-
while (i < ordered.length) {
|
|
2067
|
-
let current = ordered[i];
|
|
2068
|
-
let j = i + 1;
|
|
2069
|
-
while (j < ordered.length && smooth(ordered[j - 1], ordered[j])) {
|
|
2070
|
-
const run = ordered.slice(i, j + 1);
|
|
2071
|
-
const pts = [];
|
|
2072
|
-
run.forEach((s, k) => {
|
|
2073
|
-
for (let q = k === 0 ? 0 : 1; q <= 12; q++) pts.push(segmentPoint(s, q / 12));
|
|
2074
|
-
});
|
|
2075
|
-
const fit = fitCubicRun(pts, tolerance, segmentTangent(run[0], 0), segmentTangent(run[run.length - 1], 1));
|
|
2076
|
-
if (fit.length !== 1) break;
|
|
2077
|
-
const c = fit[0];
|
|
2078
|
-
current = [run[0][0], c.p1, c.p2, run[run.length - 1][3]];
|
|
2079
|
-
j++;
|
|
2080
|
-
}
|
|
2081
|
-
out.push(current);
|
|
2082
|
-
i = j;
|
|
2083
|
-
}
|
|
2084
|
-
return { segments: out, closed: true };
|
|
2085
|
-
});
|
|
2086
|
-
return contoursToPath(contours);
|
|
2087
|
-
}
|
|
2088
|
-
function joinStyle(join, miterLimit) {
|
|
2089
|
-
return {
|
|
2090
|
-
join: join ?? "miter",
|
|
2091
|
-
miterLimit: miterLimit !== void 0 && Number.isFinite(miterLimit) ? Math.max(1, miterLimit) : 4
|
|
2092
|
-
};
|
|
2093
|
-
}
|
|
2094
|
-
function strokeOutlineRings(input, options) {
|
|
2095
|
-
const h = options.width / 2;
|
|
2096
|
-
if (!(h > 0) || !Number.isFinite(h)) return [];
|
|
2097
|
-
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
2098
|
-
const style = { ...joinStyle(options.join, options.miterLimit), cap: options.cap ?? "butt" };
|
|
2099
|
-
let contours = pathToContours(input);
|
|
2100
|
-
const rings = [];
|
|
2101
|
-
if (options.dash && options.dash.length > 0) {
|
|
2102
|
-
const dashed = dashContours(contours, options.dash, options.dashOffset ?? 0);
|
|
2103
|
-
if (dashed) {
|
|
2104
|
-
contours = dashed.contours;
|
|
2105
|
-
for (const dot2 of dashed.dots) rings.push(...dotRings(dot2.point, dot2.tangent, h, style.cap));
|
|
2106
|
-
}
|
|
2107
|
-
}
|
|
2108
|
-
for (const contour of contours) rings.push(...strokeContour(contour, h, style, tol));
|
|
2109
|
-
return ringsToPath(rings);
|
|
2110
|
-
}
|
|
2111
|
-
function outlineStroke(input, options) {
|
|
2112
|
-
const h = options.width / 2;
|
|
2113
|
-
if (!(h > 0) || !Number.isFinite(h)) return [];
|
|
2114
|
-
let source;
|
|
2115
|
-
try {
|
|
2116
|
-
source = contoursToPath(pathToContours(input));
|
|
2117
|
-
} catch {
|
|
2118
|
-
return [];
|
|
2119
|
-
}
|
|
2120
|
-
if (source.some((c) => c.type !== "Z" && Object.values(c).some((v) => typeof v === "number" && !Number.isFinite(v)))) return [];
|
|
2121
|
-
const raw = strokeOutlineRings(source, options);
|
|
2122
|
-
if (raw.length === 0) return [];
|
|
2123
|
-
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
2124
|
-
const sourceContours = pathToContours(source);
|
|
2125
|
-
const operand = { path: raw, fillRule: "nonzero" };
|
|
2126
|
-
try {
|
|
2127
|
-
const rings = pathBooleanRings("union", [operand], options);
|
|
2128
|
-
const cleaned = dropSpurious(rings, (face, ring) => {
|
|
2129
|
-
if (ring.area >= 0) return false;
|
|
2130
|
-
const p = deepPoint(face);
|
|
2131
|
-
return !!p && distanceToBezierPath(sourceContours, p) < h * (1 - 1e-4) - 1e-6;
|
|
2132
|
-
});
|
|
2133
|
-
return mergeSmoothRuns(cleaned, tol);
|
|
2134
|
-
} catch {
|
|
2135
|
-
return pathBoolean("union", [operand], options).path;
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
function offsetPath(input, distance, options = {}) {
|
|
2139
|
-
if (!Number.isFinite(distance)) return [];
|
|
2140
|
-
const contours = pathToContours(input);
|
|
2141
|
-
if (contours.some((c) => c.segments.some((s) => s.some((p) => !Number.isFinite(p[0]) || !Number.isFinite(p[1]))))) return [];
|
|
2142
|
-
const closed = contours.filter((c) => c.closed && c.segments.length > 0);
|
|
2143
|
-
const open = contours.filter((c) => !c.closed && c.segments.length > 0);
|
|
2144
|
-
const fillRule = options.fillRule ?? "nonzero";
|
|
2145
|
-
const fill = { path: contoursToPath(closed), fillRule };
|
|
2146
|
-
const d = Math.abs(distance);
|
|
2147
|
-
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : DEFAULT_TOLERANCE;
|
|
2148
|
-
if (d === 0) return pathBoolean("union", [fill], options).path;
|
|
2149
|
-
const strokeOptions = { width: 2 * d, join: options.join ?? "miter", miterLimit: options.miterLimit, cap: "butt", tolerance: tol };
|
|
2150
|
-
const ring = { path: strokeOutlineRings(contoursToPath(closed), strokeOptions), fillRule: "nonzero" };
|
|
2151
|
-
const openRing = {
|
|
2152
|
-
path: distance > 0 ? strokeOutlineRings(contoursToPath(open), strokeOptions) : [],
|
|
2153
|
-
fillRule: "nonzero"
|
|
2154
|
-
};
|
|
2155
|
-
const grow = distance > 0;
|
|
2156
|
-
const operands = [fill, ring, openRing];
|
|
2157
|
-
try {
|
|
2158
|
-
const rings = pathBooleanRings(grow ? (m) => m[0] || m[1] || m[2] : (m) => m[0] && !m[1], operands, options);
|
|
2159
|
-
const sourceContours = contours;
|
|
2160
|
-
const cleaned = dropSpurious(rings, (face, r) => {
|
|
2161
|
-
if (grow ? r.area >= 0 : r.area <= 0) return false;
|
|
2162
|
-
const p = deepPoint(face);
|
|
2163
|
-
return !!p && distanceToBezierPath(sourceContours, p) < d * (1 - 1e-4) - 1e-6;
|
|
2164
|
-
});
|
|
2165
|
-
return mergeSmoothRuns(cleaned, tol);
|
|
2166
|
-
} catch {
|
|
2167
|
-
return grow ? pathBoolean("union", operands, options).path : pathBoolean("difference", [fill, ring], options).path;
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
1725
|
// src/canvas/shapeNodes.ts
|
|
2172
1726
|
var SHAPE_DATA_KEY = "shape";
|
|
2173
1727
|
var SHAPE_NODE_TYPE = "shape";
|
|
@@ -2656,8 +2210,8 @@ function snapResize(rect, handle, targets, options = {}) {
|
|
|
2656
2210
|
const ratio = rect.height > 0 ? rect.width / rect.height : 0;
|
|
2657
2211
|
if (options.keepAspectRatio && ratio > 0 && (hitX || hitY)) {
|
|
2658
2212
|
if (axes.x !== 0 && axes.y !== 0) {
|
|
2659
|
-
const
|
|
2660
|
-
const useX =
|
|
2213
|
+
const dist = (h, horizontal) => h ? Math.abs(h.value - (horizontal ? axes.x < 0 ? x0 : x1 : axes.y < 0 ? y0 : y1)) : Infinity;
|
|
2214
|
+
const useX = dist(hitX, true) <= dist(hitY, false);
|
|
2661
2215
|
if (useX && hitX) {
|
|
2662
2216
|
setEdge(true, hitX.value);
|
|
2663
2217
|
const height = (nx1 - nx0) / ratio;
|
|
@@ -3022,7 +2576,7 @@ function layoutFrameInner(s, frame) {
|
|
|
3022
2576
|
const b = s.boxes.get(id);
|
|
3023
2577
|
return horizontal ? [b.w, b.h] : [b.h, b.w];
|
|
3024
2578
|
};
|
|
3025
|
-
const resize = (it, main,
|
|
2579
|
+
const resize = (it, main, cross) => resizeChild(s, it.id, horizontal ? main : cross, horizontal ? cross : main);
|
|
3026
2580
|
if (!wraps) {
|
|
3027
2581
|
for (const it of items) {
|
|
3028
2582
|
if (!it.fillCross || it.fillMain) continue;
|
|
@@ -3036,13 +2590,13 @@ function layoutFrameInner(s, frame) {
|
|
|
3036
2590
|
let used = 0;
|
|
3037
2591
|
items.forEach((it, i) => {
|
|
3038
2592
|
const sz = it.fillMain ? it.minMain ?? 0 : it.main;
|
|
3039
|
-
const
|
|
3040
|
-
if (cur.length > 0 && used +
|
|
2593
|
+
const add = cur.length === 0 ? sz : Math.max(gap, 0) + sz;
|
|
2594
|
+
if (cur.length > 0 && used + add > innerMainFixed + 1e-6) {
|
|
3041
2595
|
lines.push(cur);
|
|
3042
2596
|
cur = [];
|
|
3043
2597
|
used = sz;
|
|
3044
2598
|
} else {
|
|
3045
|
-
used +=
|
|
2599
|
+
used += add;
|
|
3046
2600
|
}
|
|
3047
2601
|
cur.push(i);
|
|
3048
2602
|
});
|
|
@@ -3058,8 +2612,8 @@ function layoutFrameInner(s, frame) {
|
|
|
3058
2612
|
}
|
|
3059
2613
|
for (const it of items) {
|
|
3060
2614
|
if (!it.fillMain) continue;
|
|
3061
|
-
const
|
|
3062
|
-
resize(it, it.main,
|
|
2615
|
+
const cross = it.fillCross && !wraps ? clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross) : it.cross;
|
|
2616
|
+
resize(it, it.main, cross);
|
|
3063
2617
|
it.cross = sizeOf2(it.id)[1];
|
|
3064
2618
|
}
|
|
3065
2619
|
if (baseline) {
|
|
@@ -3073,8 +2627,8 @@ function layoutFrameInner(s, frame) {
|
|
|
3073
2627
|
const inLine = line2.map((i) => items[i]);
|
|
3074
2628
|
const mainUsed = inLine.reduce((sum, it) => sum + it.main, 0) + gaps;
|
|
3075
2629
|
const allFill = inLine.every((it) => it.fillCross);
|
|
3076
|
-
const
|
|
3077
|
-
extents.push([mainUsed,
|
|
2630
|
+
const cross = inLine.filter((it) => allFill || !it.fillCross).reduce((m, it) => Math.max(m, it.baseOff + it.cross), 0);
|
|
2631
|
+
extents.push([mainUsed, cross]);
|
|
3078
2632
|
}
|
|
3079
2633
|
const contentMain = extents.reduce((m, l) => Math.max(m, l[0]), 0);
|
|
3080
2634
|
let crossGap = al.rowGap !== void 0 ? finite(al.rowGap) : gap;
|
|
@@ -3556,13 +3110,13 @@ function getAutoLayoutInsertTarget(nodes, frameId, point, options = {}) {
|
|
|
3556
3110
|
const horizontal = al.mode !== "vertical";
|
|
3557
3111
|
const main = (b) => horizontal ? b.x : b.y;
|
|
3558
3112
|
const mainSize = (b) => horizontal ? b.w : b.h;
|
|
3559
|
-
const
|
|
3113
|
+
const cross = (b) => horizontal ? b.y : b.x;
|
|
3560
3114
|
const crossSize = (b) => horizontal ? b.h : b.w;
|
|
3561
3115
|
const p = { x: px2, y: py };
|
|
3562
3116
|
const multiLine = al.mode === "grid" || !!al.wrap;
|
|
3563
3117
|
let index = 0;
|
|
3564
3118
|
for (const b of siblings) {
|
|
3565
|
-
const before = multiLine ?
|
|
3119
|
+
const before = multiLine ? cross(b) + crossSize(b) <= cross(p) || cross(b) <= cross(p) && main(b) + mainSize(b) / 2 < main(p) : main(b) + mainSize(b) / 2 < main(p);
|
|
3566
3120
|
if (before) index += 1;
|
|
3567
3121
|
}
|
|
3568
3122
|
const [pt, pr, pb, pl] = resolvePadding(al.padding);
|
|
@@ -3571,13 +3125,13 @@ function getAutoLayoutInsertTarget(nodes, frameId, point, options = {}) {
|
|
|
3571
3125
|
const f = s.boxes.get(frameId);
|
|
3572
3126
|
let guide;
|
|
3573
3127
|
if (horizontal) {
|
|
3574
|
-
const x = prev && next && Math.abs(
|
|
3128
|
+
const x = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.x + prev.w + next.x) / 2 : prev ? prev.x + prev.w : next ? next.x : pl;
|
|
3575
3129
|
const ref = next ?? prev;
|
|
3576
3130
|
const y1 = ref ? ref.y : pt;
|
|
3577
3131
|
const y2 = ref ? ref.y + ref.h : f.h - pb;
|
|
3578
3132
|
guide = { orientation: "vertical", kind: "edge", x1: origin.x + x, y1: origin.y + y1, x2: origin.x + x, y2: origin.y + y2 };
|
|
3579
3133
|
} else {
|
|
3580
|
-
const y = prev && next && Math.abs(
|
|
3134
|
+
const y = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.y + prev.h + next.y) / 2 : prev ? prev.y + prev.h : next ? next.y : pt;
|
|
3581
3135
|
const ref = next ?? prev;
|
|
3582
3136
|
const x1 = ref ? ref.x : pl;
|
|
3583
3137
|
const x2 = ref ? ref.x + ref.w : f.w - pr;
|
|
@@ -6449,8 +6003,8 @@ function sizeOf(node) {
|
|
|
6449
6003
|
return { width: node.width, height: node.height, styleWidth: s.width, styleHeight: s.height };
|
|
6450
6004
|
}
|
|
6451
6005
|
var splitGroup = (group) => {
|
|
6452
|
-
const
|
|
6453
|
-
return
|
|
6006
|
+
const dot = group.indexOf(".");
|
|
6007
|
+
return dot < 0 ? [group, ""] : [group.slice(0, dot), group.slice(dot + 1)];
|
|
6454
6008
|
};
|
|
6455
6009
|
function readOverrideGroup(node, group) {
|
|
6456
6010
|
const data = dataOf(node);
|
|
@@ -6563,7 +6117,7 @@ function listGroups(node, out) {
|
|
|
6563
6117
|
if (LINK_KEYS.has(k)) continue;
|
|
6564
6118
|
const prefix = NESTED_KEYS[k];
|
|
6565
6119
|
if (prefix) {
|
|
6566
|
-
if (isRecord(v)) for (const
|
|
6120
|
+
if (isRecord(v)) for (const sub of Object.keys(v)) out.add(`${prefix}.${sub}`);
|
|
6567
6121
|
continue;
|
|
6568
6122
|
}
|
|
6569
6123
|
out.add(`data.${k}`);
|
|
@@ -7876,11 +7430,11 @@ function restoreCanvasMainComponent(nodes, id, options = {}) {
|
|
|
7876
7430
|
if (g.get(inst.componentId)) return fail(nodes, "invalid", "The main component still exists.");
|
|
7877
7431
|
if (enclosingInstanceIn(g, id) !== void 0) return fail(nodes, "nested-instance", "Select the outer instance.");
|
|
7878
7432
|
const compId = inst.componentId;
|
|
7879
|
-
const
|
|
7433
|
+
const sub = g.subtree(id);
|
|
7880
7434
|
const map = /* @__PURE__ */ new Map([[id, compId]]);
|
|
7881
7435
|
const taken = new Set(nodes.map((n) => n.id));
|
|
7882
7436
|
taken.add(compId);
|
|
7883
|
-
for (const d of
|
|
7437
|
+
for (const d of sub) {
|
|
7884
7438
|
if (d === id) continue;
|
|
7885
7439
|
const src = enclosingInstanceIn(g, d) === id ? getComponentSourceId(g.get(d)) : void 0;
|
|
7886
7440
|
if (src && !taken.has(src)) {
|
|
@@ -7890,7 +7444,7 @@ function restoreCanvasMainComponent(nodes, id, options = {}) {
|
|
|
7890
7444
|
}
|
|
7891
7445
|
const nested = [];
|
|
7892
7446
|
const replaced = /* @__PURE__ */ new Map();
|
|
7893
|
-
for (const d of
|
|
7447
|
+
for (const d of sub) {
|
|
7894
7448
|
let n = g.get(d);
|
|
7895
7449
|
const nid = map.get(d) ?? d;
|
|
7896
7450
|
const parentId = n.parentId !== void 0 ? map.get(n.parentId) ?? n.parentId : void 0;
|
|
@@ -8057,15 +7611,15 @@ function addCanvasVariant(nodes, setId, options = {}) {
|
|
|
8057
7611
|
const taken = new Set(g.byId.keys());
|
|
8058
7612
|
taken.add(id);
|
|
8059
7613
|
const map = /* @__PURE__ */ new Map([[fromId, id]]);
|
|
8060
|
-
const
|
|
8061
|
-
for (const d of
|
|
7614
|
+
const sub = g.subtree(fromId);
|
|
7615
|
+
for (const d of sub) {
|
|
8062
7616
|
if (d === fromId) continue;
|
|
8063
7617
|
const nid = uniqueId(`${id}-${d}`, taken);
|
|
8064
7618
|
taken.add(nid);
|
|
8065
7619
|
map.set(d, nid);
|
|
8066
7620
|
}
|
|
8067
7621
|
const order = variantOrder([...edit.variants.map((v) => v.id), id], edit.values);
|
|
8068
|
-
const subSet = new Set(
|
|
7622
|
+
const subSet = new Set(sub);
|
|
8069
7623
|
const copies = nodes.filter((n) => subSet.has(n.id)).map((n) => {
|
|
8070
7624
|
const next = { ...n, id: map.get(n.id) };
|
|
8071
7625
|
if (n.parentId !== void 0 && n.id !== fromId) next.parentId = map.get(n.parentId) ?? n.parentId;
|
|
@@ -8624,8 +8178,8 @@ function findStrokesAtPoint(point, nodes, radius = 12) {
|
|
|
8624
8178
|
}
|
|
8625
8179
|
const localPoint = [point[0] - rect.x, point[1] - rect.y];
|
|
8626
8180
|
try {
|
|
8627
|
-
const
|
|
8628
|
-
if (
|
|
8181
|
+
const dist = distanceToBezierPath(shape.d, localPoint);
|
|
8182
|
+
if (dist <= effectiveRadius) {
|
|
8629
8183
|
matches2.push(node);
|
|
8630
8184
|
}
|
|
8631
8185
|
} catch {
|
|
@@ -8930,6 +8484,7 @@ export {
|
|
|
8930
8484
|
findStrokesAtPoint,
|
|
8931
8485
|
findVariant,
|
|
8932
8486
|
fitCubicRun,
|
|
8487
|
+
fitCubicWithTangents,
|
|
8933
8488
|
fitCubics,
|
|
8934
8489
|
fitFreehandPath,
|
|
8935
8490
|
fitPathData,
|