@pixerate/editor 0.35.0 → 0.36.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/vector/index.cjs +1118 -261
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +326 -20
- package/dist/vector/index.d.ts +326 -20
- package/dist/vector/index.js +1032 -175
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
package/dist/vector/index.cjs
CHANGED
|
@@ -22,6 +22,10 @@ var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
25
29
|
|
|
26
30
|
|
|
27
31
|
|
|
@@ -30,17 +34,430 @@ var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
|
|
|
30
34
|
var _chunkBGNPT5PEcjs = require('../chunk-BGNPT5PE.cjs');
|
|
31
35
|
|
|
32
36
|
// src/vector/types.ts
|
|
37
|
+
var VECTOR_CORNER_KINDS = ["round", "inverted", "chamfer"];
|
|
38
|
+
var VECTOR_ARROWHEADS = ["triangle", "arrow", "open", "circle", "square", "bar"];
|
|
33
39
|
var VECTOR_TOOLS = ["select", "direct", "pen", "pencil", "rect", "ellipse", "polygon", "star", "line", "scissors", "knife", "eraser"];
|
|
34
40
|
var VECTOR_TRANSFORM_HANDLES = ["nw", "n", "ne", "e", "se", "s", "sw", "w", "rotate"];
|
|
35
41
|
|
|
36
|
-
// src/vector/
|
|
42
|
+
// src/vector/corners.ts
|
|
37
43
|
var EPS = 1e-9;
|
|
44
|
+
var MIN_SINE = 1e-6;
|
|
45
|
+
var sub = (a, b) => ({ x: a.x - b.x, y: a.y - b.y });
|
|
46
|
+
var add = (a, b) => ({ x: a.x + b.x, y: a.y + b.y });
|
|
47
|
+
var mul = (a, k) => ({ x: a.x * k, y: a.y * k });
|
|
48
|
+
var dot = (a, b) => a.x * b.x + a.y * b.y;
|
|
49
|
+
var cross = (a, b) => a.x * b.y - a.y * b.x;
|
|
50
|
+
var len = (a) => Math.hypot(a.x, a.y);
|
|
51
|
+
var pt = (p) => [p.x, p.y];
|
|
52
|
+
var vec = (p) => ({ x: p[0], y: p[1] });
|
|
53
|
+
var onAnchor = (a, h) => !h || Math.abs(h.x - a.x) < EPS && Math.abs(h.y - a.y) < EPS;
|
|
54
|
+
var Side = class {
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
constructor(a, h1, h2, b) {
|
|
59
|
+
this.straight = onAnchor(a, h1) && onAnchor(b, h2);
|
|
60
|
+
this.curve = this.straight ? [pt(a), pt(b)] : [pt(a), pt(_nullishCoalesce(h1, () => ( a))), pt(_nullishCoalesce(h2, () => ( b))), pt(b)];
|
|
61
|
+
this.length = this.straight ? Math.hypot(b.x - a.x, b.y - a.y) : _chunkBGNPT5PEcjs.segmentLength.call(void 0, this.curve);
|
|
62
|
+
}
|
|
63
|
+
/** Unit direction the side leaves the corner in (towards its first control point off the corner). */
|
|
64
|
+
direction() {
|
|
65
|
+
const p0 = vec(this.curve[0]);
|
|
66
|
+
for (const q of this.curve.slice(1)) {
|
|
67
|
+
const d = sub(vec(q), p0);
|
|
68
|
+
const l = len(d);
|
|
69
|
+
if (l > EPS) return mul(d, 1 / l);
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
/** The point `s` along the side from the corner: its parameter, position and the direction the side runs on in there. */
|
|
74
|
+
at(s, u) {
|
|
75
|
+
if (this.straight) {
|
|
76
|
+
const t2 = this.length > EPS ? Math.min(1, Math.max(0, s / this.length)) : 0;
|
|
77
|
+
return { t: t2, p: add(vec(this.curve[0]), mul(u, s)), dir: u };
|
|
78
|
+
}
|
|
79
|
+
const t = _chunkBGNPT5PEcjs.segmentParamAtLength.call(void 0, this.curve, s, this.length);
|
|
80
|
+
const d = vec(_chunkBGNPT5PEcjs.segmentDerivative.call(void 0, this.curve, t));
|
|
81
|
+
const l = len(d);
|
|
82
|
+
return { t, p: vec(_chunkBGNPT5PEcjs.segmentPoint.call(void 0, this.curve, t)), dir: l > EPS ? mul(d, 1 / l) : u };
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function cornerOf(sp, s, i) {
|
|
86
|
+
const n = sp.anchors.length;
|
|
87
|
+
if (n < 2 || !sp.closed && (i === 0 || i === n - 1)) return null;
|
|
88
|
+
if (n === 2 && sp.closed) return null;
|
|
89
|
+
const a = sp.anchors[i];
|
|
90
|
+
if (a.type === "smooth" || a.type === "symmetric") return null;
|
|
91
|
+
const prev = sp.anchors[(i - 1 + n) % n];
|
|
92
|
+
const next = sp.anchors[(i + 1) % n];
|
|
93
|
+
const sideU = new Side(a, a.in, prev.out, prev);
|
|
94
|
+
const sideV = new Side(a, a.out, next.in, next);
|
|
95
|
+
const u = sideU.direction();
|
|
96
|
+
const v2 = sideV.direction();
|
|
97
|
+
if (!u || !v2) return null;
|
|
98
|
+
const lu = sideU.length;
|
|
99
|
+
const lv = sideV.length;
|
|
100
|
+
if (!(lu > EPS && lv > EPS) || !Number.isFinite(lu) || !Number.isFinite(lv)) return null;
|
|
101
|
+
const cos = Math.max(-1, Math.min(1, dot(u, v2)));
|
|
102
|
+
const sin = Math.abs(cross(u, v2));
|
|
103
|
+
if (sin <= MIN_SINE) return null;
|
|
104
|
+
return { subpath: s, index: i, at: { x: a.x, y: a.y }, u, v: v2, lu, lv, cos, sin, angle: Math.atan2(sin, cos) * 180 / Math.PI, maxRadius: Math.min(lu, lv) / 2 * sin / (1 + cos), sideU, sideV };
|
|
105
|
+
}
|
|
106
|
+
var strip = ({ sideU: _u, sideV: _v, ...info }) => info;
|
|
107
|
+
function vectorCornerAt(sp, index, subpath = 0) {
|
|
108
|
+
const c = cornerOf(sp, subpath, index);
|
|
109
|
+
return c ? strip(c) : null;
|
|
110
|
+
}
|
|
111
|
+
function vectorCorners(subpaths) {
|
|
112
|
+
const out = [];
|
|
113
|
+
subpaths.forEach((sp, s) => {
|
|
114
|
+
for (let i = 0; i < sp.anchors.length; i++) {
|
|
115
|
+
const c = cornerOf(sp, s, i);
|
|
116
|
+
if (c) out.push(strip(c));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
var cornerSetback = (c, r) => r * (1 + c.cos) / c.sin;
|
|
122
|
+
var fitCornerRadius = (c, radius) => Number.isFinite(radius) ? Math.min(Math.max(0, radius), c.maxRadius) : 0;
|
|
123
|
+
var cornerBisectorPoint = (c, k) => add(c.at, mul(add(c.u, c.v), k));
|
|
124
|
+
var cornerRadiusChange = (c, d) => dot(d, add(c.u, c.v)) * c.sin / (2 + 2 * c.cos);
|
|
125
|
+
function arcHandle(cos) {
|
|
126
|
+
const c = Math.max(-1, Math.min(1, cos));
|
|
127
|
+
const sinHalf = Math.sqrt(Math.max(0, (1 - c) / 2));
|
|
128
|
+
const cosHalf = Math.sqrt(Math.max(0, (1 + c) / 2));
|
|
129
|
+
return 4 / 3 * sinHalf / (1 + cosHalf);
|
|
130
|
+
}
|
|
131
|
+
function squareTo(a, b) {
|
|
132
|
+
const w = sub(b, mul(a, dot(a, b)));
|
|
133
|
+
const l = len(w);
|
|
134
|
+
return l > EPS ? mul(w, 1 / l) : { x: 0, y: 0 };
|
|
135
|
+
}
|
|
136
|
+
function cutCorner(c, radius, kind) {
|
|
137
|
+
const s = Math.min(cornerSetback(c, radius), Math.min(c.lu, c.lv) / 2);
|
|
138
|
+
if (!(s > EPS)) return null;
|
|
139
|
+
const a = c.sideU.at(s, c.u);
|
|
140
|
+
const b = c.sideV.at(s, c.v);
|
|
141
|
+
if (kind === "chamfer") return { tu: a.t, tv: b.t, start: a.p, out: null, in: null, end: b.p };
|
|
142
|
+
if (kind === "inverted") {
|
|
143
|
+
const h = s * arcHandle(dot(a.dir, b.dir));
|
|
144
|
+
return { tu: a.t, tv: b.t, start: a.p, out: add(a.p, mul(squareTo(a.dir, b.dir), h)), in: add(b.p, mul(squareTo(b.dir, a.dir), h)), end: b.p };
|
|
145
|
+
}
|
|
146
|
+
const d1 = mul(a.dir, -1);
|
|
147
|
+
const d2 = mul(b.dir, -1);
|
|
148
|
+
const turn = Math.acos(Math.max(-1, Math.min(1, -dot(d1, d2))));
|
|
149
|
+
const chord = len(sub(b.p, a.p));
|
|
150
|
+
const k = turn < 1e-9 ? chord / 3 : 4 / 3 * Math.tan(turn / 4) * chord / (2 * Math.sin(turn / 2));
|
|
151
|
+
if (!Number.isFinite(k)) return null;
|
|
152
|
+
return { tu: a.t, tv: b.t, start: a.p, out: add(a.p, mul(d1, k)), in: add(b.p, mul(d2, k)), end: b.p };
|
|
153
|
+
}
|
|
154
|
+
var radiusOf = (a) => {
|
|
155
|
+
const r = _optionalChain([a, 'access', _2 => _2.corner, 'optionalAccess', _3 => _3.radius]);
|
|
156
|
+
return typeof r === "number" && r > 0 && Number.isFinite(r) ? r : 0;
|
|
157
|
+
};
|
|
158
|
+
function hasVectorCorners(subpaths) {
|
|
159
|
+
return subpaths.some((sp) => sp.anchors.some((a) => radiusOf(a) > 0));
|
|
160
|
+
}
|
|
161
|
+
function expandVectorCornersOf(sp, subpath = 0) {
|
|
162
|
+
const n = sp.anchors.length;
|
|
163
|
+
const cuts = sp.anchors.map((a, i) => {
|
|
164
|
+
const r = radiusOf(a);
|
|
165
|
+
if (!r) return null;
|
|
166
|
+
const c = cornerOf(sp, subpath, i);
|
|
167
|
+
if (!c) return null;
|
|
168
|
+
const fitted = fitCornerRadius(c, r);
|
|
169
|
+
return fitted > EPS ? cutCorner(c, fitted, _nullishCoalesce(_optionalChain([a, 'access', _4 => _4.corner, 'optionalAccess', _5 => _5.kind]), () => ( "round"))) : null;
|
|
170
|
+
});
|
|
171
|
+
if (!cuts.some(Boolean)) return { subpath: { closed: sp.closed, anchors: sp.anchors.map(plain) }, sources: sp.anchors.map((_, i) => i) };
|
|
172
|
+
const trimmed = sp.anchors.map((a, j) => {
|
|
173
|
+
const k = (j + 1) % n;
|
|
174
|
+
if (k === 0 && !sp.closed) return void 0;
|
|
175
|
+
const b = sp.anchors[k];
|
|
176
|
+
const from = cuts[j];
|
|
177
|
+
const to = cuts[k];
|
|
178
|
+
if (!from && !to) return void 0;
|
|
179
|
+
if (onAnchor(a, a.out) && onAnchor(b, b.in)) return { out: null, in: null };
|
|
180
|
+
const s0 = from ? from.tv : 0;
|
|
181
|
+
const s1 = to ? 1 - to.tu : 1;
|
|
182
|
+
const seg = [pt(a), pt(_nullishCoalesce(a.out, () => ( a))), pt(_nullishCoalesce(b.in, () => ( b))), pt(b)];
|
|
183
|
+
const part = _chunkBGNPT5PEcjs.subSegment.call(void 0, seg, s0, Math.max(s0, s1));
|
|
184
|
+
return { out: vec(part[1]), in: vec(part[2]) };
|
|
185
|
+
});
|
|
186
|
+
const anchors = [];
|
|
187
|
+
const sources = [];
|
|
188
|
+
let closing = null;
|
|
189
|
+
const handleIn = (i, a) => {
|
|
190
|
+
const t = trimmed[(i - 1 + n) % n];
|
|
191
|
+
return t ? t.in : _nullishCoalesce(a.in, () => ( null));
|
|
192
|
+
};
|
|
193
|
+
const handleOut = (i, a) => {
|
|
194
|
+
const t = trimmed[i];
|
|
195
|
+
return t ? t.out : _nullishCoalesce(a.out, () => ( null));
|
|
196
|
+
};
|
|
197
|
+
sp.anchors.forEach((a, i) => {
|
|
198
|
+
const c = cuts[i];
|
|
199
|
+
if (!c) {
|
|
200
|
+
anchors.push(withHandles({ x: a.x, y: a.y, ...a.type ? { type: a.type } : {} }, handleIn(i, a), handleOut(i, a)));
|
|
201
|
+
sources.push(i);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const start = withHandles({ x: c.start.x, y: c.start.y }, handleIn(i, a), c.out);
|
|
205
|
+
const end = withHandles({ x: c.end.x, y: c.end.y }, c.in, handleOut(i, a));
|
|
206
|
+
if (i === 0 && sp.closed) closing = start;
|
|
207
|
+
else {
|
|
208
|
+
anchors.push(start);
|
|
209
|
+
sources.push(i);
|
|
210
|
+
}
|
|
211
|
+
anchors.push(end);
|
|
212
|
+
sources.push(i);
|
|
213
|
+
});
|
|
214
|
+
if (closing) {
|
|
215
|
+
anchors.push(closing);
|
|
216
|
+
sources.push(0);
|
|
217
|
+
}
|
|
218
|
+
return { subpath: { closed: sp.closed, anchors }, sources };
|
|
219
|
+
}
|
|
220
|
+
function withHandles(a, hin, hout) {
|
|
221
|
+
if (hin && !onAnchor(a, hin)) a.in = { x: hin.x, y: hin.y };
|
|
222
|
+
if (hout && !onAnchor(a, hout)) a.out = { x: hout.x, y: hout.y };
|
|
223
|
+
return a;
|
|
224
|
+
}
|
|
225
|
+
function plain(a) {
|
|
226
|
+
if (!("corner" in a)) return a;
|
|
227
|
+
const { corner: _c, ...rest } = a;
|
|
228
|
+
return rest;
|
|
229
|
+
}
|
|
230
|
+
function expandVectorCorners(subpaths) {
|
|
231
|
+
if (!hasVectorCorners(subpaths)) return subpaths;
|
|
232
|
+
return subpaths.map((sp, s) => sp.anchors.some((a) => radiusOf(a) > 0) ? expandVectorCornersOf(sp, s).subpath : sp);
|
|
233
|
+
}
|
|
234
|
+
function setAnchorCorner(a, radius, kind) {
|
|
235
|
+
const { corner, ...rest } = a;
|
|
236
|
+
const r = Number.isFinite(radius) ? Math.max(0, radius) : 0;
|
|
237
|
+
const k = _nullishCoalesce(kind, () => ( _optionalChain([corner, 'optionalAccess', _6 => _6.kind])));
|
|
238
|
+
if (r <= 0 && !kind) return rest;
|
|
239
|
+
return { ...rest, corner: { radius: r, ...k && k !== "round" ? { kind: k } : {} } };
|
|
240
|
+
}
|
|
241
|
+
function nextVectorCornerKind(kind) {
|
|
242
|
+
return kind === "inverted" ? "chamfer" : kind === "chamfer" ? "round" : "inverted";
|
|
243
|
+
}
|
|
244
|
+
function setSubpathCorners(sp, radius, kind) {
|
|
245
|
+
return { closed: sp.closed, anchors: sp.anchors.map((a) => setAnchorCorner(a, radius, kind)) };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/vector/stroke.ts
|
|
249
|
+
var KAPPA = 0.5522847498307936;
|
|
250
|
+
var NOTCH = 0.7;
|
|
251
|
+
function isClosedBezierShape(path) {
|
|
252
|
+
const contours = _chunkBGNPT5PEcjs.pathToContours.call(void 0, path).filter((c) => c.segments.length > 0);
|
|
253
|
+
return contours.length > 0 && contours.every((c) => c.closed);
|
|
254
|
+
}
|
|
255
|
+
function effectiveStrokeAlign(style, closedShape) {
|
|
256
|
+
const a = _nullishCoalesce(style.strokeAlign, () => ( "center"));
|
|
257
|
+
return closedShape ? a : "center";
|
|
258
|
+
}
|
|
259
|
+
function hasStrokeExtras(style) {
|
|
260
|
+
return (_nullishCoalesce(style.strokeAlign, () => ( "center"))) !== "center" || !!style.startArrow || !!style.endArrow;
|
|
261
|
+
}
|
|
262
|
+
var capExtent = (style, width) => style.strokeLinecap === "round" || style.strokeLinecap === "square" ? width / 2 : 0;
|
|
263
|
+
function arrowheadWeight(style, end) {
|
|
264
|
+
const scale = end === "start" ? style.startArrowScale : style.endArrowScale;
|
|
265
|
+
const s = typeof scale === "number" && scale > 0 && Number.isFinite(scale) ? scale : 1;
|
|
266
|
+
return Math.max(0.25, (_nullishCoalesce(style.strokeWidth, () => ( 1))) * s);
|
|
267
|
+
}
|
|
268
|
+
function arrowheadInset(kind, hw, cap) {
|
|
269
|
+
const l = 4 * hw;
|
|
270
|
+
const solid = (back) => Math.max(back / 2, cap);
|
|
271
|
+
switch (kind) {
|
|
272
|
+
case "triangle":
|
|
273
|
+
case "circle":
|
|
274
|
+
case "square":
|
|
275
|
+
return solid(l);
|
|
276
|
+
case "arrow":
|
|
277
|
+
return solid(NOTCH * l);
|
|
278
|
+
case "bar":
|
|
279
|
+
return solid(0.75 * hw);
|
|
280
|
+
case "open":
|
|
281
|
+
return Math.max(hw * Math.sqrt(l * l + l * l / 4) / (l / 2), cap);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
var v = (x, y) => ({ x, y });
|
|
285
|
+
var plus = (a, b, k = 1) => ({ x: a.x + b.x * k, y: a.y + b.y * k });
|
|
286
|
+
var unit = (a) => {
|
|
287
|
+
const l = Math.hypot(a.x, a.y);
|
|
288
|
+
return l > 0 ? { x: a.x / l, y: a.y / l } : { x: 1, y: 0 };
|
|
289
|
+
};
|
|
290
|
+
function polygon(pts) {
|
|
291
|
+
return [{ type: "M", x: pts[0].x, y: pts[0].y }, ...pts.slice(1).map((p) => ({ type: "L", x: p.x, y: p.y })), { type: "Z" }];
|
|
292
|
+
}
|
|
293
|
+
function circle(c, r) {
|
|
294
|
+
const k = r * KAPPA;
|
|
295
|
+
const { x, y } = c;
|
|
296
|
+
return [
|
|
297
|
+
{ type: "M", x: x + r, y },
|
|
298
|
+
{ type: "C", x1: x + r, y1: y + k, x2: x + k, y2: y + r, x, y: y + r },
|
|
299
|
+
{ type: "C", x1: x - k, y1: y + r, x2: x - r, y2: y + k, x: x - r, y },
|
|
300
|
+
{ type: "C", x1: x - r, y1: y - k, x2: x - k, y2: y - r, x, y: y - r },
|
|
301
|
+
{ type: "C", x1: x + k, y1: y - r, x2: x + r, y2: y - k, x: x + r, y },
|
|
302
|
+
{ type: "Z" }
|
|
303
|
+
];
|
|
304
|
+
}
|
|
305
|
+
function arrowheadPath(kind, tip, dir, hw) {
|
|
306
|
+
const n = v(-dir.y, dir.x);
|
|
307
|
+
const l = 4 * hw;
|
|
308
|
+
const half = l / 2;
|
|
309
|
+
const base = plus(tip, dir, -l);
|
|
310
|
+
switch (kind) {
|
|
311
|
+
case "triangle":
|
|
312
|
+
return polygon([tip, plus(base, n, half), plus(base, n, -half)]);
|
|
313
|
+
case "arrow":
|
|
314
|
+
return polygon([tip, plus(base, n, half), plus(tip, dir, -NOTCH * l), plus(base, n, -half)]);
|
|
315
|
+
case "open": {
|
|
316
|
+
const t = hw;
|
|
317
|
+
const a = plus(base, n, half);
|
|
318
|
+
const b = plus(base, n, -half);
|
|
319
|
+
const ua = unit(plus(a, tip, -1));
|
|
320
|
+
const ub = unit(plus(b, tip, -1));
|
|
321
|
+
const na = v(-ua.y, ua.x);
|
|
322
|
+
const nb = v(ub.y, -ub.x);
|
|
323
|
+
const inner = plus(tip, dir, -(t * Math.hypot(a.x - tip.x, a.y - tip.y)) / half);
|
|
324
|
+
return polygon([tip, a, plus(a, na, t), inner, plus(b, nb, t), b]);
|
|
325
|
+
}
|
|
326
|
+
case "circle":
|
|
327
|
+
return circle(plus(tip, dir, -half), half);
|
|
328
|
+
case "square":
|
|
329
|
+
return polygon([plus(tip, n, half), plus(base, n, half), plus(base, n, -half), plus(tip, n, -half)]);
|
|
330
|
+
case "bar": {
|
|
331
|
+
const t = 0.75 * hw;
|
|
332
|
+
return polygon([plus(tip, n, half), plus(plus(tip, n, half), dir, -t), plus(plus(tip, n, -half), dir, -t), plus(tip, n, -half)]);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
var toVec = (p) => ({ x: p[0], y: p[1] });
|
|
337
|
+
var segLen = (s) => _chunkBGNPT5PEcjs.segmentLength.call(void 0, s);
|
|
338
|
+
function endOf(segs, atStart) {
|
|
339
|
+
const long = (s2) => segLen(s2) > 1e-9;
|
|
340
|
+
if (atStart) {
|
|
341
|
+
const s2 = _nullishCoalesce(segs.find(long), () => ( segs[0]));
|
|
342
|
+
const t2 = _chunkBGNPT5PEcjs.segmentTangent.call(void 0, s2, 0);
|
|
343
|
+
return { p: toVec(segs[0][0]), out: v(-t2[0], -t2[1]) };
|
|
344
|
+
}
|
|
345
|
+
const s = _nullishCoalesce([...segs].reverse().find(long), () => ( segs[segs.length - 1]));
|
|
346
|
+
const t = _chunkBGNPT5PEcjs.segmentTangent.call(void 0, s, 1);
|
|
347
|
+
const last = segs[segs.length - 1];
|
|
348
|
+
return { p: toVec(last[last.length - 1]), out: v(t[0], t[1]) };
|
|
349
|
+
}
|
|
350
|
+
function pointAlong(segs, fromStart, dist3) {
|
|
351
|
+
const order = fromStart ? segs : [...segs].reverse();
|
|
352
|
+
let acc = 0;
|
|
353
|
+
for (const s of order) {
|
|
354
|
+
const l = segLen(s);
|
|
355
|
+
if (acc + l >= dist3) {
|
|
356
|
+
const want = fromStart ? dist3 - acc : l - (dist3 - acc);
|
|
357
|
+
const pts = _chunkBGNPT5PEcjs.trimSegments.call(void 0, [s], 0, want);
|
|
358
|
+
const p = pts.length ? pts[0][pts[0].length - 1] : s[0];
|
|
359
|
+
return toVec(p);
|
|
360
|
+
}
|
|
361
|
+
acc += l;
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
function vectorStrokeParts(path, style) {
|
|
366
|
+
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
367
|
+
const contours = _chunkBGNPT5PEcjs.pathToContours.call(void 0, path).filter((c) => c.segments.length > 0);
|
|
368
|
+
const closedShape = contours.length > 0 && contours.every((c) => c.closed);
|
|
369
|
+
const align = effectiveStrokeAlign(style, closedShape);
|
|
370
|
+
const drawWidth = align === "center" ? width : width * 2;
|
|
371
|
+
const heads = [];
|
|
372
|
+
if (!contours.length || !style.startArrow && !style.endArrow) return { align, line: path, drawWidth, heads };
|
|
373
|
+
const first = contours[0];
|
|
374
|
+
const last = contours[contours.length - 1];
|
|
375
|
+
const cap = capExtent(style, width);
|
|
376
|
+
const tipMode = style.arrowAlign === "tip";
|
|
377
|
+
const trims = contours.map(() => [0, 0]);
|
|
378
|
+
const place = (end, contour, ci) => {
|
|
379
|
+
const kind = end === "start" ? style.startArrow : style.endArrow;
|
|
380
|
+
if (!kind || contour.closed) return;
|
|
381
|
+
const hw = arrowheadWeight(style, end);
|
|
382
|
+
const inset = arrowheadInset(kind, hw, cap);
|
|
383
|
+
const atStart = end === "start";
|
|
384
|
+
const { p, out } = endOf(contour.segments, atStart);
|
|
385
|
+
let tip;
|
|
386
|
+
let dir;
|
|
387
|
+
if (tipMode) {
|
|
388
|
+
const q = pointAlong(contour.segments, atStart, inset);
|
|
389
|
+
const d = q ? v(p.x - q.x, p.y - q.y) : null;
|
|
390
|
+
dir = d && Math.hypot(d.x, d.y) > 1e-9 ? unit(d) : out;
|
|
391
|
+
tip = p;
|
|
392
|
+
trims[ci][atStart ? 0 : 1] = inset;
|
|
393
|
+
} else {
|
|
394
|
+
tip = plus(p, out, inset);
|
|
395
|
+
dir = out;
|
|
396
|
+
}
|
|
397
|
+
heads.push({ end, kind, tip, dir, inset, path: arrowheadPath(kind, tip, dir, hw) });
|
|
398
|
+
};
|
|
399
|
+
place("start", first, 0);
|
|
400
|
+
place("end", last, contours.length - 1);
|
|
401
|
+
if (!tipMode || !heads.length) return { align, line: path, drawWidth, heads };
|
|
402
|
+
const trimmed = contours.map((c, i) => {
|
|
403
|
+
const [s0, s1] = trims[i];
|
|
404
|
+
if (!s0 && !s1) return c;
|
|
405
|
+
const lengths = c.segments.map(segLen);
|
|
406
|
+
const total = lengths.reduce((a, b) => a + b, 0);
|
|
407
|
+
return { closed: false, segments: total - s1 > s0 ? _chunkBGNPT5PEcjs.trimSegments.call(void 0, c.segments, s0, total - s1, lengths) : [] };
|
|
408
|
+
});
|
|
409
|
+
return { align, line: _chunkBGNPT5PEcjs.contoursToPath.call(void 0, trimmed), drawWidth, heads };
|
|
410
|
+
}
|
|
411
|
+
function vectorStrokeOutlinePath(path, style) {
|
|
412
|
+
const parts = vectorStrokeParts(path, style);
|
|
413
|
+
const stroke = _chunkBGNPT5PEcjs.outlineStroke.call(void 0, parts.line, {
|
|
414
|
+
width: parts.drawWidth,
|
|
415
|
+
join: _nullishCoalesce(style.strokeLinejoin, () => ( "miter")),
|
|
416
|
+
cap: _nullishCoalesce(style.strokeLinecap, () => ( "butt")),
|
|
417
|
+
..._optionalChain([style, 'access', _7 => _7.strokeDasharray, 'optionalAccess', _8 => _8.length]) ? { dash: style.strokeDasharray } : {}
|
|
418
|
+
});
|
|
419
|
+
const fill = { path, fillRule: _nullishCoalesce(style.fillRule, () => ( "nonzero")) };
|
|
420
|
+
let area = stroke;
|
|
421
|
+
if (parts.align === "inside") area = _chunkBGNPT5PEcjs.pathBoolean.call(void 0, "intersection", [stroke, fill]).path;
|
|
422
|
+
else if (parts.align === "outside") area = _chunkBGNPT5PEcjs.pathBoolean.call(void 0, "difference", [stroke, fill]).path;
|
|
423
|
+
if (!parts.heads.length) return area;
|
|
424
|
+
return _chunkBGNPT5PEcjs.pathBoolean.call(void 0, "union", [area, ...parts.heads.map((h) => h.path)]).path;
|
|
425
|
+
}
|
|
426
|
+
function hitTestVectorStroke(path, p, style, tolerance = 0) {
|
|
427
|
+
const parts = vectorStrokeParts(path, style);
|
|
428
|
+
const point = [p.x, p.y];
|
|
429
|
+
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
430
|
+
for (const h of parts.heads) {
|
|
431
|
+
if (_chunkBGNPT5PEcjs.pointInBezierPath.call(void 0, h.path, point) || tolerance > 0 && _chunkBGNPT5PEcjs.distanceToBezierPath.call(void 0, h.path, point) <= tolerance) return true;
|
|
432
|
+
}
|
|
433
|
+
if (!parts.line.length) return false;
|
|
434
|
+
const d = _chunkBGNPT5PEcjs.distanceToBezierPath.call(void 0, parts.line, point);
|
|
435
|
+
if (parts.align === "center") return d <= width / 2 + tolerance;
|
|
436
|
+
if (d > width + tolerance) return false;
|
|
437
|
+
if (d <= tolerance) return true;
|
|
438
|
+
const inside = _chunkBGNPT5PEcjs.pointInBezierPath.call(void 0, path, point, _nullishCoalesce(style.fillRule, () => ( "nonzero")));
|
|
439
|
+
return parts.align === "inside" ? inside : !inside;
|
|
440
|
+
}
|
|
441
|
+
function vectorStrokeReach(style) {
|
|
442
|
+
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
443
|
+
const align = _nullishCoalesce(style.strokeAlign, () => ( "center"));
|
|
444
|
+
let reach = align === "center" ? width / 2 : align === "outside" ? width : 0;
|
|
445
|
+
if (style.strokeLinejoin !== "round" && style.strokeLinejoin !== "bevel") reach *= 4;
|
|
446
|
+
for (const end of ["start", "end"]) {
|
|
447
|
+
if (end === "start" ? style.startArrow : style.endArrow) reach = Math.max(reach, 8 * arrowheadWeight(style, end) + width);
|
|
448
|
+
}
|
|
449
|
+
return reach;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// src/vector/geometry.ts
|
|
453
|
+
var EPS2 = 1e-9;
|
|
38
454
|
var cloneAnchor = (a) => ({
|
|
39
455
|
x: a.x,
|
|
40
456
|
y: a.y,
|
|
41
457
|
...a.in ? { in: { x: a.in.x, y: a.in.y } } : {},
|
|
42
458
|
...a.out ? { out: { x: a.out.x, y: a.out.y } } : {},
|
|
43
|
-
...a.type && a.type !== "corner" ? { type: a.type } : {}
|
|
459
|
+
...a.type && a.type !== "corner" ? { type: a.type } : {},
|
|
460
|
+
...a.corner ? { corner: { ...a.corner } } : {}
|
|
44
461
|
});
|
|
45
462
|
var cloneSubpath = (s) => ({ anchors: s.anchors.map(cloneAnchor), closed: s.closed });
|
|
46
463
|
function cloneVectorNode(node) {
|
|
@@ -58,7 +475,7 @@ function hasPaint(paint) {
|
|
|
58
475
|
return true;
|
|
59
476
|
}
|
|
60
477
|
var handleOf = (a, side) => _nullishCoalesce(a[side], () => ( { x: a.x, y: a.y }));
|
|
61
|
-
var isOnAnchor = (a, h) => !h || Math.abs(h.x - a.x) <
|
|
478
|
+
var isOnAnchor = (a, h) => !h || Math.abs(h.x - a.x) < EPS2 && Math.abs(h.y - a.y) < EPS2;
|
|
62
479
|
function subpathSegmentCount(sp) {
|
|
63
480
|
const n = sp.anchors.length;
|
|
64
481
|
if (n < 2) return 0;
|
|
@@ -72,9 +489,9 @@ function subpathSegment(sp, i) {
|
|
|
72
489
|
const c2 = handleOf(b, "in");
|
|
73
490
|
return [[a.x, a.y], [c1.x, c1.y], [c2.x, c2.y], [b.x, b.y]];
|
|
74
491
|
}
|
|
75
|
-
function subpathsToBezier(subpaths) {
|
|
492
|
+
function subpathsToBezier(subpaths, options = {}) {
|
|
76
493
|
const out = [];
|
|
77
|
-
for (const sp of subpaths) {
|
|
494
|
+
for (const sp of options.corners === false ? subpaths : expandVectorCorners(subpaths)) {
|
|
78
495
|
if (sp.anchors.length === 0) continue;
|
|
79
496
|
const first = sp.anchors[0];
|
|
80
497
|
out.push({ type: "M", x: first.x, y: first.y });
|
|
@@ -104,9 +521,9 @@ function inferAnchorType(a) {
|
|
|
104
521
|
const oy = a.out.y - a.y;
|
|
105
522
|
const li = Math.hypot(ix, iy);
|
|
106
523
|
const lo = Math.hypot(ox, oy);
|
|
107
|
-
const
|
|
108
|
-
const
|
|
109
|
-
if (Math.abs(
|
|
524
|
+
const cross2 = (ix * oy - iy * ox) / (li * lo);
|
|
525
|
+
const dot2 = (ix * ox + iy * oy) / (li * lo);
|
|
526
|
+
if (Math.abs(cross2) > 1e-3 || dot2 > 0) return "corner";
|
|
110
527
|
return Math.abs(li - lo) <= 1e-3 * Math.max(li, lo) ? "symmetric" : "smooth";
|
|
111
528
|
}
|
|
112
529
|
function bezierToSubpaths(input) {
|
|
@@ -249,8 +666,12 @@ function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX) {
|
|
|
249
666
|
if (path.length === 0) return false;
|
|
250
667
|
const point = [p.x, p.y];
|
|
251
668
|
if (hasPaint(node.fill) && _chunkBGNPT5PEcjs.pointInBezierPath.call(void 0, path, point, _nullishCoalesce(node.fillRule, () => ( "nonzero")))) return true;
|
|
252
|
-
|
|
253
|
-
return _chunkBGNPT5PEcjs.distanceToBezierPath.call(void 0, path, point) <=
|
|
669
|
+
if (hasPaint(node.stroke)) return hitTestVectorStroke(path, p, node, tolerance);
|
|
670
|
+
return _chunkBGNPT5PEcjs.distanceToBezierPath.call(void 0, path, point) <= tolerance;
|
|
671
|
+
}
|
|
672
|
+
function vectorStrokeOutline(node, parent = IDENTITY_MATRIX) {
|
|
673
|
+
if (!hasPaint(node.stroke) || !((_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0)) return [];
|
|
674
|
+
return vectorStrokeOutlinePath(vectorPathWorldBezier(node, parent), node);
|
|
254
675
|
}
|
|
255
676
|
function hitTestVectorNodes(nodes, p, tolerance = 0) {
|
|
256
677
|
for (let i = nodes.length - 1; i >= 0; i--) {
|
|
@@ -268,8 +689,8 @@ function nearestSegment(node, p) {
|
|
|
268
689
|
const seg = subpathSegment(sp, i);
|
|
269
690
|
const hit = _chunkBGNPT5PEcjs.segmentNearest.call(void 0, seg, [p.x, p.y]);
|
|
270
691
|
if (!best || hit.distance < best.distance) {
|
|
271
|
-
const
|
|
272
|
-
best = { subpath: s, segment: i, t: hit.t, point: { x:
|
|
692
|
+
const pt2 = _chunkBGNPT5PEcjs.segmentPoint.call(void 0, seg, hit.t);
|
|
693
|
+
best = { subpath: s, segment: i, t: hit.t, point: { x: pt2[0], y: pt2[1] }, distance: hit.distance };
|
|
273
694
|
}
|
|
274
695
|
}
|
|
275
696
|
});
|
|
@@ -303,8 +724,8 @@ function invertMatrix(m) {
|
|
|
303
724
|
if (!det || !Number.isFinite(det)) return IDENTITY_MATRIX;
|
|
304
725
|
return [d / det, -b / det, -c / det, a / det, (c * f - d * e) / det, (b * e - a * f) / det];
|
|
305
726
|
}
|
|
306
|
-
function applyMatrixLinear(m,
|
|
307
|
-
return { x: m[0] *
|
|
727
|
+
function applyMatrixLinear(m, v2) {
|
|
728
|
+
return { x: m[0] * v2.x + m[2] * v2.y, y: m[1] * v2.x + m[3] * v2.y };
|
|
308
729
|
}
|
|
309
730
|
function matrixRotation(m) {
|
|
310
731
|
const [a, b, c, d] = m;
|
|
@@ -338,6 +759,7 @@ function bakeIntoGeometry(node, m) {
|
|
|
338
759
|
if (a.in) next.in = applyMatrix(m, a.in);
|
|
339
760
|
if (a.out) next.out = applyMatrix(m, a.out);
|
|
340
761
|
if (a.type) next.type = a.type;
|
|
762
|
+
if (a.corner) next.corner = { ...a.corner };
|
|
341
763
|
return next;
|
|
342
764
|
})
|
|
343
765
|
}))
|
|
@@ -389,12 +811,12 @@ function moveAnchorHandle(a, side, pos, breakHandles = false) {
|
|
|
389
811
|
if (breakHandles) delete next.type;
|
|
390
812
|
const dx = pos.x - a.x;
|
|
391
813
|
const dy = pos.y - a.y;
|
|
392
|
-
const
|
|
814
|
+
const len2 = Math.hypot(dx, dy);
|
|
393
815
|
if (type === "symmetric") next[other] = { x: a.x - dx, y: a.y - dy };
|
|
394
|
-
else if (type === "smooth" &&
|
|
816
|
+
else if (type === "smooth" && len2 > EPS2) {
|
|
395
817
|
const o = a[other];
|
|
396
|
-
const olen = o ? Math.hypot(o.x - a.x, o.y - a.y) :
|
|
397
|
-
next[other] = { x: a.x - dx /
|
|
818
|
+
const olen = o ? Math.hypot(o.x - a.x, o.y - a.y) : len2;
|
|
819
|
+
next[other] = { x: a.x - dx / len2 * olen, y: a.y - dy / len2 * olen };
|
|
398
820
|
}
|
|
399
821
|
if (isOnAnchor(next, next.in)) delete next.in;
|
|
400
822
|
if (isOnAnchor(next, next.out)) delete next.out;
|
|
@@ -421,15 +843,15 @@ function convertAnchor(sp, index, type) {
|
|
|
421
843
|
else if (prev && next) dir = { x: next.x - prev.x, y: next.y - prev.y };
|
|
422
844
|
else if (next) dir = { x: next.x - a.x, y: next.y - a.y };
|
|
423
845
|
else if (prev) dir = { x: a.x - prev.x, y: a.y - prev.y };
|
|
424
|
-
if (!dir || Math.hypot(dir.x, dir.y) <
|
|
846
|
+
if (!dir || Math.hypot(dir.x, dir.y) < EPS2) return { anchors, closed: sp.closed };
|
|
425
847
|
const dl = Math.hypot(dir.x, dir.y);
|
|
426
848
|
const ux = dir.x / dl;
|
|
427
849
|
const uy = dir.y / dl;
|
|
428
850
|
lenIn = a.in && !isOnAnchor(a, a.in) ? Math.hypot(a.in.x - a.x, a.in.y - a.y) : prev ? Math.hypot(prev.x - a.x, prev.y - a.y) / 3 : 0;
|
|
429
851
|
lenOut = a.out && !isOnAnchor(a, a.out) ? Math.hypot(a.out.x - a.x, a.out.y - a.y) : next ? Math.hypot(next.x - a.x, next.y - a.y) / 3 : 0;
|
|
430
852
|
if (type === "symmetric") lenIn = lenOut = (lenIn + lenOut) / 2 || Math.max(lenIn, lenOut);
|
|
431
|
-
if (lenIn >
|
|
432
|
-
if (lenOut >
|
|
853
|
+
if (lenIn > EPS2) a.in = { x: a.x - ux * lenIn, y: a.y - uy * lenIn };
|
|
854
|
+
if (lenOut > EPS2) a.out = { x: a.x + ux * lenOut, y: a.y + uy * lenOut };
|
|
433
855
|
a.type = type;
|
|
434
856
|
return { anchors, closed: sp.closed };
|
|
435
857
|
}
|
|
@@ -465,37 +887,24 @@ function reverseSubpath(sp) {
|
|
|
465
887
|
if (a.out) next.in = { ...a.out };
|
|
466
888
|
if (a.in) next.out = { ...a.in };
|
|
467
889
|
if (a.type) next.type = a.type;
|
|
890
|
+
if (a.corner) next.corner = { ...a.corner };
|
|
468
891
|
return next;
|
|
469
892
|
});
|
|
470
893
|
return { anchors, closed: sp.closed };
|
|
471
894
|
}
|
|
472
|
-
var
|
|
473
|
-
function rectSubpath(b, radius = 0) {
|
|
895
|
+
var KAPPA2 = 0.5522847498307936;
|
|
896
|
+
function rectSubpath(b, radius = 0, kind) {
|
|
474
897
|
const { x, y, width: w, height: h } = b;
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
return { anchors: [{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h }], closed: true };
|
|
478
|
-
}
|
|
479
|
-
const k = r * KAPPA;
|
|
480
|
-
const anchors = [
|
|
481
|
-
{ x: x + r, y, in: { x: x + r - k, y } },
|
|
482
|
-
{ x: x + w - r, y, out: { x: x + w - r + k, y } },
|
|
483
|
-
{ x: x + w, y: y + r, in: { x: x + w, y: y + r - k } },
|
|
484
|
-
{ x: x + w, y: y + h - r, out: { x: x + w, y: y + h - r + k } },
|
|
485
|
-
{ x: x + w - r, y: y + h, in: { x: x + w - r + k, y: y + h } },
|
|
486
|
-
{ x: x + r, y: y + h, out: { x: x + r - k, y: y + h } },
|
|
487
|
-
{ x, y: y + h - r, in: { x, y: y + h - r + k } },
|
|
488
|
-
{ x, y: y + r, out: { x, y: y + r - k } }
|
|
489
|
-
];
|
|
490
|
-
return { anchors, closed: true };
|
|
898
|
+
const sp = { anchors: [{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h }], closed: true };
|
|
899
|
+
return radius > 0 ? setSubpathCorners(sp, radius, kind) : sp;
|
|
491
900
|
}
|
|
492
901
|
function ellipseSubpath(b) {
|
|
493
902
|
const rx = b.width / 2;
|
|
494
903
|
const ry = b.height / 2;
|
|
495
904
|
const cx = b.x + rx;
|
|
496
905
|
const cy = b.y + ry;
|
|
497
|
-
const kx = rx *
|
|
498
|
-
const ky = ry *
|
|
906
|
+
const kx = rx * KAPPA2;
|
|
907
|
+
const ky = ry * KAPPA2;
|
|
499
908
|
return {
|
|
500
909
|
closed: true,
|
|
501
910
|
anchors: [
|
|
@@ -543,15 +952,52 @@ function roundSubpaths(subpaths, precision = 3) {
|
|
|
543
952
|
}
|
|
544
953
|
|
|
545
954
|
// src/vector/svg.ts
|
|
955
|
+
function vectorCornersAttribute(subpaths, precision = 3) {
|
|
956
|
+
const out = [];
|
|
957
|
+
subpaths.forEach(
|
|
958
|
+
(sp, s) => sp.anchors.forEach((a, i) => {
|
|
959
|
+
if (!a.corner || !(a.corner.radius > 0)) return;
|
|
960
|
+
out.push(`${s}.${i}:${_chunkBGNPT5PEcjs.formatNumber.call(void 0, a.corner.radius, precision)}${a.corner.kind && a.corner.kind !== "round" ? `:${a.corner.kind}` : ""}`);
|
|
961
|
+
})
|
|
962
|
+
);
|
|
963
|
+
return out.join(" ");
|
|
964
|
+
}
|
|
965
|
+
function applyVectorCornersAttribute(subpaths, value) {
|
|
966
|
+
for (const item of value.trim().split(/\s+/)) {
|
|
967
|
+
const m = /^(\d+)\.(\d+):([\d.eE+-]+)(?::([a-z]+))?$/.exec(item);
|
|
968
|
+
if (!m) continue;
|
|
969
|
+
const a = _optionalChain([subpaths, 'access', _9 => _9[+m[1]], 'optionalAccess', _10 => _10.anchors, 'access', _11 => _11[+m[2]]]);
|
|
970
|
+
const radius = parseFloat(m[3]);
|
|
971
|
+
if (!a || !(radius > 0)) continue;
|
|
972
|
+
const kind = VECTOR_CORNER_KINDS.includes(m[4]) ? m[4] : void 0;
|
|
973
|
+
a.corner = { radius, ...kind && kind !== "round" ? { kind } : {} };
|
|
974
|
+
}
|
|
975
|
+
return subpaths;
|
|
976
|
+
}
|
|
546
977
|
var escapeAttr = (value) => value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
547
978
|
function vectorPaintToSvg(paint, gradientId) {
|
|
548
979
|
if (!hasPaint(paint)) return { value: "none", gradient: null };
|
|
549
980
|
if (typeof paint === "string") return { value: paint, gradient: null };
|
|
550
981
|
return { value: `url(#${gradientId})`, gradient: _chunkBGNPT5PEcjs.gradientToSvgDef.call(void 0, paint, gradientId) };
|
|
551
982
|
}
|
|
983
|
+
function vectorStrokeSvgParts(node, clipId, precision = 3) {
|
|
984
|
+
if (!hasPaint(node.stroke) || !hasStrokeExtras(node)) return void 0;
|
|
985
|
+
const path = subpathsToBezier(node.subpaths);
|
|
986
|
+
const parts = vectorStrokeParts(path, node);
|
|
987
|
+
if (parts.align === "center" && !parts.heads.length) return void 0;
|
|
988
|
+
let clip = null;
|
|
989
|
+
if (parts.align !== "center") {
|
|
990
|
+
const b = _chunkBGNPT5PEcjs.bezierPathBounds.call(void 0, path);
|
|
991
|
+
const pad = vectorStrokeReach(node) + 1;
|
|
992
|
+
const bounds = b ? { x: round2(b.minX - pad), y: round2(b.minY - pad), width: round2(b.maxX - b.minX + 2 * pad), height: round2(b.maxY - b.minY + 2 * pad) } : { x: 0, y: 0, width: 0, height: 0 };
|
|
993
|
+
clip = { kind: parts.align === "inside" ? "clip" : "mask", id: clipId, bounds };
|
|
994
|
+
}
|
|
995
|
+
return { align: parts.align, d: _chunkBGNPT5PEcjs.bezierPathToSvg.call(void 0, parts.line, { precision }), width: parts.drawWidth, clip, heads: parts.heads.map((h) => _chunkBGNPT5PEcjs.bezierPathToSvg.call(void 0, h.path, { precision })) };
|
|
996
|
+
}
|
|
997
|
+
var round2 = (n) => Math.round(n * 100) / 100;
|
|
552
998
|
function gradientMarkup(def) {
|
|
553
999
|
const tag = def.type === "radial" ? "radialGradient" : "linearGradient";
|
|
554
|
-
const attrs = Object.entries(def.attrs).map(([k,
|
|
1000
|
+
const attrs = Object.entries(def.attrs).map(([k, v2]) => ` ${k}="${escapeAttr(String(v2))}"`).join("");
|
|
555
1001
|
const stops = def.stops.map((s) => `<stop offset="${s.offset}" stop-color="${escapeAttr(s.stopColor)}"${s.stopOpacity !== void 0 ? ` stop-opacity="${s.stopOpacity}"` : ""}/>`).join("");
|
|
556
1002
|
return `<${tag} id="${escapeAttr(def.id)}"${attrs}>${stops}</${tag}>`;
|
|
557
1003
|
}
|
|
@@ -582,15 +1028,53 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
582
1028
|
const stroke = vectorPaintToSvg(node.stroke, `${prefix}stroke-${node.id}`);
|
|
583
1029
|
if (fill.gradient) defs.push(gradientMarkup(fill.gradient));
|
|
584
1030
|
if (stroke.gradient) defs.push(gradientMarkup(stroke.gradient));
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
if (
|
|
592
|
-
|
|
593
|
-
|
|
1031
|
+
const d = vectorPathData(node, precision);
|
|
1032
|
+
const corners2 = vectorCornersAttribute(node.subpaths, precision);
|
|
1033
|
+
const live = corners2 ? ` data-vector-d="${_chunkBGNPT5PEcjs.bezierPathToSvg.call(void 0, subpathsToBezier(node.subpaths, { corners: false }), { precision })}" data-vector-corners="${corners2}"` : "";
|
|
1034
|
+
const fillAttrs = ` fill="${escapeAttr(fill.value)}"${node.fillRule === "evenodd" ? ` fill-rule="evenodd"` : ""}`;
|
|
1035
|
+
const lineAttrs = (width) => {
|
|
1036
|
+
let out2 = ` stroke="${escapeAttr(stroke.value)}" stroke-width="${num(width)}"`;
|
|
1037
|
+
if (node.strokeLinecap && node.strokeLinecap !== "butt") out2 += ` stroke-linecap="${node.strokeLinecap}"`;
|
|
1038
|
+
if (node.strokeLinejoin && node.strokeLinejoin !== "miter") out2 += ` stroke-linejoin="${node.strokeLinejoin}"`;
|
|
1039
|
+
if (_optionalChain([node, 'access', _12 => _12.strokeDasharray, 'optionalAccess', _13 => _13.length])) out2 += ` stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
|
|
1040
|
+
return out2;
|
|
1041
|
+
};
|
|
1042
|
+
const parts = stroke.value !== "none" ? vectorStrokeSvgParts(node, `${prefix}clip-${node.id}`, precision) : void 0;
|
|
1043
|
+
if (!parts) {
|
|
1044
|
+
lines.push(`${indent(depth)}<path${common(node)} d="${d}"${fillAttrs}${stroke.value !== "none" ? lineAttrs(_nullishCoalesce(node.strokeWidth, () => ( 1))) : ""}${live}/>`);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
let data = ` data-vector-path="" data-vector-stroke-width="${num(_nullishCoalesce(node.strokeWidth, () => ( 1)))}"`;
|
|
1048
|
+
if (parts.align !== "center") data += ` data-vector-stroke-align="${parts.align}"`;
|
|
1049
|
+
if (node.startArrow) data += ` data-vector-start-arrow="${node.startArrow}"`;
|
|
1050
|
+
if (node.endArrow) data += ` data-vector-end-arrow="${node.endArrow}"`;
|
|
1051
|
+
if (node.arrowAlign && node.arrowAlign !== "extend") data += ` data-vector-arrow-align="${node.arrowAlign}"`;
|
|
1052
|
+
if (node.startArrowScale !== void 0 && node.startArrowScale !== 1) data += ` data-vector-start-arrow-scale="${num(node.startArrowScale)}"`;
|
|
1053
|
+
if (node.endArrowScale !== void 0 && node.endArrowScale !== 1) data += ` data-vector-end-arrow-scale="${num(node.endArrowScale)}"`;
|
|
1054
|
+
lines.push(`${indent(depth)}<g${common(node)}${data}>`);
|
|
1055
|
+
lines.push(`${indent(depth + 1)}<path data-vector-part="fill" d="${d}"${fillAttrs}${live}/>`);
|
|
1056
|
+
if (options.strokes === "outline") {
|
|
1057
|
+
const area = _chunkBGNPT5PEcjs.bezierPathToSvg.call(void 0, vectorStrokeOutlinePath(subpathsToBezier(node.subpaths), node), { precision });
|
|
1058
|
+
lines.push(`${indent(depth + 1)}<path data-vector-part="stroke-outline" d="${area}" fill="${escapeAttr(stroke.value)}"/>`);
|
|
1059
|
+
} else {
|
|
1060
|
+
let clip = "";
|
|
1061
|
+
if (parts.clip) {
|
|
1062
|
+
const rule = node.fillRule === "evenodd" ? "evenodd" : "nonzero";
|
|
1063
|
+
const id = escapeAttr(parts.clip.id);
|
|
1064
|
+
if (parts.clip.kind === "clip") {
|
|
1065
|
+
defs.push(`<clipPath id="${id}"><path d="${d}" clip-rule="${rule}"/></clipPath>`);
|
|
1066
|
+
clip = ` clip-path="url(#${id})"`;
|
|
1067
|
+
} else {
|
|
1068
|
+
const b = parts.clip.bounds;
|
|
1069
|
+
const box = `x="${num(b.x)}" y="${num(b.y)}" width="${num(b.width)}" height="${num(b.height)}"`;
|
|
1070
|
+
defs.push(`<mask id="${id}" maskUnits="userSpaceOnUse" ${box}><rect ${box} fill="#fff"/><path d="${d}" fill="#000" fill-rule="${rule}"/></mask>`);
|
|
1071
|
+
clip = ` mask="url(#${id})"`;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
lines.push(`${indent(depth + 1)}<path data-vector-part="stroke" d="${parts.d}" fill="none"${lineAttrs(parts.width)}${clip}/>`);
|
|
1075
|
+
for (const h2 of parts.heads) lines.push(`${indent(depth + 1)}<path data-vector-part="head" d="${h2}" fill="${escapeAttr(stroke.value)}"/>`);
|
|
1076
|
+
}
|
|
1077
|
+
lines.push(`${indent(depth)}</g>`);
|
|
594
1078
|
};
|
|
595
1079
|
for (const node of doc.nodes) emit(node, 1);
|
|
596
1080
|
const w = num(doc.width);
|
|
@@ -733,7 +1217,7 @@ function resolveGradient(id, raw, seen = /* @__PURE__ */ new Set()) {
|
|
|
733
1217
|
seen.add(id);
|
|
734
1218
|
let stops = readStops(el);
|
|
735
1219
|
const href = _nullishCoalesce(el.attrs.href, () => ( el.attrs["xlink:href"]));
|
|
736
|
-
if (!stops.length && _optionalChain([href, 'optionalAccess',
|
|
1220
|
+
if (!stops.length && _optionalChain([href, 'optionalAccess', _14 => _14.startsWith, 'call', _15 => _15("#")])) stops = _nullishCoalesce(_optionalChain([resolveGradient, 'call', _16 => _16(href.slice(1), raw, seen), 'optionalAccess', _17 => _17.stops]), () => ( []));
|
|
737
1221
|
if (!stops.length) return null;
|
|
738
1222
|
if (el.name === "radialGradient") {
|
|
739
1223
|
return { type: "radial", cx: fraction(el.attrs.cx, 0.5), cy: fraction(el.attrs.cy, 0.5), r: fraction(el.attrs.r, 0.5), stops };
|
|
@@ -765,11 +1249,11 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
765
1249
|
const rawGradients = /* @__PURE__ */ new Map();
|
|
766
1250
|
collectGradients(root, rawGradients);
|
|
767
1251
|
const paint = (value) => {
|
|
768
|
-
const
|
|
769
|
-
const url = /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec(
|
|
1252
|
+
const v2 = value.trim();
|
|
1253
|
+
const url = /^url\(\s*['"]?#([^'")\s]+)['"]?\s*\)/.exec(v2);
|
|
770
1254
|
if (url) return _nullishCoalesce(resolveGradient(url[1], rawGradients), () => ( null));
|
|
771
|
-
if (
|
|
772
|
-
return
|
|
1255
|
+
if (v2 === "none" || v2 === "") return null;
|
|
1256
|
+
return v2;
|
|
773
1257
|
};
|
|
774
1258
|
const viewBox = numberList(root.attrs.viewBox);
|
|
775
1259
|
const width = viewBox.length === 4 ? viewBox[2] : length(root.attrs.width, 300);
|
|
@@ -779,8 +1263,13 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
779
1263
|
const shapeOf = (el) => {
|
|
780
1264
|
const a = el.attrs;
|
|
781
1265
|
switch (el.name) {
|
|
782
|
-
case "path":
|
|
1266
|
+
case "path": {
|
|
1267
|
+
if (a["data-vector-d"] && a["data-vector-corners"]) {
|
|
1268
|
+
const sharp = bezierToSubpaths(a["data-vector-d"]);
|
|
1269
|
+
if (sharp.length) return applyVectorCornersAttribute(sharp, a["data-vector-corners"]);
|
|
1270
|
+
}
|
|
783
1271
|
return a.d ? bezierToSubpaths(a.d) : null;
|
|
1272
|
+
}
|
|
784
1273
|
case "rect": {
|
|
785
1274
|
const w = length(a.width);
|
|
786
1275
|
const h = length(a.height);
|
|
@@ -814,6 +1303,56 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
814
1303
|
}
|
|
815
1304
|
return null;
|
|
816
1305
|
};
|
|
1306
|
+
const strokeStyle = (s) => ({
|
|
1307
|
+
...s.strokeWidth ? { strokeWidth: length(s.strokeWidth, 1) } : {},
|
|
1308
|
+
...s.strokeLinecap ? { strokeLinecap: s.strokeLinecap } : {},
|
|
1309
|
+
...s.strokeLinejoin ? { strokeLinejoin: s.strokeLinejoin } : {},
|
|
1310
|
+
...s.strokeDasharray && s.strokeDasharray !== "none" ? { strokeDasharray: numberList(s.strokeDasharray) } : {},
|
|
1311
|
+
...s.fillRule === "evenodd" ? { fillRule: "evenodd" } : {}
|
|
1312
|
+
});
|
|
1313
|
+
const placed = (node, m) => {
|
|
1314
|
+
if (m === IDENTITY_MATRIX) return node;
|
|
1315
|
+
const next = transformVectorNode(node, m);
|
|
1316
|
+
const strokeScale = Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
1317
|
+
if (hasPaint(next.stroke) && strokeScale > 0 && Math.abs(strokeScale - 1) > 1e-9) next.strokeWidth = (_nullishCoalesce(next.strokeWidth, () => ( 1))) * strokeScale;
|
|
1318
|
+
return next;
|
|
1319
|
+
};
|
|
1320
|
+
const mergedPath = (g, style, m, meta) => {
|
|
1321
|
+
const part = (name) => g.children.find((c) => c.name === "path" && c.attrs["data-vector-part"] === name);
|
|
1322
|
+
const fillEl = part("fill");
|
|
1323
|
+
const subpaths = fillEl ? shapeOf(fillEl) : null;
|
|
1324
|
+
if (!fillEl || !_optionalChain([subpaths, 'optionalAccess', _18 => _18.length])) return null;
|
|
1325
|
+
const a = g.attrs;
|
|
1326
|
+
const fs = readStyle(fillEl, style);
|
|
1327
|
+
const strokeEl = part("stroke");
|
|
1328
|
+
const outlineEl = part("stroke-outline");
|
|
1329
|
+
const ss = strokeEl ? readStyle(strokeEl, style) : null;
|
|
1330
|
+
const width2 = length(a["data-vector-stroke-width"], ss ? length(ss.strokeWidth, 1) : 1);
|
|
1331
|
+
const arrow = (v2) => VECTOR_ARROWHEADS.includes(v2) ? v2 : void 0;
|
|
1332
|
+
const scale = (v2) => {
|
|
1333
|
+
const n = v2 === void 0 ? NaN : parseFloat(v2);
|
|
1334
|
+
return n > 0 ? n : void 0;
|
|
1335
|
+
};
|
|
1336
|
+
const align = a["data-vector-stroke-align"];
|
|
1337
|
+
const node = {
|
|
1338
|
+
id: idFor(g),
|
|
1339
|
+
type: "path",
|
|
1340
|
+
...meta,
|
|
1341
|
+
subpaths,
|
|
1342
|
+
fill: paint(fs.fill),
|
|
1343
|
+
stroke: ss ? paint(ss.stroke) : outlineEl ? paint(readStyle(outlineEl, style).fill) : null,
|
|
1344
|
+
...ss ? strokeStyle(ss) : {},
|
|
1345
|
+
...fs.fillRule === "evenodd" ? { fillRule: "evenodd" } : {},
|
|
1346
|
+
strokeWidth: width2,
|
|
1347
|
+
...align === "inside" || align === "outside" ? { strokeAlign: align } : {},
|
|
1348
|
+
...arrow(a["data-vector-start-arrow"]) ? { startArrow: arrow(a["data-vector-start-arrow"]) } : {},
|
|
1349
|
+
...arrow(a["data-vector-end-arrow"]) ? { endArrow: arrow(a["data-vector-end-arrow"]) } : {},
|
|
1350
|
+
...a["data-vector-arrow-align"] === "tip" ? { arrowAlign: "tip" } : {},
|
|
1351
|
+
...scale(a["data-vector-start-arrow-scale"]) ? { startArrowScale: scale(a["data-vector-start-arrow-scale"]) } : {},
|
|
1352
|
+
...scale(a["data-vector-end-arrow-scale"]) ? { endArrowScale: scale(a["data-vector-end-arrow-scale"]) } : {}
|
|
1353
|
+
};
|
|
1354
|
+
return placed(node, m);
|
|
1355
|
+
};
|
|
817
1356
|
const visit = (el, style, matrix) => {
|
|
818
1357
|
const out = [];
|
|
819
1358
|
for (const child of el.children) {
|
|
@@ -827,6 +1366,11 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
827
1366
|
...opacity !== void 0 && Number.isFinite(opacity) && opacity < 1 ? { opacity } : {},
|
|
828
1367
|
...hidden ? { visible: false } : {}
|
|
829
1368
|
};
|
|
1369
|
+
if (child.name === "g" && child.attrs["data-vector-path"] !== void 0) {
|
|
1370
|
+
const node2 = mergedPath(child, s, m, meta);
|
|
1371
|
+
if (node2) out.push(node2);
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
830
1374
|
if (child.name === "g" || child.name === "svg" || child.name === "a" || child.name === "switch") {
|
|
831
1375
|
const children = visit(child, s, m);
|
|
832
1376
|
if (!children.length) continue;
|
|
@@ -836,24 +1380,18 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
836
1380
|
}
|
|
837
1381
|
const subpaths = shapeOf(child);
|
|
838
1382
|
if (!subpaths || !subpaths.length) continue;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
};
|
|
852
|
-
if (m !== IDENTITY_MATRIX) {
|
|
853
|
-
node = transformVectorNode(node, m);
|
|
854
|
-
const strokeScale = Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
855
|
-
if (hasPaint(node.stroke) && strokeScale > 0 && Math.abs(strokeScale - 1) > 1e-9) node.strokeWidth = (_nullishCoalesce(node.strokeWidth, () => ( 1))) * strokeScale;
|
|
856
|
-
}
|
|
1383
|
+
const node = placed(
|
|
1384
|
+
{
|
|
1385
|
+
id: idFor(child),
|
|
1386
|
+
type: "path",
|
|
1387
|
+
...meta,
|
|
1388
|
+
subpaths,
|
|
1389
|
+
fill: child.name === "line" ? null : paint(s.fill),
|
|
1390
|
+
stroke: paint(s.stroke),
|
|
1391
|
+
...strokeStyle(s)
|
|
1392
|
+
},
|
|
1393
|
+
m
|
|
1394
|
+
);
|
|
857
1395
|
out.push(node);
|
|
858
1396
|
}
|
|
859
1397
|
return out;
|
|
@@ -865,7 +1403,7 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
865
1403
|
// src/vector/snap.ts
|
|
866
1404
|
var VECTOR_CONSTRUCTION_ANGLES = [0, 45, 90, 135];
|
|
867
1405
|
function constrainToLeave(leave, p) {
|
|
868
|
-
if (!_optionalChain([leave, 'optionalAccess',
|
|
1406
|
+
if (!_optionalChain([leave, 'optionalAccess', _19 => _19.constrain])) return p;
|
|
869
1407
|
const dx = p.x - leave.at.x;
|
|
870
1408
|
const dy = p.y - leave.at.y;
|
|
871
1409
|
switch (leave.constrain) {
|
|
@@ -876,9 +1414,9 @@ function constrainToLeave(leave, p) {
|
|
|
876
1414
|
return { x: leave.at.x + Math.sign(dx || 1) * s, y: leave.at.y + Math.sign(dy || 1) * s };
|
|
877
1415
|
}
|
|
878
1416
|
default: {
|
|
879
|
-
const
|
|
1417
|
+
const len2 = Math.hypot(dx, dy);
|
|
880
1418
|
const a = Math.round(Math.atan2(dy, dx) / (Math.PI / 4)) * (Math.PI / 4);
|
|
881
|
-
return { x: leave.at.x + Math.cos(a) *
|
|
1419
|
+
return { x: leave.at.x + Math.cos(a) * len2, y: leave.at.y + Math.sin(a) * len2 };
|
|
882
1420
|
}
|
|
883
1421
|
}
|
|
884
1422
|
}
|
|
@@ -887,24 +1425,24 @@ var CROSSING_PAIRS = 32;
|
|
|
887
1425
|
var CURVE_SAMPLES = 48;
|
|
888
1426
|
var BISECT = 50;
|
|
889
1427
|
var EQUAL = 1e-6;
|
|
890
|
-
function bound(sorted, key,
|
|
1428
|
+
function bound(sorted, key, v2, strict) {
|
|
891
1429
|
let lo = 0;
|
|
892
1430
|
let hi = sorted.length;
|
|
893
1431
|
while (lo < hi) {
|
|
894
1432
|
const mid = lo + hi >>> 1;
|
|
895
1433
|
const k = key(sorted[mid]);
|
|
896
|
-
if (strict ? k <=
|
|
1434
|
+
if (strict ? k <= v2 : k < v2) lo = mid + 1;
|
|
897
1435
|
else hi = mid;
|
|
898
1436
|
}
|
|
899
1437
|
return lo;
|
|
900
1438
|
}
|
|
901
|
-
function within(sorted, key,
|
|
902
|
-
return sorted.slice(bound(sorted, key,
|
|
1439
|
+
function within(sorted, key, v2, tol) {
|
|
1440
|
+
return sorted.slice(bound(sorted, key, v2 - tol, false), bound(sorted, key, v2 + tol, true));
|
|
903
1441
|
}
|
|
904
|
-
var linesNear = (lines,
|
|
1442
|
+
var linesNear = (lines, v2, tol) => within(lines, (l) => l.v, v2, tol);
|
|
905
1443
|
var distance = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
906
1444
|
var toPoint = (p) => [p.x, p.y];
|
|
907
|
-
var
|
|
1445
|
+
var toVec2 = (p) => ({ x: p[0], y: p[1] });
|
|
908
1446
|
var LABELS = {
|
|
909
1447
|
anchor: "anchor",
|
|
910
1448
|
centre: "centre",
|
|
@@ -976,7 +1514,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
976
1514
|
moving.set(r.nodeId, set);
|
|
977
1515
|
}
|
|
978
1516
|
const t = _VectorSnapTargets.collect(doc, new Set(moving.keys()), "segments", false);
|
|
979
|
-
t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access',
|
|
1517
|
+
t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access', _20 => _20.get, 'call', _21 => _21(id), 'optionalAccess', _22 => _22.has, 'call', _23 => _23(`${s}:${i}`)]), true);
|
|
980
1518
|
return t.index();
|
|
981
1519
|
}
|
|
982
1520
|
/**
|
|
@@ -1022,7 +1560,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1022
1560
|
const count = subpathSegmentCount(sp);
|
|
1023
1561
|
for (let i = 0; i < count && budget > 0; i++) {
|
|
1024
1562
|
if (moving(i) || moving((i + 1) % n)) continue;
|
|
1025
|
-
const seg = subpathSegment(sp, i).map((q) => toPoint(applyMatrix(m,
|
|
1563
|
+
const seg = subpathSegment(sp, i).map((q) => toPoint(applyMatrix(m, toVec2(q))));
|
|
1026
1564
|
let minX = Infinity;
|
|
1027
1565
|
let minY = Infinity;
|
|
1028
1566
|
let maxX = -Infinity;
|
|
@@ -1094,7 +1632,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1094
1632
|
}
|
|
1095
1633
|
const b = vectorNodeBounds(n, parent);
|
|
1096
1634
|
const f = nodeFrame(n, parent, b);
|
|
1097
|
-
if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess',
|
|
1635
|
+
if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess', _24 => _24.centre]), () => ( null)));
|
|
1098
1636
|
}
|
|
1099
1637
|
};
|
|
1100
1638
|
visit(doc.nodes, IDENTITY_MATRIX);
|
|
@@ -1139,7 +1677,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1139
1677
|
lines: lines2,
|
|
1140
1678
|
labels: [this.label(q, kind)]
|
|
1141
1679
|
});
|
|
1142
|
-
if (_optionalChain([leave, 'optionalAccess',
|
|
1680
|
+
if (_optionalChain([leave, 'optionalAccess', _25 => _25.constrain])) {
|
|
1143
1681
|
const q = constrainToLeave(leave, p);
|
|
1144
1682
|
const hit = this.slide(leave.at, { x: q.x - leave.at.x, y: q.y - leave.at.y }, q, tol, true);
|
|
1145
1683
|
return hit ? { point: hit.point, x: true, y: true, ...this.linedUp(hit.point, hit.from) } : none(q);
|
|
@@ -1155,7 +1693,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1155
1693
|
}
|
|
1156
1694
|
const on = this.onSegment(near2);
|
|
1157
1695
|
if (on) return at(on, "path");
|
|
1158
|
-
if (_optionalChain([leave, 'optionalAccess',
|
|
1696
|
+
if (_optionalChain([leave, 'optionalAccess', _26 => _26.angles, 'optionalAccess', _27 => _27.length])) {
|
|
1159
1697
|
const c = construction(leave, p, tol);
|
|
1160
1698
|
if (c) {
|
|
1161
1699
|
const hit = this.slide(leave.at, c.dir, c.point, tol, false);
|
|
@@ -1166,9 +1704,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1166
1704
|
return { point: c.point, kind: "construction", x: true, y: true, lines: [line("construction", leave.at, c.point)], labels: [] };
|
|
1167
1705
|
}
|
|
1168
1706
|
}
|
|
1169
|
-
const nearest = (lines2,
|
|
1707
|
+
const nearest = (lines2, v2) => {
|
|
1170
1708
|
let best = null;
|
|
1171
|
-
for (const l of linesNear(lines2,
|
|
1709
|
+
for (const l of linesNear(lines2, v2, tol)) if (!best || Math.abs(l.v - v2) < Math.abs(best.v - v2)) best = l;
|
|
1172
1710
|
return best;
|
|
1173
1711
|
};
|
|
1174
1712
|
const bx = nearest(this.xs, p.x);
|
|
@@ -1228,16 +1766,16 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1228
1766
|
/** Target segments whose control box reaches `p` and which pass within `tol` of it, nearest first. */
|
|
1229
1767
|
segmentsNear(p, tol) {
|
|
1230
1768
|
const out = [];
|
|
1231
|
-
const
|
|
1769
|
+
const pt2 = toPoint(p);
|
|
1232
1770
|
for (const s of this.segments) {
|
|
1233
1771
|
if (p.x < s.minX - tol || p.x > s.maxX + tol || p.y < s.minY - tol || p.y > s.maxY + tol) continue;
|
|
1234
|
-
const hit = _chunkBGNPT5PEcjs.segmentNearest.call(void 0, s.seg,
|
|
1772
|
+
const hit = _chunkBGNPT5PEcjs.segmentNearest.call(void 0, s.seg, pt2);
|
|
1235
1773
|
if (hit.distance <= tol) out.push({ seg: s.seg, t: hit.t, distance: hit.distance });
|
|
1236
1774
|
}
|
|
1237
1775
|
return out.sort((a, b) => a.distance - b.distance);
|
|
1238
1776
|
}
|
|
1239
1777
|
onSegment(near2) {
|
|
1240
|
-
return near2.length ?
|
|
1778
|
+
return near2.length ? toVec2(_chunkBGNPT5PEcjs.segmentPoint.call(void 0, near2[0].seg, near2[0].t)) : null;
|
|
1241
1779
|
}
|
|
1242
1780
|
/** Where two of the target segments near `p` cross, the crossing nearest `p` within `tol`. */
|
|
1243
1781
|
crossing(near2, p, tol) {
|
|
@@ -1247,7 +1785,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1247
1785
|
for (let i = 0; i < list.length; i++) {
|
|
1248
1786
|
for (let j = i + 1; j < list.length; j++) {
|
|
1249
1787
|
for (const hit of _chunkBGNPT5PEcjs.segmentIntersections.call(void 0, list[i].seg, list[j].seg)) {
|
|
1250
|
-
const q =
|
|
1788
|
+
const q = toVec2(hit.point);
|
|
1251
1789
|
const d = distance(q, p);
|
|
1252
1790
|
if (d <= tol && d < bestD) {
|
|
1253
1791
|
best = q;
|
|
@@ -1285,15 +1823,15 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1285
1823
|
* with nothing spaces the box evenly in its row or column. Returns the correction and guides.
|
|
1286
1824
|
*/
|
|
1287
1825
|
snapRect(r, tol, options = {}) {
|
|
1288
|
-
const axes = { x: _optionalChain([options, 'access',
|
|
1826
|
+
const axes = { x: _optionalChain([options, 'access', _28 => _28.axes, 'optionalAccess', _29 => _29.x]) !== false, y: _optionalChain([options, 'access', _30 => _30.axes, 'optionalAccess', _31 => _31.y]) !== false };
|
|
1289
1827
|
const nearest = (lines, values) => {
|
|
1290
1828
|
let best = null;
|
|
1291
|
-
for (const
|
|
1829
|
+
for (const v2 of values) for (const l of linesNear(lines, v2, tol)) if (!best || Math.abs(l.v - v2) < Math.abs(best.d)) best = { d: l.v - v2, from: l.from };
|
|
1292
1830
|
return best;
|
|
1293
1831
|
};
|
|
1294
1832
|
const bx = axes.x ? nearest(this.xs, [r.x, r.x + r.width / 2, r.x + r.width]) : null;
|
|
1295
1833
|
const by = axes.y ? nearest(this.ys, [r.y, r.y + r.height / 2, r.y + r.height]) : null;
|
|
1296
|
-
const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess',
|
|
1834
|
+
const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess', _32 => _32.d]), () => ( 0)), dy: _nullishCoalesce(_optionalChain([by, 'optionalAccess', _33 => _33.d]), () => ( 0)), x: !!bx, y: !!by, lines: [], labels: [] };
|
|
1297
1835
|
const done = { ...r, x: r.x + out.dx, y: r.y + out.dy };
|
|
1298
1836
|
if (bx) {
|
|
1299
1837
|
const x = bx.from.x;
|
|
@@ -1331,7 +1869,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1331
1869
|
evenSpacing(r, horizontal, tol) {
|
|
1332
1870
|
const span = (b, x) => x ? [b.x, b.x + b.width] : [b.y, b.y + b.height];
|
|
1333
1871
|
const [r0, r1] = span(r, horizontal);
|
|
1334
|
-
const
|
|
1872
|
+
const len2 = r1 - r0;
|
|
1335
1873
|
const [c0, c1] = span(r, !horizontal);
|
|
1336
1874
|
const row = this.boxes.map((b) => ({ b, a0: span(b, horizontal)[0], a1: span(b, horizontal)[1] })).filter((e) => span(e.b, !horizontal)[0] < c1 && span(e.b, !horizontal)[1] > c0 && (e.a1 <= r0 + tol || e.a0 >= r1 - tol)).sort((a, b) => a.a0 - b.a0);
|
|
1337
1875
|
if (!row.length) return null;
|
|
@@ -1351,17 +1889,17 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1351
1889
|
if (e.a0 >= r1 - tol && (!after || e.a0 < after.a0)) after = e;
|
|
1352
1890
|
}
|
|
1353
1891
|
const starts = [];
|
|
1354
|
-
if (before && after && after.a0 - before.a1 >
|
|
1892
|
+
if (before && after && after.a0 - before.a1 > len2) starts.push({ start: (before.a1 + after.a0 - len2) / 2, repeats: null });
|
|
1355
1893
|
for (const { g } of pairs) {
|
|
1356
1894
|
if (before) starts.push({ start: before.a1 + g, repeats: g });
|
|
1357
|
-
if (after) starts.push({ start: after.a0 - g -
|
|
1895
|
+
if (after) starts.push({ start: after.a0 - g - len2, repeats: g });
|
|
1358
1896
|
}
|
|
1359
1897
|
let pick = null;
|
|
1360
1898
|
for (const s of starts) if (Math.abs(s.start - r0) <= tol && (!pick || Math.abs(s.start - r0) < Math.abs(pick.start - r0))) pick = s;
|
|
1361
1899
|
if (!pick) return null;
|
|
1362
1900
|
const { start, repeats } = pick;
|
|
1363
1901
|
const at = horizontal ? { ...r, x: start } : { ...r, y: start };
|
|
1364
|
-
const end = start +
|
|
1902
|
+
const end = start + len2;
|
|
1365
1903
|
const gaps = [];
|
|
1366
1904
|
if (before && (repeats === null || Math.abs(start - before.a1 - repeats) <= EQUAL)) gaps.push([before.a1, start, mid(before.b, at)]);
|
|
1367
1905
|
if (after && (repeats === null || Math.abs(after.a0 - end - repeats) <= EQUAL)) gaps.push([end, after.a0, mid(after.b, at)]);
|
|
@@ -1372,9 +1910,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1372
1910
|
}
|
|
1373
1911
|
/** A gap mark: a line across the gap with a tick at each end, and its length as a label. */
|
|
1374
1912
|
gapMarks([u0, u1, c], horizontal, tick, out) {
|
|
1375
|
-
const
|
|
1376
|
-
out.lines.push(line("spacing",
|
|
1377
|
-
out.labels.push(this.label(
|
|
1913
|
+
const pt2 = (u, v2) => horizontal ? { x: u, y: v2 } : { x: v2, y: u };
|
|
1914
|
+
out.lines.push(line("spacing", pt2(u0, c), pt2(u1, c)), line("spacing", pt2(u0, c - tick), pt2(u0, c + tick)), line("spacing", pt2(u1, c - tick), pt2(u1, c + tick)));
|
|
1915
|
+
out.labels.push(this.label(pt2((u0 + u1) / 2, c), "spacing", fmtLength(u1 - u0)));
|
|
1378
1916
|
}
|
|
1379
1917
|
/** The other objects' side length nearest `length`, within `tol`, or null. */
|
|
1380
1918
|
matchSize(length2, tol) {
|
|
@@ -1401,9 +1939,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1401
1939
|
const hp = handlePos(handle, frame);
|
|
1402
1940
|
const d0 = { x: hp.x - origin.x, y: hp.y - origin.y };
|
|
1403
1941
|
const valid = (n, s) => Number.isFinite(n) && n * s > 0;
|
|
1404
|
-
const nearest = (
|
|
1942
|
+
const nearest = (v2, lines) => {
|
|
1405
1943
|
let best = null;
|
|
1406
|
-
for (const l of linesNear(lines,
|
|
1944
|
+
for (const l of linesNear(lines, v2, tol)) if (!best || Math.abs(l.v - v2) < Math.abs(best.v - v2)) best = l;
|
|
1407
1945
|
return best;
|
|
1408
1946
|
};
|
|
1409
1947
|
let nx = sx;
|
|
@@ -1416,9 +1954,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1416
1954
|
const on = this.nearestPoint(p, tol);
|
|
1417
1955
|
const tries = [];
|
|
1418
1956
|
if (on) tries.push({ tx: on.p.x, ty: on.p.y, s: { hx: null, hy: null, on } });
|
|
1419
|
-
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess',
|
|
1420
|
-
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess',
|
|
1421
|
-
tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess',
|
|
1957
|
+
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _34 => _34.v]), () => ( null)), ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _35 => _35.v]), () => ( null)), s: { hx, hy, on: null } });
|
|
1958
|
+
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _36 => _36.v]), () => ( null)), ty: null, s: { hx, hy: null, on: null } });
|
|
1959
|
+
tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _37 => _37.v]), () => ( null)), s: { hx: null, hy, on: null } });
|
|
1422
1960
|
for (const { tx, ty, s } of tries) {
|
|
1423
1961
|
if (tx === null && ty === null) continue;
|
|
1424
1962
|
const q = applyMatrix(toLocal, { x: _nullishCoalesce(tx, () => ( p.x)), y: _nullishCoalesce(ty, () => ( p.y)) });
|
|
@@ -1454,9 +1992,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1454
1992
|
};
|
|
1455
1993
|
for (const h of [handle, ...ends]) {
|
|
1456
1994
|
const hv = handlePos(h, frame);
|
|
1457
|
-
const
|
|
1458
|
-
const base = applyMatrix(toDoc, { x: origin.x + c.x *
|
|
1459
|
-
const dir = applyMatrix(toDoc, { x: e.x *
|
|
1995
|
+
const v2 = { x: hv.x - origin.x, y: hv.y - origin.y };
|
|
1996
|
+
const base = applyMatrix(toDoc, { x: origin.x + c.x * v2.x, y: origin.y + c.y * v2.y });
|
|
1997
|
+
const dir = applyMatrix(toDoc, { x: e.x * v2.x, y: e.y * v2.y });
|
|
1460
1998
|
const p = { x: base.x + dir.x * s0, y: base.y + dir.y * s0 };
|
|
1461
1999
|
const l2 = dir.x * dir.x + dir.y * dir.y;
|
|
1462
2000
|
const on = l2 > 1e-18 ? this.nearestPoint(p, tol) : null;
|
|
@@ -1489,16 +2027,16 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1489
2027
|
const sized = [];
|
|
1490
2028
|
if (!proportional) {
|
|
1491
2029
|
if (movesX && !snap.hx && !(frame.angle && snap.hy) && frame.width > 1e-9) {
|
|
1492
|
-
const
|
|
1493
|
-
if (
|
|
1494
|
-
out.sx = Math.sign(out.sx || 1) * (
|
|
2030
|
+
const len2 = this.matchSize(Math.abs(out.sx) * frame.width, tol);
|
|
2031
|
+
if (len2 !== null && len2 > 0) {
|
|
2032
|
+
out.sx = Math.sign(out.sx || 1) * (len2 / frame.width);
|
|
1495
2033
|
sized.push("x");
|
|
1496
2034
|
}
|
|
1497
2035
|
}
|
|
1498
2036
|
if (movesY && !snap.hy && !(frame.angle && snap.hx) && frame.height > 1e-9) {
|
|
1499
|
-
const
|
|
1500
|
-
if (
|
|
1501
|
-
out.sy = Math.sign(out.sy || 1) * (
|
|
2037
|
+
const len2 = this.matchSize(Math.abs(out.sy) * frame.height, tol);
|
|
2038
|
+
if (len2 !== null && len2 > 0) {
|
|
2039
|
+
out.sy = Math.sign(out.sy || 1) * (len2 / frame.height);
|
|
1502
2040
|
sized.push("y");
|
|
1503
2041
|
}
|
|
1504
2042
|
}
|
|
@@ -1549,14 +2087,14 @@ function line(kind, a, b) {
|
|
|
1549
2087
|
return { kind, x1: a.x, y1: a.y, x2: b.x, y2: b.y };
|
|
1550
2088
|
}
|
|
1551
2089
|
function construction(leave, p, tol) {
|
|
1552
|
-
const
|
|
1553
|
-
if (Math.hypot(
|
|
2090
|
+
const v2 = { x: p.x - leave.at.x, y: p.y - leave.at.y };
|
|
2091
|
+
if (Math.hypot(v2.x, v2.y) <= tol) return null;
|
|
1554
2092
|
let best = null;
|
|
1555
2093
|
for (const a of _nullishCoalesce(leave.angles, () => ( []))) {
|
|
1556
2094
|
const r = a * Math.PI / 180;
|
|
1557
2095
|
const exact = (n) => Math.abs(n) < 1e-12 ? 0 : n;
|
|
1558
2096
|
const dir = { x: exact(Math.cos(r)), y: exact(-Math.sin(r)) };
|
|
1559
|
-
const k =
|
|
2097
|
+
const k = v2.x * dir.x + v2.y * dir.y;
|
|
1560
2098
|
const point = { x: leave.at.x + dir.x * k, y: leave.at.y + dir.y * k };
|
|
1561
2099
|
const d = distance(point, p);
|
|
1562
2100
|
if (d <= tol && (!best || d < best.d)) best = { dir, point, d };
|
|
@@ -1581,7 +2119,7 @@ function solveOnSegment(seg, base, cond) {
|
|
|
1581
2119
|
vals.push(cond(r, d));
|
|
1582
2120
|
scale = Math.max(scale, Math.hypot(r[0], r[1]) * Math.hypot(d[0], d[1]));
|
|
1583
2121
|
}
|
|
1584
|
-
if (!(scale > 0) || vals.every((
|
|
2122
|
+
if (!(scale > 0) || vals.every((v2) => Math.abs(v2) <= scale * 1e-12)) return [];
|
|
1585
2123
|
const out = [];
|
|
1586
2124
|
for (let i = 0; i < CURVE_SAMPLES; i++) {
|
|
1587
2125
|
const ga = vals[i];
|
|
@@ -1614,8 +2152,8 @@ function solveOnSegment(seg, base, cond) {
|
|
|
1614
2152
|
}
|
|
1615
2153
|
|
|
1616
2154
|
// src/vector/pathEdit.ts
|
|
1617
|
-
var
|
|
1618
|
-
var
|
|
2155
|
+
var EPS3 = 1e-9;
|
|
2156
|
+
var unit2 = (x, y) => {
|
|
1619
2157
|
const l = Math.hypot(x, y);
|
|
1620
2158
|
return l > 1e-12 && Number.isFinite(l) ? [x / l, y / l] : null;
|
|
1621
2159
|
};
|
|
@@ -1628,14 +2166,14 @@ function cubicOf(sp, i) {
|
|
|
1628
2166
|
var isLine = (sp, i) => subpathSegment(sp, i).length === 2;
|
|
1629
2167
|
function startTangent(c) {
|
|
1630
2168
|
for (let k = 1; k < 4; k++) {
|
|
1631
|
-
const u =
|
|
2169
|
+
const u = unit2(c[k][0] - c[0][0], c[k][1] - c[0][1]);
|
|
1632
2170
|
if (u) return u;
|
|
1633
2171
|
}
|
|
1634
2172
|
return [1, 0];
|
|
1635
2173
|
}
|
|
1636
2174
|
function endTangent(c) {
|
|
1637
2175
|
for (let k = 2; k >= 0; k--) {
|
|
1638
|
-
const u =
|
|
2176
|
+
const u = unit2(c[3][0] - c[k][0], c[3][1] - c[k][1]);
|
|
1639
2177
|
if (u) return u;
|
|
1640
2178
|
}
|
|
1641
2179
|
return [1, 0];
|
|
@@ -1643,11 +2181,11 @@ function endTangent(c) {
|
|
|
1643
2181
|
function sample(c, n, out, withStart) {
|
|
1644
2182
|
for (let i = withStart ? 0 : 1; i <= n; i++) out.push(_chunkBGNPT5PEcjs.segmentPoint.call(void 0, c, i / n));
|
|
1645
2183
|
}
|
|
1646
|
-
var
|
|
2184
|
+
var onAnchor2 = (a, h) => !h || Math.abs(h.x - a.x) < EPS3 && Math.abs(h.y - a.y) < EPS3;
|
|
1647
2185
|
function tidy(a, keepType = true) {
|
|
1648
2186
|
const next = cloneAnchor(a);
|
|
1649
|
-
if (
|
|
1650
|
-
if (
|
|
2187
|
+
if (onAnchor2(next, next.in)) delete next.in;
|
|
2188
|
+
if (onAnchor2(next, next.out)) delete next.out;
|
|
1651
2189
|
const shown = inferAnchorType(next);
|
|
1652
2190
|
const type = keepType && a.type ? a.type === "symmetric" && shown !== "symmetric" ? shown === "corner" ? "corner" : "smooth" : a.type === "smooth" && shown === "corner" ? "corner" : a.type : shown;
|
|
1653
2191
|
if (type === "corner") delete next.type;
|
|
@@ -1755,8 +2293,8 @@ function curvatureMoveAnchor(sp, index, q) {
|
|
|
1755
2293
|
const a = sp.anchors[index];
|
|
1756
2294
|
if (!a) return { anchors, closed: sp.closed };
|
|
1757
2295
|
const own = [
|
|
1758
|
-
a.in && !
|
|
1759
|
-
a.out && !
|
|
2296
|
+
a.in && !onAnchor2(a, a.in) ? { x: a.in.x - a.x, y: a.in.y - a.y } : null,
|
|
2297
|
+
a.out && !onAnchor2(a, a.out) ? { x: a.out.x - a.x, y: a.out.y - a.y } : null
|
|
1760
2298
|
];
|
|
1761
2299
|
const ends = [null, null];
|
|
1762
2300
|
neighbours(sp, index).forEach((j, side) => {
|
|
@@ -1775,15 +2313,16 @@ function curvatureMoveAnchor(sp, index, q) {
|
|
|
1775
2313
|
if (own[0]) moved.in = { x: q.x + own[0].x, y: q.y + own[0].y };
|
|
1776
2314
|
if (own[1]) moved.out = { x: q.x + own[1].x, y: q.y + own[1].y };
|
|
1777
2315
|
if (a.type) moved.type = a.type;
|
|
2316
|
+
if (a.corner) moved.corner = { ...a.corner };
|
|
1778
2317
|
const [prev, next] = ends;
|
|
1779
2318
|
if (a.type && a.type !== "corner" && prev && next) {
|
|
1780
2319
|
const dx = next.x - prev.x;
|
|
1781
2320
|
const dy = next.y - prev.y;
|
|
1782
2321
|
const l = Math.hypot(dx, dy);
|
|
1783
2322
|
if (l > 1e-9) {
|
|
1784
|
-
const
|
|
1785
|
-
let li =
|
|
1786
|
-
let lo =
|
|
2323
|
+
const len2 = (h, to) => h ? Math.hypot(h.x, h.y) : Math.hypot(q.x - to.x, q.y - to.y) / 3;
|
|
2324
|
+
let li = len2(own[0], prev);
|
|
2325
|
+
let lo = len2(own[1], next);
|
|
1787
2326
|
if (a.type === "symmetric") li = lo = (li + lo) / 2;
|
|
1788
2327
|
moved.in = { x: q.x - dx * li / l, y: q.y - dy * li / l };
|
|
1789
2328
|
moved.out = { x: q.x + dx * lo / l, y: q.y + dy * lo / l };
|
|
@@ -1824,7 +2363,7 @@ function splitSubpathAt(sp, segment, t, endTolerance = 1e-6) {
|
|
|
1824
2363
|
const { subpath, index } = insertAnchor(sp, segment, t);
|
|
1825
2364
|
return cutSubpathAt(subpath, [index]);
|
|
1826
2365
|
}
|
|
1827
|
-
var
|
|
2366
|
+
var endOf2 = (sp, last) => sp.anchors[last ? sp.anchors.length - 1 : 0];
|
|
1828
2367
|
var dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
1829
2368
|
function reverse(sp) {
|
|
1830
2369
|
return {
|
|
@@ -1834,6 +2373,7 @@ function reverse(sp) {
|
|
|
1834
2373
|
if (a.out) next.in = { ...a.out };
|
|
1835
2374
|
if (a.in) next.out = { ...a.in };
|
|
1836
2375
|
if (a.type) next.type = a.type;
|
|
2376
|
+
if (a.corner) next.corner = { ...a.corner };
|
|
1837
2377
|
return next;
|
|
1838
2378
|
})
|
|
1839
2379
|
};
|
|
@@ -1867,7 +2407,7 @@ function joinSubpaths(subpaths, tolerance) {
|
|
|
1867
2407
|
for (let j = i + 1; j < open.length; j++) {
|
|
1868
2408
|
for (const ei of [false, true]) {
|
|
1869
2409
|
for (const ej of [false, true]) {
|
|
1870
|
-
const d = dist(
|
|
2410
|
+
const d = dist(endOf2(open[i], ei), endOf2(open[j], ej));
|
|
1871
2411
|
if (d < best.d) best = { d, i, j, ei, ej };
|
|
1872
2412
|
}
|
|
1873
2413
|
}
|
|
@@ -1905,7 +2445,7 @@ function smoothSubpath(sp, amount = 1, only) {
|
|
|
1905
2445
|
const prev = orig[(i + n - 1) % n];
|
|
1906
2446
|
const next = orig[(i + 1) % n];
|
|
1907
2447
|
const p = orig[i];
|
|
1908
|
-
const dir =
|
|
2448
|
+
const dir = unit2(next.x - prev.x, next.y - prev.y);
|
|
1909
2449
|
if (!dir) continue;
|
|
1910
2450
|
const li = dist(p, prev) / 3;
|
|
1911
2451
|
const lo = dist(p, next) / 3;
|
|
@@ -1962,12 +2502,12 @@ function mergePair(a, b, tol) {
|
|
|
1962
2502
|
if (a.line && b.line) {
|
|
1963
2503
|
const cx = b3[0] - a0[0];
|
|
1964
2504
|
const cy = b3[1] - a0[1];
|
|
1965
|
-
const
|
|
1966
|
-
if (
|
|
2505
|
+
const len2 = Math.hypot(cx, cy);
|
|
2506
|
+
if (len2 < 1e-12) return null;
|
|
1967
2507
|
const mx = a3[0] - a0[0];
|
|
1968
2508
|
const my = a3[1] - a0[1];
|
|
1969
|
-
const along = (mx * cx + my * cy) /
|
|
1970
|
-
return Math.abs((mx * cy - my * cx) /
|
|
2509
|
+
const along = (mx * cx + my * cy) / len2;
|
|
2510
|
+
return Math.abs((mx * cy - my * cx) / len2) <= tol && along >= 0 && along <= len2 ? { c: [a0, b3], line: true } : null;
|
|
1971
2511
|
}
|
|
1972
2512
|
const ca = a.line ? [a0, a0, a3, a3] : a.c;
|
|
1973
2513
|
const cb = b.line ? [a3, a3, b3, b3] : b.c;
|
|
@@ -2091,7 +2631,7 @@ function lineHits(p, q, seg) {
|
|
|
2091
2631
|
const dy = q[1] - p[1];
|
|
2092
2632
|
const len2 = dx * dx + dy * dy;
|
|
2093
2633
|
if (len2 < 1e-24) return [];
|
|
2094
|
-
const h = (
|
|
2634
|
+
const h = (pt2) => (pt2[0] - p[0]) * -dy + (pt2[1] - p[1]) * dx;
|
|
2095
2635
|
let coeffs;
|
|
2096
2636
|
if (seg.length === 2) coeffs = [0, 0, h(seg[1]) - h(seg[0]), h(seg[0])];
|
|
2097
2637
|
else {
|
|
@@ -2099,7 +2639,7 @@ function lineHits(p, q, seg) {
|
|
|
2099
2639
|
coeffs = [-h0 + 3 * h1 - 3 * h2 + h3, 3 * h0 - 6 * h1 + 3 * h2, -3 * h0 + 3 * h1, h0];
|
|
2100
2640
|
}
|
|
2101
2641
|
if (coeffs.every((c) => Math.abs(c) < 1e-12 * Math.max(1, len2))) return [];
|
|
2102
|
-
const scale = Math.sqrt(len2) * Math.max(1, ...seg.map((
|
|
2642
|
+
const scale = Math.sqrt(len2) * Math.max(1, ...seg.map((pt2) => Math.abs(pt2[0]) + Math.abs(pt2[1])));
|
|
2103
2643
|
const out = [];
|
|
2104
2644
|
for (const t of rootsInUnit(...coeffs, scale)) {
|
|
2105
2645
|
const point = _chunkBGNPT5PEcjs.segmentPoint.call(void 0, seg, t);
|
|
@@ -2326,12 +2866,12 @@ function simplifyPolyline(points, tolerance) {
|
|
|
2326
2866
|
const [ax, ay] = points[a];
|
|
2327
2867
|
const dx = points[b][0] - ax;
|
|
2328
2868
|
const dy = points[b][1] - ay;
|
|
2329
|
-
const
|
|
2869
|
+
const len2 = Math.hypot(dx, dy);
|
|
2330
2870
|
let far = -1;
|
|
2331
2871
|
let farD = 0;
|
|
2332
2872
|
for (let i = a + 1; i < b; i++) {
|
|
2333
2873
|
const [px, py] = points[i];
|
|
2334
|
-
const d =
|
|
2874
|
+
const d = len2 < 1e-12 ? Math.hypot(px - ax, py - ay) : Math.abs((px - ax) * dy - (py - ay) * dx) / len2;
|
|
2335
2875
|
if (d > farD) {
|
|
2336
2876
|
farD = d;
|
|
2337
2877
|
far = i;
|
|
@@ -2443,11 +2983,11 @@ function snapSquare(x, y, w, h) {
|
|
|
2443
2983
|
}
|
|
2444
2984
|
function turning(a, b, c) {
|
|
2445
2985
|
const u = [b[0] - a[0], b[1] - a[1]];
|
|
2446
|
-
const
|
|
2986
|
+
const v2 = [c[0] - b[0], c[1] - b[1]];
|
|
2447
2987
|
const lu = Math.hypot(u[0], u[1]);
|
|
2448
|
-
const lv = Math.hypot(
|
|
2988
|
+
const lv = Math.hypot(v2[0], v2[1]);
|
|
2449
2989
|
if (lu <= 0 || lv <= 0) return 0;
|
|
2450
|
-
return Math.acos(Math.min(1, Math.max(-1, (u[0] *
|
|
2990
|
+
return Math.acos(Math.min(1, Math.max(-1, (u[0] * v2[0] + u[1] * v2[1]) / (lu * lv)))) * 180 / Math.PI;
|
|
2451
2991
|
}
|
|
2452
2992
|
function rdp(p, eps) {
|
|
2453
2993
|
const n = p.length;
|
|
@@ -2575,6 +3115,21 @@ function recognizeInkShape(points, options = {}) {
|
|
|
2575
3115
|
var DEFAULT_VECTOR_SNAP = { grid: 0, objects: true, guides: true, threshold: 5, angles: VECTOR_CONSTRUCTION_ANGLES };
|
|
2576
3116
|
var DEFAULT_VECTOR_PATH_EDIT = { keepShapeOnDelete: true, curvatureMoves: false, pencilSmoothing: 0, recognizeShapes: false, eraserSize: 10 };
|
|
2577
3117
|
var VECTOR_PENCIL_STRING_PX = 100;
|
|
3118
|
+
var VECTOR_STYLE_KEYS = [
|
|
3119
|
+
"fill",
|
|
3120
|
+
"stroke",
|
|
3121
|
+
"strokeWidth",
|
|
3122
|
+
"strokeLinecap",
|
|
3123
|
+
"strokeLinejoin",
|
|
3124
|
+
"strokeDasharray",
|
|
3125
|
+
"fillRule",
|
|
3126
|
+
"strokeAlign",
|
|
3127
|
+
"startArrow",
|
|
3128
|
+
"endArrow",
|
|
3129
|
+
"arrowAlign",
|
|
3130
|
+
"startArrowScale",
|
|
3131
|
+
"endArrowScale"
|
|
3132
|
+
];
|
|
2578
3133
|
var VECTOR_CLIPBOARD_TYPE = "pixerate/vector";
|
|
2579
3134
|
var DEFAULT_DEFAULTS = {
|
|
2580
3135
|
fill: "#d4d4d8",
|
|
@@ -2602,7 +3157,7 @@ function getEditablePathIds(state) {
|
|
|
2602
3157
|
}
|
|
2603
3158
|
}
|
|
2604
3159
|
}
|
|
2605
|
-
return [...ids].filter((id) => _optionalChain([findVectorNode, 'call',
|
|
3160
|
+
return [...ids].filter((id) => _optionalChain([findVectorNode, 'call', _38 => _38(state.document.nodes, id), 'optionalAccess', _39 => _39.type]) === "path");
|
|
2606
3161
|
}
|
|
2607
3162
|
function getVisibleAnchors(state) {
|
|
2608
3163
|
const out = [];
|
|
@@ -2617,7 +3172,7 @@ function getVisibleHandles(state) {
|
|
|
2617
3172
|
const seen = /* @__PURE__ */ new Set();
|
|
2618
3173
|
const push = (node, s, i, handle) => {
|
|
2619
3174
|
const sp = node.subpaths[s];
|
|
2620
|
-
const a = _optionalChain([sp, 'optionalAccess',
|
|
3175
|
+
const a = _optionalChain([sp, 'optionalAccess', _40 => _40.anchors, 'access', _41 => _41[i]]);
|
|
2621
3176
|
if (!a || !a[handle]) return;
|
|
2622
3177
|
const key = `${node.id}:${s}:${i}:${handle}`;
|
|
2623
3178
|
if (seen.has(key)) return;
|
|
@@ -2626,8 +3181,8 @@ function getVisibleHandles(state) {
|
|
|
2626
3181
|
};
|
|
2627
3182
|
if (state.tool === "pen" && state.pen) {
|
|
2628
3183
|
const node = findVectorNode(state.document.nodes, state.pen.nodeId);
|
|
2629
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
2630
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
3184
|
+
const sp = _optionalChain([node, 'optionalAccess', _42 => _42.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
|
|
3185
|
+
if (_optionalChain([node, 'optionalAccess', _43 => _43.type]) === "path" && sp) {
|
|
2631
3186
|
const last = sp.anchors.length - 1;
|
|
2632
3187
|
push(node, state.pen.subpath, last, "in");
|
|
2633
3188
|
push(node, state.pen.subpath, last, "out");
|
|
@@ -2651,9 +3206,32 @@ function getVisibleHandles(state) {
|
|
|
2651
3206
|
}
|
|
2652
3207
|
return out;
|
|
2653
3208
|
}
|
|
3209
|
+
var VECTOR_CORNER_WIDGET_INSET = 10;
|
|
3210
|
+
function getVectorCornerWidgets(state) {
|
|
3211
|
+
if (state.tool !== "direct" || state.pen) return [];
|
|
3212
|
+
const zoom = state.viewport.zoom;
|
|
3213
|
+
const out = [];
|
|
3214
|
+
for (const id of getEditablePathIds(state)) {
|
|
3215
|
+
const node = findVectorNode(state.document.nodes, id);
|
|
3216
|
+
const picked = state.selectedAnchors.filter((r) => r.nodeId === id);
|
|
3217
|
+
const m = _nullishCoalesce(vectorWorldMatrix(state.document.nodes, id), () => ( IDENTITY_MATRIX));
|
|
3218
|
+
for (const c of vectorCorners(node.subpaths)) {
|
|
3219
|
+
if (picked.length && !picked.some((r) => r.subpath === c.subpath && r.index === c.index)) continue;
|
|
3220
|
+
const side = Math.min(c.lu, c.lv);
|
|
3221
|
+
if (side * zoom < 3 * VECTOR_CORNER_WIDGET_INSET) continue;
|
|
3222
|
+
const a = node.subpaths[c.subpath].anchors[c.index];
|
|
3223
|
+
const radius = _nullishCoalesce(_optionalChain([a, 'access', _44 => _44.corner, 'optionalAccess', _45 => _45.radius]), () => ( 0));
|
|
3224
|
+
const drawn = fitCornerRadius(c, radius);
|
|
3225
|
+
const k = Math.min(Math.max(drawn / c.sin, VECTOR_CORNER_WIDGET_INSET / (zoom * Math.sqrt(1 + c.cos))), side / 2);
|
|
3226
|
+
const p = applyMatrix(m, cornerBisectorPoint(c, k));
|
|
3227
|
+
out.push({ ref: { nodeId: id, subpath: c.subpath, index: c.index }, x: p.x, y: p.y, radius, drawnRadius: drawn, kind: _nullishCoalesce(_optionalChain([a, 'access', _46 => _46.corner, 'optionalAccess', _47 => _47.kind]), () => ( "round")), corner: c });
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
return out;
|
|
3231
|
+
}
|
|
2654
3232
|
function getAnchor(doc, ref) {
|
|
2655
3233
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
2656
|
-
return _optionalChain([node, 'optionalAccess',
|
|
3234
|
+
return _optionalChain([node, 'optionalAccess', _48 => _48.type]) === "path" ? _optionalChain([node, 'access', _49 => _49.subpaths, 'access', _50 => _50[ref.subpath], 'optionalAccess', _51 => _51.anchors, 'access', _52 => _52[ref.index]]) : void 0;
|
|
2657
3235
|
}
|
|
2658
3236
|
function getAnchorWorld(doc, ref) {
|
|
2659
3237
|
const a = getAnchor(doc, ref);
|
|
@@ -2909,7 +3487,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
2909
3487
|
notify(docChanged = false) {
|
|
2910
3488
|
this.revision++;
|
|
2911
3489
|
this.state = this.computeState();
|
|
2912
|
-
if (docChanged) _optionalChain([this, 'access',
|
|
3490
|
+
if (docChanged) _optionalChain([this, 'access', _53 => _53.onChange, 'optionalCall', _54 => _54(this.doc)]);
|
|
2913
3491
|
const state = this.state;
|
|
2914
3492
|
this.listeners.forEach((listener) => {
|
|
2915
3493
|
try {
|
|
@@ -2939,20 +3517,20 @@ var VectorEditorController = (_class3 = class {
|
|
|
2939
3517
|
return applyMatrix(invertMatrix(this.worldOf(id, doc)), p);
|
|
2940
3518
|
}
|
|
2941
3519
|
cursorFor() {
|
|
2942
|
-
if (_optionalChain([this, 'access',
|
|
2943
|
-
if (_optionalChain([this, 'access',
|
|
2944
|
-
if (_optionalChain([this, 'access',
|
|
3520
|
+
if (_optionalChain([this, 'access', _55 => _55.drag, 'optionalAccess', _56 => _56.kind]) === "pan" || this.spaceHeld) return this.drag ? "grabbing" : "grab";
|
|
3521
|
+
if (_optionalChain([this, 'access', _57 => _57.drag, 'optionalAccess', _58 => _58.kind]) === "rotate") return "grabbing";
|
|
3522
|
+
if (_optionalChain([this, 'access', _59 => _59.drag, 'optionalAccess', _60 => _60.kind]) === "move") return "move";
|
|
2945
3523
|
const h = this.hover;
|
|
2946
3524
|
switch (this.tool) {
|
|
2947
3525
|
case "select":
|
|
2948
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
2949
|
-
return _optionalChain([h, 'optionalAccess',
|
|
3526
|
+
if (_optionalChain([h, 'optionalAccess', _61 => _61.transformHandle])) return vectorResizeCursor(h.transformHandle, _nullishCoalesce(_optionalChain([this, 'access', _62 => _62.frameOf, 'call', _63 => _63(this.selectedRoots()), 'optionalAccess', _64 => _64.angle]), () => ( 0)));
|
|
3527
|
+
return _optionalChain([h, 'optionalAccess', _65 => _65.nodeId]) ? "move" : "default";
|
|
2950
3528
|
case "direct":
|
|
2951
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
2952
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
2953
|
-
return _optionalChain([h, 'optionalAccess',
|
|
3529
|
+
if (_optionalChain([h, 'optionalAccess', _66 => _66.anchor]) || _optionalChain([h, 'optionalAccess', _67 => _67.handle]) || _optionalChain([h, 'optionalAccess', _68 => _68.corner])) return "pointer";
|
|
3530
|
+
if (_optionalChain([h, 'optionalAccess', _69 => _69.segment])) return "copy";
|
|
3531
|
+
return _optionalChain([h, 'optionalAccess', _70 => _70.nodeId]) ? "move" : "default";
|
|
2954
3532
|
case "pen":
|
|
2955
|
-
return _optionalChain([h, 'optionalAccess',
|
|
3533
|
+
return _optionalChain([h, 'optionalAccess', _71 => _71.anchor]) ? "pointer" : "crosshair";
|
|
2956
3534
|
default:
|
|
2957
3535
|
return "crosshair";
|
|
2958
3536
|
}
|
|
@@ -2972,7 +3550,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
2972
3550
|
this.selection = s.selection.filter((id) => this.getNode(id));
|
|
2973
3551
|
this.anchors = s.anchors.filter((r) => getAnchor(this.doc, r));
|
|
2974
3552
|
this.editingId = s.editingId && this.getNode(s.editingId) ? s.editingId : null;
|
|
2975
|
-
this.pen = s.pen && _optionalChain([this, 'access',
|
|
3553
|
+
this.pen = s.pen && _optionalChain([this, 'access', _72 => _72.getNode, 'call', _73 => _73(s.pen.nodeId), 'optionalAccess', _74 => _74.subpaths, 'optionalAccess', _75 => _75[s.pen.subpath]]) ? s.pen : null;
|
|
2976
3554
|
} finally {
|
|
2977
3555
|
this.applying = false;
|
|
2978
3556
|
}
|
|
@@ -3033,12 +3611,12 @@ var VectorEditorController = (_class3 = class {
|
|
|
3033
3611
|
// Viewport
|
|
3034
3612
|
// -------------------------------------------------------------------------
|
|
3035
3613
|
screenToDocument(p) {
|
|
3036
|
-
const
|
|
3037
|
-
return { x: (p.x -
|
|
3614
|
+
const v2 = this.viewport;
|
|
3615
|
+
return { x: (p.x - v2.x) / v2.zoom, y: (p.y - v2.y) / v2.zoom };
|
|
3038
3616
|
}
|
|
3039
3617
|
documentToScreen(p) {
|
|
3040
|
-
const
|
|
3041
|
-
return { x: p.x *
|
|
3618
|
+
const v2 = this.viewport;
|
|
3619
|
+
return { x: p.x * v2.zoom + v2.x, y: p.y * v2.zoom + v2.y };
|
|
3042
3620
|
}
|
|
3043
3621
|
setViewport(viewport) {
|
|
3044
3622
|
const next = { ...this.viewport, ...viewport };
|
|
@@ -3105,9 +3683,9 @@ var VectorEditorController = (_class3 = class {
|
|
|
3105
3683
|
toggleSnapping(on = !this.snap.objects) {
|
|
3106
3684
|
this.setSnap({ objects: on });
|
|
3107
3685
|
}
|
|
3108
|
-
gridValue(
|
|
3686
|
+
gridValue(v2) {
|
|
3109
3687
|
const g = this.snap.grid;
|
|
3110
|
-
return g > 0 ? Math.round(
|
|
3688
|
+
return g > 0 ? Math.round(v2 / g) * g : v2;
|
|
3111
3689
|
}
|
|
3112
3690
|
snapPoint(p) {
|
|
3113
3691
|
return { x: this.gridValue(p.x), y: this.gridValue(p.y) };
|
|
@@ -3136,7 +3714,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3136
3714
|
if (res.kind) {
|
|
3137
3715
|
this.snappedToObject = true;
|
|
3138
3716
|
this.setGuides(res);
|
|
3139
|
-
return _optionalChain([leave, 'optionalAccess',
|
|
3717
|
+
return _optionalChain([leave, 'optionalAccess', _76 => _76.constrain]) ? res.point : { x: res.x ? res.point.x : this.gridValue(res.point.x), y: res.y ? res.point.y : this.gridValue(res.point.y) };
|
|
3140
3718
|
}
|
|
3141
3719
|
}
|
|
3142
3720
|
this.setGuides(null);
|
|
@@ -3154,14 +3732,14 @@ var VectorEditorController = (_class3 = class {
|
|
|
3154
3732
|
/** Where the pointer at `p` would place a point with the pen or a shape tool (and the guides showing why). */
|
|
3155
3733
|
hoverSnap(p, input) {
|
|
3156
3734
|
if (this.tool === "pen") {
|
|
3157
|
-
const sp = this.pen ? _optionalChain([this, 'access',
|
|
3158
|
-
if (this.pen && sp && _optionalChain([this, 'access',
|
|
3735
|
+
const sp = this.pen ? _optionalChain([this, 'access', _77 => _77.getNode, 'call', _78 => _78(this.pen.nodeId), 'optionalAccess', _79 => _79.subpaths, 'access', _80 => _80[this.pen.subpath]]) : void 0;
|
|
3736
|
+
if (this.pen && sp && _optionalChain([this, 'access', _81 => _81.hover, 'optionalAccess', _82 => _82.anchor])) {
|
|
3159
3737
|
this.setGuides(null);
|
|
3160
3738
|
return p;
|
|
3161
3739
|
}
|
|
3162
3740
|
const last = this.pen && sp ? getAnchorWorld(this.doc, { nodeId: this.pen.nodeId, subpath: this.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
|
|
3163
3741
|
const leave = last ? { at: { x: last.x, y: last.y }, constrain: input.shift ? "angle" : null } : null;
|
|
3164
|
-
return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access',
|
|
3742
|
+
return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access', _83 => _83.pen, 'optionalAccess', _84 => _84.nodeId]), () => ( null))));
|
|
3165
3743
|
}
|
|
3166
3744
|
if (SHAPE_TOOLS.has(this.tool)) return this.snapDrawn(p, null, input, () => this.drawingTargets(null));
|
|
3167
3745
|
this.setGuides(null);
|
|
@@ -3263,7 +3841,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3263
3841
|
let subpath;
|
|
3264
3842
|
switch (input.kind) {
|
|
3265
3843
|
case "rect":
|
|
3266
|
-
subpath = rectSubpath(b
|
|
3844
|
+
subpath = rectSubpath(b);
|
|
3267
3845
|
break;
|
|
3268
3846
|
case "ellipse":
|
|
3269
3847
|
subpath = ellipseSubpath(b);
|
|
@@ -3278,10 +3856,13 @@ var VectorEditorController = (_class3 = class {
|
|
|
3278
3856
|
subpath = lineSubpath({ x: b.x, y: b.y }, { x: b.x + b.width, y: b.y + b.height });
|
|
3279
3857
|
break;
|
|
3280
3858
|
}
|
|
3859
|
+
const radius = _nullishCoalesce(input.cornerRadius, () => ( d.cornerRadius));
|
|
3860
|
+
const kind = _nullishCoalesce(input.cornerKind, () => ( d.cornerKind));
|
|
3861
|
+
if ((input.kind === "rect" || input.kind === "polygon" || input.kind === "star") && radius > 0) subpath = setSubpathCorners(subpath, radius, kind);
|
|
3281
3862
|
const names = { rect: "Rectangle", ellipse: "Ellipse", polygon: "Polygon", star: "Star", line: "Line" };
|
|
3282
3863
|
const style = this.styleFor(input.kind === "line");
|
|
3283
3864
|
const own = {};
|
|
3284
|
-
for (const key of
|
|
3865
|
+
for (const key of VECTOR_STYLE_KEYS) {
|
|
3285
3866
|
if (input[key] !== void 0) own[key] = input[key];
|
|
3286
3867
|
}
|
|
3287
3868
|
return { id: this.newId(), type: "path", name: _nullishCoalesce(input.name, () => ( names[input.kind])), ...style, ...own, subpaths: [subpath] };
|
|
@@ -3304,6 +3885,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
3304
3885
|
if (d.strokeLinejoin) out.strokeLinejoin = d.strokeLinejoin;
|
|
3305
3886
|
if (d.strokeDasharray) out.strokeDasharray = d.strokeDasharray;
|
|
3306
3887
|
if (d.fillRule) out.fillRule = d.fillRule;
|
|
3888
|
+
if (d.strokeAlign && d.strokeAlign !== "center") out.strokeAlign = d.strokeAlign;
|
|
3889
|
+
for (const key of ["startArrow", "endArrow", "arrowAlign", "startArrowScale", "endArrowScale"]) if (d[key]) out[key] = d[key];
|
|
3307
3890
|
return out;
|
|
3308
3891
|
}
|
|
3309
3892
|
/** Merges `patch` into a node (paths take style and geometry; groups name / visibility / opacity). */
|
|
@@ -3328,6 +3911,95 @@ var VectorEditorController = (_class3 = class {
|
|
|
3328
3911
|
});
|
|
3329
3912
|
return { ok: true };
|
|
3330
3913
|
}
|
|
3914
|
+
/**
|
|
3915
|
+
* Sets the live corner radius (and optionally the kind) of anchors: `refs`, else the selected
|
|
3916
|
+
* anchors (direct tool), else every anchor of the `ids` / selected paths. Radius 0 makes the
|
|
3917
|
+
* corners sharp again. Corners shrink to fit when drawn, so any radius is accepted.
|
|
3918
|
+
*/
|
|
3919
|
+
setCornerRadius(radius, options = {}) {
|
|
3920
|
+
if (!Number.isFinite(radius) || radius < 0) return { ok: false, message: "The radius must be a number of at least 0." };
|
|
3921
|
+
const refs = this.cornerTargets(options);
|
|
3922
|
+
if (!refs.length) return { ok: false, message: "Nothing is selected." };
|
|
3923
|
+
this.change(radius > 0 ? "Corner Radius" : "Sharpen Corners", () => {
|
|
3924
|
+
this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, radius, options.kind));
|
|
3925
|
+
});
|
|
3926
|
+
return { ok: true };
|
|
3927
|
+
}
|
|
3928
|
+
/** Sets the live corner kind of the same anchors as `setCornerRadius`, keeping their radii. */
|
|
3929
|
+
setCornerKind(kind, options = {}) {
|
|
3930
|
+
const refs = this.cornerTargets(options);
|
|
3931
|
+
if (!refs.length) return { ok: false, message: "Nothing is selected." };
|
|
3932
|
+
this.change("Corner Kind", () => {
|
|
3933
|
+
this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _85 => _85.corner, 'optionalAccess', _86 => _86.radius]), () => ( 0)), kind));
|
|
3934
|
+
});
|
|
3935
|
+
return { ok: true };
|
|
3936
|
+
}
|
|
3937
|
+
/** Anchors a corner change applies to (see `setCornerRadius`). */
|
|
3938
|
+
cornerTargets(options) {
|
|
3939
|
+
if (options.refs) return options.refs.filter((r) => getAnchor(this.doc, r));
|
|
3940
|
+
if (!options.ids && this.tool === "direct" && this.anchors.length) return this.anchors.slice();
|
|
3941
|
+
const out = [];
|
|
3942
|
+
for (const id of _nullishCoalesce(options.ids, () => ( this.selection))) {
|
|
3943
|
+
const node = this.getNode(id);
|
|
3944
|
+
if (!node) continue;
|
|
3945
|
+
for (const p of collectPathNodes(node)) {
|
|
3946
|
+
if (p.locked) continue;
|
|
3947
|
+
p.subpaths.forEach((sp, s) => sp.anchors.forEach((_, i) => out.push({ nodeId: p.id, subpath: s, index: i })));
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
return out;
|
|
3951
|
+
}
|
|
3952
|
+
/**
|
|
3953
|
+
* Outline Stroke: replaces each selected (or given) path's stroke with a filled path of the
|
|
3954
|
+
* area it paints (alignment, joins, caps, dashes and arrowheads included), placed above a copy
|
|
3955
|
+
* of the path that keeps the fill (left out when there is none). Returns the new paths' ids.
|
|
3956
|
+
*/
|
|
3957
|
+
outlineStroke(options = {}) {
|
|
3958
|
+
const roots = _nullishCoalesce(options.ids, () => ( this.selectedRoots()));
|
|
3959
|
+
const paths = [];
|
|
3960
|
+
for (const id of roots) {
|
|
3961
|
+
const node = this.getNode(id);
|
|
3962
|
+
if (node) {
|
|
3963
|
+
for (const p of collectPathNodes(node)) if (!p.locked && hasPaint(p.stroke) && (_nullishCoalesce(p.strokeWidth, () => ( 1))) > 0) paths.push(p);
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
if (!paths.length) return [];
|
|
3967
|
+
const created = [];
|
|
3968
|
+
const replace = /* @__PURE__ */ new Map();
|
|
3969
|
+
for (const p of paths) {
|
|
3970
|
+
const outline = bezierToSubpaths(vectorStrokeOutlinePath(subpathsToBezier(p.subpaths), p));
|
|
3971
|
+
if (!outline.length) continue;
|
|
3972
|
+
const {
|
|
3973
|
+
stroke,
|
|
3974
|
+
strokeWidth: _w,
|
|
3975
|
+
strokeLinecap: _c,
|
|
3976
|
+
strokeLinejoin: _j,
|
|
3977
|
+
strokeDasharray: _d,
|
|
3978
|
+
strokeAlign: _a,
|
|
3979
|
+
startArrow: _s,
|
|
3980
|
+
endArrow: _e,
|
|
3981
|
+
arrowAlign: _al,
|
|
3982
|
+
startArrowScale: _ss,
|
|
3983
|
+
endArrowScale: _es,
|
|
3984
|
+
...rest
|
|
3985
|
+
} = cloneVectorNode(p);
|
|
3986
|
+
const id = this.newId();
|
|
3987
|
+
const strokeNode = { ...rest, id, name: `${_nullishCoalesce(p.name, () => ( "Path"))} Stroke`, subpaths: outline, fill: _nullishCoalesce(stroke, () => ( null)), stroke: null, fillRule: "nonzero" };
|
|
3988
|
+
const list = hasPaint(p.fill) ? [{ ...rest, stroke: null }, strokeNode] : [strokeNode];
|
|
3989
|
+
created.push(id);
|
|
3990
|
+
replace.set(p.id, list);
|
|
3991
|
+
}
|
|
3992
|
+
if (!created.length) return [];
|
|
3993
|
+
this.change("Outline Stroke", () => {
|
|
3994
|
+
let nodes = this.doc.nodes;
|
|
3995
|
+
for (const [id, list] of replace) nodes = spliceTree(nodes, id, list);
|
|
3996
|
+
this.setDoc(nodes);
|
|
3997
|
+
this.selection = created;
|
|
3998
|
+
this.anchors = [];
|
|
3999
|
+
this.editingId = null;
|
|
4000
|
+
});
|
|
4001
|
+
return created;
|
|
4002
|
+
}
|
|
3331
4003
|
rename(id, name) {
|
|
3332
4004
|
return this.updateNode(id, { name }, { label: "Rename" });
|
|
3333
4005
|
}
|
|
@@ -3396,10 +4068,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
3396
4068
|
return this.selection.filter((id) => {
|
|
3397
4069
|
let covered = false;
|
|
3398
4070
|
const loc = locateVectorNode(this.doc.nodes, id);
|
|
3399
|
-
let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess',
|
|
4071
|
+
let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _87 => _87.parent]), () => ( null));
|
|
3400
4072
|
while (parent) {
|
|
3401
4073
|
if (this.selection.includes(parent.id)) covered = true;
|
|
3402
|
-
parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call',
|
|
4074
|
+
parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _88 => _88(this.doc.nodes, parent.id), 'optionalAccess', _89 => _89.parent]), () => ( null));
|
|
3403
4075
|
}
|
|
3404
4076
|
return !covered;
|
|
3405
4077
|
});
|
|
@@ -3582,8 +4254,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
3582
4254
|
if (!ids.length) return null;
|
|
3583
4255
|
const locs = ids.map((id2) => locateVectorNode(this.doc.nodes, id2));
|
|
3584
4256
|
if (locs.some((l) => !l)) return null;
|
|
3585
|
-
const parent = _nullishCoalesce(_optionalChain([locs, 'access',
|
|
3586
|
-
if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access',
|
|
4257
|
+
const parent = _nullishCoalesce(_optionalChain([locs, 'access', _90 => _90[0], 'access', _91 => _91.parent, 'optionalAccess', _92 => _92.id]), () => ( null));
|
|
4258
|
+
if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _93 => _93.parent, 'optionalAccess', _94 => _94.id]), () => ( null))) !== parent)) return null;
|
|
3587
4259
|
const id = this.newId();
|
|
3588
4260
|
this.change("Group", () => {
|
|
3589
4261
|
const set = new Set(ids);
|
|
@@ -3606,7 +4278,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3606
4278
|
}
|
|
3607
4279
|
/** Replaces selected groups with their children. */
|
|
3608
4280
|
ungroup(options = {}) {
|
|
3609
|
-
const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess',
|
|
4281
|
+
const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _95 => _95.type]) === "group");
|
|
3610
4282
|
if (!groups.length) return { ok: false, message: "Select a group to ungroup." };
|
|
3611
4283
|
const set = new Set(groups.map((g) => g.id));
|
|
3612
4284
|
this.change("Ungroup", () => {
|
|
@@ -3720,7 +4392,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3720
4392
|
}
|
|
3721
4393
|
/** Splits selected compound paths into one path per subpath. */
|
|
3722
4394
|
breakApart(options = {}) {
|
|
3723
|
-
const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess',
|
|
4395
|
+
const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _96 => _96.type]) === "path" && n.subpaths.length > 1);
|
|
3724
4396
|
if (!paths.length) return { ok: false, message: "Select a compound path to break apart." };
|
|
3725
4397
|
const created = [];
|
|
3726
4398
|
const set = new Set(paths.map((p) => p.id));
|
|
@@ -3782,7 +4454,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3782
4454
|
/** `doc` with anchor `ref` moved to document point `to` by a Curvature-tool move. */
|
|
3783
4455
|
curvatureMoved(doc, ref, to) {
|
|
3784
4456
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
3785
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
4457
|
+
if (_optionalChain([node, 'optionalAccess', _97 => _97.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
|
|
3786
4458
|
const q = this.toLocal(ref.nodeId, to, doc);
|
|
3787
4459
|
const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? curvatureMoveAnchor(sp, ref.index, q) : sp);
|
|
3788
4460
|
const nodes = mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n);
|
|
@@ -3791,7 +4463,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3791
4463
|
/** `doc` with segment `ref` bent through document point `p` at parameter `t`. */
|
|
3792
4464
|
bent(doc, ref, t, p) {
|
|
3793
4465
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
3794
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
4466
|
+
if (_optionalChain([node, 'optionalAccess', _98 => _98.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
|
|
3795
4467
|
const q = this.toLocal(ref.nodeId, p, doc);
|
|
3796
4468
|
const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? bendSegment(sp, ref.segment, t, q) : sp);
|
|
3797
4469
|
return { ...doc, nodes: mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n) };
|
|
@@ -3802,7 +4474,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3802
4474
|
*/
|
|
3803
4475
|
bendSegment(ref, to, t = 0.5) {
|
|
3804
4476
|
const node = this.getNode(ref.nodeId);
|
|
3805
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
4477
|
+
const sp = _optionalChain([node, 'optionalAccess', _99 => _99.type]) === "path" ? node.subpaths[ref.subpath] : void 0;
|
|
3806
4478
|
if (!sp || ref.segment < 0 || ref.segment >= (sp.closed ? sp.anchors.length : sp.anchors.length - 1) || sp.anchors.length < 2) return { ok: false, message: "There is no such segment." };
|
|
3807
4479
|
if (node.locked) return { ok: false, message: "The path is locked." };
|
|
3808
4480
|
this.change("Bend Segment", () => {
|
|
@@ -3837,7 +4509,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3837
4509
|
/** Adds an anchor on the nearest segment of `nodeId` to document point `point` (shape unchanged). */
|
|
3838
4510
|
insertAnchorAt(nodeId, point) {
|
|
3839
4511
|
const node = this.getNode(nodeId);
|
|
3840
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
4512
|
+
if (_optionalChain([node, 'optionalAccess', _100 => _100.type]) !== "path") return null;
|
|
3841
4513
|
const hit = nearestSegment(node, this.toLocal(nodeId, point));
|
|
3842
4514
|
if (!hit) return null;
|
|
3843
4515
|
const { subpath, index } = insertAnchor(node.subpaths[hit.subpath], hit.segment, hit.t);
|
|
@@ -3881,7 +4553,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3881
4553
|
setClosed(closed, nodeId) {
|
|
3882
4554
|
const targets = nodeId ? (() => {
|
|
3883
4555
|
const n = this.getNode(nodeId);
|
|
3884
|
-
return _optionalChain([n, 'optionalAccess',
|
|
4556
|
+
return _optionalChain([n, 'optionalAccess', _101 => _101.type]) === "path" ? n.subpaths.map((_, s) => ({ nodeId, subpath: s })) : [];
|
|
3885
4557
|
})() : this.anchors.map((r) => ({ nodeId: r.nodeId, subpath: r.subpath }));
|
|
3886
4558
|
if (!targets.length) return { ok: false, message: "Select a path or points." };
|
|
3887
4559
|
this.change(closed ? "Close Path" : "Open Path", () => {
|
|
@@ -3930,7 +4602,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3930
4602
|
const map = (p) => applyMatrix(m, p);
|
|
3931
4603
|
return from.subpaths.map((sp) => ({
|
|
3932
4604
|
closed: sp.closed,
|
|
3933
|
-
anchors: sp.anchors.map((a) => ({ ...map(a), ...a.in ? { in: map(a.in) } : {}, ...a.out ? { out: map(a.out) } : {}, ...a.type ? { type: a.type } : {} }))
|
|
4605
|
+
anchors: sp.anchors.map((a) => ({ ...map(a), ...a.in ? { in: map(a.in) } : {}, ...a.out ? { out: map(a.out) } : {}, ...a.type ? { type: a.type } : {}, ...a.corner ? { corner: { ...a.corner } } : {} }))
|
|
3934
4606
|
}));
|
|
3935
4607
|
}
|
|
3936
4608
|
/**
|
|
@@ -4035,7 +4707,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4035
4707
|
*/
|
|
4036
4708
|
cutPathAt(nodeId, point) {
|
|
4037
4709
|
const node = this.getNode(nodeId);
|
|
4038
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
4710
|
+
if (_optionalChain([node, 'optionalAccess', _102 => _102.type]) !== "path" || node.locked) return null;
|
|
4039
4711
|
const local = this.toLocal(nodeId, point);
|
|
4040
4712
|
const hit = nearestSegment(node, local);
|
|
4041
4713
|
if (!hit) return null;
|
|
@@ -4085,7 +4757,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4085
4757
|
if (n.visible === false || n.locked || parent && blocked.has(parent.id)) blocked.add(n.id);
|
|
4086
4758
|
});
|
|
4087
4759
|
const visible = (p) => !blocked.has(p.id);
|
|
4088
|
-
if (_optionalChain([ids, 'optionalAccess',
|
|
4760
|
+
if (_optionalChain([ids, 'optionalAccess', _103 => _103.length]) || this.selection.length) return this.pathTargets(_nullishCoalesce(ids, () => ( this.selection))).filter(visible);
|
|
4089
4761
|
const box = polylineBounds(points.map(toPoint2), pad);
|
|
4090
4762
|
if (!box) return [];
|
|
4091
4763
|
const out = [];
|
|
@@ -4171,7 +4843,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4171
4843
|
finishPath() {
|
|
4172
4844
|
if (!this.pen) return;
|
|
4173
4845
|
const node = this.getNode(this.pen.nodeId);
|
|
4174
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
4846
|
+
const sp = _optionalChain([node, 'optionalAccess', _104 => _104.subpaths, 'access', _105 => _105[this.pen.subpath]]);
|
|
4175
4847
|
const pen = this.pen;
|
|
4176
4848
|
this.pen = null;
|
|
4177
4849
|
this.pointer = null;
|
|
@@ -4215,7 +4887,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4215
4887
|
if (trimmed.startsWith("{")) {
|
|
4216
4888
|
try {
|
|
4217
4889
|
const data = JSON.parse(trimmed);
|
|
4218
|
-
if (_optionalChain([data, 'optionalAccess',
|
|
4890
|
+
if (_optionalChain([data, 'optionalAccess', _106 => _106.type]) === VECTOR_CLIPBOARD_TYPE && Array.isArray(data.nodes)) nodes = data.nodes;
|
|
4219
4891
|
} catch (e2) {
|
|
4220
4892
|
nodes = null;
|
|
4221
4893
|
}
|
|
@@ -4227,7 +4899,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4227
4899
|
}
|
|
4228
4900
|
}
|
|
4229
4901
|
} else nodes = this.clipboard;
|
|
4230
|
-
if (!_optionalChain([nodes, 'optionalAccess',
|
|
4902
|
+
if (!_optionalChain([nodes, 'optionalAccess', _107 => _107.length])) return [];
|
|
4231
4903
|
const offset = _nullishCoalesce(options.offset, () => ( (text && !text.trim().startsWith("{") ? { x: 0, y: 0 } : { x: 10, y: 10 })));
|
|
4232
4904
|
const copies = nodes.map((n) => transformVectorNode(this.freshIds(n), translateMatrix(offset.x, offset.y)));
|
|
4233
4905
|
this.change("Paste", () => {
|
|
@@ -4278,13 +4950,29 @@ var VectorEditorController = (_class3 = class {
|
|
|
4278
4950
|
hitHandle(screen) {
|
|
4279
4951
|
for (const ref of getVisibleHandles(this.view()).reverse()) {
|
|
4280
4952
|
const a = getAnchorWorld(this.doc, ref);
|
|
4281
|
-
const h = _optionalChain([a, 'optionalAccess',
|
|
4953
|
+
const h = _optionalChain([a, 'optionalAccess', _108 => _108[ref.handle]]);
|
|
4282
4954
|
if (!h) continue;
|
|
4283
4955
|
const s = this.documentToScreen(h);
|
|
4284
4956
|
if (Math.hypot(s.x - screen.x, s.y - screen.y) <= this.hitRadius) return ref;
|
|
4285
4957
|
}
|
|
4286
4958
|
return null;
|
|
4287
4959
|
}
|
|
4960
|
+
cornerView() {
|
|
4961
|
+
return { ...this.view(), viewport: this.viewport };
|
|
4962
|
+
}
|
|
4963
|
+
hitCornerWidget(screen) {
|
|
4964
|
+
let best = null;
|
|
4965
|
+
let bestD = Infinity;
|
|
4966
|
+
for (const w of getVectorCornerWidgets(this.cornerView())) {
|
|
4967
|
+
const s = this.documentToScreen(w);
|
|
4968
|
+
const d = Math.hypot(s.x - screen.x, s.y - screen.y);
|
|
4969
|
+
if (d <= this.hitRadius && d < bestD) {
|
|
4970
|
+
best = w;
|
|
4971
|
+
bestD = d;
|
|
4972
|
+
}
|
|
4973
|
+
}
|
|
4974
|
+
return best;
|
|
4975
|
+
}
|
|
4288
4976
|
hitAnchor(screen, refs) {
|
|
4289
4977
|
let best = null;
|
|
4290
4978
|
let bestD = Infinity;
|
|
@@ -4343,6 +5031,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
4343
5031
|
if (handle) return { nodeId: handle.nodeId, handle };
|
|
4344
5032
|
const anchor = this.hitAnchor(screen, getVisibleAnchors(this.view()));
|
|
4345
5033
|
if (anchor) return { nodeId: anchor.nodeId, anchor };
|
|
5034
|
+
const widget = this.hitCornerWidget(screen);
|
|
5035
|
+
if (widget) return { nodeId: widget.ref.nodeId, corner: widget.ref };
|
|
4346
5036
|
for (const id of getEditablePathIds(this.view())) {
|
|
4347
5037
|
const node = this.getNode(id);
|
|
4348
5038
|
const seg = nearestSegment(node, this.toLocal(id, p));
|
|
@@ -4500,6 +5190,13 @@ var VectorEditorController = (_class3 = class {
|
|
|
4500
5190
|
this.notify();
|
|
4501
5191
|
return;
|
|
4502
5192
|
}
|
|
5193
|
+
const widget = this.hitCornerWidget(screen);
|
|
5194
|
+
if (widget) {
|
|
5195
|
+
const refs = getVectorCornerWidgets(this.cornerView()).map((w) => w.ref);
|
|
5196
|
+
this.drag = { kind: "corner", widget, refs, start: p, before: this.snapshot(), base: this.doc, moved: false, alt: !!input.alt, shift: !!input.shift };
|
|
5197
|
+
this.notify();
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
4503
5200
|
for (const id of getEditablePathIds(this.view())) {
|
|
4504
5201
|
const node = this.getNode(id);
|
|
4505
5202
|
const seg = nearestSegment(node, this.toLocal(id, p));
|
|
@@ -4543,7 +5240,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4543
5240
|
}
|
|
4544
5241
|
downPen(screen, p, input) {
|
|
4545
5242
|
const before = this.snapshot();
|
|
4546
|
-
const sp = this.pen ? _optionalChain([this, 'access',
|
|
5243
|
+
const sp = this.pen ? _optionalChain([this, 'access', _109 => _109.getNode, 'call', _110 => _110(this.pen.nodeId), 'optionalAccess', _111 => _111.subpaths, 'access', _112 => _112[this.pen.subpath]]) : void 0;
|
|
4547
5244
|
if (this.pen && sp) {
|
|
4548
5245
|
const pen = this.pen;
|
|
4549
5246
|
const first = { nodeId: pen.nodeId, subpath: pen.subpath, index: 0 };
|
|
@@ -4557,10 +5254,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
4557
5254
|
}
|
|
4558
5255
|
const last = getAnchorWorld(this.doc, { nodeId: pen.nodeId, subpath: pen.subpath, index: sp.anchors.length - 1 });
|
|
4559
5256
|
const leave = { at: { x: last.x, y: last.y }, constrain: input.shift ? "angle" : null };
|
|
4560
|
-
let
|
|
4561
|
-
|
|
5257
|
+
let pt3 = this.snapDrawn(p, leave, input, () => this.drawingTargets(pen.nodeId));
|
|
5258
|
+
pt3 = this.toLocal(pen.nodeId, pt3);
|
|
4562
5259
|
const node2 = this.getNode(pen.nodeId);
|
|
4563
|
-
const anchors = [...sp.anchors, { x:
|
|
5260
|
+
const anchors = [...sp.anchors, { x: pt3.x, y: pt3.y }];
|
|
4564
5261
|
this.replaceNode(pen.nodeId, { ...node2, subpaths: node2.subpaths.map((s, i) => i === pen.subpath ? { ...s, anchors } : s) });
|
|
4565
5262
|
const ref2 = { nodeId: pen.nodeId, subpath: pen.subpath, index: anchors.length - 1 };
|
|
4566
5263
|
this.anchors = [ref2];
|
|
@@ -4588,8 +5285,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
4588
5285
|
this.notify(this.doc !== before.doc);
|
|
4589
5286
|
return;
|
|
4590
5287
|
}
|
|
4591
|
-
const
|
|
4592
|
-
const node = { id: this.newId(), type: "path", name: "Path", ...this.styleFor(true), subpaths: [{ anchors: [{ x:
|
|
5288
|
+
const pt2 = this.snapDrawn(p, null, input, () => this.drawingTargets(null));
|
|
5289
|
+
const node = { id: this.newId(), type: "path", name: "Path", ...this.styleFor(true), subpaths: [{ anchors: [{ x: pt2.x, y: pt2.y }], closed: false }] };
|
|
4593
5290
|
this.setDoc([...this.doc.nodes, node]);
|
|
4594
5291
|
this.pen = { nodeId: node.id, subpath: 0 };
|
|
4595
5292
|
this.selection = [node.id];
|
|
@@ -4737,13 +5434,25 @@ var VectorEditorController = (_class3 = class {
|
|
|
4737
5434
|
case "handle": {
|
|
4738
5435
|
const anchor = getAnchorWorld(drag.base, drag.ref);
|
|
4739
5436
|
const leave = anchor ? { at: { x: anchor.x, y: anchor.y }, constrain: input.shift ? "angle" : null } : null;
|
|
4740
|
-
const
|
|
4741
|
-
const local = this.toLocal(drag.ref.nodeId,
|
|
5437
|
+
const pt2 = this.snapDrawn(p, leave, input, () => drag.targets ??= VectorSnapTargets.forHandle(drag.base, drag.ref.nodeId));
|
|
5438
|
+
const local = this.toLocal(drag.ref.nodeId, pt2, drag.base);
|
|
4742
5439
|
this.doc = this.updateAnchors(drag.base, [drag.ref], (a) => moveAnchorHandle(a, drag.ref.handle, local, input.alt));
|
|
4743
5440
|
this.interaction = { type: "handle", ref: drag.ref };
|
|
4744
5441
|
this.notify(true);
|
|
4745
5442
|
return;
|
|
4746
5443
|
}
|
|
5444
|
+
case "corner": {
|
|
5445
|
+
if (!drag.moved && Math.hypot(p.x - drag.start.x, p.y - drag.start.y) * this.viewport.zoom < 3) return;
|
|
5446
|
+
drag.moved = true;
|
|
5447
|
+
const c = drag.widget.corner;
|
|
5448
|
+
const inv = invertMatrix(this.worldOf(drag.widget.ref.nodeId, drag.base));
|
|
5449
|
+
const d = applyMatrixLinear(inv, { x: p.x - drag.start.x, y: p.y - drag.start.y });
|
|
5450
|
+
const radius = Math.max(0, Math.min(c.maxRadius, drag.widget.drawnRadius + cornerRadiusChange(c, d)));
|
|
5451
|
+
this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, radius));
|
|
5452
|
+
this.interaction = { type: "corner", ref: drag.widget.ref, radius };
|
|
5453
|
+
this.notify(true);
|
|
5454
|
+
return;
|
|
5455
|
+
}
|
|
4747
5456
|
case "bend": {
|
|
4748
5457
|
if (!drag.moved && Math.hypot(p.x - drag.start.x, p.y - drag.start.y) * this.viewport.zoom < 2) return;
|
|
4749
5458
|
drag.moved = true;
|
|
@@ -4769,10 +5478,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
4769
5478
|
return;
|
|
4770
5479
|
}
|
|
4771
5480
|
this.guides = null;
|
|
4772
|
-
let
|
|
4773
|
-
if (input.shift)
|
|
5481
|
+
let pt2 = p;
|
|
5482
|
+
if (input.shift) pt2 = constrain45(anchor, pt2);
|
|
4774
5483
|
const side = drag.closing ? "in" : "out";
|
|
4775
|
-
const pos = this.toLocal(drag.ref.nodeId, drag.closing ? { x: 2 * anchor.x -
|
|
5484
|
+
const pos = this.toLocal(drag.ref.nodeId, drag.closing ? { x: 2 * anchor.x - pt2.x, y: 2 * anchor.y - pt2.y } : pt2, drag.base);
|
|
4776
5485
|
this.doc = this.updateAnchors(drag.base, [drag.ref], (a) => {
|
|
4777
5486
|
if (drag.outOnly || drag.altBreaks && input.alt) return moveAnchorHandle(a, side, pos, true);
|
|
4778
5487
|
return moveAnchorHandle({ ...a, type: "symmetric" }, side, pos);
|
|
@@ -4782,7 +5491,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4782
5491
|
}
|
|
4783
5492
|
case "shape": {
|
|
4784
5493
|
const node = this.getNode(drag.nodeId);
|
|
4785
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5494
|
+
if (_optionalChain([node, 'optionalAccess', _113 => _113.type]) !== "path") return;
|
|
4786
5495
|
const leave = { at: drag.start, constrain: input.shift ? drag.tool === "line" ? "angle" : "square" : null, curves: false };
|
|
4787
5496
|
let end = this.snapDrawn(p, leave, input, () => drag.targets ??= this.drawingTargets(null));
|
|
4788
5497
|
if (!this.snappedToObject && drag.tool !== "line" && !input.shift && !input.mod && this.snap.objects && drag.targets) end = this.matchShapeSize(drag.targets, drag.start, end, input.alt);
|
|
@@ -4821,9 +5530,9 @@ var VectorEditorController = (_class3 = class {
|
|
|
4821
5530
|
}
|
|
4822
5531
|
const string = drag.lazy.string();
|
|
4823
5532
|
const node = this.getNode(drag.nodeId);
|
|
4824
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5533
|
+
if (_optionalChain([node, 'optionalAccess', _114 => _114.type]) !== "path") return;
|
|
4825
5534
|
if (!moved) {
|
|
4826
|
-
if (string && _optionalChain([this, 'access',
|
|
5535
|
+
if (string && _optionalChain([this, 'access', _115 => _115.interaction, 'optionalAccess', _116 => _116.type]) === "draw") {
|
|
4827
5536
|
this.interaction = { ...this.interaction, string: [{ x: string[0][0], y: string[0][1] }, { x: string[1][0], y: string[1][1] }] };
|
|
4828
5537
|
this.notify();
|
|
4829
5538
|
}
|
|
@@ -4859,8 +5568,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
4859
5568
|
}
|
|
4860
5569
|
this.setGuides(res);
|
|
4861
5570
|
return {
|
|
4862
|
-
dx: _optionalChain([res, 'optionalAccess',
|
|
4863
|
-
dy: _optionalChain([res, 'optionalAccess',
|
|
5571
|
+
dx: _optionalChain([res, 'optionalAccess', _117 => _117.x]) ? dx + res.dx : axes.x ? this.gridValue(origin.x + dx) - origin.x : dx,
|
|
5572
|
+
dy: _optionalChain([res, 'optionalAccess', _118 => _118.y]) ? dy + res.dy : axes.y ? this.gridValue(origin.y + dy) - origin.y : dy
|
|
4864
5573
|
};
|
|
4865
5574
|
}
|
|
4866
5575
|
/** The anchor a point drag snaps by, where it started: the grabbed one, else the moving one nearest the press. */
|
|
@@ -4885,12 +5594,12 @@ var VectorEditorController = (_class3 = class {
|
|
|
4885
5594
|
const guides = { lines: [], labels: [] };
|
|
4886
5595
|
for (const axis of ["x", "y"]) {
|
|
4887
5596
|
const d = end[axis] - start[axis];
|
|
4888
|
-
const
|
|
4889
|
-
if (
|
|
4890
|
-
out[axis] = start[axis] + Math.sign(d) *
|
|
5597
|
+
const len2 = Math.abs(d) > 1e-9 ? targets.matchSize(Math.abs(d) * k, tol) : null;
|
|
5598
|
+
if (len2 === null || len2 <= 0) continue;
|
|
5599
|
+
out[axis] = start[axis] + Math.sign(d) * len2 / k;
|
|
4891
5600
|
const from = { ...out, [axis]: fromCentre ? 2 * start[axis] - out[axis] : start[axis] };
|
|
4892
5601
|
guides.lines.push({ kind: "size", x1: from.x, y1: from.y, x2: out.x, y2: out.y });
|
|
4893
|
-
guides.labels.push({ kind: "size", x: (from.x + out.x) / 2, y: (from.y + out.y) / 2, text: `${axis === "x" ? "W" : "H"} ${Math.round(
|
|
5602
|
+
guides.labels.push({ kind: "size", x: (from.x + out.x) / 2, y: (from.y + out.y) / 2, text: `${axis === "x" ? "W" : "H"} ${Math.round(len2 * 100) / 100}` });
|
|
4894
5603
|
}
|
|
4895
5604
|
this.setGuides(guides);
|
|
4896
5605
|
return out;
|
|
@@ -4935,6 +5644,20 @@ var VectorEditorController = (_class3 = class {
|
|
|
4935
5644
|
return;
|
|
4936
5645
|
}
|
|
4937
5646
|
return this.commit("Bend Segment", drag.before);
|
|
5647
|
+
case "corner": {
|
|
5648
|
+
if (drag.moved) return this.commit("Corner Radius", drag.before);
|
|
5649
|
+
if (drag.alt) {
|
|
5650
|
+
const kind = nextVectorCornerKind(drag.widget.kind);
|
|
5651
|
+
this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _119 => _119.corner, 'optionalAccess', _120 => _120.radius]), () => ( 0)), kind));
|
|
5652
|
+
return this.commit("Corner Kind", drag.before);
|
|
5653
|
+
}
|
|
5654
|
+
const ref = drag.widget.ref;
|
|
5655
|
+
const has = this.anchors.some((a) => sameRef(a, ref));
|
|
5656
|
+
this.editingId = ref.nodeId;
|
|
5657
|
+
this.anchors = drag.shift ? has ? this.anchors.filter((a) => !sameRef(a, ref)) : [...this.anchors, ref] : [ref];
|
|
5658
|
+
this.notify();
|
|
5659
|
+
return;
|
|
5660
|
+
}
|
|
4938
5661
|
case "stroke": {
|
|
4939
5662
|
this.notify();
|
|
4940
5663
|
if (drag.tool === "knife") this.knife(drag.points);
|
|
@@ -4960,7 +5683,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4960
5683
|
}
|
|
4961
5684
|
case "pencil": {
|
|
4962
5685
|
const node = this.getNode(drag.nodeId);
|
|
4963
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5686
|
+
if (_optionalChain([node, 'optionalAccess', _121 => _121.type]) !== "path" || drag.points.length < 2) {
|
|
4964
5687
|
this.doc = drag.before.doc;
|
|
4965
5688
|
this.notify(true);
|
|
4966
5689
|
return;
|
|
@@ -5034,7 +5757,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5034
5757
|
this.convertAnchors(a.in || a.out ? "corner" : "smooth", [anchor]);
|
|
5035
5758
|
return;
|
|
5036
5759
|
}
|
|
5037
|
-
const id = _nullishCoalesce(_optionalChain([this, 'access',
|
|
5760
|
+
const id = _nullishCoalesce(_optionalChain([this, 'access', _122 => _122.hover, 'optionalAccess', _123 => _123.segment, 'optionalAccess', _124 => _124.nodeId]), () => ( this.editingId));
|
|
5038
5761
|
if (id) {
|
|
5039
5762
|
const node = this.getNode(id);
|
|
5040
5763
|
const seg = node ? nearestSegment(node, this.toLocal(id, p)) : null;
|
|
@@ -5114,7 +5837,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5114
5837
|
this.finishPath();
|
|
5115
5838
|
return true;
|
|
5116
5839
|
}
|
|
5117
|
-
if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access',
|
|
5840
|
+
if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access', _125 => _125.getNode, 'call', _126 => _126(this.selection[0]), 'optionalAccess', _127 => _127.type]) === "path") {
|
|
5118
5841
|
this.tool = "direct";
|
|
5119
5842
|
this.editingId = this.selection[0];
|
|
5120
5843
|
this.notify();
|
|
@@ -5179,9 +5902,9 @@ function inkShapeSubpath(shape) {
|
|
|
5179
5902
|
function constrain45(origin, p) {
|
|
5180
5903
|
const dx = p.x - origin.x;
|
|
5181
5904
|
const dy = p.y - origin.y;
|
|
5182
|
-
const
|
|
5905
|
+
const len2 = Math.hypot(dx, dy);
|
|
5183
5906
|
const a = Math.round(Math.atan2(dy, dx) / (Math.PI / 4)) * (Math.PI / 4);
|
|
5184
|
-
return { x: origin.x + Math.cos(a) *
|
|
5907
|
+
return { x: origin.x + Math.cos(a) * len2, y: origin.y + Math.sin(a) * len2 };
|
|
5185
5908
|
}
|
|
5186
5909
|
function scaleFor(handle, b, p, mods = {}) {
|
|
5187
5910
|
const west = handle.includes("w");
|
|
@@ -5218,17 +5941,19 @@ function renderNode(node, defs, idPrefix) {
|
|
|
5218
5941
|
const stroke = vectorPaintToSvg(node.stroke, `${idPrefix}stroke-${node.id}`);
|
|
5219
5942
|
if (fill.gradient) defs.push(fill.gradient);
|
|
5220
5943
|
if (stroke.gradient) defs.push(stroke.gradient);
|
|
5944
|
+
const strokeParts = stroke.value !== "none" ? vectorStrokeSvgParts(node, `${idPrefix}clip-${node.id}`) : void 0;
|
|
5221
5945
|
return {
|
|
5222
5946
|
kind: "path",
|
|
5223
5947
|
id: node.id,
|
|
5224
5948
|
...node.transform ? { transform: fmtMatrix(node.transform) } : {},
|
|
5949
|
+
...strokeParts ? { strokeParts } : {},
|
|
5225
5950
|
d: vectorPathData(node),
|
|
5226
5951
|
fill: fill.value,
|
|
5227
5952
|
stroke: stroke.value,
|
|
5228
5953
|
strokeWidth: _nullishCoalesce(node.strokeWidth, () => ( 1)),
|
|
5229
5954
|
...node.strokeLinecap ? { strokeLinecap: node.strokeLinecap } : {},
|
|
5230
5955
|
...node.strokeLinejoin ? { strokeLinejoin: node.strokeLinejoin } : {},
|
|
5231
|
-
..._optionalChain([node, 'access',
|
|
5956
|
+
..._optionalChain([node, 'access', _128 => _128.strokeDasharray, 'optionalAccess', _129 => _129.length]) ? { strokeDasharray: node.strokeDasharray.join(" ") } : {},
|
|
5232
5957
|
fillRule: _nullishCoalesce(node.fillRule, () => ( "nonzero")),
|
|
5233
5958
|
opacity: _nullishCoalesce(node.opacity, () => ( 1))
|
|
5234
5959
|
};
|
|
@@ -5237,9 +5962,9 @@ function getVectorSceneRenderData(state, options = {}) {
|
|
|
5237
5962
|
const defs = [];
|
|
5238
5963
|
const prefix = _nullishCoalesce(options.idPrefix, () => ( "ve-"));
|
|
5239
5964
|
const nodes = state.document.nodes.map((n) => renderNode(n, defs, prefix)).filter((n) => !!n);
|
|
5240
|
-
const
|
|
5965
|
+
const v2 = state.viewport;
|
|
5241
5966
|
return {
|
|
5242
|
-
transform: `translate(${fmt(
|
|
5967
|
+
transform: `translate(${fmt(v2.x)} ${fmt(v2.y)}) scale(${v2.zoom})`,
|
|
5243
5968
|
width: state.document.width,
|
|
5244
5969
|
height: state.document.height,
|
|
5245
5970
|
...state.document.background ? { background: state.document.background } : {},
|
|
@@ -5249,8 +5974,8 @@ function getVectorSceneRenderData(state, options = {}) {
|
|
|
5249
5974
|
}
|
|
5250
5975
|
var toScreen = (state, p) => ({ x: p.x * state.viewport.zoom + state.viewport.x, y: p.y * state.viewport.zoom + state.viewport.y });
|
|
5251
5976
|
function screenOutline(state, node) {
|
|
5252
|
-
const
|
|
5253
|
-
const view = [
|
|
5977
|
+
const v2 = state.viewport;
|
|
5978
|
+
const view = [v2.zoom, 0, 0, v2.zoom, v2.x, v2.y];
|
|
5254
5979
|
const parent = _nullishCoalesce(vectorParentMatrix(state.document.nodes, node.id), () => ( IDENTITY_MATRIX));
|
|
5255
5980
|
return collectWithMatrix(node, parent).map(({ path, parent: m }) => _chunkBGNPT5PEcjs.bezierPathToSvg.call(void 0, _chunkBGNPT5PEcjs.transformBezierPath.call(void 0, vectorPathWorldBezier(path, m), view), { precision: 2 })).join(" ");
|
|
5256
5981
|
}
|
|
@@ -5277,9 +6002,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
5277
6002
|
};
|
|
5278
6003
|
for (const id of state.selection) outline(id, true);
|
|
5279
6004
|
if (state.editingId) outline(state.editingId, true);
|
|
5280
|
-
if (_optionalChain([state, 'access',
|
|
6005
|
+
if (_optionalChain([state, 'access', _130 => _130.hover, 'optionalAccess', _131 => _131.nodeId]) && !state.interaction) outline(state.hover.nodeId, false);
|
|
5281
6006
|
let selectionBox = null;
|
|
5282
|
-
if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access',
|
|
6007
|
+
if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access', _132 => _132.interaction, 'optionalAccess', _133 => _133.type]) !== "marquee") {
|
|
5283
6008
|
const g = getVectorSelectionBoxGeometry(state.selectionFrame, state.viewport);
|
|
5284
6009
|
selectionBox = { ...g.box, angle: g.angle, transform: g.transform, corners: g.corners, handles: g.handles };
|
|
5285
6010
|
}
|
|
@@ -5289,9 +6014,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
5289
6014
|
const a = getAnchorWorld(doc, ref);
|
|
5290
6015
|
const s = toScreen(state, a);
|
|
5291
6016
|
const closes = !!state.pen && state.pen.nodeId === ref.nodeId && state.pen.subpath === ref.subpath && ref.index === 0;
|
|
5292
|
-
return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access',
|
|
6017
|
+
return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access', _134 => _134.hover, 'optionalAccess', _135 => _135.anchor]), ref), closes };
|
|
5293
6018
|
});
|
|
5294
|
-
if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access',
|
|
6019
|
+
if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access', _136 => _136.hover, 'optionalAccess', _137 => _137.anchor])) {
|
|
5295
6020
|
const a = getAnchorWorld(doc, state.hover.anchor);
|
|
5296
6021
|
if (a) {
|
|
5297
6022
|
const s = toScreen(state, a);
|
|
@@ -5300,15 +6025,15 @@ function getVectorOverlayRenderData(state) {
|
|
|
5300
6025
|
}
|
|
5301
6026
|
const handles = getVisibleHandles(state).flatMap((ref) => {
|
|
5302
6027
|
const a = getAnchorWorld(doc, ref);
|
|
5303
|
-
const h = _optionalChain([a, 'optionalAccess',
|
|
6028
|
+
const h = _optionalChain([a, 'optionalAccess', _138 => _138[ref.handle]]);
|
|
5304
6029
|
if (!a || !h) return [];
|
|
5305
6030
|
const s = toScreen(state, h);
|
|
5306
6031
|
const sa = toScreen(state, a);
|
|
5307
|
-
const hovered = !!_optionalChain([state, 'access',
|
|
6032
|
+
const hovered = !!_optionalChain([state, 'access', _139 => _139.hover, 'optionalAccess', _140 => _140.handle]) && sameAnchor(state.hover.handle, ref) && state.hover.handle.handle === ref.handle;
|
|
5308
6033
|
return [{ ref, x: s.x, y: s.y, anchorX: sa.x, anchorY: sa.y, hovered }];
|
|
5309
6034
|
});
|
|
5310
6035
|
let marquee = null;
|
|
5311
|
-
if (_optionalChain([state, 'access',
|
|
6036
|
+
if (_optionalChain([state, 'access', _141 => _141.interaction, 'optionalAccess', _142 => _142.type]) === "marquee") {
|
|
5312
6037
|
const b = state.interaction.bounds;
|
|
5313
6038
|
const tl = toScreen(state, b);
|
|
5314
6039
|
marquee = { x: tl.x, y: tl.y, width: b.width * z, height: b.height * z };
|
|
@@ -5316,7 +6041,7 @@ function getVectorOverlayRenderData(state) {
|
|
|
5316
6041
|
let penPreview = null;
|
|
5317
6042
|
if (state.tool === "pen" && state.pen && state.pointer && !state.interaction) {
|
|
5318
6043
|
const node = findVectorNode(doc.nodes, state.pen.nodeId);
|
|
5319
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
6044
|
+
const sp = _optionalChain([node, 'optionalAccess', _143 => _143.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
|
|
5320
6045
|
const last = sp ? getAnchorWorld(doc, { nodeId: state.pen.nodeId, subpath: state.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
|
|
5321
6046
|
if (last) {
|
|
5322
6047
|
const a = toScreen(state, last);
|
|
@@ -5329,9 +6054,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
5329
6054
|
const artboard = { x: origin.x, y: origin.y, width: doc.width * z, height: doc.height * z };
|
|
5330
6055
|
let status = null;
|
|
5331
6056
|
const it = state.interaction;
|
|
5332
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
5333
|
-
else if (_optionalChain([it, 'optionalAccess',
|
|
5334
|
-
else if (_optionalChain([it, 'optionalAccess',
|
|
6057
|
+
if (_optionalChain([it, 'optionalAccess', _144 => _144.type]) === "rotate") status = `${Math.round(it.angle)}\xB0`;
|
|
6058
|
+
else if (_optionalChain([it, 'optionalAccess', _145 => _145.type]) === "move" || _optionalChain([it, 'optionalAccess', _146 => _146.type]) === "anchors") status = `\u0394 ${fmt(it.dx)}, ${fmt(it.dy)}`;
|
|
6059
|
+
else if (_optionalChain([it, 'optionalAccess', _147 => _147.type]) === "scale" || _optionalChain([it, 'optionalAccess', _148 => _148.type]) === "draw") {
|
|
5335
6060
|
const b = it.type === "draw" ? findVectorNode(doc.nodes, it.nodeId) ? vectorNodeBounds(findVectorNode(doc.nodes, it.nodeId)) : null : state.selectionFrame;
|
|
5336
6061
|
if (b) status = `W ${fmt(b.width)} \xD7 H ${fmt(b.height)}`;
|
|
5337
6062
|
}
|
|
@@ -5348,19 +6073,25 @@ function getVectorOverlayRenderData(state) {
|
|
|
5348
6073
|
}
|
|
5349
6074
|
}
|
|
5350
6075
|
let toolStroke = null;
|
|
5351
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
6076
|
+
if (_optionalChain([it, 'optionalAccess', _149 => _149.type]) === "stroke") {
|
|
5352
6077
|
const pts = it.points.map((q) => toScreen(state, q));
|
|
5353
6078
|
const d = pts.map((q, i) => `${i ? "L" : "M"}${fmt(q.x)} ${fmt(q.y)}`).join("") + (pts.length === 1 ? `L${fmt(pts[0].x)} ${fmt(pts[0].y)}` : "");
|
|
5354
6079
|
toolStroke = { tool: it.tool, d, width: fmt(it.width * z) };
|
|
5355
6080
|
}
|
|
5356
6081
|
let pencilString = null;
|
|
5357
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
6082
|
+
if (_optionalChain([it, 'optionalAccess', _150 => _150.type]) === "draw" && it.string) {
|
|
5358
6083
|
const a = toScreen(state, it.string[0]);
|
|
5359
6084
|
const b = toScreen(state, it.string[1]);
|
|
5360
6085
|
pencilString = { x1: fmt(a.x), y1: fmt(a.y), x2: fmt(b.x), y2: fmt(b.y) };
|
|
5361
6086
|
}
|
|
5362
|
-
const
|
|
5363
|
-
|
|
6087
|
+
const dragged = _optionalChain([it, 'optionalAccess', _151 => _151.type]) === "corner" ? it.ref : null;
|
|
6088
|
+
const cornerWidgets = getVectorCornerWidgets(state).map((w) => {
|
|
6089
|
+
const s = toScreen(state, w);
|
|
6090
|
+
return { ref: w.ref, x: fmt(s.x), y: fmt(s.y), radius: w.radius, kind: w.kind, hovered: sameAnchor(_optionalChain([state, 'access', _152 => _152.hover, 'optionalAccess', _153 => _153.corner]), w.ref), active: !!dragged };
|
|
6091
|
+
});
|
|
6092
|
+
if (_optionalChain([it, 'optionalAccess', _154 => _154.type]) === "corner") status = `R ${fmt(it.radius)}`;
|
|
6093
|
+
const cutPoint = state.tool === "scissors" && _optionalChain([state, 'access', _155 => _155.hover, 'optionalAccess', _156 => _156.segment]) && !it ? (({ x, y }) => ({ x: fmt(x), y: fmt(y) }))(toScreen(state, state.hover.segment.point)) : null;
|
|
6094
|
+
return { outlines, selectionBox, anchors, handles, marquee, penPreview, artboard, guides, status, toolStroke, pencilString, cutPoint, cornerWidgets };
|
|
5364
6095
|
}
|
|
5365
6096
|
var VECTOR_OVERLAY_THEME = {
|
|
5366
6097
|
accent: "#0ea5e9",
|
|
@@ -5372,7 +6103,9 @@ var VECTOR_OVERLAY_THEME = {
|
|
|
5372
6103
|
eraserFill: "rgba(239, 68, 68, 0.25)",
|
|
5373
6104
|
transformHandleSize: 8,
|
|
5374
6105
|
anchorSize: 7,
|
|
5375
|
-
handleRadius: 3.5
|
|
6106
|
+
handleRadius: 3.5,
|
|
6107
|
+
/** Radius of a live corner widget (a ring with a dot). */
|
|
6108
|
+
cornerWidgetRadius: 4
|
|
5376
6109
|
};
|
|
5377
6110
|
function toVectorModifiers(event) {
|
|
5378
6111
|
return { shift: !!event.shiftKey, alt: !!event.altKey, mod: !!(event.metaKey || event.ctrlKey) };
|
|
@@ -5388,7 +6121,7 @@ function isVectorTextTarget(target) {
|
|
|
5388
6121
|
if (!el || typeof el !== "object") return false;
|
|
5389
6122
|
const tag = (_nullishCoalesce(el.tagName, () => ( ""))).toUpperCase();
|
|
5390
6123
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
5391
|
-
return !!el.isContentEditable || _optionalChain([el, 'access',
|
|
6124
|
+
return !!el.isContentEditable || _optionalChain([el, 'access', _157 => _157.getAttribute, 'optionalCall', _158 => _158("contenteditable")]) === "true";
|
|
5392
6125
|
}
|
|
5393
6126
|
function getVectorSelectionStyle(state) {
|
|
5394
6127
|
const paths = [];
|
|
@@ -5396,18 +6129,68 @@ function getVectorSelectionStyle(state) {
|
|
|
5396
6129
|
const node = findVectorNode(state.document.nodes, id);
|
|
5397
6130
|
if (node) paths.push(...collect(node));
|
|
5398
6131
|
}
|
|
6132
|
+
const anchorMode = state.tool === "direct" && !!_optionalChain([state, 'access', _159 => _159.selectedAnchors, 'optionalAccess', _160 => _160.length]);
|
|
6133
|
+
if (anchorMode) {
|
|
6134
|
+
for (const r of state.selectedAnchors) {
|
|
6135
|
+
if (paths.some((p) => p.id === r.nodeId)) continue;
|
|
6136
|
+
const node = findVectorNode(state.document.nodes, r.nodeId);
|
|
6137
|
+
if (_optionalChain([node, 'optionalAccess', _161 => _161.type]) === "path") paths.push(node);
|
|
6138
|
+
}
|
|
6139
|
+
}
|
|
5399
6140
|
if (!paths.length) return null;
|
|
5400
6141
|
const first = paths[0];
|
|
5401
6142
|
const same = (get) => paths.every((p) => JSON.stringify(_nullishCoalesce(get(p), () => ( null))) === JSON.stringify(_nullishCoalesce(get(first), () => ( null))));
|
|
6143
|
+
const corners2 = [];
|
|
6144
|
+
for (const p of paths) {
|
|
6145
|
+
for (const c of vectorCorners(p.subpaths)) {
|
|
6146
|
+
if (anchorMode && !state.selectedAnchors.some((r) => r.nodeId === p.id && r.subpath === c.subpath && r.index === c.index)) continue;
|
|
6147
|
+
const corner = p.subpaths[c.subpath].anchors[c.index].corner;
|
|
6148
|
+
corners2.push({ radius: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _162 => _162.radius]), () => ( 0)), kind: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _163 => _163.kind]), () => ( "round")) });
|
|
6149
|
+
}
|
|
6150
|
+
}
|
|
6151
|
+
const c0 = _nullishCoalesce(corners2[0], () => ( { radius: 0, kind: "round" }));
|
|
5402
6152
|
return {
|
|
5403
6153
|
fill: _nullishCoalesce(first.fill, () => ( null)),
|
|
5404
6154
|
stroke: _nullishCoalesce(first.stroke, () => ( null)),
|
|
5405
6155
|
strokeWidth: _nullishCoalesce(first.strokeWidth, () => ( 1)),
|
|
5406
6156
|
opacity: _nullishCoalesce(first.opacity, () => ( 1)),
|
|
5407
|
-
|
|
6157
|
+
strokeAlign: _nullishCoalesce(first.strokeAlign, () => ( "center")),
|
|
6158
|
+
startArrow: _nullishCoalesce(first.startArrow, () => ( null)),
|
|
6159
|
+
endArrow: _nullishCoalesce(first.endArrow, () => ( null)),
|
|
6160
|
+
arrowAlign: _nullishCoalesce(first.arrowAlign, () => ( "extend")),
|
|
6161
|
+
startArrowScale: _nullishCoalesce(first.startArrowScale, () => ( 1)),
|
|
6162
|
+
endArrowScale: _nullishCoalesce(first.endArrowScale, () => ( 1)),
|
|
6163
|
+
cornerRadius: c0.radius,
|
|
6164
|
+
cornerKind: c0.kind,
|
|
6165
|
+
corners: corners2.length,
|
|
6166
|
+
hasOpenPath: paths.some((p) => p.subpaths.some((sp) => !sp.closed && sp.anchors.length > 1)),
|
|
6167
|
+
mixed: {
|
|
6168
|
+
fill: !same((p) => p.fill),
|
|
6169
|
+
stroke: !same((p) => p.stroke),
|
|
6170
|
+
strokeWidth: !same((p) => _nullishCoalesce(p.strokeWidth, () => ( 1))),
|
|
6171
|
+
opacity: !same((p) => _nullishCoalesce(p.opacity, () => ( 1))),
|
|
6172
|
+
strokeAlign: !same((p) => _nullishCoalesce(p.strokeAlign, () => ( "center"))),
|
|
6173
|
+
startArrow: !same((p) => _nullishCoalesce(p.startArrow, () => ( null))),
|
|
6174
|
+
endArrow: !same((p) => _nullishCoalesce(p.endArrow, () => ( null))),
|
|
6175
|
+
arrowAlign: !same((p) => _nullishCoalesce(p.arrowAlign, () => ( "extend"))),
|
|
6176
|
+
startArrowScale: !same((p) => _nullishCoalesce(p.startArrowScale, () => ( 1))),
|
|
6177
|
+
endArrowScale: !same((p) => _nullishCoalesce(p.endArrowScale, () => ( 1))),
|
|
6178
|
+
cornerRadius: corners2.some((c) => c.radius !== c0.radius),
|
|
6179
|
+
cornerKind: corners2.some((c) => c.kind !== c0.kind)
|
|
6180
|
+
},
|
|
5408
6181
|
pathIds: paths.map((p) => p.id)
|
|
5409
6182
|
};
|
|
5410
6183
|
}
|
|
6184
|
+
var VECTOR_STROKE_ALIGN_LABELS = { center: "Center", inside: "Inside", outside: "Outside" };
|
|
6185
|
+
var VECTOR_CORNER_KIND_LABELS = { round: "Round", inverted: "Inverted", chamfer: "Chamfer" };
|
|
6186
|
+
var VECTOR_ARROWHEAD_LABELS = {
|
|
6187
|
+
triangle: "Triangle",
|
|
6188
|
+
arrow: "Arrow",
|
|
6189
|
+
open: "Open arrow",
|
|
6190
|
+
circle: "Circle",
|
|
6191
|
+
square: "Square",
|
|
6192
|
+
bar: "Bar"
|
|
6193
|
+
};
|
|
5411
6194
|
function vectorPaintToHex(paint) {
|
|
5412
6195
|
if (typeof paint !== "string") return null;
|
|
5413
6196
|
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(paint.trim());
|
|
@@ -5420,7 +6203,8 @@ var VECTOR_PATH_ACTIONS = [
|
|
|
5420
6203
|
{ id: "average", label: "\u22B9", title: "Average Points", shortcut: "Alt+J", enabled: (_s, p) => p > 1, run: (c) => c.averageAnchors("both") },
|
|
5421
6204
|
{ id: "cut", label: "\u2702\xB7", title: "Cut at Points", enabled: (_s, p) => p > 0, run: (c) => c.cutAtAnchors() },
|
|
5422
6205
|
{ id: "clean", label: "\u2301", title: "Remove Redundant Points", enabled: (s, p) => s + p > 0, run: (c) => c.removeRedundantPoints() },
|
|
5423
|
-
{ id: "smooth", label: "\u223F", title: "Smooth", enabled: (s, p) => s + p > 0, run: (c) => c.smoothPaths() }
|
|
6206
|
+
{ id: "smooth", label: "\u223F", title: "Smooth", enabled: (s, p) => s + p > 0, run: (c) => c.smoothPaths() },
|
|
6207
|
+
{ id: "outline", label: "\u22A1", title: "Outline Stroke", enabled: (s) => s > 0, run: (c) => c.outlineStroke() }
|
|
5424
6208
|
];
|
|
5425
6209
|
var VECTOR_EDIT_TOGGLES = [
|
|
5426
6210
|
{ key: "keepShapeOnDelete", label: "Keep", title: "Keep shape when deleting points" },
|
|
@@ -5458,7 +6242,13 @@ var STYLE_PROPS = {
|
|
|
5458
6242
|
strokeLinecap: { type: "string", enum: ["butt", "round", "square"] },
|
|
5459
6243
|
strokeLinejoin: { type: "string", enum: ["miter", "round", "bevel"] },
|
|
5460
6244
|
strokeDasharray: { type: "array", items: { type: "number" } },
|
|
5461
|
-
fillRule: { type: "string", enum: ["nonzero", "evenodd"] }
|
|
6245
|
+
fillRule: { type: "string", enum: ["nonzero", "evenodd"] },
|
|
6246
|
+
strokeAlign: { type: "string", enum: ["center", "inside", "outside"], description: "Where the stroke sits on the outline (closed shapes only; open paths stroke centred)." },
|
|
6247
|
+
startArrow: { type: ["string", "null"], enum: [...VECTOR_ARROWHEADS, null], description: "Head at the start of an open path, or null for none." },
|
|
6248
|
+
endArrow: { type: ["string", "null"], enum: [...VECTOR_ARROWHEADS, null], description: "Head at the end of an open path, or null for none." },
|
|
6249
|
+
arrowAlign: { type: "string", enum: ["extend", "tip"], description: "`extend`: the tip sits past the end point; `tip`: on it, the stroke shortened under the head." },
|
|
6250
|
+
startArrowScale: { type: "number", exclusiveMinimum: 0, description: "Start head size as a multiple of the stroke width (default 1)." },
|
|
6251
|
+
endArrowScale: { type: "number", exclusiveMinimum: 0, description: "End head size as a multiple of the stroke width (default 1)." }
|
|
5462
6252
|
};
|
|
5463
6253
|
var pickStyle = (params) => {
|
|
5464
6254
|
const out = {};
|
|
@@ -5474,17 +6264,17 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5474
6264
|
const base = { group, ...options.scope ? { scope: options.scope } : {} };
|
|
5475
6265
|
const hasSelection = () => controller.getState().selection.length ? true : "Nothing is selected.";
|
|
5476
6266
|
const ids = (params) => {
|
|
5477
|
-
const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess',
|
|
6267
|
+
const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _164 => _164.ids]), () => ( controller.getState().selection));
|
|
5478
6268
|
for (const id of list2) if (!controller.getNode(id)) fail(`There is no node "${id}".`);
|
|
5479
6269
|
if (!list2.length) fail("Nothing is selected; pass ids.");
|
|
5480
6270
|
return list2;
|
|
5481
6271
|
};
|
|
5482
|
-
const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess',
|
|
6272
|
+
const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess', _165 => _165.ids, 'optionalAccess', _166 => _166.length]) ? true : hasSelection();
|
|
5483
6273
|
const anchorsOf = (refs) => {
|
|
5484
6274
|
if (!refs) return [...controller.getState().selectedAnchors];
|
|
5485
6275
|
for (const r of refs) {
|
|
5486
6276
|
const node = controller.getNode(r.nodeId);
|
|
5487
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
6277
|
+
if (_optionalChain([node, 'optionalAccess', _167 => _167.type]) !== "path" || !_optionalChain([node, 'access', _168 => _168.subpaths, 'access', _169 => _169[r.subpath], 'optionalAccess', _170 => _170.anchors, 'access', _171 => _171[r.index]])) fail(`There is no anchor ${r.index} on subpath ${r.subpath} of "${r.nodeId}".`);
|
|
5488
6278
|
}
|
|
5489
6279
|
return refs;
|
|
5490
6280
|
};
|
|
@@ -5551,7 +6341,8 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5551
6341
|
y: { type: "number" },
|
|
5552
6342
|
width: { type: "number", description: "For a line: the x offset of its end." },
|
|
5553
6343
|
height: { type: "number", description: "For a line: the y offset of its end." },
|
|
5554
|
-
cornerRadius: { type: "number", minimum: 0 },
|
|
6344
|
+
cornerRadius: { type: "number", minimum: 0, description: "Live corner radius of a rect, polygon or star." },
|
|
6345
|
+
cornerKind: { type: "string", enum: VECTOR_CORNER_KINDS },
|
|
5555
6346
|
sides: { type: "integer", minimum: 3 },
|
|
5556
6347
|
points: { type: "integer", minimum: 3 },
|
|
5557
6348
|
innerRatio: { type: "number", minimum: 0, maximum: 1 },
|
|
@@ -5574,7 +6365,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5574
6365
|
run: (_ctx, params) => {
|
|
5575
6366
|
const id = controller.addPath(params.d, { ...pickStyle(params), ...params.name ? { name: params.name } : {} });
|
|
5576
6367
|
const node = controller.getNode(id);
|
|
5577
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
6368
|
+
if (_optionalChain([node, 'optionalAccess', _172 => _172.type]) === "path" && !node.subpaths.length) {
|
|
5578
6369
|
controller.undo();
|
|
5579
6370
|
fail("The path data has no points.");
|
|
5580
6371
|
}
|
|
@@ -5597,6 +6388,38 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5597
6388
|
return { ok: true };
|
|
5598
6389
|
}
|
|
5599
6390
|
},
|
|
6391
|
+
{
|
|
6392
|
+
...base,
|
|
6393
|
+
id: `${prefix}setCorners`,
|
|
6394
|
+
label: "Corner Radius\u2026",
|
|
6395
|
+
keywords: ["round", "rounded", "corners", "radius", "fillet", "chamfer", "live corners"],
|
|
6396
|
+
description: "Sets the live corner radius (and optionally `kind`: round, inverted or chamfer) of `anchors`, else the selected points (direct tool), else every corner of `ids` / the selection. Radius 0 makes corners sharp; radii shrink to fit short sides. The anchors stay editable.",
|
|
6397
|
+
params: { type: "object", properties: { radius: { type: "number", minimum: 0 }, kind: { type: "string", enum: VECTOR_CORNER_KINDS }, ids: IDS, anchors: ANCHORS } },
|
|
6398
|
+
undoable: true,
|
|
6399
|
+
run: (_ctx, params) => {
|
|
6400
|
+
const refs = _optionalChain([params, 'optionalAccess', _173 => _173.anchors]) ? anchorsOf(params.anchors) : void 0;
|
|
6401
|
+
const target = { refs, ids: _optionalChain([params, 'optionalAccess', _174 => _174.ids]) ? ids(params) : void 0 };
|
|
6402
|
+
if (_optionalChain([params, 'optionalAccess', _175 => _175.radius]) !== void 0) check(controller.setCornerRadius(params.radius, { ...target, kind: params.kind }));
|
|
6403
|
+
else if (_optionalChain([params, 'optionalAccess', _176 => _176.kind])) check(controller.setCornerKind(params.kind, target));
|
|
6404
|
+
else fail("Pass `radius` and / or `kind`.");
|
|
6405
|
+
return { ok: true };
|
|
6406
|
+
}
|
|
6407
|
+
},
|
|
6408
|
+
{
|
|
6409
|
+
...base,
|
|
6410
|
+
id: `${prefix}outlineStroke`,
|
|
6411
|
+
label: "Outline Stroke",
|
|
6412
|
+
keywords: ["expand", "stroke to path", "outline", "convert stroke"],
|
|
6413
|
+
description: "Turns the stroke of paths into filled shapes of the area it paints (alignment, caps, joins, dashes and arrowheads included). Returns the new ids.",
|
|
6414
|
+
params: { type: "object", properties: { ids: IDS } },
|
|
6415
|
+
enabled: enabledFor,
|
|
6416
|
+
undoable: true,
|
|
6417
|
+
run: (_ctx, params) => {
|
|
6418
|
+
const created = controller.outlineStroke({ ids: _optionalChain([params, 'optionalAccess', _177 => _177.ids]) ? ids(params) : void 0 });
|
|
6419
|
+
if (!created.length) fail("No selected path has a stroke.");
|
|
6420
|
+
return { ids: created };
|
|
6421
|
+
}
|
|
6422
|
+
},
|
|
5600
6423
|
{
|
|
5601
6424
|
...base,
|
|
5602
6425
|
id: `${prefix}transform`,
|
|
@@ -5707,7 +6530,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5707
6530
|
enabled: enabledFor,
|
|
5708
6531
|
undoable: true,
|
|
5709
6532
|
run: (_ctx, params) => {
|
|
5710
|
-
const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess',
|
|
6533
|
+
const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess', _178 => _178.name]) });
|
|
5711
6534
|
if (!id) fail("Only nodes that share a parent can be grouped.");
|
|
5712
6535
|
return { id };
|
|
5713
6536
|
}
|
|
@@ -5735,7 +6558,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5735
6558
|
params: { type: "object", properties: { anchors: ANCHORS, keepShape: { type: "boolean" } } },
|
|
5736
6559
|
undoable: true,
|
|
5737
6560
|
run: (_ctx, params) => {
|
|
5738
|
-
check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess',
|
|
6561
|
+
check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _179 => _179.anchors])), { keepShape: _optionalChain([params, 'optionalAccess', _180 => _180.keepShape]) }));
|
|
5739
6562
|
return { ok: true };
|
|
5740
6563
|
}
|
|
5741
6564
|
},
|
|
@@ -5790,7 +6613,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5790
6613
|
params: { type: "object", properties: { ids: IDS, tolerance: { type: "number", minimum: 0 } } },
|
|
5791
6614
|
undoable: true,
|
|
5792
6615
|
run: (_ctx, params) => {
|
|
5793
|
-
check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess',
|
|
6616
|
+
check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess', _181 => _181.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _182 => _182.tolerance]) }));
|
|
5794
6617
|
return { selection: controller.getState().selection };
|
|
5795
6618
|
}
|
|
5796
6619
|
},
|
|
@@ -5804,7 +6627,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5804
6627
|
params: { type: "object", properties: { axis: { type: "string", enum: ["horizontal", "vertical", "both"] }, anchors: ANCHORS } },
|
|
5805
6628
|
undoable: true,
|
|
5806
6629
|
run: (_ctx, params) => {
|
|
5807
|
-
check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess',
|
|
6630
|
+
check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _183 => _183.axis]), () => ( "both")), anchorsOf(_optionalChain([params, 'optionalAccess', _184 => _184.anchors]))));
|
|
5808
6631
|
return { ok: true };
|
|
5809
6632
|
}
|
|
5810
6633
|
},
|
|
@@ -5818,7 +6641,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5818
6641
|
enabled: enabledFor,
|
|
5819
6642
|
undoable: true,
|
|
5820
6643
|
run: (_ctx, params) => {
|
|
5821
|
-
check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess',
|
|
6644
|
+
check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess', _185 => _185.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _186 => _186.tolerance]) }));
|
|
5822
6645
|
return { ok: true };
|
|
5823
6646
|
}
|
|
5824
6647
|
},
|
|
@@ -5831,7 +6654,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5831
6654
|
params: { type: "object", properties: { ids: IDS, amount: { type: "number", minimum: 0, maximum: 1 }, anchors: ANCHORS } },
|
|
5832
6655
|
undoable: true,
|
|
5833
6656
|
run: (_ctx, params) => {
|
|
5834
|
-
check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess',
|
|
6657
|
+
check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess', _187 => _187.ids]) ? ids(params) : void 0, amount: _optionalChain([params, 'optionalAccess', _188 => _188.amount]), refs: _optionalChain([params, 'optionalAccess', _189 => _189.anchors]) }));
|
|
5835
6658
|
return { ok: true };
|
|
5836
6659
|
}
|
|
5837
6660
|
},
|
|
@@ -5844,14 +6667,14 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5844
6667
|
params: { type: "object", properties: { nodeId: { type: "string" }, x: { type: "number" }, y: { type: "number" }, anchors: ANCHORS } },
|
|
5845
6668
|
undoable: true,
|
|
5846
6669
|
run: (_ctx, params) => {
|
|
5847
|
-
if (_optionalChain([params, 'optionalAccess',
|
|
6670
|
+
if (_optionalChain([params, 'optionalAccess', _190 => _190.nodeId]) !== void 0) {
|
|
5848
6671
|
if (!controller.getNode(params.nodeId)) fail(`There is no node "${params.nodeId}".`);
|
|
5849
6672
|
if (params.x === void 0 || params.y === void 0) fail("Pass x and y with nodeId.");
|
|
5850
6673
|
const created = controller.cutPathAt(params.nodeId, { x: params.x, y: params.y });
|
|
5851
6674
|
if (!created) fail("Nothing to cut there (the end of an open path, or a locked path).");
|
|
5852
6675
|
return { ids: created };
|
|
5853
6676
|
}
|
|
5854
|
-
check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess',
|
|
6677
|
+
check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _191 => _191.anchors]))));
|
|
5855
6678
|
return { ids: controller.getState().selection };
|
|
5856
6679
|
}
|
|
5857
6680
|
},
|
|
@@ -5901,7 +6724,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5901
6724
|
},
|
|
5902
6725
|
run: (_ctx, params) => {
|
|
5903
6726
|
const patch = {};
|
|
5904
|
-
for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize"]) if (_optionalChain([params, 'optionalAccess',
|
|
6727
|
+
for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize"]) if (_optionalChain([params, 'optionalAccess', _192 => _192[key]]) !== void 0) patch[key] = params[key];
|
|
5905
6728
|
controller.setEditing(patch);
|
|
5906
6729
|
return { editing: controller.getState().editing };
|
|
5907
6730
|
}
|
|
@@ -5926,7 +6749,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
5926
6749
|
keywords: ["download", "save", "markup"],
|
|
5927
6750
|
description: "Returns the document as SVG markup.",
|
|
5928
6751
|
params: { type: "object", properties: { precision: { type: "integer", minimum: 0, maximum: 8 } } },
|
|
5929
|
-
run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess',
|
|
6752
|
+
run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess', _193 => _193.precision]) }) })
|
|
5930
6753
|
},
|
|
5931
6754
|
{
|
|
5932
6755
|
...base,
|
|
@@ -6058,5 +6881,39 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6058
6881
|
|
|
6059
6882
|
|
|
6060
6883
|
|
|
6061
|
-
|
|
6884
|
+
|
|
6885
|
+
|
|
6886
|
+
|
|
6887
|
+
|
|
6888
|
+
|
|
6889
|
+
|
|
6890
|
+
|
|
6891
|
+
|
|
6892
|
+
|
|
6893
|
+
|
|
6894
|
+
|
|
6895
|
+
|
|
6896
|
+
|
|
6897
|
+
|
|
6898
|
+
|
|
6899
|
+
|
|
6900
|
+
|
|
6901
|
+
|
|
6902
|
+
|
|
6903
|
+
|
|
6904
|
+
|
|
6905
|
+
|
|
6906
|
+
|
|
6907
|
+
|
|
6908
|
+
|
|
6909
|
+
|
|
6910
|
+
|
|
6911
|
+
|
|
6912
|
+
|
|
6913
|
+
|
|
6914
|
+
|
|
6915
|
+
|
|
6916
|
+
|
|
6917
|
+
|
|
6918
|
+
exports.DEFAULT_VECTOR_PATH_EDIT = DEFAULT_VECTOR_PATH_EDIT; exports.DEFAULT_VECTOR_SNAP = DEFAULT_VECTOR_SNAP; exports.IDENTITY_MATRIX = IDENTITY_MATRIX; exports.KAPPA = KAPPA2; exports.LazyMouse = LazyMouse; exports.VECTOR_ARROWHEADS = VECTOR_ARROWHEADS; exports.VECTOR_ARROWHEAD_LABELS = VECTOR_ARROWHEAD_LABELS; exports.VECTOR_CLIPBOARD_TYPE = VECTOR_CLIPBOARD_TYPE; exports.VECTOR_CONSTRUCTION_ANGLES = VECTOR_CONSTRUCTION_ANGLES; exports.VECTOR_CORNER_KINDS = VECTOR_CORNER_KINDS; exports.VECTOR_CORNER_KIND_LABELS = VECTOR_CORNER_KIND_LABELS; exports.VECTOR_CORNER_WIDGET_INSET = VECTOR_CORNER_WIDGET_INSET; exports.VECTOR_EDIT_TOGGLES = VECTOR_EDIT_TOGGLES; exports.VECTOR_INK_MAX_CORNERS = VECTOR_INK_MAX_CORNERS; exports.VECTOR_OVERLAY_THEME = VECTOR_OVERLAY_THEME; exports.VECTOR_PATH_ACTIONS = VECTOR_PATH_ACTIONS; exports.VECTOR_PENCIL_STRING_PX = VECTOR_PENCIL_STRING_PX; exports.VECTOR_ROTATE_HANDLE_OFFSET = VECTOR_ROTATE_HANDLE_OFFSET; exports.VECTOR_STROKE_ALIGN_LABELS = VECTOR_STROKE_ALIGN_LABELS; exports.VECTOR_STYLE_KEYS = VECTOR_STYLE_KEYS; exports.VECTOR_TOOLS = VECTOR_TOOLS; exports.VECTOR_TOOL_GLYPHS = VECTOR_TOOL_GLYPHS; exports.VECTOR_TOOL_SHORTCUTS = VECTOR_TOOL_SHORTCUTS; exports.VECTOR_TRANSFORM_HANDLES = VECTOR_TRANSFORM_HANDLES; exports.VectorEditorController = VectorEditorController; exports.VectorSnapTargets = VectorSnapTargets; exports.applyMatrix = applyMatrix; exports.applyMatrixLinear = applyMatrixLinear; exports.applyVectorCornersAttribute = applyVectorCornersAttribute; exports.arrowheadInset = arrowheadInset; exports.arrowheadPath = arrowheadPath; exports.arrowheadWeight = arrowheadWeight; exports.bendSegment = bendSegment; exports.bezierToSubpaths = bezierToSubpaths; exports.boundsFromPoints = boundsFromPoints; exports.boundsIntersect = boundsIntersect; exports.cloneAnchor = cloneAnchor; exports.cloneSubpath = cloneSubpath; exports.cloneVectorDocument = cloneVectorDocument; exports.cloneVectorNode = cloneVectorNode; exports.collectPathNodes = collectPathNodes; exports.constrainToLeave = constrainToLeave; exports.convertAnchor = convertAnchor; exports.cornerBisectorPoint = cornerBisectorPoint; exports.cornerRadiusChange = cornerRadiusChange; exports.cornerSetback = cornerSetback; exports.createVectorCommands = createVectorCommands; exports.curvatureMoveAnchor = curvatureMoveAnchor; exports.cutSubpathAt = cutSubpathAt; exports.decomposeRigid = decomposeRigid; exports.effectiveStrokeAlign = effectiveStrokeAlign; exports.ellipseSubpath = ellipseSubpath; exports.eraseFromFill = eraseFromFill; exports.eraseFromOutline = eraseFromOutline; exports.eraserRegion = eraserRegion; exports.expandVectorCorners = expandVectorCorners; exports.expandVectorCornersOf = expandVectorCornersOf; exports.findVectorNode = findVectorNode; exports.fitCornerRadius = fitCornerRadius; exports.getAnchor = getAnchor; exports.getAnchorWorld = getAnchorWorld; exports.getEditablePathIds = getEditablePathIds; exports.getTransformHandlePositions = getTransformHandlePositions; exports.getVectorCornerWidgets = getVectorCornerWidgets; exports.getVectorOverlayRenderData = getVectorOverlayRenderData; exports.getVectorSceneRenderData = getVectorSceneRenderData; exports.getVectorSelectionBoxGeometry = getVectorSelectionBoxGeometry; exports.getVectorSelectionFrame = getVectorSelectionFrame; exports.getVectorSelectionStyle = getVectorSelectionStyle; exports.getVisibleAnchors = getVisibleAnchors; exports.getVisibleHandles = getVisibleHandles; exports.hasPaint = hasPaint; exports.hasStrokeExtras = hasStrokeExtras; exports.hasVectorCorners = hasVectorCorners; exports.hitTestVectorNode = hitTestVectorNode; exports.hitTestVectorNodes = hitTestVectorNodes; exports.hitTestVectorStroke = hitTestVectorStroke; exports.inferAnchorType = inferAnchorType; exports.insertAnchor = insertAnchor; exports.invertMatrix = invertMatrix; exports.isClosedBezierShape = isClosedBezierShape; exports.isIdentityMatrix = isIdentityMatrix; exports.isVectorTextTarget = isVectorTextTarget; exports.joinSubpaths = joinSubpaths; exports.knifePath = knifePath; exports.lineSubpath = lineSubpath; exports.locateVectorNode = locateVectorNode; exports.matrixRotation = matrixRotation; exports.moveAnchorHandle = moveAnchorHandle; exports.multiplyMatrices = multiplyMatrices; exports.nearestSegment = nearestSegment; exports.nextVectorCornerKind = nextVectorCornerKind; exports.nodeMatrix = nodeMatrix; exports.parseSvgTransform = parseSvgTransform; exports.parseVectorSvg = parseVectorSvg; exports.polygonSubpath = polygonSubpath; exports.polylineBounds = polylineBounds; exports.recognizeInkShape = recognizeInkShape; exports.rectSubpath = rectSubpath; exports.removeAnchorKeepingShape = removeAnchorKeepingShape; exports.removeAnchors = removeAnchors; exports.removeAnchorsKeepingShape = removeAnchorsKeepingShape; exports.removeRedundantPoints = removeRedundantPoints; exports.reverseSubpath = reverseSubpath; exports.rotateMatrix = rotateMatrix; exports.roundSubpaths = roundSubpaths; exports.scaleFor = scaleFor; exports.scaleMatrix = scaleMatrix; exports.setAnchorCorner = setAnchorCorner; exports.setSubpathCorners = setSubpathCorners; exports.simplifyPolyline = simplifyPolyline; exports.smoothSubpath = smoothSubpath; exports.splitIntoFaces = splitIntoFaces; exports.splitSubpathAt = splitSubpathAt; exports.starSubpath = starSubpath; exports.subpathPointAt = subpathPointAt; exports.subpathSegment = subpathSegment; exports.subpathSegmentCount = subpathSegmentCount; exports.subpathsToBezier = subpathsToBezier; exports.toVectorKeyInput = toVectorKeyInput; exports.toVectorModifiers = toVectorModifiers; exports.toVectorPointerInput = toVectorPointerInput; exports.transformVectorNode = transformVectorNode; exports.translateAnchor = translateAnchor; exports.translateMatrix = translateMatrix; exports.unionBounds = unionBounds; exports.vectorCornerAt = vectorCornerAt; exports.vectorCorners = vectorCorners; exports.vectorCornersAttribute = vectorCornersAttribute; exports.vectorDocumentToSvg = vectorDocumentToSvg; exports.vectorInkShapeName = vectorInkShapeName; exports.vectorNodeBounds = vectorNodeBounds; exports.vectorNodeRotation = vectorNodeRotation; exports.vectorNodeToBezier = vectorNodeToBezier; exports.vectorPaintToHex = vectorPaintToHex; exports.vectorPaintToSvg = vectorPaintToSvg; exports.vectorParentMatrix = vectorParentMatrix; exports.vectorPathData = vectorPathData; exports.vectorPathWorldBezier = vectorPathWorldBezier; exports.vectorResizeCursor = vectorResizeCursor; exports.vectorStrokeOutline = vectorStrokeOutline; exports.vectorStrokeOutlinePath = vectorStrokeOutlinePath; exports.vectorStrokeParts = vectorStrokeParts; exports.vectorStrokeReach = vectorStrokeReach; exports.vectorStrokeSvgParts = vectorStrokeSvgParts; exports.vectorToolLabel = vectorToolLabel; exports.vectorWorldMatrix = vectorWorldMatrix; exports.walkVectorNodes = walkVectorNodes;
|
|
6062
6919
|
//# sourceMappingURL=index.cjs.map
|