@pixerate/editor 0.36.0 → 0.38.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 +17 -0
- package/dist/canvas/index.cjs +37 -25
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.d.cts +3 -217
- package/dist/canvas/index.d.ts +3 -217
- package/dist/canvas/index.js +13 -1
- package/dist/canvas/index.js.map +1 -1
- package/dist/{chunk-BGNPT5PE.cjs → chunk-7EDLVBOO.cjs} +671 -19
- package/dist/chunk-7EDLVBOO.cjs.map +1 -0
- package/dist/{chunk-EGPIVUEF.js → chunk-ZCCU3VNI.js} +668 -16
- package/dist/chunk-ZCCU3VNI.js.map +1 -0
- package/dist/pathfinder-Bd87_lsQ.d.cts +994 -0
- package/dist/pathfinder-fLmmFOJw.d.ts +994 -0
- package/dist/vector/index.cjs +1900 -297
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +620 -8
- package/dist/vector/index.d.ts +620 -8
- package/dist/vector/index.js +1696 -93
- package/dist/vector/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/bezier-BvqVmWMg.d.ts +0 -547
- package/dist/bezier-D8bsO-L0.d.cts +0 -547
- package/dist/chunk-BGNPT5PE.cjs.map +0 -1
- package/dist/chunk-EGPIVUEF.js.map +0 -1
package/dist/vector/index.cjs
CHANGED
|
@@ -31,13 +31,35 @@ var _chunkQKLRAA4Tcjs = require('../chunk-QKLRAA4T.cjs');
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
var _chunk7EDLVBOOcjs = require('../chunk-7EDLVBOO.cjs');
|
|
35
40
|
|
|
36
41
|
// src/vector/types.ts
|
|
37
42
|
var VECTOR_CORNER_KINDS = ["round", "inverted", "chamfer"];
|
|
38
43
|
var VECTOR_ARROWHEADS = ["triangle", "arrow", "open", "circle", "square", "bar"];
|
|
39
|
-
var VECTOR_TOOLS = [
|
|
44
|
+
var VECTOR_TOOLS = [
|
|
45
|
+
"select",
|
|
46
|
+
"direct",
|
|
47
|
+
"pen",
|
|
48
|
+
"pencil",
|
|
49
|
+
"rect",
|
|
50
|
+
"ellipse",
|
|
51
|
+
"polygon",
|
|
52
|
+
"star",
|
|
53
|
+
"line",
|
|
54
|
+
"scissors",
|
|
55
|
+
"knife",
|
|
56
|
+
"eraser",
|
|
57
|
+
"width",
|
|
58
|
+
"shapeBuilder",
|
|
59
|
+
"paintBucket"
|
|
60
|
+
];
|
|
40
61
|
var VECTOR_TRANSFORM_HANDLES = ["nw", "n", "ne", "e", "se", "s", "sw", "w", "rotate"];
|
|
62
|
+
var VECTOR_PATHFINDER_OPERATIONS = ["divide", "trim", "merge", "crop", "outline", "minusBack"];
|
|
41
63
|
|
|
42
64
|
// src/vector/corners.ts
|
|
43
65
|
var EPS = 1e-9;
|
|
@@ -58,7 +80,7 @@ var Side = class {
|
|
|
58
80
|
constructor(a, h1, h2, b) {
|
|
59
81
|
this.straight = onAnchor(a, h1) && onAnchor(b, h2);
|
|
60
82
|
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) :
|
|
83
|
+
this.length = this.straight ? Math.hypot(b.x - a.x, b.y - a.y) : _chunk7EDLVBOOcjs.segmentLength.call(void 0, this.curve);
|
|
62
84
|
}
|
|
63
85
|
/** Unit direction the side leaves the corner in (towards its first control point off the corner). */
|
|
64
86
|
direction() {
|
|
@@ -76,10 +98,10 @@ var Side = class {
|
|
|
76
98
|
const t2 = this.length > EPS ? Math.min(1, Math.max(0, s / this.length)) : 0;
|
|
77
99
|
return { t: t2, p: add(vec(this.curve[0]), mul(u, s)), dir: u };
|
|
78
100
|
}
|
|
79
|
-
const t =
|
|
80
|
-
const d = vec(
|
|
101
|
+
const t = _chunk7EDLVBOOcjs.segmentParamAtLength.call(void 0, this.curve, s, this.length);
|
|
102
|
+
const d = vec(_chunk7EDLVBOOcjs.segmentDerivative.call(void 0, this.curve, t));
|
|
81
103
|
const l = len(d);
|
|
82
|
-
return { t, p: vec(
|
|
104
|
+
return { t, p: vec(_chunk7EDLVBOOcjs.segmentPoint.call(void 0, this.curve, t)), dir: l > EPS ? mul(d, 1 / l) : u };
|
|
83
105
|
}
|
|
84
106
|
};
|
|
85
107
|
function cornerOf(sp, s, i) {
|
|
@@ -152,7 +174,7 @@ function cutCorner(c, radius, kind) {
|
|
|
152
174
|
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
175
|
}
|
|
154
176
|
var radiusOf = (a) => {
|
|
155
|
-
const r = _optionalChain([a, 'access',
|
|
177
|
+
const r = _optionalChain([a, 'access', _3 => _3.corner, 'optionalAccess', _4 => _4.radius]);
|
|
156
178
|
return typeof r === "number" && r > 0 && Number.isFinite(r) ? r : 0;
|
|
157
179
|
};
|
|
158
180
|
function hasVectorCorners(subpaths) {
|
|
@@ -166,7 +188,7 @@ function expandVectorCornersOf(sp, subpath = 0) {
|
|
|
166
188
|
const c = cornerOf(sp, subpath, i);
|
|
167
189
|
if (!c) return null;
|
|
168
190
|
const fitted = fitCornerRadius(c, r);
|
|
169
|
-
return fitted > EPS ? cutCorner(c, fitted, _nullishCoalesce(_optionalChain([a, 'access',
|
|
191
|
+
return fitted > EPS ? cutCorner(c, fitted, _nullishCoalesce(_optionalChain([a, 'access', _5 => _5.corner, 'optionalAccess', _6 => _6.kind]), () => ( "round"))) : null;
|
|
170
192
|
});
|
|
171
193
|
if (!cuts.some(Boolean)) return { subpath: { closed: sp.closed, anchors: sp.anchors.map(plain) }, sources: sp.anchors.map((_, i) => i) };
|
|
172
194
|
const trimmed = sp.anchors.map((a, j) => {
|
|
@@ -180,7 +202,7 @@ function expandVectorCornersOf(sp, subpath = 0) {
|
|
|
180
202
|
const s0 = from ? from.tv : 0;
|
|
181
203
|
const s1 = to ? 1 - to.tu : 1;
|
|
182
204
|
const seg = [pt(a), pt(_nullishCoalesce(a.out, () => ( a))), pt(_nullishCoalesce(b.in, () => ( b))), pt(b)];
|
|
183
|
-
const part =
|
|
205
|
+
const part = _chunk7EDLVBOOcjs.subSegment.call(void 0, seg, s0, Math.max(s0, s1));
|
|
184
206
|
return { out: vec(part[1]), in: vec(part[2]) };
|
|
185
207
|
});
|
|
186
208
|
const anchors = [];
|
|
@@ -234,7 +256,7 @@ function expandVectorCorners(subpaths) {
|
|
|
234
256
|
function setAnchorCorner(a, radius, kind) {
|
|
235
257
|
const { corner, ...rest } = a;
|
|
236
258
|
const r = Number.isFinite(radius) ? Math.max(0, radius) : 0;
|
|
237
|
-
const k = _nullishCoalesce(kind, () => ( _optionalChain([corner, 'optionalAccess',
|
|
259
|
+
const k = _nullishCoalesce(kind, () => ( _optionalChain([corner, 'optionalAccess', _7 => _7.kind])));
|
|
238
260
|
if (r <= 0 && !kind) return rest;
|
|
239
261
|
return { ...rest, corner: { radius: r, ...k && k !== "round" ? { kind: k } : {} } };
|
|
240
262
|
}
|
|
@@ -245,19 +267,561 @@ function setSubpathCorners(sp, radius, kind) {
|
|
|
245
267
|
return { closed: sp.closed, anchors: sp.anchors.map((a) => setAnchorCorner(a, radius, kind)) };
|
|
246
268
|
}
|
|
247
269
|
|
|
270
|
+
// src/vector/width.ts
|
|
271
|
+
var VECTOR_WIDTH_PROFILE_MAX_POINTS = 64;
|
|
272
|
+
var VECTOR_WIDTH_PROFILE_MAX_SCALE = 1e3;
|
|
273
|
+
var VECTOR_WIDTH_SAME_T = 1e-6;
|
|
274
|
+
var sym = (t, s) => ({ t, left: s, right: s });
|
|
275
|
+
var VECTOR_WIDTH_PRESETS = [
|
|
276
|
+
{ id: "uniform", label: "Uniform", points: [] },
|
|
277
|
+
{ id: "taperStart", label: "Taper start", points: [sym(0, 0), sym(1, 1)] },
|
|
278
|
+
{ id: "taperEnd", label: "Taper end", points: [sym(0, 1), sym(1, 0)] },
|
|
279
|
+
{ id: "taperBoth", label: "Taper both", points: [sym(0, 0), sym(0.5, 1), sym(1, 0)] },
|
|
280
|
+
// Full width at the ends, swelling to twice the width in the middle.
|
|
281
|
+
{ id: "bulge", label: "Bulge", points: [sym(0, 1), sym(0.5, 2), sym(1, 1)] },
|
|
282
|
+
// Full width at the ends, pinched to a quarter in the middle.
|
|
283
|
+
{ id: "pinch", label: "Pinch", points: [sym(0, 1), sym(0.5, 0.25), sym(1, 1)] },
|
|
284
|
+
// A round head a fifth of the way along, then a long taper to the end.
|
|
285
|
+
{ id: "teardrop", label: "Teardrop", points: [sym(0, 0), sym(0.2, 1), sym(1, 0)] },
|
|
286
|
+
// Two swells between narrow necks.
|
|
287
|
+
{ id: "wave", label: "Wave", points: [sym(0, 0.3), sym(0.25, 1), sym(0.5, 0.3), sym(0.75, 1), sym(1, 0.3)] },
|
|
288
|
+
// A pen stroke: a quick press, a slow lift.
|
|
289
|
+
{ id: "pressure", label: "Pressure", points: [sym(0, 0.15), sym(0.12, 0.85), sym(0.45, 1), sym(0.8, 0.7), sym(1, 0.05)] }
|
|
290
|
+
];
|
|
291
|
+
var VECTOR_WIDTH_PRESET_IDS = VECTOR_WIDTH_PRESETS.map((p) => p.id);
|
|
292
|
+
var clean = (v2, max) => typeof v2 === "number" && Number.isFinite(v2) ? Math.min(Math.max(v2, 0), max) : null;
|
|
293
|
+
function sanitizeWidthProfile(points) {
|
|
294
|
+
if (!Array.isArray(points)) return [];
|
|
295
|
+
const out = [];
|
|
296
|
+
for (const p of points) {
|
|
297
|
+
if (!p || typeof p !== "object") continue;
|
|
298
|
+
const t = clean(p.t, 1);
|
|
299
|
+
const l = clean(p.left, VECTOR_WIDTH_PROFILE_MAX_SCALE);
|
|
300
|
+
const r = clean(p.right, VECTOR_WIDTH_PROFILE_MAX_SCALE);
|
|
301
|
+
if (t === null || l === null && r === null) continue;
|
|
302
|
+
out.push({ t, left: _nullishCoalesce(l, () => ( r)), right: _nullishCoalesce(r, () => ( l)) });
|
|
303
|
+
if (out.length >= VECTOR_WIDTH_PROFILE_MAX_POINTS) break;
|
|
304
|
+
}
|
|
305
|
+
return out.map((p, i) => [p, i]).sort((a, b) => a[0].t - b[0].t || a[1] - b[1]).map(([p]) => p);
|
|
306
|
+
}
|
|
307
|
+
function isUniformWidthProfile(points) {
|
|
308
|
+
return !_optionalChain([points, 'optionalAccess', _8 => _8.length]) || points.every((p) => p.left === 1 && p.right === 1);
|
|
309
|
+
}
|
|
310
|
+
function secant(pts, i, k) {
|
|
311
|
+
const a = pts[i];
|
|
312
|
+
const b = pts[i + 1];
|
|
313
|
+
return a && b && b.t - a.t > 1e-12 ? (b[k] - a[k]) / (b.t - a.t) : 0;
|
|
314
|
+
}
|
|
315
|
+
function tangent(pts, i, k) {
|
|
316
|
+
const last = pts.length - 1;
|
|
317
|
+
if (i <= 0) return secant(pts, 0, k);
|
|
318
|
+
if (i >= last) return secant(pts, last - 1, k);
|
|
319
|
+
const d0 = secant(pts, i - 1, k);
|
|
320
|
+
const d1 = secant(pts, i, k);
|
|
321
|
+
return d0 * d1 <= 0 ? 0 : 2 * d0 * d1 / (d0 + d1);
|
|
322
|
+
}
|
|
323
|
+
function interp(pts, t, k) {
|
|
324
|
+
const first = pts[0];
|
|
325
|
+
const last = pts[pts.length - 1];
|
|
326
|
+
if (!(t > first.t)) return first[k];
|
|
327
|
+
if (t >= last.t) return last[k];
|
|
328
|
+
let i = 0;
|
|
329
|
+
while (i + 1 < pts.length && pts[i + 1].t <= t) i++;
|
|
330
|
+
const a = pts[i];
|
|
331
|
+
const b = pts[i + 1];
|
|
332
|
+
const h = b.t - a.t;
|
|
333
|
+
if (h <= 1e-12) return b[k];
|
|
334
|
+
const u = (t - a.t) / h;
|
|
335
|
+
const u2 = u * u;
|
|
336
|
+
const u3 = u2 * u;
|
|
337
|
+
const w = (2 * u3 - 3 * u2 + 1) * a[k] + (u3 - 2 * u2 + u) * h * tangent(pts, i, k) + (3 * u2 - 2 * u3) * b[k] + (u3 - u2) * h * tangent(pts, i + 1, k);
|
|
338
|
+
return Math.max(0, w);
|
|
339
|
+
}
|
|
340
|
+
function widthProfileAt(points, t) {
|
|
341
|
+
if (!_optionalChain([points, 'optionalAccess', _9 => _9.length])) return { left: 1, right: 1 };
|
|
342
|
+
return { left: interp(points, t, "left"), right: interp(points, t, "right") };
|
|
343
|
+
}
|
|
344
|
+
function widthProfileMaxScale(points) {
|
|
345
|
+
if (!_optionalChain([points, 'optionalAccess', _10 => _10.length])) return 1;
|
|
346
|
+
return points.reduce((m, p) => Math.max(m, p.left, p.right), 0);
|
|
347
|
+
}
|
|
348
|
+
function widthProfilePreset(id) {
|
|
349
|
+
const p = VECTOR_WIDTH_PRESETS.find((q) => q.id === id);
|
|
350
|
+
return p ? p.points.map((q) => ({ ...q })) : null;
|
|
351
|
+
}
|
|
352
|
+
function widthProfilePresetId(points) {
|
|
353
|
+
if (isUniformWidthProfile(points)) return "uniform";
|
|
354
|
+
const same = (a, b) => a.length === b.length && a.every((p, i) => Math.abs(p.t - b[i].t) < 1e-9 && Math.abs(p.left - b[i].left) < 1e-9 && Math.abs(p.right - b[i].right) < 1e-9);
|
|
355
|
+
return _nullishCoalesce(_optionalChain([VECTOR_WIDTH_PRESETS, 'access', _11 => _11.find, 'call', _12 => _12((p) => p.points.length && same(points, p.points)), 'optionalAccess', _13 => _13.id]), () => ( "custom"));
|
|
356
|
+
}
|
|
357
|
+
function reverseWidthProfile(points) {
|
|
358
|
+
return points.map((p) => ({ t: 1 - p.t, left: p.right, right: p.left })).reverse();
|
|
359
|
+
}
|
|
360
|
+
function mirrorWidthProfile(points) {
|
|
361
|
+
return points.map((p) => ({ t: p.t, left: p.right, right: p.left }));
|
|
362
|
+
}
|
|
363
|
+
function editable(points) {
|
|
364
|
+
return _optionalChain([points, 'optionalAccess', _14 => _14.length]) ? points.map((p) => ({ ...p })) : [sym(0, 1), sym(1, 1)];
|
|
365
|
+
}
|
|
366
|
+
function insertWidthPoint(points, t, sides2 = {}, options = {}) {
|
|
367
|
+
const pts = editable(points);
|
|
368
|
+
const tt = Math.min(Math.max(Number.isFinite(t) ? t : 0, 0), 1);
|
|
369
|
+
const here = widthProfileAt(_optionalChain([points, 'optionalAccess', _15 => _15.length]) ? points : null, tt);
|
|
370
|
+
const p = {
|
|
371
|
+
t: tt,
|
|
372
|
+
left: _nullishCoalesce(clean(sides2.left, VECTOR_WIDTH_PROFILE_MAX_SCALE), () => ( here.left)),
|
|
373
|
+
right: _nullishCoalesce(clean(sides2.right, VECTOR_WIDTH_PROFILE_MAX_SCALE), () => ( here.right))
|
|
374
|
+
};
|
|
375
|
+
const same = pts.findIndex((q) => Math.abs(q.t - tt) <= VECTOR_WIDTH_SAME_T);
|
|
376
|
+
if (same >= 0 && !options.step) {
|
|
377
|
+
pts[same] = { ...p, t: pts[same].t };
|
|
378
|
+
return { points: pts, index: same };
|
|
379
|
+
}
|
|
380
|
+
let i = 0;
|
|
381
|
+
while (i < pts.length && pts[i].t <= tt) i++;
|
|
382
|
+
if (pts.length >= VECTOR_WIDTH_PROFILE_MAX_POINTS) return { points: pts, index: Math.max(0, i - 1) };
|
|
383
|
+
pts.splice(i, 0, p);
|
|
384
|
+
return { points: pts, index: i };
|
|
385
|
+
}
|
|
386
|
+
function setWidthPoint(points, index, patch) {
|
|
387
|
+
const pts = points.map((p2) => ({ ...p2 }));
|
|
388
|
+
const p = pts[index];
|
|
389
|
+
if (!p) return pts;
|
|
390
|
+
if (typeof patch.t === "number" && Number.isFinite(patch.t)) {
|
|
391
|
+
const lo = index > 0 ? pts[index - 1].t : 0;
|
|
392
|
+
const hi = index < pts.length - 1 ? pts[index + 1].t : 1;
|
|
393
|
+
p.t = Math.min(Math.max(patch.t, lo), Math.max(hi, lo));
|
|
394
|
+
}
|
|
395
|
+
const l = clean(patch.left, VECTOR_WIDTH_PROFILE_MAX_SCALE);
|
|
396
|
+
const r = clean(patch.right, VECTOR_WIDTH_PROFILE_MAX_SCALE);
|
|
397
|
+
if (l !== null) p.left = l;
|
|
398
|
+
if (r !== null) p.right = r;
|
|
399
|
+
return pts;
|
|
400
|
+
}
|
|
401
|
+
function removeWidthPoints(points, indices) {
|
|
402
|
+
const drop = new Set(indices);
|
|
403
|
+
return points.filter((_, i) => !drop.has(i)).map((p) => ({ ...p }));
|
|
404
|
+
}
|
|
405
|
+
function ease(u, e) {
|
|
406
|
+
const x = Math.min(Math.max(u, 0), 1);
|
|
407
|
+
const round = Math.sqrt(Math.max(0, 1 - (1 - x) * (1 - x)));
|
|
408
|
+
return x + (round - x) * Math.min(Math.max(e, 0), 1);
|
|
409
|
+
}
|
|
410
|
+
function taperWaveFactor(t, taper, wave) {
|
|
411
|
+
let k = 1;
|
|
412
|
+
if (taper) {
|
|
413
|
+
let ls = Math.max(0, _nullishCoalesce(taper.startLength, () => ( 0)));
|
|
414
|
+
let le = Math.max(0, _nullishCoalesce(taper.endLength, () => ( 0)));
|
|
415
|
+
if (ls + le > 1) {
|
|
416
|
+
const f = 1 / (ls + le);
|
|
417
|
+
ls *= f;
|
|
418
|
+
le *= f;
|
|
419
|
+
}
|
|
420
|
+
const sw = Math.min(Math.max(_nullishCoalesce(taper.startWidth, () => ( 0)), 0), 1);
|
|
421
|
+
const ew = Math.min(Math.max(_nullishCoalesce(taper.endWidth, () => ( 0)), 0), 1);
|
|
422
|
+
if (ls > 0 && t < ls) k = Math.min(k, sw + (1 - sw) * ease(t / ls, _nullishCoalesce(taper.startEase, () => ( 0))));
|
|
423
|
+
if (le > 0 && t > 1 - le) k = Math.min(k, ew + (1 - ew) * ease((1 - t) / le, _nullishCoalesce(taper.endEase, () => ( 0))));
|
|
424
|
+
}
|
|
425
|
+
if (wave) {
|
|
426
|
+
const cycles = _nullishCoalesce(wave.cycles, () => ( 4));
|
|
427
|
+
const amount = Math.min(Math.max(_nullishCoalesce(wave.amount, () => ( 0.5)), 0), 1);
|
|
428
|
+
if (cycles > 0 && amount > 0) {
|
|
429
|
+
const ph = 2 * Math.PI * t * cycles + (_nullishCoalesce(wave.phase, () => ( 0))) * Math.PI / 180;
|
|
430
|
+
k *= 1 - amount * (0.5 - 0.5 * Math.cos(ph));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return k;
|
|
434
|
+
}
|
|
435
|
+
function generateWidthProfile(options) {
|
|
436
|
+
const cycles = options.wave ? Math.max(0, _nullishCoalesce(options.wave.cycles, () => ( 4))) : 0;
|
|
437
|
+
const n = Math.max(8, Math.min(VECTOR_WIDTH_PROFILE_MAX_POINTS * 4, _nullishCoalesce(options.samples, () => ( Math.ceil(32 + cycles * 16)))));
|
|
438
|
+
const raw = [];
|
|
439
|
+
for (let i = 0; i <= n; i++) raw.push([i / n, taperWaveFactor(i / n, options.taper, options.wave)]);
|
|
440
|
+
const ts = [_optionalChain([options, 'access', _16 => _16.taper, 'optionalAccess', _17 => _17.startLength]), _optionalChain([options, 'access', _18 => _18.taper, 'optionalAccess', _19 => _19.endLength]) !== void 0 ? 1 - options.taper.endLength : void 0];
|
|
441
|
+
for (const t of ts) if (typeof t === "number" && t > 0 && t < 1) raw.push([t, taperWaveFactor(t, options.taper, options.wave)]);
|
|
442
|
+
raw.sort((a, b) => a[0] - b[0]);
|
|
443
|
+
const kept = simplifySamples(raw, _nullishCoalesce(options.tolerance, () => ( 0.01)), VECTOR_WIDTH_PROFILE_MAX_POINTS);
|
|
444
|
+
return kept.map(([t, k]) => sym(t, k));
|
|
445
|
+
}
|
|
446
|
+
function simplifySamples(samples, tolerance, max) {
|
|
447
|
+
if (samples.length <= 2) return samples.slice();
|
|
448
|
+
const keep = new Array(samples.length).fill(false);
|
|
449
|
+
keep[0] = keep[samples.length - 1] = true;
|
|
450
|
+
const stack = [[0, samples.length - 1]];
|
|
451
|
+
while (stack.length) {
|
|
452
|
+
const [a, b] = stack.pop();
|
|
453
|
+
const [ta, va] = samples[a];
|
|
454
|
+
const [tb, vb] = samples[b];
|
|
455
|
+
let worst = -1;
|
|
456
|
+
let err = tolerance;
|
|
457
|
+
for (let i = a + 1; i < b; i++) {
|
|
458
|
+
const [t, v2] = samples[i];
|
|
459
|
+
const lin = tb - ta > 1e-12 ? va + (vb - va) * (t - ta) / (tb - ta) : va;
|
|
460
|
+
const e = Math.abs(v2 - lin);
|
|
461
|
+
if (e > err) {
|
|
462
|
+
err = e;
|
|
463
|
+
worst = i;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
if (worst >= 0) {
|
|
467
|
+
keep[worst] = true;
|
|
468
|
+
stack.push([a, worst], [worst, b]);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
let out = samples.filter((_, i) => keep[i]);
|
|
472
|
+
while (out.length > max) out = out.filter((_, i) => i === 0 || i === out.length - 1 || i % 2 === 0);
|
|
473
|
+
return out;
|
|
474
|
+
}
|
|
475
|
+
var VECTOR_PRESSURE_NOMINAL = 0.5;
|
|
476
|
+
function pressureWidthProfile(samples, options = {}) {
|
|
477
|
+
const raw = samples.filter((s) => Number.isFinite(s.t) && Number.isFinite(s.pressure)).map((s) => [Math.min(Math.max(s.t, 0), 1), Math.max(0.05, Math.min(1, Math.max(0, s.pressure)) / VECTOR_PRESSURE_NOMINAL)]);
|
|
478
|
+
if (raw.length < 2) return [];
|
|
479
|
+
if (raw.every((s) => Math.abs(s[1] - raw[0][1]) < 1e-6)) return [];
|
|
480
|
+
return simplifySamples(raw, _nullishCoalesce(options.tolerance, () => ( 0.02)), VECTOR_WIDTH_PROFILE_MAX_POINTS).map(([t, k]) => sym(t, Math.round(k * 1e3) / 1e3));
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/vector/varstroke.ts
|
|
484
|
+
var SAMPLES_PER_SUBPATH = 128;
|
|
485
|
+
var MAX_DASHES = 5e3;
|
|
486
|
+
var sub2 = (a, b) => [a[0] - b[0], a[1] - b[1]];
|
|
487
|
+
var along = (p, v2, k) => [p[0] + v2[0] * k, p[1] + v2[1] * k];
|
|
488
|
+
var lerp = (a, b, u) => [a[0] + (b[0] - a[0]) * u, a[1] + (b[1] - a[1]) * u];
|
|
489
|
+
var dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1]);
|
|
490
|
+
var unitOf = (v2) => {
|
|
491
|
+
const l = Math.hypot(v2[0], v2[1]);
|
|
492
|
+
return l > 0 ? [v2[0] / l, v2[1] / l] : [1, 0];
|
|
493
|
+
};
|
|
494
|
+
var leftNormal = (d) => [d[1], -d[0]];
|
|
495
|
+
function flatten(segments, closed, tol) {
|
|
496
|
+
const pts = [];
|
|
497
|
+
const corner = [];
|
|
498
|
+
const push = (p, isCorner) => {
|
|
499
|
+
const last = pts[pts.length - 1];
|
|
500
|
+
if (last && dist(last, p) <= 1e-9) {
|
|
501
|
+
corner[corner.length - 1] ||= isCorner;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
pts.push(p);
|
|
505
|
+
corner.push(isCorner);
|
|
506
|
+
};
|
|
507
|
+
for (const seg of segments) {
|
|
508
|
+
const flat = _chunk7EDLVBOOcjs.flattenChain.call(void 0, [seg], tol);
|
|
509
|
+
if (dist(seg[0], seg[seg.length - 1]) <= 1e-12 && flat.length > 1) flat.push(seg[seg.length - 1]);
|
|
510
|
+
flat.forEach((p, i) => push(p, i === 0 || i === flat.length - 1));
|
|
511
|
+
}
|
|
512
|
+
if (closed && pts.length > 2 && dist(pts[0], pts[pts.length - 1]) > 1e-9) push(pts[0], true);
|
|
513
|
+
if (pts.length < 2) return null;
|
|
514
|
+
let total = 0;
|
|
515
|
+
for (let i = 1; i < pts.length; i++) total += dist(pts[i - 1], pts[i]);
|
|
516
|
+
if (!(total > 0)) return null;
|
|
517
|
+
const step = Math.max(total / SAMPLES_PER_SUBPATH, tol);
|
|
518
|
+
const fine = [pts[0]];
|
|
519
|
+
const fineCorner = [corner[0]];
|
|
520
|
+
for (let i = 1; i < pts.length; i++) {
|
|
521
|
+
const n = Math.max(1, Math.ceil(dist(pts[i - 1], pts[i]) / step));
|
|
522
|
+
for (let k = 1; k <= n; k++) {
|
|
523
|
+
fine.push(k === n ? pts[i] : lerp(pts[i - 1], pts[i], k / n));
|
|
524
|
+
fineCorner.push(k === n ? corner[i] : false);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const s = [0];
|
|
528
|
+
for (let i = 1; i < fine.length; i++) s.push(s[i - 1] + dist(fine[i - 1], fine[i]));
|
|
529
|
+
return { pts: fine, s, corner: fineCorner, closed };
|
|
530
|
+
}
|
|
531
|
+
function dashIntervals(pattern, offset, len2) {
|
|
532
|
+
let pat = pattern.map((v2) => Number.isFinite(v2) ? Math.max(0, v2) : 0);
|
|
533
|
+
if (pat.length % 2 === 1) pat = [...pat, ...pat];
|
|
534
|
+
const period = pat.reduce((a, b) => a + b, 0);
|
|
535
|
+
if (pat.length < 2 || !(period > 1e-9) || !(len2 > 0)) return [[0, len2]];
|
|
536
|
+
let pos = ((Number.isFinite(offset) ? offset : 0) % period + period) % period;
|
|
537
|
+
let idx = 0;
|
|
538
|
+
while (pos >= pat[idx]) {
|
|
539
|
+
pos -= pat[idx];
|
|
540
|
+
idx = (idx + 1) % pat.length;
|
|
541
|
+
}
|
|
542
|
+
const out = [];
|
|
543
|
+
let s = 0;
|
|
544
|
+
let guard = 0;
|
|
545
|
+
while (s < len2 && guard++ < MAX_DASHES * pat.length) {
|
|
546
|
+
const e = Math.min(s + pat[idx] - pos, len2);
|
|
547
|
+
if (idx % 2 === 0 && e >= s) out.push([s, e]);
|
|
548
|
+
s += pat[idx] - pos;
|
|
549
|
+
pos = 0;
|
|
550
|
+
idx = (idx + 1) % pat.length;
|
|
551
|
+
}
|
|
552
|
+
return out;
|
|
553
|
+
}
|
|
554
|
+
function at(poly, t) {
|
|
555
|
+
let i = 1;
|
|
556
|
+
while (i < poly.pts.length - 1 && poly.s[i] <= t) i++;
|
|
557
|
+
const a = poly.s[i - 1];
|
|
558
|
+
const b = poly.s[i];
|
|
559
|
+
const u = b > a ? Math.min(Math.max((t - a) / (b - a), 0), 1) : 0;
|
|
560
|
+
return [lerp(poly.pts[i - 1], poly.pts[i], u), i];
|
|
561
|
+
}
|
|
562
|
+
function arcPoints(c, a0, sweep, r0, r1, tol) {
|
|
563
|
+
const r = Math.max(r0, r1);
|
|
564
|
+
if (!(r > tol * 0.5) || !Number.isFinite(sweep)) return [];
|
|
565
|
+
const stepAngle = 2 * Math.acos(Math.min(Math.max(1 - tol / r, -1), 1));
|
|
566
|
+
const n = Math.min(128, Math.max(2, Math.ceil(Math.abs(sweep) / Math.max(stepAngle, 1e-3))));
|
|
567
|
+
const out = [];
|
|
568
|
+
for (let k = 1; k < n; k++) {
|
|
569
|
+
const f = k / n;
|
|
570
|
+
const a = a0 + sweep * f;
|
|
571
|
+
const rr = r0 + (r1 - r0) * f;
|
|
572
|
+
out.push([c[0] + Math.cos(a) * rr, c[1] + Math.sin(a) * rr]);
|
|
573
|
+
}
|
|
574
|
+
return out;
|
|
575
|
+
}
|
|
576
|
+
function crossing(a0, a1, b0, b1) {
|
|
577
|
+
const r = sub2(a1, a0);
|
|
578
|
+
const q = sub2(b1, b0);
|
|
579
|
+
const den = r[0] * q[1] - r[1] * q[0];
|
|
580
|
+
if (Math.abs(den) < 1e-12) return null;
|
|
581
|
+
const w = sub2(b0, a0);
|
|
582
|
+
const t = (w[0] * q[1] - w[1] * q[0]) / den;
|
|
583
|
+
const u = (w[0] * r[1] - w[1] * r[0]) / den;
|
|
584
|
+
return t > 1e-9 && t <= 1 && u >= 0 && u < 1 - 1e-9 ? [a0[0] + r[0] * t, a0[1] + r[1] * t] : null;
|
|
585
|
+
}
|
|
586
|
+
function variableStrokeRings(path, options) {
|
|
587
|
+
const half = options.width / 2;
|
|
588
|
+
if (!(half > 0) || !Number.isFinite(half)) return [];
|
|
589
|
+
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : 0.05;
|
|
590
|
+
const join = _nullishCoalesce(options.join, () => ( "miter"));
|
|
591
|
+
const cap = _nullishCoalesce(options.cap, () => ( "butt"));
|
|
592
|
+
const miterLimit = options.miterLimit && options.miterLimit >= 1 ? options.miterLimit : 4;
|
|
593
|
+
const rings = [];
|
|
594
|
+
const push = (out, p) => {
|
|
595
|
+
const last = out[out.length - 1];
|
|
596
|
+
if (!last || dist(last, p) > 1e-12) out.push(p);
|
|
597
|
+
};
|
|
598
|
+
for (const contour of _chunk7EDLVBOOcjs.pathToContours.call(void 0, path)) {
|
|
599
|
+
if (!contour.segments.length) continue;
|
|
600
|
+
const poly = flatten(contour.segments, contour.closed, Math.min(tol, half) / 4);
|
|
601
|
+
if (!poly) continue;
|
|
602
|
+
const len2 = poly.s[poly.s.length - 1];
|
|
603
|
+
const sides2 = (s) => {
|
|
604
|
+
const w = widthProfileAt(options.profile, s / len2);
|
|
605
|
+
return [w.left * half, w.right * half];
|
|
606
|
+
};
|
|
607
|
+
const intervals = _optionalChain([options, 'access', _20 => _20.dash, 'optionalAccess', _21 => _21.some, 'call', _22 => _22((v2) => v2 > 0)]) ? dashIntervals(options.dash, _nullishCoalesce(options.dashOffset, () => ( 0)), len2) : [[0, len2]];
|
|
608
|
+
const whole = intervals.length === 1 && intervals[0][0] <= 0 && intervals[0][1] >= len2;
|
|
609
|
+
for (const [a, b] of intervals) {
|
|
610
|
+
const [pa, ia] = at(poly, a);
|
|
611
|
+
const [pb, ib] = at(poly, b);
|
|
612
|
+
const pts = [{ p: pa, s: a, corner: poly.corner[0] && a <= 0 }];
|
|
613
|
+
for (let i = ia; i < ib; i++) pts.push({ p: poly.pts[i], s: poly.s[i], corner: poly.corner[i] });
|
|
614
|
+
pts.push({ p: pb, s: b, corner: false });
|
|
615
|
+
const run = pts.filter((q, i) => i === 0 || dist(q.p, pts[i - 1].p) > 1e-9);
|
|
616
|
+
if (run.length < 2) {
|
|
617
|
+
const [l, r] = sides2(a);
|
|
618
|
+
const w2 = (l + r) / 2;
|
|
619
|
+
if (cap === "round" && w2 > 0) rings.push([[pa[0] + w2, pa[1]], ...arcPoints(pa, 0, 2 * Math.PI, w2, w2, tol)]);
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const closed = whole && poly.closed;
|
|
623
|
+
const m = run.length - 1;
|
|
624
|
+
const dirs = [];
|
|
625
|
+
for (let i = 0; i < m; i++) dirs.push(unitOf(sub2(run[i + 1].p, run[i].p)));
|
|
626
|
+
const normals = dirs.map(leftNormal);
|
|
627
|
+
const w = run.map((q) => sides2(q.s));
|
|
628
|
+
const side = (sigma) => {
|
|
629
|
+
const k = sigma > 0 ? 0 : 1;
|
|
630
|
+
const S = (i) => along(run[i].p, normals[i], sigma * w[i][k]);
|
|
631
|
+
const E = (i) => along(run[i + 1].p, normals[i], sigma * w[i + 1][k]);
|
|
632
|
+
const out = [S(0)];
|
|
633
|
+
for (let i = 0; i < m; i++) {
|
|
634
|
+
const seam = i === m - 1;
|
|
635
|
+
if (seam && !closed) {
|
|
636
|
+
push(out, E(i));
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
const j = seam ? 0 : i + 1;
|
|
640
|
+
const p = run[i + 1].p;
|
|
641
|
+
const d0 = dirs[i];
|
|
642
|
+
const d1 = dirs[j];
|
|
643
|
+
const cross2 = d0[0] * d1[1] - d0[1] * d1[0];
|
|
644
|
+
const dot2 = d0[0] * d1[0] + d0[1] * d1[1];
|
|
645
|
+
const r0 = w[i + 1][k];
|
|
646
|
+
const r1 = w[j][k];
|
|
647
|
+
const e = E(i);
|
|
648
|
+
const st = S(j);
|
|
649
|
+
if (Math.abs(cross2) < 1e-12 && dot2 > 0) {
|
|
650
|
+
push(out, e);
|
|
651
|
+
if (!seam) push(out, st);
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
const uturn = Math.abs(cross2) < 1e-12;
|
|
655
|
+
const outer = uturn ? sigma > 0 : cross2 * sigma > 0;
|
|
656
|
+
if (!outer) {
|
|
657
|
+
const x = seam ? null : crossing(out[out.length - 1], e, st, E(j));
|
|
658
|
+
if (x) push(out, x);
|
|
659
|
+
else {
|
|
660
|
+
push(out, e);
|
|
661
|
+
push(out, p);
|
|
662
|
+
if (!seam) push(out, st);
|
|
663
|
+
}
|
|
664
|
+
continue;
|
|
665
|
+
}
|
|
666
|
+
push(out, e);
|
|
667
|
+
const theta = uturn ? Math.PI : Math.atan2(cross2, dot2);
|
|
668
|
+
const r = (r0 + r1) / 2;
|
|
669
|
+
const kind = run[i + 1].corner || seam && poly.corner[0] ? join : "round";
|
|
670
|
+
if (r > 1e-9) {
|
|
671
|
+
if (kind === "round") {
|
|
672
|
+
if (r * (1 - Math.cos(Math.abs(theta) / 2)) > tol * 0.25) {
|
|
673
|
+
for (const q of arcPoints(p, Math.atan2(e[1] - p[1], e[0] - p[0]), theta, r0, r1, tol)) push(out, q);
|
|
674
|
+
}
|
|
675
|
+
} else if (kind === "miter") {
|
|
676
|
+
const halfCos = Math.cos(theta / 2);
|
|
677
|
+
const bis = [normals[i][0] + normals[j][0], normals[i][1] + normals[j][1]];
|
|
678
|
+
const bl = Math.hypot(bis[0], bis[1]);
|
|
679
|
+
if (halfCos > 1e-6 && 1 / halfCos <= miterLimit && bl > 1e-9) push(out, along(p, bis, sigma * r / halfCos / bl));
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
if (!seam) push(out, st);
|
|
683
|
+
}
|
|
684
|
+
if (closed && out.length > 1 && dist(out[0], out[out.length - 1]) <= 1e-12) out.pop();
|
|
685
|
+
return out;
|
|
686
|
+
};
|
|
687
|
+
const left = side(1);
|
|
688
|
+
const right = side(-1);
|
|
689
|
+
if (closed) {
|
|
690
|
+
rings.push(left, right.reverse());
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const capPoints = (atStart) => {
|
|
694
|
+
if (cap === "butt") return [];
|
|
695
|
+
const i = atStart ? 0 : m;
|
|
696
|
+
const d = atStart ? dirs[0] : dirs[m - 1];
|
|
697
|
+
const [l, r] = w[i];
|
|
698
|
+
if (!(l + r > 1e-9)) return [];
|
|
699
|
+
const p = run[i].p;
|
|
700
|
+
const n = leftNormal(d);
|
|
701
|
+
const L = along(p, n, l);
|
|
702
|
+
const R = along(p, n, -r);
|
|
703
|
+
if (cap === "round") {
|
|
704
|
+
const a0 = Math.atan2(d[1], d[0]) + (atStart ? Math.PI / 2 : -Math.PI / 2);
|
|
705
|
+
return arcPoints(p, a0, Math.PI, atStart ? r : l, atStart ? l : r, tol);
|
|
706
|
+
}
|
|
707
|
+
const ext = (l + r) / 2;
|
|
708
|
+
const o = atStart ? [-d[0], -d[1]] : d;
|
|
709
|
+
return atStart ? [along(R, o, ext), along(L, o, ext)] : [along(L, o, ext), along(R, o, ext)];
|
|
710
|
+
};
|
|
711
|
+
const ring = [];
|
|
712
|
+
for (const q of [...left, ...capPoints(false), ...right.reverse(), ...capPoints(true)]) push(ring, q);
|
|
713
|
+
if (ring.length > 2) rings.push(ring);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return rings;
|
|
717
|
+
}
|
|
718
|
+
function variableStrokeOutline(path, options) {
|
|
719
|
+
const pieces = variableStrokeRings(path, options);
|
|
720
|
+
if (!pieces.length) return [];
|
|
721
|
+
const tol = options.tolerance && options.tolerance > 0 ? options.tolerance : 0.05;
|
|
722
|
+
let polygons;
|
|
723
|
+
try {
|
|
724
|
+
polygons = _chunk7EDLVBOOcjs.polygonBoolean.call(void 0, "union", [{ rings: pieces, fillRule: "nonzero" }]);
|
|
725
|
+
} catch (e2) {
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
const out = [];
|
|
729
|
+
for (const polygon2 of polygons) {
|
|
730
|
+
for (const ring of polygon2) {
|
|
731
|
+
if (ring.length < 3) continue;
|
|
732
|
+
const cubics = _chunk7EDLVBOOcjs.fitCubics.call(void 0, ring, tol, { closed: true, cornerAngleDeg: 25 });
|
|
733
|
+
if (!cubics.length) continue;
|
|
734
|
+
out.push({ type: "M", x: cubics[0].p0[0], y: cubics[0].p0[1] });
|
|
735
|
+
cubics.forEach((c, i) => {
|
|
736
|
+
if (_chunk7EDLVBOOcjs.isStraightCubic.call(void 0, c, tol * 0.02)) {
|
|
737
|
+
if (i < cubics.length - 1) out.push({ type: "L", x: c.p3[0], y: c.p3[1] });
|
|
738
|
+
} else out.push({ type: "C", x1: c.p1[0], y1: c.p1[1], x2: c.p2[0], y2: c.p2[1], x: c.p3[0], y: c.p3[1] });
|
|
739
|
+
});
|
|
740
|
+
out.push({ type: "Z" });
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
return out;
|
|
744
|
+
}
|
|
745
|
+
function nearestStrokePosition(path, p, only) {
|
|
746
|
+
let best = null;
|
|
747
|
+
_chunk7EDLVBOOcjs.pathToContours.call(void 0, path).forEach((c, ci) => {
|
|
748
|
+
if (!c.segments.length || only !== void 0 && ci !== only) return;
|
|
749
|
+
const lengths = c.segments.map((s) => _chunk7EDLVBOOcjs.segmentLength.call(void 0, s));
|
|
750
|
+
const total = lengths.reduce((a, b) => a + b, 0);
|
|
751
|
+
if (!(total > 0)) return;
|
|
752
|
+
let acc = 0;
|
|
753
|
+
c.segments.forEach((seg, si) => {
|
|
754
|
+
const near2 = _chunk7EDLVBOOcjs.segmentNearest.call(void 0, seg, p);
|
|
755
|
+
if (!best || near2.distance < best.distance) {
|
|
756
|
+
const s = acc + _chunk7EDLVBOOcjs.segmentLength.call(void 0, seg, 0, near2.t);
|
|
757
|
+
const tan = _chunk7EDLVBOOcjs.segmentTangent.call(void 0, seg, near2.t);
|
|
758
|
+
const pt2 = seg.length === 2 ? lerp(seg[0], seg[1], near2.t) : evalSeg(seg, near2.t);
|
|
759
|
+
const n = leftNormal([tan[0], tan[1]]);
|
|
760
|
+
const side = (p[0] - pt2[0]) * n[0] + (p[1] - pt2[1]) * n[1] >= 0 ? "left" : "right";
|
|
761
|
+
best = { contour: ci, t: Math.min(Math.max(s / total, 0), 1), distance: near2.distance, side, point: pt2, tangent: [tan[0], tan[1]], length: total };
|
|
762
|
+
}
|
|
763
|
+
acc += lengths[si];
|
|
764
|
+
});
|
|
765
|
+
});
|
|
766
|
+
return best;
|
|
767
|
+
}
|
|
768
|
+
function evalSeg(seg, t) {
|
|
769
|
+
let pts = seg.map((q) => [q[0], q[1]]);
|
|
770
|
+
while (pts.length > 1) pts = pts.slice(1).map((q, i) => lerp(pts[i], q, t));
|
|
771
|
+
return pts[0];
|
|
772
|
+
}
|
|
773
|
+
function strokePositionPoint(path, index, t) {
|
|
774
|
+
const c = _chunk7EDLVBOOcjs.pathToContours.call(void 0, path)[index];
|
|
775
|
+
if (!_optionalChain([c, 'optionalAccess', _23 => _23.segments, 'access', _24 => _24.length])) return null;
|
|
776
|
+
const lengths = c.segments.map((s) => _chunk7EDLVBOOcjs.segmentLength.call(void 0, s));
|
|
777
|
+
const total = lengths.reduce((a, b) => a + b, 0);
|
|
778
|
+
let want = Math.min(Math.max(t, 0), 1) * total;
|
|
779
|
+
for (let i = 0; i < c.segments.length; i++) {
|
|
780
|
+
const seg = c.segments[i];
|
|
781
|
+
if (want <= lengths[i] + 1e-12 || i === c.segments.length - 1) {
|
|
782
|
+
let lo = 0;
|
|
783
|
+
let hi = 1;
|
|
784
|
+
const target = Math.min(want, lengths[i]);
|
|
785
|
+
for (let k = 0; k < 40; k++) {
|
|
786
|
+
const mid = (lo + hi) / 2;
|
|
787
|
+
if (_chunk7EDLVBOOcjs.segmentLength.call(void 0, seg, 0, mid) < target) lo = mid;
|
|
788
|
+
else hi = mid;
|
|
789
|
+
}
|
|
790
|
+
const u = (lo + hi) / 2;
|
|
791
|
+
const tan = _chunk7EDLVBOOcjs.segmentTangent.call(void 0, seg, u);
|
|
792
|
+
return { point: evalSeg(seg, u), tangent: [tan[0], tan[1]] };
|
|
793
|
+
}
|
|
794
|
+
want -= lengths[i];
|
|
795
|
+
}
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
|
|
248
799
|
// src/vector/stroke.ts
|
|
249
800
|
var KAPPA = 0.5522847498307936;
|
|
250
801
|
var NOTCH = 0.7;
|
|
251
802
|
function isClosedBezierShape(path) {
|
|
252
|
-
const contours =
|
|
803
|
+
const contours = _chunk7EDLVBOOcjs.pathToContours.call(void 0, path).filter((c) => c.segments.length > 0);
|
|
253
804
|
return contours.length > 0 && contours.every((c) => c.closed);
|
|
254
805
|
}
|
|
255
806
|
function effectiveStrokeAlign(style, closedShape) {
|
|
256
807
|
const a = _nullishCoalesce(style.strokeAlign, () => ( "center"));
|
|
257
808
|
return closedShape ? a : "center";
|
|
258
809
|
}
|
|
810
|
+
function strokeWidthProfileOf(style) {
|
|
811
|
+
if (!_optionalChain([style, 'access', _25 => _25.strokeWidthProfile, 'optionalAccess', _26 => _26.length])) return null;
|
|
812
|
+
const p = sanitizeWidthProfile(style.strokeWidthProfile);
|
|
813
|
+
return isUniformWidthProfile(p) ? null : p;
|
|
814
|
+
}
|
|
259
815
|
function hasStrokeExtras(style) {
|
|
260
|
-
return (_nullishCoalesce(style.strokeAlign, () => ( "center"))) !== "center" || !!style.startArrow || !!style.endArrow;
|
|
816
|
+
return (_nullishCoalesce(style.strokeAlign, () => ( "center"))) !== "center" || !!style.startArrow || !!style.endArrow || !!strokeWidthProfileOf(style);
|
|
817
|
+
}
|
|
818
|
+
function vectorStrokeLineArea(parts, style, tolerance) {
|
|
819
|
+
const profile = strokeWidthProfileOf(style);
|
|
820
|
+
const dash = _optionalChain([style, 'access', _27 => _27.strokeDasharray, 'optionalAccess', _28 => _28.length]) ? { dash: style.strokeDasharray } : {};
|
|
821
|
+
const join = _nullishCoalesce(style.strokeLinejoin, () => ( "miter"));
|
|
822
|
+
const cap = _nullishCoalesce(style.strokeLinecap, () => ( "butt"));
|
|
823
|
+
if (profile) return variableStrokeOutline(parts.line, { width: parts.drawWidth, profile, join, cap, ...dash, ...tolerance ? { tolerance } : {} });
|
|
824
|
+
return _chunk7EDLVBOOcjs.outlineStroke.call(void 0, parts.line, { width: parts.drawWidth, join, cap, ...dash, ...tolerance ? { tolerance } : {} });
|
|
261
825
|
}
|
|
262
826
|
var capExtent = (style, width) => style.strokeLinecap === "round" || style.strokeLinecap === "square" ? width / 2 : 0;
|
|
263
827
|
function arrowheadWeight(style, end) {
|
|
@@ -334,27 +898,27 @@ function arrowheadPath(kind, tip, dir, hw) {
|
|
|
334
898
|
}
|
|
335
899
|
}
|
|
336
900
|
var toVec = (p) => ({ x: p[0], y: p[1] });
|
|
337
|
-
var segLen = (s) =>
|
|
901
|
+
var segLen = (s) => _chunk7EDLVBOOcjs.segmentLength.call(void 0, s);
|
|
338
902
|
function endOf(segs, atStart) {
|
|
339
903
|
const long = (s2) => segLen(s2) > 1e-9;
|
|
340
904
|
if (atStart) {
|
|
341
905
|
const s2 = _nullishCoalesce(segs.find(long), () => ( segs[0]));
|
|
342
|
-
const t2 =
|
|
906
|
+
const t2 = _chunk7EDLVBOOcjs.segmentTangent.call(void 0, s2, 0);
|
|
343
907
|
return { p: toVec(segs[0][0]), out: v(-t2[0], -t2[1]) };
|
|
344
908
|
}
|
|
345
909
|
const s = _nullishCoalesce([...segs].reverse().find(long), () => ( segs[segs.length - 1]));
|
|
346
|
-
const t =
|
|
910
|
+
const t = _chunk7EDLVBOOcjs.segmentTangent.call(void 0, s, 1);
|
|
347
911
|
const last = segs[segs.length - 1];
|
|
348
912
|
return { p: toVec(last[last.length - 1]), out: v(t[0], t[1]) };
|
|
349
913
|
}
|
|
350
|
-
function pointAlong(segs, fromStart,
|
|
914
|
+
function pointAlong(segs, fromStart, dist4) {
|
|
351
915
|
const order = fromStart ? segs : [...segs].reverse();
|
|
352
916
|
let acc = 0;
|
|
353
917
|
for (const s of order) {
|
|
354
918
|
const l = segLen(s);
|
|
355
|
-
if (acc + l >=
|
|
356
|
-
const want = fromStart ?
|
|
357
|
-
const pts =
|
|
919
|
+
if (acc + l >= dist4) {
|
|
920
|
+
const want = fromStart ? dist4 - acc : l - (dist4 - acc);
|
|
921
|
+
const pts = _chunk7EDLVBOOcjs.trimSegments.call(void 0, [s], 0, want);
|
|
358
922
|
const p = pts.length ? pts[0][pts[0].length - 1] : s[0];
|
|
359
923
|
return toVec(p);
|
|
360
924
|
}
|
|
@@ -364,7 +928,7 @@ function pointAlong(segs, fromStart, dist3) {
|
|
|
364
928
|
}
|
|
365
929
|
function vectorStrokeParts(path, style) {
|
|
366
930
|
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
367
|
-
const contours =
|
|
931
|
+
const contours = _chunk7EDLVBOOcjs.pathToContours.call(void 0, path).filter((c) => c.segments.length > 0);
|
|
368
932
|
const closedShape = contours.length > 0 && contours.every((c) => c.closed);
|
|
369
933
|
const align = effectiveStrokeAlign(style, closedShape);
|
|
370
934
|
const drawWidth = align === "center" ? width : width * 2;
|
|
@@ -404,42 +968,54 @@ function vectorStrokeParts(path, style) {
|
|
|
404
968
|
if (!s0 && !s1) return c;
|
|
405
969
|
const lengths = c.segments.map(segLen);
|
|
406
970
|
const total = lengths.reduce((a, b) => a + b, 0);
|
|
407
|
-
return { closed: false, segments: total - s1 > s0 ?
|
|
971
|
+
return { closed: false, segments: total - s1 > s0 ? _chunk7EDLVBOOcjs.trimSegments.call(void 0, c.segments, s0, total - s1, lengths) : [] };
|
|
408
972
|
});
|
|
409
|
-
return { align, line:
|
|
973
|
+
return { align, line: _chunk7EDLVBOOcjs.contoursToPath.call(void 0, trimmed), drawWidth, heads };
|
|
410
974
|
}
|
|
411
975
|
function vectorStrokeOutlinePath(path, style) {
|
|
412
976
|
const parts = vectorStrokeParts(path, style);
|
|
413
|
-
const stroke =
|
|
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
|
-
});
|
|
977
|
+
const stroke = vectorStrokeLineArea(parts, style);
|
|
419
978
|
const fill = { path, fillRule: _nullishCoalesce(style.fillRule, () => ( "nonzero")) };
|
|
420
979
|
let area = stroke;
|
|
421
|
-
if (parts.align === "inside") area =
|
|
422
|
-
else if (parts.align === "outside") area =
|
|
980
|
+
if (parts.align === "inside") area = _chunk7EDLVBOOcjs.pathBoolean.call(void 0, "intersection", [stroke, fill]).path;
|
|
981
|
+
else if (parts.align === "outside") area = _chunk7EDLVBOOcjs.pathBoolean.call(void 0, "difference", [stroke, fill]).path;
|
|
423
982
|
if (!parts.heads.length) return area;
|
|
424
|
-
return
|
|
983
|
+
return _chunk7EDLVBOOcjs.pathBoolean.call(void 0, "union", [area, ...parts.heads.map((h) => h.path)]).path;
|
|
425
984
|
}
|
|
426
985
|
function hitTestVectorStroke(path, p, style, tolerance = 0) {
|
|
427
986
|
const parts = vectorStrokeParts(path, style);
|
|
428
987
|
const point = [p.x, p.y];
|
|
429
988
|
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
430
989
|
for (const h of parts.heads) {
|
|
431
|
-
if (
|
|
990
|
+
if (_chunk7EDLVBOOcjs.pointInBezierPath.call(void 0, h.path, point) || tolerance > 0 && _chunk7EDLVBOOcjs.distanceToBezierPath.call(void 0, h.path, point) <= tolerance) return true;
|
|
432
991
|
}
|
|
433
992
|
if (!parts.line.length) return false;
|
|
434
|
-
const
|
|
435
|
-
|
|
436
|
-
|
|
993
|
+
const profile = strokeWidthProfileOf(style);
|
|
994
|
+
let d;
|
|
995
|
+
let reach = width / 2;
|
|
996
|
+
if (profile) {
|
|
997
|
+
const near2 = nearestStrokePosition(parts.line, point);
|
|
998
|
+
if (!near2) return false;
|
|
999
|
+
d = near2.distance;
|
|
1000
|
+
const w = widthProfileAt(profile, near2.t);
|
|
1001
|
+
reach = width / 2 * (near2.side === "left" ? w.left : w.right);
|
|
1002
|
+
if (parts.align !== "center") reach *= 2;
|
|
1003
|
+
const atEnd = near2.t <= 1e-9 || near2.t >= 1 - 1e-9;
|
|
1004
|
+
if (atEnd && (style.strokeLinecap === "round" || style.strokeLinecap === "square") && d > reach) {
|
|
1005
|
+
reach = Math.max(reach, width / 2 * (w.left + w.right) / 2);
|
|
1006
|
+
}
|
|
1007
|
+
} else {
|
|
1008
|
+
d = _chunk7EDLVBOOcjs.distanceToBezierPath.call(void 0, parts.line, point);
|
|
1009
|
+
if (parts.align !== "center") reach = width;
|
|
1010
|
+
}
|
|
1011
|
+
if (parts.align === "center") return d <= reach + tolerance;
|
|
1012
|
+
if (d > reach + tolerance) return false;
|
|
437
1013
|
if (d <= tolerance) return true;
|
|
438
|
-
const inside =
|
|
1014
|
+
const inside = _chunk7EDLVBOOcjs.pointInBezierPath.call(void 0, path, point, _nullishCoalesce(style.fillRule, () => ( "nonzero")));
|
|
439
1015
|
return parts.align === "inside" ? inside : !inside;
|
|
440
1016
|
}
|
|
441
1017
|
function vectorStrokeReach(style) {
|
|
442
|
-
const width = _nullishCoalesce(style.strokeWidth, () => ( 1));
|
|
1018
|
+
const width = (_nullishCoalesce(style.strokeWidth, () => ( 1))) * widthProfileMaxScale(strokeWidthProfileOf(style));
|
|
443
1019
|
const align = _nullishCoalesce(style.strokeAlign, () => ( "center"));
|
|
444
1020
|
let reach = align === "center" ? width / 2 : align === "outside" ? width : 0;
|
|
445
1021
|
if (style.strokeLinejoin !== "round" && style.strokeLinejoin !== "bevel") reach *= 4;
|
|
@@ -511,7 +1087,7 @@ function vectorNodeToBezier(node) {
|
|
|
511
1087
|
}
|
|
512
1088
|
function vectorPathData(input, precision = 3) {
|
|
513
1089
|
const subpaths = Array.isArray(input) ? input : input.subpaths;
|
|
514
|
-
return
|
|
1090
|
+
return _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, subpathsToBezier(subpaths), { precision });
|
|
515
1091
|
}
|
|
516
1092
|
function inferAnchorType(a) {
|
|
517
1093
|
if (isOnAnchor(a, a.in) || isOnAnchor(a, a.out)) return "corner";
|
|
@@ -527,7 +1103,7 @@ function inferAnchorType(a) {
|
|
|
527
1103
|
return Math.abs(li - lo) <= 1e-3 * Math.max(li, lo) ? "symmetric" : "smooth";
|
|
528
1104
|
}
|
|
529
1105
|
function bezierToSubpaths(input) {
|
|
530
|
-
const path =
|
|
1106
|
+
const path = _chunk7EDLVBOOcjs.toBezierPath.call(void 0, input);
|
|
531
1107
|
const out = [];
|
|
532
1108
|
let current = null;
|
|
533
1109
|
const last = () => current.anchors[current.anchors.length - 1];
|
|
@@ -624,14 +1200,14 @@ function nodeMatrix(node) {
|
|
|
624
1200
|
function vectorPathWorldBezier(node, parent = IDENTITY_MATRIX) {
|
|
625
1201
|
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
626
1202
|
const path = subpathsToBezier(node.subpaths);
|
|
627
|
-
return isIdentityMatrix(m) ? path :
|
|
1203
|
+
return isIdentityMatrix(m) ? path : _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, path, m);
|
|
628
1204
|
}
|
|
629
1205
|
function vectorNodeBounds(node, parent = IDENTITY_MATRIX) {
|
|
630
1206
|
if (node.type === "group") {
|
|
631
1207
|
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
632
1208
|
return unionBounds(node.children.map((c) => vectorNodeBounds(c, m)));
|
|
633
1209
|
}
|
|
634
|
-
const b =
|
|
1210
|
+
const b = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, vectorPathWorldBezier(node, parent));
|
|
635
1211
|
if (!b) return null;
|
|
636
1212
|
return { x: b.minX, y: b.minY, width: b.maxX - b.minX, height: b.maxY - b.minY };
|
|
637
1213
|
}
|
|
@@ -665,9 +1241,9 @@ function hitTestVectorNode(node, p, tolerance = 0, parent = IDENTITY_MATRIX) {
|
|
|
665
1241
|
const path = vectorPathWorldBezier(node, parent);
|
|
666
1242
|
if (path.length === 0) return false;
|
|
667
1243
|
const point = [p.x, p.y];
|
|
668
|
-
if (hasPaint(node.fill) &&
|
|
1244
|
+
if (hasPaint(node.fill) && _chunk7EDLVBOOcjs.pointInBezierPath.call(void 0, path, point, _nullishCoalesce(node.fillRule, () => ( "nonzero")))) return true;
|
|
669
1245
|
if (hasPaint(node.stroke)) return hitTestVectorStroke(path, p, node, tolerance);
|
|
670
|
-
return
|
|
1246
|
+
return _chunk7EDLVBOOcjs.distanceToBezierPath.call(void 0, path, point) <= tolerance;
|
|
671
1247
|
}
|
|
672
1248
|
function vectorStrokeOutline(node, parent = IDENTITY_MATRIX) {
|
|
673
1249
|
if (!hasPaint(node.stroke) || !((_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0)) return [];
|
|
@@ -687,9 +1263,9 @@ function nearestSegment(node, p) {
|
|
|
687
1263
|
const count = subpathSegmentCount(sp);
|
|
688
1264
|
for (let i = 0; i < count; i++) {
|
|
689
1265
|
const seg = subpathSegment(sp, i);
|
|
690
|
-
const hit =
|
|
1266
|
+
const hit = _chunk7EDLVBOOcjs.segmentNearest.call(void 0, seg, [p.x, p.y]);
|
|
691
1267
|
if (!best || hit.distance < best.distance) {
|
|
692
|
-
const pt2 =
|
|
1268
|
+
const pt2 = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, hit.t);
|
|
693
1269
|
best = { subpath: s, segment: i, t: hit.t, point: { x: pt2[0], y: pt2[1] }, distance: hit.distance };
|
|
694
1270
|
}
|
|
695
1271
|
}
|
|
@@ -749,8 +1325,10 @@ function bakeIntoGeometry(node, m) {
|
|
|
749
1325
|
if (isIdentityMatrix(m)) return node;
|
|
750
1326
|
if (node.type === "group") return { ...node, children: node.children.map((c) => transformVectorNode(c, m)) };
|
|
751
1327
|
const path = node;
|
|
1328
|
+
const mirrored = m[0] * m[3] - m[1] * m[2] < 0 && _optionalChain([path, 'access', _29 => _29.strokeWidthProfile, 'optionalAccess', _30 => _30.length]);
|
|
752
1329
|
return {
|
|
753
1330
|
...path,
|
|
1331
|
+
...mirrored ? { strokeWidthProfile: mirrorWidthProfile(path.strokeWidthProfile) } : {},
|
|
754
1332
|
subpaths: path.subpaths.map((sp) => ({
|
|
755
1333
|
closed: sp.closed,
|
|
756
1334
|
anchors: sp.anchors.map((a) => {
|
|
@@ -861,7 +1439,7 @@ function insertAnchor(sp, segment, t) {
|
|
|
861
1439
|
const ia = segment;
|
|
862
1440
|
const ib = (segment + 1) % n;
|
|
863
1441
|
const seg = subpathSegment(sp, segment);
|
|
864
|
-
const [left, right] =
|
|
1442
|
+
const [left, right] = _chunk7EDLVBOOcjs.splitSegment.call(void 0, seg, t);
|
|
865
1443
|
const mid = left[left.length - 1];
|
|
866
1444
|
const anchor = { x: mid[0], y: mid[1] };
|
|
867
1445
|
if (seg.length === 4) {
|
|
@@ -915,8 +1493,8 @@ function ellipseSubpath(b) {
|
|
|
915
1493
|
]
|
|
916
1494
|
};
|
|
917
1495
|
}
|
|
918
|
-
function polygonSubpath(b,
|
|
919
|
-
const n = Math.max(3, Math.round(
|
|
1496
|
+
function polygonSubpath(b, sides2 = 6) {
|
|
1497
|
+
const n = Math.max(3, Math.round(sides2));
|
|
920
1498
|
const cx = b.x + b.width / 2;
|
|
921
1499
|
const cy = b.y + b.height / 2;
|
|
922
1500
|
const anchors = [];
|
|
@@ -957,7 +1535,7 @@ function vectorCornersAttribute(subpaths, precision = 3) {
|
|
|
957
1535
|
subpaths.forEach(
|
|
958
1536
|
(sp, s) => sp.anchors.forEach((a, i) => {
|
|
959
1537
|
if (!a.corner || !(a.corner.radius > 0)) return;
|
|
960
|
-
out.push(`${s}.${i}:${
|
|
1538
|
+
out.push(`${s}.${i}:${_chunk7EDLVBOOcjs.formatNumber.call(void 0, a.corner.radius, precision)}${a.corner.kind && a.corner.kind !== "round" ? `:${a.corner.kind}` : ""}`);
|
|
961
1539
|
})
|
|
962
1540
|
);
|
|
963
1541
|
return out.join(" ");
|
|
@@ -966,7 +1544,7 @@ function applyVectorCornersAttribute(subpaths, value) {
|
|
|
966
1544
|
for (const item of value.trim().split(/\s+/)) {
|
|
967
1545
|
const m = /^(\d+)\.(\d+):([\d.eE+-]+)(?::([a-z]+))?$/.exec(item);
|
|
968
1546
|
if (!m) continue;
|
|
969
|
-
const a = _optionalChain([subpaths, 'access',
|
|
1547
|
+
const a = _optionalChain([subpaths, 'access', _31 => _31[+m[1]], 'optionalAccess', _32 => _32.anchors, 'access', _33 => _33[+m[2]]]);
|
|
970
1548
|
const radius = parseFloat(m[3]);
|
|
971
1549
|
if (!a || !(radius > 0)) continue;
|
|
972
1550
|
const kind = VECTOR_CORNER_KINDS.includes(m[4]) ? m[4] : void 0;
|
|
@@ -978,21 +1556,49 @@ var escapeAttr = (value) => value.replace(/&/g, "&").replace(/"/g, """)
|
|
|
978
1556
|
function vectorPaintToSvg(paint, gradientId) {
|
|
979
1557
|
if (!hasPaint(paint)) return { value: "none", gradient: null };
|
|
980
1558
|
if (typeof paint === "string") return { value: paint, gradient: null };
|
|
981
|
-
return { value: `url(#${gradientId})`, gradient:
|
|
1559
|
+
return { value: `url(#${gradientId})`, gradient: _chunk7EDLVBOOcjs.gradientToSvgDef.call(void 0, paint, gradientId) };
|
|
982
1560
|
}
|
|
1561
|
+
var partsCache = /* @__PURE__ */ new WeakMap();
|
|
983
1562
|
function vectorStrokeSvgParts(node, clipId, precision = 3) {
|
|
984
1563
|
if (!hasPaint(node.stroke) || !hasStrokeExtras(node)) return void 0;
|
|
1564
|
+
const hit = partsCache.get(node);
|
|
1565
|
+
if (hit && hit.clipId === clipId && hit.precision === precision) return hit.parts;
|
|
1566
|
+
const parts = computeStrokeSvgParts(node, clipId, precision);
|
|
1567
|
+
partsCache.set(node, { clipId, precision, parts });
|
|
1568
|
+
return parts;
|
|
1569
|
+
}
|
|
1570
|
+
function computeStrokeSvgParts(node, clipId, precision) {
|
|
985
1571
|
const path = subpathsToBezier(node.subpaths);
|
|
986
1572
|
const parts = vectorStrokeParts(path, node);
|
|
987
|
-
|
|
1573
|
+
const profiled = !!strokeWidthProfileOf(node);
|
|
1574
|
+
if (parts.align === "center" && !parts.heads.length && !profiled) return void 0;
|
|
988
1575
|
let clip = null;
|
|
989
1576
|
if (parts.align !== "center") {
|
|
990
|
-
const b =
|
|
1577
|
+
const b = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, path);
|
|
991
1578
|
const pad = vectorStrokeReach(node) + 1;
|
|
992
1579
|
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
1580
|
clip = { kind: parts.align === "inside" ? "clip" : "mask", id: clipId, bounds };
|
|
994
1581
|
}
|
|
995
|
-
return {
|
|
1582
|
+
return {
|
|
1583
|
+
align: parts.align,
|
|
1584
|
+
d: _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, parts.line, { precision }),
|
|
1585
|
+
width: parts.drawWidth,
|
|
1586
|
+
...profiled && (_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0 ? { outline: _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, vectorStrokeLineArea(parts, node), { precision }) } : {},
|
|
1587
|
+
clip,
|
|
1588
|
+
heads: parts.heads.map((h) => _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, h.path, { precision }))
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function widthProfileToAttribute(points, precision = 4) {
|
|
1592
|
+
return points.map((p) => [p.t, p.left, p.right].map((n) => _chunk7EDLVBOOcjs.formatNumber.call(void 0, n, precision)).join(",")).join(";");
|
|
1593
|
+
}
|
|
1594
|
+
function widthProfileFromAttribute(value) {
|
|
1595
|
+
if (!value) return [];
|
|
1596
|
+
return sanitizeWidthProfile(
|
|
1597
|
+
value.split(";").map((part) => {
|
|
1598
|
+
const [t, left, right] = part.split(",").map((n) => parseFloat(n));
|
|
1599
|
+
return { t, left, right: Number.isFinite(right) ? right : left };
|
|
1600
|
+
})
|
|
1601
|
+
);
|
|
996
1602
|
}
|
|
997
1603
|
var round2 = (n) => Math.round(n * 100) / 100;
|
|
998
1604
|
function gradientMarkup(def) {
|
|
@@ -1007,11 +1613,11 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
1007
1613
|
const pretty = options.pretty !== false;
|
|
1008
1614
|
const defs = [];
|
|
1009
1615
|
const lines = [];
|
|
1010
|
-
const num = (n) =>
|
|
1616
|
+
const num = (n) => _chunk7EDLVBOOcjs.formatNumber.call(void 0, n, precision);
|
|
1011
1617
|
const indent = (depth) => pretty ? " ".repeat(depth) : "";
|
|
1012
1618
|
const common = (node) => {
|
|
1013
1619
|
let out2 = ` id="${escapeAttr(node.id)}"`;
|
|
1014
|
-
if (node.transform) out2 += ` transform="matrix(${node.transform.map((n) =>
|
|
1620
|
+
if (node.transform) out2 += ` transform="matrix(${node.transform.map((n) => _chunk7EDLVBOOcjs.formatNumber.call(void 0, n, 6)).join(" ")})"`;
|
|
1015
1621
|
if (node.opacity !== void 0 && node.opacity < 1) out2 += ` opacity="${num(node.opacity)}"`;
|
|
1016
1622
|
if (node.visible === false) out2 += ` display="none"`;
|
|
1017
1623
|
return out2;
|
|
@@ -1030,13 +1636,13 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
1030
1636
|
if (stroke.gradient) defs.push(gradientMarkup(stroke.gradient));
|
|
1031
1637
|
const d = vectorPathData(node, precision);
|
|
1032
1638
|
const corners2 = vectorCornersAttribute(node.subpaths, precision);
|
|
1033
|
-
const live = corners2 ? ` data-vector-d="${
|
|
1639
|
+
const live = corners2 ? ` data-vector-d="${_chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, subpathsToBezier(node.subpaths, { corners: false }), { precision })}" data-vector-corners="${corners2}"` : "";
|
|
1034
1640
|
const fillAttrs = ` fill="${escapeAttr(fill.value)}"${node.fillRule === "evenodd" ? ` fill-rule="evenodd"` : ""}`;
|
|
1035
1641
|
const lineAttrs = (width) => {
|
|
1036
1642
|
let out2 = ` stroke="${escapeAttr(stroke.value)}" stroke-width="${num(width)}"`;
|
|
1037
1643
|
if (node.strokeLinecap && node.strokeLinecap !== "butt") out2 += ` stroke-linecap="${node.strokeLinecap}"`;
|
|
1038
1644
|
if (node.strokeLinejoin && node.strokeLinejoin !== "miter") out2 += ` stroke-linejoin="${node.strokeLinejoin}"`;
|
|
1039
|
-
if (_optionalChain([node, 'access',
|
|
1645
|
+
if (_optionalChain([node, 'access', _34 => _34.strokeDasharray, 'optionalAccess', _35 => _35.length])) out2 += ` stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
|
|
1040
1646
|
return out2;
|
|
1041
1647
|
};
|
|
1042
1648
|
const parts = stroke.value !== "none" ? vectorStrokeSvgParts(node, `${prefix}clip-${node.id}`, precision) : void 0;
|
|
@@ -1051,10 +1657,17 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
1051
1657
|
if (node.arrowAlign && node.arrowAlign !== "extend") data += ` data-vector-arrow-align="${node.arrowAlign}"`;
|
|
1052
1658
|
if (node.startArrowScale !== void 0 && node.startArrowScale !== 1) data += ` data-vector-start-arrow-scale="${num(node.startArrowScale)}"`;
|
|
1053
1659
|
if (node.endArrowScale !== void 0 && node.endArrowScale !== 1) data += ` data-vector-end-arrow-scale="${num(node.endArrowScale)}"`;
|
|
1660
|
+
const profile = strokeWidthProfileOf(node);
|
|
1661
|
+
if (profile) {
|
|
1662
|
+
data += ` data-vector-width-profile="${widthProfileToAttribute(profile)}"`;
|
|
1663
|
+
if (node.strokeLinecap && node.strokeLinecap !== "butt") data += ` data-vector-stroke-linecap="${node.strokeLinecap}"`;
|
|
1664
|
+
if (node.strokeLinejoin && node.strokeLinejoin !== "miter") data += ` data-vector-stroke-linejoin="${node.strokeLinejoin}"`;
|
|
1665
|
+
if (_optionalChain([node, 'access', _36 => _36.strokeDasharray, 'optionalAccess', _37 => _37.length])) data += ` data-vector-stroke-dasharray="${node.strokeDasharray.map(num).join(" ")}"`;
|
|
1666
|
+
}
|
|
1054
1667
|
lines.push(`${indent(depth)}<g${common(node)}${data}>`);
|
|
1055
1668
|
lines.push(`${indent(depth + 1)}<path data-vector-part="fill" d="${d}"${fillAttrs}${live}/>`);
|
|
1056
1669
|
if (options.strokes === "outline") {
|
|
1057
|
-
const area =
|
|
1670
|
+
const area = _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, vectorStrokeOutlinePath(subpathsToBezier(node.subpaths), node), { precision });
|
|
1058
1671
|
lines.push(`${indent(depth + 1)}<path data-vector-part="stroke-outline" d="${area}" fill="${escapeAttr(stroke.value)}"/>`);
|
|
1059
1672
|
} else {
|
|
1060
1673
|
let clip = "";
|
|
@@ -1071,7 +1684,8 @@ function vectorDocumentToSvg(doc, options = {}) {
|
|
|
1071
1684
|
clip = ` mask="url(#${id})"`;
|
|
1072
1685
|
}
|
|
1073
1686
|
}
|
|
1074
|
-
lines.push(`${indent(depth + 1)}<path data-vector-part="stroke" d="${parts.
|
|
1687
|
+
if (parts.outline !== void 0) lines.push(`${indent(depth + 1)}<path data-vector-part="stroke-outline" d="${parts.outline}" fill="${escapeAttr(stroke.value)}"${clip}/>`);
|
|
1688
|
+
else lines.push(`${indent(depth + 1)}<path data-vector-part="stroke" d="${parts.d}" fill="none"${lineAttrs(parts.width)}${clip}/>`);
|
|
1075
1689
|
for (const h2 of parts.heads) lines.push(`${indent(depth + 1)}<path data-vector-part="head" d="${h2}" fill="${escapeAttr(stroke.value)}"/>`);
|
|
1076
1690
|
}
|
|
1077
1691
|
lines.push(`${indent(depth)}</g>`);
|
|
@@ -1217,7 +1831,7 @@ function resolveGradient(id, raw, seen = /* @__PURE__ */ new Set()) {
|
|
|
1217
1831
|
seen.add(id);
|
|
1218
1832
|
let stops = readStops(el);
|
|
1219
1833
|
const href = _nullishCoalesce(el.attrs.href, () => ( el.attrs["xlink:href"]));
|
|
1220
|
-
if (!stops.length && _optionalChain([href, 'optionalAccess',
|
|
1834
|
+
if (!stops.length && _optionalChain([href, 'optionalAccess', _38 => _38.startsWith, 'call', _39 => _39("#")])) stops = _nullishCoalesce(_optionalChain([resolveGradient, 'call', _40 => _40(href.slice(1), raw, seen), 'optionalAccess', _41 => _41.stops]), () => ( []));
|
|
1221
1835
|
if (!stops.length) return null;
|
|
1222
1836
|
if (el.name === "radialGradient") {
|
|
1223
1837
|
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 };
|
|
@@ -1321,7 +1935,7 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
1321
1935
|
const part = (name) => g.children.find((c) => c.name === "path" && c.attrs["data-vector-part"] === name);
|
|
1322
1936
|
const fillEl = part("fill");
|
|
1323
1937
|
const subpaths = fillEl ? shapeOf(fillEl) : null;
|
|
1324
|
-
if (!fillEl || !_optionalChain([subpaths, 'optionalAccess',
|
|
1938
|
+
if (!fillEl || !_optionalChain([subpaths, 'optionalAccess', _42 => _42.length])) return null;
|
|
1325
1939
|
const a = g.attrs;
|
|
1326
1940
|
const fs = readStyle(fillEl, style);
|
|
1327
1941
|
const strokeEl = part("stroke");
|
|
@@ -1334,6 +1948,11 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
1334
1948
|
return n > 0 ? n : void 0;
|
|
1335
1949
|
};
|
|
1336
1950
|
const align = a["data-vector-stroke-align"];
|
|
1951
|
+
const profile = widthProfileFromAttribute(a["data-vector-width-profile"]);
|
|
1952
|
+
const kept = (key, values) => values.includes(a[key]) ? a[key] : void 0;
|
|
1953
|
+
const keptCap = kept("data-vector-stroke-linecap", ["round", "square"]);
|
|
1954
|
+
const keptJoin = kept("data-vector-stroke-linejoin", ["round", "bevel"]);
|
|
1955
|
+
const keptDash = a["data-vector-stroke-dasharray"] ? numberList(a["data-vector-stroke-dasharray"]) : void 0;
|
|
1337
1956
|
const node = {
|
|
1338
1957
|
id: idFor(g),
|
|
1339
1958
|
type: "path",
|
|
@@ -1349,7 +1968,11 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
1349
1968
|
...arrow(a["data-vector-end-arrow"]) ? { endArrow: arrow(a["data-vector-end-arrow"]) } : {},
|
|
1350
1969
|
...a["data-vector-arrow-align"] === "tip" ? { arrowAlign: "tip" } : {},
|
|
1351
1970
|
...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"]) } : {}
|
|
1971
|
+
...scale(a["data-vector-end-arrow-scale"]) ? { endArrowScale: scale(a["data-vector-end-arrow-scale"]) } : {},
|
|
1972
|
+
...profile.length ? { strokeWidthProfile: profile } : {},
|
|
1973
|
+
...keptCap ? { strokeLinecap: keptCap } : {},
|
|
1974
|
+
...keptJoin ? { strokeLinejoin: keptJoin } : {},
|
|
1975
|
+
..._optionalChain([keptDash, 'optionalAccess', _43 => _43.length]) ? { strokeDasharray: keptDash } : {}
|
|
1353
1976
|
};
|
|
1354
1977
|
return placed(node, m);
|
|
1355
1978
|
};
|
|
@@ -1403,7 +2026,7 @@ function parseVectorSvg(svg, options = {}) {
|
|
|
1403
2026
|
// src/vector/snap.ts
|
|
1404
2027
|
var VECTOR_CONSTRUCTION_ANGLES = [0, 45, 90, 135];
|
|
1405
2028
|
function constrainToLeave(leave, p) {
|
|
1406
|
-
if (!_optionalChain([leave, 'optionalAccess',
|
|
2029
|
+
if (!_optionalChain([leave, 'optionalAccess', _44 => _44.constrain])) return p;
|
|
1407
2030
|
const dx = p.x - leave.at.x;
|
|
1408
2031
|
const dy = p.y - leave.at.y;
|
|
1409
2032
|
switch (leave.constrain) {
|
|
@@ -1514,7 +2137,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1514
2137
|
moving.set(r.nodeId, set);
|
|
1515
2138
|
}
|
|
1516
2139
|
const t = _VectorSnapTargets.collect(doc, new Set(moving.keys()), "segments", false);
|
|
1517
|
-
t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access',
|
|
2140
|
+
t.pushPaths(doc, new Set(moving.keys()), (id, s, i) => !!_optionalChain([moving, 'access', _45 => _45.get, 'call', _46 => _46(id), 'optionalAccess', _47 => _47.has, 'call', _48 => _48(`${s}:${i}`)]), true);
|
|
1518
2141
|
return t.index();
|
|
1519
2142
|
}
|
|
1520
2143
|
/**
|
|
@@ -1632,7 +2255,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1632
2255
|
}
|
|
1633
2256
|
const b = vectorNodeBounds(n, parent);
|
|
1634
2257
|
const f = nodeFrame(n, parent, b);
|
|
1635
|
-
if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess',
|
|
2258
|
+
if (b) self.pushRect(b, "edge", _nullishCoalesce(_optionalChain([f, 'optionalAccess', _49 => _49.centre]), () => ( null)));
|
|
1636
2259
|
}
|
|
1637
2260
|
};
|
|
1638
2261
|
visit(doc.nodes, IDENTITY_MATRIX);
|
|
@@ -1669,7 +2292,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1669
2292
|
*/
|
|
1670
2293
|
snapFrom(p, leave, tol) {
|
|
1671
2294
|
const none = (q) => ({ point: q, kind: null, x: false, y: false, lines: [], labels: [] });
|
|
1672
|
-
const
|
|
2295
|
+
const at2 = (q, kind, lines2 = []) => ({
|
|
1673
2296
|
point: q,
|
|
1674
2297
|
kind,
|
|
1675
2298
|
x: true,
|
|
@@ -1677,23 +2300,23 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1677
2300
|
lines: lines2,
|
|
1678
2301
|
labels: [this.label(q, kind)]
|
|
1679
2302
|
});
|
|
1680
|
-
if (_optionalChain([leave, 'optionalAccess',
|
|
2303
|
+
if (_optionalChain([leave, 'optionalAccess', _50 => _50.constrain])) {
|
|
1681
2304
|
const q = constrainToLeave(leave, p);
|
|
1682
2305
|
const hit = this.slide(leave.at, { x: q.x - leave.at.x, y: q.y - leave.at.y }, q, tol, true);
|
|
1683
2306
|
return hit ? { point: hit.point, x: true, y: true, ...this.linedUp(hit.point, hit.from) } : none(q);
|
|
1684
2307
|
}
|
|
1685
2308
|
const point = this.nearestPoint(p, tol);
|
|
1686
|
-
if (point) return
|
|
2309
|
+
if (point) return at2(point.p, point.kind);
|
|
1687
2310
|
const near2 = this.segmentsNear(p, tol);
|
|
1688
|
-
const
|
|
1689
|
-
if (
|
|
2311
|
+
const crossing2 = this.crossing(near2, p, tol);
|
|
2312
|
+
if (crossing2) return at2(crossing2, "intersect");
|
|
1690
2313
|
if (leave && leave.curves !== false) {
|
|
1691
2314
|
const foot = this.curvePoint(near2, leave.at, p, tol);
|
|
1692
|
-
if (foot) return
|
|
2315
|
+
if (foot) return at2(foot.point, foot.kind, [line("construction", leave.at, foot.point)]);
|
|
1693
2316
|
}
|
|
1694
2317
|
const on = this.onSegment(near2);
|
|
1695
|
-
if (on) return
|
|
1696
|
-
if (_optionalChain([leave, 'optionalAccess',
|
|
2318
|
+
if (on) return at2(on, "path");
|
|
2319
|
+
if (_optionalChain([leave, 'optionalAccess', _51 => _51.angles, 'optionalAccess', _52 => _52.length])) {
|
|
1697
2320
|
const c = construction(leave, p, tol);
|
|
1698
2321
|
if (c) {
|
|
1699
2322
|
const hit = this.slide(leave.at, c.dir, c.point, tol, false);
|
|
@@ -1739,7 +2362,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1739
2362
|
* the nearest target line crosses it, at most twice `tol` away: where it lands and the
|
|
1740
2363
|
* target point that line comes from.
|
|
1741
2364
|
*/
|
|
1742
|
-
slide(
|
|
2365
|
+
slide(at2, dir, q, tol, ray) {
|
|
1743
2366
|
const len2 = dir.x * dir.x + dir.y * dir.y;
|
|
1744
2367
|
if (!Number.isFinite(len2) || len2 <= 1e-18) return null;
|
|
1745
2368
|
const reach = 2 * tol;
|
|
@@ -1747,10 +2370,10 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1747
2370
|
for (const vertical of [true, false]) {
|
|
1748
2371
|
const d = vertical ? dir.x : dir.y;
|
|
1749
2372
|
if (Math.abs(d) <= 1e-9) continue;
|
|
1750
|
-
const a = vertical ?
|
|
2373
|
+
const a = vertical ? at2.x : at2.y;
|
|
1751
2374
|
for (const l of linesNear(vertical ? this.xs : this.ys, vertical ? q.x : q.y, reach)) {
|
|
1752
2375
|
const s = (l.v - a) / d;
|
|
1753
|
-
const hit = vertical ? { x: l.v, y:
|
|
2376
|
+
const hit = vertical ? { x: l.v, y: at2.y + dir.y * s } : { x: at2.x + dir.x * s, y: l.v };
|
|
1754
2377
|
const moved = distance(hit, q);
|
|
1755
2378
|
if (moved <= reach && (!ray || s > 0) && (!best || moved < best.moved)) best = { moved, point: hit, from: l.from };
|
|
1756
2379
|
}
|
|
@@ -1769,13 +2392,13 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1769
2392
|
const pt2 = toPoint(p);
|
|
1770
2393
|
for (const s of this.segments) {
|
|
1771
2394
|
if (p.x < s.minX - tol || p.x > s.maxX + tol || p.y < s.minY - tol || p.y > s.maxY + tol) continue;
|
|
1772
|
-
const hit =
|
|
2395
|
+
const hit = _chunk7EDLVBOOcjs.segmentNearest.call(void 0, s.seg, pt2);
|
|
1773
2396
|
if (hit.distance <= tol) out.push({ seg: s.seg, t: hit.t, distance: hit.distance });
|
|
1774
2397
|
}
|
|
1775
2398
|
return out.sort((a, b) => a.distance - b.distance);
|
|
1776
2399
|
}
|
|
1777
2400
|
onSegment(near2) {
|
|
1778
|
-
return near2.length ? toVec2(
|
|
2401
|
+
return near2.length ? toVec2(_chunk7EDLVBOOcjs.segmentPoint.call(void 0, near2[0].seg, near2[0].t)) : null;
|
|
1779
2402
|
}
|
|
1780
2403
|
/** Where two of the target segments near `p` cross, the crossing nearest `p` within `tol`. */
|
|
1781
2404
|
crossing(near2, p, tol) {
|
|
@@ -1784,7 +2407,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1784
2407
|
let bestD = Infinity;
|
|
1785
2408
|
for (let i = 0; i < list.length; i++) {
|
|
1786
2409
|
for (let j = i + 1; j < list.length; j++) {
|
|
1787
|
-
for (const hit of
|
|
2410
|
+
for (const hit of _chunk7EDLVBOOcjs.segmentIntersections.call(void 0, list[i].seg, list[j].seg)) {
|
|
1788
2411
|
const q = toVec2(hit.point);
|
|
1789
2412
|
const d = distance(q, p);
|
|
1790
2413
|
if (d <= tol && d < bestD) {
|
|
@@ -1823,7 +2446,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1823
2446
|
* with nothing spaces the box evenly in its row or column. Returns the correction and guides.
|
|
1824
2447
|
*/
|
|
1825
2448
|
snapRect(r, tol, options = {}) {
|
|
1826
|
-
const axes = { x: _optionalChain([options, 'access',
|
|
2449
|
+
const axes = { x: _optionalChain([options, 'access', _53 => _53.axes, 'optionalAccess', _54 => _54.x]) !== false, y: _optionalChain([options, 'access', _55 => _55.axes, 'optionalAccess', _56 => _56.y]) !== false };
|
|
1827
2450
|
const nearest = (lines, values) => {
|
|
1828
2451
|
let best = null;
|
|
1829
2452
|
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 };
|
|
@@ -1831,7 +2454,7 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1831
2454
|
};
|
|
1832
2455
|
const bx = axes.x ? nearest(this.xs, [r.x, r.x + r.width / 2, r.x + r.width]) : null;
|
|
1833
2456
|
const by = axes.y ? nearest(this.ys, [r.y, r.y + r.height / 2, r.y + r.height]) : null;
|
|
1834
|
-
const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess',
|
|
2457
|
+
const out = { dx: _nullishCoalesce(_optionalChain([bx, 'optionalAccess', _57 => _57.d]), () => ( 0)), dy: _nullishCoalesce(_optionalChain([by, 'optionalAccess', _58 => _58.d]), () => ( 0)), x: !!bx, y: !!by, lines: [], labels: [] };
|
|
1835
2458
|
const done = { ...r, x: r.x + out.dx, y: r.y + out.dy };
|
|
1836
2459
|
if (bx) {
|
|
1837
2460
|
const x = bx.from.x;
|
|
@@ -1898,11 +2521,11 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1898
2521
|
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;
|
|
1899
2522
|
if (!pick) return null;
|
|
1900
2523
|
const { start, repeats } = pick;
|
|
1901
|
-
const
|
|
2524
|
+
const at2 = horizontal ? { ...r, x: start } : { ...r, y: start };
|
|
1902
2525
|
const end = start + len2;
|
|
1903
2526
|
const gaps = [];
|
|
1904
|
-
if (before && (repeats === null || Math.abs(start - before.a1 - repeats) <= EQUAL)) gaps.push([before.a1, start, mid(before.b,
|
|
1905
|
-
if (after && (repeats === null || Math.abs(after.a0 - end - repeats) <= EQUAL)) gaps.push([end, after.a0, mid(after.b,
|
|
2527
|
+
if (before && (repeats === null || Math.abs(start - before.a1 - repeats) <= EQUAL)) gaps.push([before.a1, start, mid(before.b, at2)]);
|
|
2528
|
+
if (after && (repeats === null || Math.abs(after.a0 - end - repeats) <= EQUAL)) gaps.push([end, after.a0, mid(after.b, at2)]);
|
|
1906
2529
|
if (repeats !== null) {
|
|
1907
2530
|
for (const p of pairs) if (Math.abs(p.g - repeats) <= EQUAL) gaps.push(p.gap);
|
|
1908
2531
|
}
|
|
@@ -1954,9 +2577,9 @@ var VectorSnapTargets = (_class = class _VectorSnapTargets {
|
|
|
1954
2577
|
const on = this.nearestPoint(p, tol);
|
|
1955
2578
|
const tries = [];
|
|
1956
2579
|
if (on) tries.push({ tx: on.p.x, ty: on.p.y, s: { hx: null, hy: null, on } });
|
|
1957
|
-
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess',
|
|
1958
|
-
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess',
|
|
1959
|
-
tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess',
|
|
2580
|
+
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _59 => _59.v]), () => ( null)), ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _60 => _60.v]), () => ( null)), s: { hx, hy, on: null } });
|
|
2581
|
+
tries.push({ tx: _nullishCoalesce(_optionalChain([hx, 'optionalAccess', _61 => _61.v]), () => ( null)), ty: null, s: { hx, hy: null, on: null } });
|
|
2582
|
+
tries.push({ tx: null, ty: _nullishCoalesce(_optionalChain([hy, 'optionalAccess', _62 => _62.v]), () => ( null)), s: { hx: null, hy, on: null } });
|
|
1960
2583
|
for (const { tx, ty, s } of tries) {
|
|
1961
2584
|
if (tx === null && ty === null) continue;
|
|
1962
2585
|
const q = applyMatrix(toLocal, { x: _nullishCoalesce(tx, () => ( p.x)), y: _nullishCoalesce(ty, () => ( p.y)) });
|
|
@@ -2106,15 +2729,15 @@ var crossCondition = (r, d) => r[0] * d[1] - r[1] * d[0];
|
|
|
2106
2729
|
function solveOnSegment(seg, base, cond) {
|
|
2107
2730
|
const b = [base.x, base.y];
|
|
2108
2731
|
const g = (t) => {
|
|
2109
|
-
const p =
|
|
2110
|
-
return cond([p[0] - b[0], p[1] - b[1]],
|
|
2732
|
+
const p = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, t);
|
|
2733
|
+
return cond([p[0] - b[0], p[1] - b[1]], _chunk7EDLVBOOcjs.segmentDerivative.call(void 0, seg, t));
|
|
2111
2734
|
};
|
|
2112
2735
|
const vals = [];
|
|
2113
2736
|
let scale = 0;
|
|
2114
2737
|
for (let i = 0; i <= CURVE_SAMPLES; i++) {
|
|
2115
2738
|
const t = i / CURVE_SAMPLES;
|
|
2116
|
-
const p =
|
|
2117
|
-
const d =
|
|
2739
|
+
const p = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, t);
|
|
2740
|
+
const d = _chunk7EDLVBOOcjs.segmentDerivative.call(void 0, seg, t);
|
|
2118
2741
|
const r = [p[0] - b[0], p[1] - b[1]];
|
|
2119
2742
|
vals.push(cond(r, d));
|
|
2120
2743
|
scale = Math.max(scale, Math.hypot(r[0], r[1]) * Math.hypot(d[0], d[1]));
|
|
@@ -2141,8 +2764,8 @@ function solveOnSegment(seg, base, cond) {
|
|
|
2141
2764
|
} else hi = m;
|
|
2142
2765
|
}
|
|
2143
2766
|
const t = (lo + hi) / 2;
|
|
2144
|
-
const p =
|
|
2145
|
-
const dv =
|
|
2767
|
+
const p = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, t);
|
|
2768
|
+
const dv = _chunk7EDLVBOOcjs.segmentDerivative.call(void 0, seg, t);
|
|
2146
2769
|
const r = Math.hypot(p[0] - b[0], p[1] - b[1]);
|
|
2147
2770
|
const dl = Math.hypot(dv[0], dv[1]);
|
|
2148
2771
|
if (!(r > 1e-9 && dl > 0) || Math.abs(cond([p[0] - b[0], p[1] - b[1]], dv)) > 1e-6 * r * dl) continue;
|
|
@@ -2179,7 +2802,7 @@ function endTangent(c) {
|
|
|
2179
2802
|
return [1, 0];
|
|
2180
2803
|
}
|
|
2181
2804
|
function sample(c, n, out, withStart) {
|
|
2182
|
-
for (let i = withStart ? 0 : 1; i <= n; i++) out.push(
|
|
2805
|
+
for (let i = withStart ? 0 : 1; i <= n; i++) out.push(_chunk7EDLVBOOcjs.segmentPoint.call(void 0, c, i / n));
|
|
2183
2806
|
}
|
|
2184
2807
|
var onAnchor2 = (a, h) => !h || Math.abs(h.x - a.x) < EPS3 && Math.abs(h.y - a.y) < EPS3;
|
|
2185
2808
|
function tidy(a, keepType = true) {
|
|
@@ -2225,7 +2848,7 @@ function fitAcross(pts, N, t0, t1) {
|
|
|
2225
2848
|
const u = [];
|
|
2226
2849
|
for (let i = 0; i <= N; i++) u.push(k * i / N);
|
|
2227
2850
|
for (let i = 1; i <= N; i++) u.push(k + (1 - k) * i / N);
|
|
2228
|
-
return
|
|
2851
|
+
return _chunk7EDLVBOOcjs.fitCubicWithTangents.call(void 0, pts, u, t0, t1);
|
|
2229
2852
|
};
|
|
2230
2853
|
return goldenMin(fit, 0, 1);
|
|
2231
2854
|
}
|
|
@@ -2285,7 +2908,7 @@ function bendSegment(sp, segment, t, p) {
|
|
|
2285
2908
|
return { anchors, closed: sp.closed };
|
|
2286
2909
|
}
|
|
2287
2910
|
function subpathPointAt(sp, segment, t) {
|
|
2288
|
-
const [x, y] =
|
|
2911
|
+
const [x, y] = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, subpathSegment(sp, segment), t);
|
|
2289
2912
|
return { x, y };
|
|
2290
2913
|
}
|
|
2291
2914
|
function curvatureMoveAnchor(sp, index, q) {
|
|
@@ -2331,9 +2954,9 @@ function curvatureMoveAnchor(sp, index, q) {
|
|
|
2331
2954
|
anchors[index] = moved;
|
|
2332
2955
|
return { anchors, closed: sp.closed };
|
|
2333
2956
|
}
|
|
2334
|
-
function cutSubpathAt(sp,
|
|
2957
|
+
function cutSubpathAt(sp, at2) {
|
|
2335
2958
|
const n = sp.anchors.length;
|
|
2336
|
-
const cuts = [...new Set(
|
|
2959
|
+
const cuts = [...new Set(at2)].filter((i) => Number.isInteger(i) && i >= 0 && i < n && (sp.closed || i > 0 && i < n - 1)).sort((a, b) => a - b);
|
|
2337
2960
|
if (!cuts.length || n < 2) return [{ anchors: sp.anchors.map(cloneAnchor), closed: sp.closed }];
|
|
2338
2961
|
const first = cuts[0];
|
|
2339
2962
|
const run = sp.closed ? Array.from({ length: n + 1 }, (_, i) => sp.anchors[(first + i) % n]) : sp.anchors;
|
|
@@ -2364,7 +2987,7 @@ function splitSubpathAt(sp, segment, t, endTolerance = 1e-6) {
|
|
|
2364
2987
|
return cutSubpathAt(subpath, [index]);
|
|
2365
2988
|
}
|
|
2366
2989
|
var endOf2 = (sp, last) => sp.anchors[last ? sp.anchors.length - 1 : 0];
|
|
2367
|
-
var
|
|
2990
|
+
var dist2 = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
|
|
2368
2991
|
function reverse(sp) {
|
|
2369
2992
|
return {
|
|
2370
2993
|
closed: sp.closed,
|
|
@@ -2391,7 +3014,7 @@ function joinSubpaths(subpaths, tolerance) {
|
|
|
2391
3014
|
const sp = open[0];
|
|
2392
3015
|
const first = sp.anchors[0];
|
|
2393
3016
|
const last = sp.anchors[sp.anchors.length - 1];
|
|
2394
|
-
if (sp.anchors.length > 2 &&
|
|
3017
|
+
if (sp.anchors.length > 2 && dist2(first, last) <= tolerance) {
|
|
2395
3018
|
sp.anchors.pop();
|
|
2396
3019
|
sp.anchors[0] = tidy({ ...first, in: _nullishCoalesce(last.in, () => ( null)) }, false);
|
|
2397
3020
|
} else {
|
|
@@ -2407,7 +3030,7 @@ function joinSubpaths(subpaths, tolerance) {
|
|
|
2407
3030
|
for (let j = i + 1; j < open.length; j++) {
|
|
2408
3031
|
for (const ei of [false, true]) {
|
|
2409
3032
|
for (const ej of [false, true]) {
|
|
2410
|
-
const d =
|
|
3033
|
+
const d = dist2(endOf2(open[i], ei), endOf2(open[j], ej));
|
|
2411
3034
|
if (d < best.d) best = { d, i, j, ei, ej };
|
|
2412
3035
|
}
|
|
2413
3036
|
}
|
|
@@ -2447,8 +3070,8 @@ function smoothSubpath(sp, amount = 1, only) {
|
|
|
2447
3070
|
const p = orig[i];
|
|
2448
3071
|
const dir = unit2(next.x - prev.x, next.y - prev.y);
|
|
2449
3072
|
if (!dir) continue;
|
|
2450
|
-
const li =
|
|
2451
|
-
const lo =
|
|
3073
|
+
const li = dist2(p, prev) / 3;
|
|
3074
|
+
const lo = dist2(p, next) / 3;
|
|
2452
3075
|
const hin = _nullishCoalesce(p.in, () => ( p));
|
|
2453
3076
|
const hout = _nullishCoalesce(p.out, () => ( p));
|
|
2454
3077
|
const target = (h, x, y) => ({ x: h.x + (x - h.x) * t, y: h.y + (y - h.y) * t });
|
|
@@ -2475,12 +3098,12 @@ function segsOf(sp) {
|
|
|
2475
3098
|
function segsToSubpath(segs, closed, types) {
|
|
2476
3099
|
if (!segs.length) return null;
|
|
2477
3100
|
const anchors = [];
|
|
2478
|
-
const
|
|
2479
|
-
anchors.push(
|
|
3101
|
+
const at2 = (p) => ({ x: p[0], y: p[1] });
|
|
3102
|
+
anchors.push(at2(segs[0].c[0]));
|
|
2480
3103
|
for (const s of segs) {
|
|
2481
3104
|
const end = s.c[s.c.length - 1];
|
|
2482
3105
|
if (!s.line) anchors[anchors.length - 1].out = { x: s.c[1][0], y: s.c[1][1] };
|
|
2483
|
-
const next =
|
|
3106
|
+
const next = at2(end);
|
|
2484
3107
|
if (!s.line) next.in = { x: s.c[2][0], y: s.c[2][1] };
|
|
2485
3108
|
anchors.push(next);
|
|
2486
3109
|
}
|
|
@@ -2506,8 +3129,8 @@ function mergePair(a, b, tol) {
|
|
|
2506
3129
|
if (len2 < 1e-12) return null;
|
|
2507
3130
|
const mx = a3[0] - a0[0];
|
|
2508
3131
|
const my = a3[1] - a0[1];
|
|
2509
|
-
const
|
|
2510
|
-
return Math.abs((mx * cy - my * cx) / len2) <= tol &&
|
|
3132
|
+
const along2 = (mx * cx + my * cy) / len2;
|
|
3133
|
+
return Math.abs((mx * cy - my * cx) / len2) <= tol && along2 >= 0 && along2 <= len2 ? { c: [a0, b3], line: true } : null;
|
|
2511
3134
|
}
|
|
2512
3135
|
const ca = a.line ? [a0, a0, a3, a3] : a.c;
|
|
2513
3136
|
const cb = b.line ? [a3, a3, b3, b3] : b.c;
|
|
@@ -2546,20 +3169,20 @@ function removeRedundantPoints(sp, tolerance) {
|
|
|
2546
3169
|
}
|
|
2547
3170
|
|
|
2548
3171
|
// src/vector/pathCut.ts
|
|
2549
|
-
var loopArea = (l) =>
|
|
3172
|
+
var loopArea = (l) => _chunk7EDLVBOOcjs.contourSignedArea.call(void 0, l.segs);
|
|
2550
3173
|
function loopSample(l) {
|
|
2551
3174
|
const k = l.chord.findIndex((c) => !c);
|
|
2552
|
-
return
|
|
3175
|
+
return _chunk7EDLVBOOcjs.segmentPoint.call(void 0, l.segs[k >= 0 ? k : 0], 0.5);
|
|
2553
3176
|
}
|
|
2554
|
-
var contains2 = (l, p) =>
|
|
3177
|
+
var contains2 = (l, p) => _chunk7EDLVBOOcjs.windingNumber.call(void 0, [l.segs], p) !== 0;
|
|
2555
3178
|
function groupFaces(loops) {
|
|
2556
|
-
const
|
|
2557
|
-
if (!
|
|
2558
|
-
const largest =
|
|
3179
|
+
const usable2 = loops.filter((l) => l.segs.length && Math.abs(loopArea(l)) > 1e-12);
|
|
3180
|
+
if (!usable2.length) return [];
|
|
3181
|
+
const largest = usable2.reduce((a, b) => Math.abs(loopArea(b)) > Math.abs(loopArea(a)) ? b : a);
|
|
2559
3182
|
const sign = Math.sign(loopArea(largest));
|
|
2560
|
-
const outers =
|
|
3183
|
+
const outers = usable2.filter((l) => Math.sign(loopArea(l)) === sign).sort((a, b) => Math.abs(loopArea(a)) - Math.abs(loopArea(b)));
|
|
2561
3184
|
const faces = new Map(outers.map((o) => [o, { loops: [o] }]));
|
|
2562
|
-
for (const hole of
|
|
3185
|
+
for (const hole of usable2.filter((l) => Math.sign(loopArea(l)) !== sign)) {
|
|
2563
3186
|
const p = loopSample(hole);
|
|
2564
3187
|
const parent = outers.find((o) => Math.abs(loopArea(o)) > Math.abs(loopArea(hole)) && contains2(o, p));
|
|
2565
3188
|
if (parent) faces.get(parent).loops.push(hole);
|
|
@@ -2567,12 +3190,12 @@ function groupFaces(loops) {
|
|
|
2567
3190
|
return outers.reverse().map((o) => faces.get(o));
|
|
2568
3191
|
}
|
|
2569
3192
|
function faceToPath(face) {
|
|
2570
|
-
return
|
|
3193
|
+
return _chunk7EDLVBOOcjs.contoursToPath.call(void 0, face.loops.map((l) => ({ segments: l.segs, closed: true })));
|
|
2571
3194
|
}
|
|
2572
3195
|
function facesOf(path, fillRule) {
|
|
2573
|
-
const normalized =
|
|
2574
|
-
const loops =
|
|
2575
|
-
const segs =
|
|
3196
|
+
const normalized = _chunk7EDLVBOOcjs.normalizeBezierPath.call(void 0, path, fillRule);
|
|
3197
|
+
const loops = _chunk7EDLVBOOcjs.pathToContours.call(void 0, normalized).map((c) => {
|
|
3198
|
+
const segs = _chunk7EDLVBOOcjs.closeContour.call(void 0, c, true).map((s) => s.slice());
|
|
2576
3199
|
return { segs, chord: segs.map(() => false) };
|
|
2577
3200
|
});
|
|
2578
3201
|
return groupFaces(loops);
|
|
@@ -2642,7 +3265,7 @@ function lineHits(p, q, seg) {
|
|
|
2642
3265
|
const scale = Math.sqrt(len2) * Math.max(1, ...seg.map((pt2) => Math.abs(pt2[0]) + Math.abs(pt2[1])));
|
|
2643
3266
|
const out = [];
|
|
2644
3267
|
for (const t of rootsInUnit(...coeffs, scale)) {
|
|
2645
|
-
const point =
|
|
3268
|
+
const point = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, t);
|
|
2646
3269
|
const s = ((point[0] - p[0]) * dx + (point[1] - p[1]) * dy) / len2;
|
|
2647
3270
|
if (s >= -1e-9 && s <= 1 + 1e-9) out.push({ s: Math.min(1, Math.max(0, s)), t, point });
|
|
2648
3271
|
}
|
|
@@ -2655,7 +3278,7 @@ function arc(l, a, b, eps) {
|
|
|
2655
3278
|
const segs = [];
|
|
2656
3279
|
const chord = [];
|
|
2657
3280
|
const push = (k, t0, t1) => {
|
|
2658
|
-
const piece = t0 <= 0 && t1 >= 1 ? l.segs[k].slice() :
|
|
3281
|
+
const piece = t0 <= 0 && t1 >= 1 ? l.segs[k].slice() : _chunk7EDLVBOOcjs.subSegment.call(void 0, l.segs[k], t0, t1);
|
|
2659
3282
|
if (!degenerate(piece, eps)) {
|
|
2660
3283
|
segs.push(piece);
|
|
2661
3284
|
chord.push(l.chord[k]);
|
|
@@ -2680,7 +3303,7 @@ function knifePath(path, fillRule, knife) {
|
|
|
2680
3303
|
if (pts.length < 2) return null;
|
|
2681
3304
|
let faces = facesOf(path, fillRule);
|
|
2682
3305
|
if (!faces.length) return null;
|
|
2683
|
-
const b =
|
|
3306
|
+
const b = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, path);
|
|
2684
3307
|
const size = b ? Math.max(b.maxX - b.minX, b.maxY - b.minY, 1) : 1;
|
|
2685
3308
|
const eps = size * 1e-9;
|
|
2686
3309
|
let cursor = -Infinity;
|
|
@@ -2694,7 +3317,7 @@ function knifePath(path, fillRule, knife) {
|
|
|
2694
3317
|
const kb = { minX: Math.min(pts[m][0], pts[m + 1][0]), maxX: Math.max(pts[m][0], pts[m + 1][0]), minY: Math.min(pts[m][1], pts[m + 1][1]), maxY: Math.max(pts[m][1], pts[m + 1][1]) };
|
|
2695
3318
|
face2.loops.forEach(
|
|
2696
3319
|
(l, li) => l.segs.forEach((seg, si) => {
|
|
2697
|
-
const sb =
|
|
3320
|
+
const sb = _chunk7EDLVBOOcjs.segmentBounds.call(void 0, seg);
|
|
2698
3321
|
if (sb.maxX < kb.minX - eps || sb.minX > kb.maxX + eps || sb.maxY < kb.minY - eps || sb.minY > kb.maxY + eps) return;
|
|
2699
3322
|
for (const h of lineHits(pts[m], pts[m + 1], seg)) {
|
|
2700
3323
|
const s = m + h.s;
|
|
@@ -2709,7 +3332,7 @@ function knifePath(path, fillRule, knife) {
|
|
|
2709
3332
|
const m = Math.min(pts.length - 2, Math.floor(s));
|
|
2710
3333
|
const u = s - m;
|
|
2711
3334
|
const q = [pts[m][0] + (pts[m + 1][0] - pts[m][0]) * u, pts[m][1] + (pts[m + 1][1] - pts[m][1]) * u];
|
|
2712
|
-
return
|
|
3335
|
+
return _chunk7EDLVBOOcjs.windingNumber.call(void 0, face2.loops.map((l) => l.segs), q) !== 0;
|
|
2713
3336
|
};
|
|
2714
3337
|
for (let i = 0; i < unique.length - 1; i++) {
|
|
2715
3338
|
const from2 = unique[i];
|
|
@@ -2769,33 +3392,33 @@ function eraserRegion(points, width) {
|
|
|
2769
3392
|
];
|
|
2770
3393
|
}
|
|
2771
3394
|
const line2 = [{ type: "M", x: pts[0][0], y: pts[0][1] }, ...pts.slice(1).map((p) => ({ type: "L", x: p[0], y: p[1] }))];
|
|
2772
|
-
return
|
|
3395
|
+
return _chunk7EDLVBOOcjs.outlineStroke.call(void 0, line2, { width, cap: "round", join: "round" });
|
|
2773
3396
|
}
|
|
2774
3397
|
function eraseFromFill(path, fillRule, region) {
|
|
2775
|
-
const overlap =
|
|
2776
|
-
if (!
|
|
2777
|
-
const rest =
|
|
3398
|
+
const overlap = _chunk7EDLVBOOcjs.pathBoolean.call(void 0, "intersection", [{ path, fillRule }, { path: region }]).path;
|
|
3399
|
+
if (!_chunk7EDLVBOOcjs.pathToContours.call(void 0, overlap).some((c) => Math.abs(_chunk7EDLVBOOcjs.contourSignedArea.call(void 0, _chunk7EDLVBOOcjs.closeContour.call(void 0, c, true))) > 1e-9)) return null;
|
|
3400
|
+
const rest = _chunk7EDLVBOOcjs.pathBoolean.call(void 0, "difference", [{ path, fillRule }, { path: region }]).path;
|
|
2778
3401
|
return splitIntoFaces(rest);
|
|
2779
3402
|
}
|
|
2780
3403
|
function eraseFromOutline(sp, region) {
|
|
2781
|
-
const regionSegs =
|
|
3404
|
+
const regionSegs = _chunk7EDLVBOOcjs.pathToContours.call(void 0, region).flatMap((c) => _chunk7EDLVBOOcjs.closeContour.call(void 0, c, true));
|
|
2782
3405
|
if (!regionSegs.length) return null;
|
|
2783
|
-
const rb =
|
|
3406
|
+
const rb = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, region);
|
|
2784
3407
|
const count = subpathSegmentCount(sp);
|
|
2785
3408
|
if (!rb || count === 0) return null;
|
|
2786
|
-
const removed = (p) =>
|
|
3409
|
+
const removed = (p) => _chunk7EDLVBOOcjs.pointInBezierPath.call(void 0, region, p, "nonzero");
|
|
2787
3410
|
const runs = [];
|
|
2788
3411
|
let cur = [];
|
|
2789
3412
|
let any = false;
|
|
2790
3413
|
for (let i = 0; i < count; i++) {
|
|
2791
3414
|
const seg = subpathSegment(sp, i);
|
|
2792
|
-
const sb =
|
|
3415
|
+
const sb = _chunk7EDLVBOOcjs.segmentBounds.call(void 0, seg);
|
|
2793
3416
|
const ts = [0, 1];
|
|
2794
3417
|
if (!(sb.maxX < rb.minX || sb.minX > rb.maxX || sb.maxY < rb.minY || sb.minY > rb.maxY)) {
|
|
2795
3418
|
for (const r of regionSegs) {
|
|
2796
|
-
const b =
|
|
3419
|
+
const b = _chunk7EDLVBOOcjs.segmentBounds.call(void 0, r);
|
|
2797
3420
|
if (b.maxX < sb.minX || b.minX > sb.maxX || b.maxY < sb.minY || b.minY > sb.maxY) continue;
|
|
2798
|
-
for (const hit of
|
|
3421
|
+
for (const hit of _chunk7EDLVBOOcjs.segmentIntersections.call(void 0, seg, r)) if (hit.ta > 1e-9 && hit.ta < 1 - 1e-9) ts.push(hit.ta);
|
|
2799
3422
|
}
|
|
2800
3423
|
}
|
|
2801
3424
|
ts.sort((a, b) => a - b);
|
|
@@ -2803,7 +3426,7 @@ function eraseFromOutline(sp, region) {
|
|
|
2803
3426
|
const t0 = ts[k];
|
|
2804
3427
|
const t1 = ts[k + 1];
|
|
2805
3428
|
if (t1 - t0 < 1e-9) continue;
|
|
2806
|
-
if (removed(
|
|
3429
|
+
if (removed(_chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, (t0 + t1) / 2))) {
|
|
2807
3430
|
any = true;
|
|
2808
3431
|
if (cur.length) runs.push(cur);
|
|
2809
3432
|
cur = [];
|
|
@@ -2822,7 +3445,7 @@ function eraseFromOutline(sp, region) {
|
|
|
2822
3445
|
for (const run of runs) {
|
|
2823
3446
|
const anchors = [];
|
|
2824
3447
|
for (const { seg, t0, t1 } of run) {
|
|
2825
|
-
const c =
|
|
3448
|
+
const c = _chunk7EDLVBOOcjs.subSegment.call(void 0, subpathSegment(sp, seg), t0, t1);
|
|
2826
3449
|
const line2 = c.length === 2;
|
|
2827
3450
|
const start = c[0];
|
|
2828
3451
|
const end = c[c.length - 1];
|
|
@@ -2939,7 +3562,7 @@ function vectorInkShapeName(shape) {
|
|
|
2939
3562
|
return shape.points.length === 3 ? "triangle" : "polygon";
|
|
2940
3563
|
}
|
|
2941
3564
|
}
|
|
2942
|
-
var
|
|
3565
|
+
var dist3 = (a, b) => Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
2943
3566
|
function bbox(pts) {
|
|
2944
3567
|
if (!pts.length) return [0, 0, 0, 0];
|
|
2945
3568
|
let [x0, y0] = pts[0];
|
|
@@ -2957,7 +3580,7 @@ function segDistance(a, b, p) {
|
|
|
2957
3580
|
const dy = b[1] - a[1];
|
|
2958
3581
|
const len2 = dx * dx + dy * dy;
|
|
2959
3582
|
const t = len2 > 0 ? Math.min(1, Math.max(0, ((p[0] - a[0]) * dx + (p[1] - a[1]) * dy) / len2)) : 0;
|
|
2960
|
-
return
|
|
3583
|
+
return dist3([a[0] + t * dx, a[1] + t * dy], p);
|
|
2961
3584
|
}
|
|
2962
3585
|
function polygonDistance(c, p) {
|
|
2963
3586
|
let best = Infinity;
|
|
@@ -3019,7 +3642,7 @@ function corners(p, diag) {
|
|
|
3019
3642
|
let far = 0;
|
|
3020
3643
|
let farD = 0;
|
|
3021
3644
|
p.forEach((q, i) => {
|
|
3022
|
-
const d =
|
|
3645
|
+
const d = dist3(start, q);
|
|
3023
3646
|
if (d > farD) {
|
|
3024
3647
|
farD = d;
|
|
3025
3648
|
far = i;
|
|
@@ -3046,7 +3669,7 @@ function corners(p, diag) {
|
|
|
3046
3669
|
}
|
|
3047
3670
|
let short = -1;
|
|
3048
3671
|
for (let j = 0; j < n; j++) {
|
|
3049
|
-
if (
|
|
3672
|
+
if (dist3(ring[j], ring[(j + 1) % n]) < 0.1 * diag) {
|
|
3050
3673
|
short = j;
|
|
3051
3674
|
break;
|
|
3052
3675
|
}
|
|
@@ -3086,8 +3709,8 @@ function recognizeInkShape(points, options = {}) {
|
|
|
3086
3709
|
const diag = Math.hypot(w, h);
|
|
3087
3710
|
if (size < minSize) return null;
|
|
3088
3711
|
let length2 = 0;
|
|
3089
|
-
for (let i = 1; i < p.length; i++) length2 +=
|
|
3090
|
-
const gap =
|
|
3712
|
+
for (let i = 1; i < p.length; i++) length2 += dist3(p[i - 1], p[i]);
|
|
3713
|
+
const gap = dist3(first, last);
|
|
3091
3714
|
if (gap > 0.85 * length2 && gap >= minSize) {
|
|
3092
3715
|
const off = Math.max(...p.map((q) => segDistance(first, last, q)));
|
|
3093
3716
|
if (off <= Math.max(0.06 * gap, 1.5 * minSize / 6)) return { kind: "line", a: first, b: last };
|
|
@@ -3111,9 +3734,188 @@ function recognizeInkShape(points, options = {}) {
|
|
|
3111
3734
|
return roundish && rms < 0.1 ? ellipse() : null;
|
|
3112
3735
|
}
|
|
3113
3736
|
|
|
3737
|
+
// src/vector/builder.ts
|
|
3738
|
+
function vectorPathEntries(doc, roots, options = {}) {
|
|
3739
|
+
const out = [];
|
|
3740
|
+
const visit = (node, parent, inside) => {
|
|
3741
|
+
if (node.visible === false || node.locked && !options.locked) return;
|
|
3742
|
+
const picked = inside || roots === null || roots.includes(node.id);
|
|
3743
|
+
if (node.type === "group") {
|
|
3744
|
+
const m = multiplyMatrices(nodeMatrix(node), parent);
|
|
3745
|
+
for (const c of node.children) visit(c, m, picked);
|
|
3746
|
+
} else if (picked) out.push({ node, parent });
|
|
3747
|
+
};
|
|
3748
|
+
for (const n of doc.nodes) visit(n, IDENTITY_MATRIX, false);
|
|
3749
|
+
return out;
|
|
3750
|
+
}
|
|
3751
|
+
var usable = (sp) => sp.anchors.length > 1;
|
|
3752
|
+
function worldOf(entry, subpaths) {
|
|
3753
|
+
return vectorPathWorldBezier({ ...entry.node, subpaths }, entry.parent);
|
|
3754
|
+
}
|
|
3755
|
+
function subpathEnclosesArea(sp) {
|
|
3756
|
+
const contour = _chunk7EDLVBOOcjs.pathToContours.call(void 0, subpathsToBezier([{ ...sp, closed: true }]))[0];
|
|
3757
|
+
if (!contour) return false;
|
|
3758
|
+
const segs = _chunk7EDLVBOOcjs.closeContour.call(void 0, contour, true);
|
|
3759
|
+
const b = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, _chunk7EDLVBOOcjs.contoursToPath.call(void 0, [{ segments: segs, closed: true }]));
|
|
3760
|
+
if (!b) return false;
|
|
3761
|
+
const w = b.maxX - b.minX;
|
|
3762
|
+
const h = b.maxY - b.minY;
|
|
3763
|
+
return Math.abs(_chunk7EDLVBOOcjs.contourSignedArea.call(void 0, segs)) > 1e-9 * (w * w + h * h);
|
|
3764
|
+
}
|
|
3765
|
+
var paintKey = (paint) => typeof paint === "string" ? paint.trim().toLowerCase() : JSON.stringify(_nullishCoalesce(paint, () => ( null)));
|
|
3766
|
+
function vectorPathfinderShape(entry, op) {
|
|
3767
|
+
const { node } = entry;
|
|
3768
|
+
const subpaths = node.subpaths.filter(usable);
|
|
3769
|
+
const closed = subpaths.map((s) => ({ ...s, closed: true }));
|
|
3770
|
+
const fillRule = _nullishCoalesce(node.fillRule, () => ( "nonzero"));
|
|
3771
|
+
if (hasPaint(node.fill)) return { path: worldOf(entry, closed), fillRule, key: `fill:${paintKey(node.fill)}`, paint: "fill" };
|
|
3772
|
+
const open = subpaths.length > 0 && subpaths.every((s) => !s.closed);
|
|
3773
|
+
if (op === "divide" && open) return { path: worldOf(entry, subpaths), line: true, paint: "line" };
|
|
3774
|
+
if (hasPaint(node.stroke) && (_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0) {
|
|
3775
|
+
const path = vectorStrokeOutline({ ...node, subpaths }, entry.parent);
|
|
3776
|
+
return { path, fillRule: "nonzero", key: `fill:${paintKey(node.stroke)}`, paint: "stroke" };
|
|
3777
|
+
}
|
|
3778
|
+
return { path: worldOf(entry, closed), fillRule, key: "none", paint: "outline" };
|
|
3779
|
+
}
|
|
3780
|
+
var STROKE_KEYS = [
|
|
3781
|
+
"stroke",
|
|
3782
|
+
"strokeWidth",
|
|
3783
|
+
"strokeLinecap",
|
|
3784
|
+
"strokeLinejoin",
|
|
3785
|
+
"strokeDasharray",
|
|
3786
|
+
"strokeAlign",
|
|
3787
|
+
"startArrow",
|
|
3788
|
+
"endArrow",
|
|
3789
|
+
"arrowAlign",
|
|
3790
|
+
"startArrowScale",
|
|
3791
|
+
"endArrowScale",
|
|
3792
|
+
"strokeWidthProfile"
|
|
3793
|
+
];
|
|
3794
|
+
function vectorResultStyle(node, paint, edge = false) {
|
|
3795
|
+
const { id: _id, subpaths: _s, transform: _t, ...rest } = node;
|
|
3796
|
+
const base = { ...rest, fillRule: "nonzero" };
|
|
3797
|
+
if (edge) {
|
|
3798
|
+
for (const k of STROKE_KEYS) delete base[k];
|
|
3799
|
+
const stroke = paint === "stroke" || !hasPaint(node.fill) ? node.stroke : node.fill;
|
|
3800
|
+
return { ...base, fill: null, stroke: _nullishCoalesce(stroke, () => ( "#000000")), strokeWidth: _nullishCoalesce(node.strokeWidth, () => ( 1)) };
|
|
3801
|
+
}
|
|
3802
|
+
if (paint === "stroke") {
|
|
3803
|
+
for (const k of STROKE_KEYS) delete base[k];
|
|
3804
|
+
return { ...base, fill: _nullishCoalesce(node.stroke, () => ( null)), stroke: null };
|
|
3805
|
+
}
|
|
3806
|
+
return base;
|
|
3807
|
+
}
|
|
3808
|
+
function vectorShapeBuilderMap(entries) {
|
|
3809
|
+
const lines = [];
|
|
3810
|
+
const inputs = entries.map((entry) => {
|
|
3811
|
+
const filled = hasPaint(entry.node.fill);
|
|
3812
|
+
const subpaths = entry.node.subpaths.filter(usable).map((sp) => !sp.closed && filled && subpathEnclosesArea(sp) ? { ...sp, closed: true } : sp);
|
|
3813
|
+
lines.push(!subpaths.some((s) => s.closed));
|
|
3814
|
+
return { path: worldOf(entry, subpaths), fillRule: _nullishCoalesce(entry.node.fillRule, () => ( "nonzero")) };
|
|
3815
|
+
});
|
|
3816
|
+
const map = _chunk7EDLVBOOcjs.PlanarMap.build(inputs);
|
|
3817
|
+
if (!map) return null;
|
|
3818
|
+
const pieces = map.chains().filter((c) => lines[c.source] && !c.closed).map((c) => {
|
|
3819
|
+
const path = _chunk7EDLVBOOcjs.contoursToPath.call(void 0, [{ segments: c.segments, closed: false }]);
|
|
3820
|
+
return { path, segments: c.segments, source: c.source, bounds: _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, path) };
|
|
3821
|
+
});
|
|
3822
|
+
return { entries: [...entries], map, lines, pieces };
|
|
3823
|
+
}
|
|
3824
|
+
function vectorShapeBuilderHit(m, p, lineTolerance = null) {
|
|
3825
|
+
const point = [p.x, p.y];
|
|
3826
|
+
if (lineTolerance !== null && lineTolerance > 0) {
|
|
3827
|
+
let best = -1;
|
|
3828
|
+
let bestD = lineTolerance;
|
|
3829
|
+
m.pieces.forEach((piece, i) => {
|
|
3830
|
+
const b = piece.bounds;
|
|
3831
|
+
if (p.x < b.minX - bestD || p.x > b.maxX + bestD || p.y < b.minY - bestD || p.y > b.maxY + bestD) return;
|
|
3832
|
+
const d = _chunk7EDLVBOOcjs.distanceToBezierPath.call(void 0, piece.path, point);
|
|
3833
|
+
if (d <= bestD) {
|
|
3834
|
+
best = i;
|
|
3835
|
+
bestD = d;
|
|
3836
|
+
}
|
|
3837
|
+
});
|
|
3838
|
+
if (best >= 0) return { line: best };
|
|
3839
|
+
}
|
|
3840
|
+
const face = m.map.faceAt(point);
|
|
3841
|
+
return face >= 0 ? { face } : null;
|
|
3842
|
+
}
|
|
3843
|
+
function samplePolyline(points, step) {
|
|
3844
|
+
const out = [];
|
|
3845
|
+
const s = Math.max(step, 1e-3);
|
|
3846
|
+
points.forEach((p, i) => {
|
|
3847
|
+
if (i > 0) {
|
|
3848
|
+
const a = points[i - 1];
|
|
3849
|
+
const n = Math.min(4e3, Math.ceil(Math.hypot(p.x - a.x, p.y - a.y) / s));
|
|
3850
|
+
for (let k = 1; k < n; k++) out.push({ x: a.x + (p.x - a.x) * k / n, y: a.y + (p.y - a.y) * k / n });
|
|
3851
|
+
}
|
|
3852
|
+
out.push(p);
|
|
3853
|
+
});
|
|
3854
|
+
return out;
|
|
3855
|
+
}
|
|
3856
|
+
function addBuilderHit(touched, hit) {
|
|
3857
|
+
if (!hit) return false;
|
|
3858
|
+
const [list, i] = "face" in hit ? [touched.faces, hit.face] : [touched.lines, hit.line];
|
|
3859
|
+
if (list.includes(i)) return false;
|
|
3860
|
+
list.push(i);
|
|
3861
|
+
return true;
|
|
3862
|
+
}
|
|
3863
|
+
function sides(m, piece) {
|
|
3864
|
+
const seg = piece.segments[Math.floor(piece.segments.length / 2)];
|
|
3865
|
+
const mid = _chunk7EDLVBOOcjs.segmentPoint.call(void 0, seg, 0.5);
|
|
3866
|
+
const t = _chunk7EDLVBOOcjs.segmentTangent.call(void 0, seg, 0.5);
|
|
3867
|
+
const chord = Math.hypot(seg[seg.length - 1][0] - seg[0][0], seg[seg.length - 1][1] - seg[0][1]);
|
|
3868
|
+
const off = Math.max(1e-6, Math.min(0.05, 0.05 * chord));
|
|
3869
|
+
return [m.map.faceAt([mid[0] - t[1] * off, mid[1] + t[0] * off]), m.map.faceAt([mid[0] + t[1] * off, mid[1] - t[0] * off])];
|
|
3870
|
+
}
|
|
3871
|
+
function planShapeBuilder(m, touched, erase) {
|
|
3872
|
+
const replace = /* @__PURE__ */ new Map();
|
|
3873
|
+
const picked = new Set(touched.faces);
|
|
3874
|
+
const faces = m.map.faces;
|
|
3875
|
+
const sourcesOf = faces.map((_, i) => m.map.faceSources(i));
|
|
3876
|
+
m.entries.forEach((_, i) => {
|
|
3877
|
+
if (m.lines[i]) {
|
|
3878
|
+
const own = m.pieces.flatMap((piece, k) => piece.source === i ? [k] : []);
|
|
3879
|
+
const keep = own.filter((k) => !touched.lines.includes(k) && !sides(m, m.pieces[k]).every((f) => f >= 0 && picked.has(f)));
|
|
3880
|
+
if (keep.length === own.length) return;
|
|
3881
|
+
replace.set(i, keep.length ? { kind: "pieces", paths: keep.map((k) => m.pieces[k].path) } : null);
|
|
3882
|
+
return;
|
|
3883
|
+
}
|
|
3884
|
+
if (!touched.faces.some((f) => sourcesOf[f].includes(i))) return;
|
|
3885
|
+
const kept = faces.flatMap((_2, f) => sourcesOf[f].includes(i) && !picked.has(f) ? [f] : []);
|
|
3886
|
+
const rest = kept.length ? m.map.merge(kept) : [];
|
|
3887
|
+
replace.set(i, rest.length ? { kind: "fill", path: rest } : null);
|
|
3888
|
+
});
|
|
3889
|
+
let merged = null;
|
|
3890
|
+
if (!erase && touched.faces.length) {
|
|
3891
|
+
const path = m.map.merge(touched.faces);
|
|
3892
|
+
const covered = touched.faces.map((f) => sourcesOf[f]).find((s) => s.length);
|
|
3893
|
+
const lastShape = m.lines.lastIndexOf(false);
|
|
3894
|
+
const style = covered ? covered[covered.length - 1] : lastShape >= 0 ? lastShape : m.entries.length - 1;
|
|
3895
|
+
if (path.length) merged = { path, style, currentFill: !covered };
|
|
3896
|
+
}
|
|
3897
|
+
return { replace, merged };
|
|
3898
|
+
}
|
|
3899
|
+
function vectorFillMap(doc, gap = 0) {
|
|
3900
|
+
const entries = vectorPathEntries(doc, null, { locked: true });
|
|
3901
|
+
return _chunk7EDLVBOOcjs.PlanarMap.build(
|
|
3902
|
+
entries.map((e) => ({ path: worldOf(e, e.node.subpaths.filter(usable)), fills: false })),
|
|
3903
|
+
{ gap, maxSegments: 2e4 }
|
|
3904
|
+
);
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3114
3907
|
// src/vector/controller.ts
|
|
3115
3908
|
var DEFAULT_VECTOR_SNAP = { grid: 0, objects: true, guides: true, threshold: 5, angles: VECTOR_CONSTRUCTION_ANGLES };
|
|
3116
|
-
var
|
|
3909
|
+
var VECTOR_FILL_GAP = 6;
|
|
3910
|
+
var DEFAULT_VECTOR_PATH_EDIT = {
|
|
3911
|
+
keepShapeOnDelete: true,
|
|
3912
|
+
curvatureMoves: false,
|
|
3913
|
+
pencilSmoothing: 0,
|
|
3914
|
+
recognizeShapes: false,
|
|
3915
|
+
eraserSize: 10,
|
|
3916
|
+
pencilPressure: "pen",
|
|
3917
|
+
fillGap: 0
|
|
3918
|
+
};
|
|
3117
3919
|
var VECTOR_PENCIL_STRING_PX = 100;
|
|
3118
3920
|
var VECTOR_STYLE_KEYS = [
|
|
3119
3921
|
"fill",
|
|
@@ -3128,7 +3930,8 @@ var VECTOR_STYLE_KEYS = [
|
|
|
3128
3930
|
"endArrow",
|
|
3129
3931
|
"arrowAlign",
|
|
3130
3932
|
"startArrowScale",
|
|
3131
|
-
"endArrowScale"
|
|
3933
|
+
"endArrowScale",
|
|
3934
|
+
"strokeWidthProfile"
|
|
3132
3935
|
];
|
|
3133
3936
|
var VECTOR_CLIPBOARD_TYPE = "pixerate/vector";
|
|
3134
3937
|
var DEFAULT_DEFAULTS = {
|
|
@@ -3157,7 +3960,7 @@ function getEditablePathIds(state) {
|
|
|
3157
3960
|
}
|
|
3158
3961
|
}
|
|
3159
3962
|
}
|
|
3160
|
-
return [...ids].filter((id) => _optionalChain([findVectorNode, 'call',
|
|
3963
|
+
return [...ids].filter((id) => _optionalChain([findVectorNode, 'call', _63 => _63(state.document.nodes, id), 'optionalAccess', _64 => _64.type]) === "path");
|
|
3161
3964
|
}
|
|
3162
3965
|
function getVisibleAnchors(state) {
|
|
3163
3966
|
const out = [];
|
|
@@ -3172,7 +3975,7 @@ function getVisibleHandles(state) {
|
|
|
3172
3975
|
const seen = /* @__PURE__ */ new Set();
|
|
3173
3976
|
const push = (node, s, i, handle) => {
|
|
3174
3977
|
const sp = node.subpaths[s];
|
|
3175
|
-
const a = _optionalChain([sp, 'optionalAccess',
|
|
3978
|
+
const a = _optionalChain([sp, 'optionalAccess', _65 => _65.anchors, 'access', _66 => _66[i]]);
|
|
3176
3979
|
if (!a || !a[handle]) return;
|
|
3177
3980
|
const key = `${node.id}:${s}:${i}:${handle}`;
|
|
3178
3981
|
if (seen.has(key)) return;
|
|
@@ -3181,8 +3984,8 @@ function getVisibleHandles(state) {
|
|
|
3181
3984
|
};
|
|
3182
3985
|
if (state.tool === "pen" && state.pen) {
|
|
3183
3986
|
const node = findVectorNode(state.document.nodes, state.pen.nodeId);
|
|
3184
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
3185
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
3987
|
+
const sp = _optionalChain([node, 'optionalAccess', _67 => _67.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
|
|
3988
|
+
if (_optionalChain([node, 'optionalAccess', _68 => _68.type]) === "path" && sp) {
|
|
3186
3989
|
const last = sp.anchors.length - 1;
|
|
3187
3990
|
push(node, state.pen.subpath, last, "in");
|
|
3188
3991
|
push(node, state.pen.subpath, last, "out");
|
|
@@ -3190,9 +3993,9 @@ function getVisibleHandles(state) {
|
|
|
3190
3993
|
return out;
|
|
3191
3994
|
}
|
|
3192
3995
|
if (state.tool !== "direct") return out;
|
|
3193
|
-
const
|
|
3996
|
+
const editable2 = new Set(getEditablePathIds(state));
|
|
3194
3997
|
for (const ref of state.selectedAnchors) {
|
|
3195
|
-
if (!
|
|
3998
|
+
if (!editable2.has(ref.nodeId)) continue;
|
|
3196
3999
|
const node = findVectorNode(state.document.nodes, ref.nodeId);
|
|
3197
4000
|
const sp = node.subpaths[ref.subpath];
|
|
3198
4001
|
if (!sp) continue;
|
|
@@ -3220,18 +4023,68 @@ function getVectorCornerWidgets(state) {
|
|
|
3220
4023
|
const side = Math.min(c.lu, c.lv);
|
|
3221
4024
|
if (side * zoom < 3 * VECTOR_CORNER_WIDGET_INSET) continue;
|
|
3222
4025
|
const a = node.subpaths[c.subpath].anchors[c.index];
|
|
3223
|
-
const radius = _nullishCoalesce(_optionalChain([a, 'access',
|
|
4026
|
+
const radius = _nullishCoalesce(_optionalChain([a, 'access', _69 => _69.corner, 'optionalAccess', _70 => _70.radius]), () => ( 0));
|
|
3224
4027
|
const drawn = fitCornerRadius(c, radius);
|
|
3225
4028
|
const k = Math.min(Math.max(drawn / c.sin, VECTOR_CORNER_WIDGET_INSET / (zoom * Math.sqrt(1 + c.cos))), side / 2);
|
|
3226
4029
|
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',
|
|
4030
|
+
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', _71 => _71.corner, 'optionalAccess', _72 => _72.kind]), () => ( "round")), corner: c });
|
|
4031
|
+
}
|
|
4032
|
+
}
|
|
4033
|
+
return out;
|
|
4034
|
+
}
|
|
4035
|
+
function vectorStrokeWidthGeometry(node) {
|
|
4036
|
+
if (!hasPaint(node.stroke) || !((_nullishCoalesce(node.strokeWidth, () => ( 1))) > 0)) return null;
|
|
4037
|
+
const parts = vectorStrokeParts(subpathsToBezier(node.subpaths), node);
|
|
4038
|
+
return parts.line.length ? { line: parts.line, unit: parts.drawWidth / 2 } : null;
|
|
4039
|
+
}
|
|
4040
|
+
function getVectorWidthHandles(state) {
|
|
4041
|
+
if (state.tool !== "width") return [];
|
|
4042
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4043
|
+
for (const id of state.selection) {
|
|
4044
|
+
const n = findVectorNode(state.document.nodes, id);
|
|
4045
|
+
if (n) for (const p of collectPathNodes(n)) ids.add(p.id);
|
|
4046
|
+
}
|
|
4047
|
+
if (_optionalChain([state, 'access', _73 => _73.hover, 'optionalAccess', _74 => _74.nodeId])) ids.add(state.hover.nodeId);
|
|
4048
|
+
if (_optionalChain([state, 'access', _75 => _75.interaction, 'optionalAccess', _76 => _76.type]) === "width") ids.add(state.interaction.ref.nodeId);
|
|
4049
|
+
if (state.selectedWidthPoint) ids.add(state.selectedWidthPoint.nodeId);
|
|
4050
|
+
const out = [];
|
|
4051
|
+
for (const id of ids) {
|
|
4052
|
+
const node = findVectorNode(state.document.nodes, id);
|
|
4053
|
+
if (_optionalChain([node, 'optionalAccess', _77 => _77.type]) !== "path" || node.visible === false || !_optionalChain([node, 'access', _78 => _78.strokeWidthProfile, 'optionalAccess', _79 => _79.length])) continue;
|
|
4054
|
+
const g = vectorStrokeWidthGeometry(node);
|
|
4055
|
+
if (!g) continue;
|
|
4056
|
+
const profile = sanitizeWidthProfile(node.strokeWidthProfile);
|
|
4057
|
+
const m = _nullishCoalesce(vectorWorldMatrix(state.document.nodes, id), () => ( IDENTITY_MATRIX));
|
|
4058
|
+
const contours = node.subpaths.length;
|
|
4059
|
+
for (let sp = 0; sp < contours; sp++) {
|
|
4060
|
+
profile.forEach((w, index) => {
|
|
4061
|
+
const at2 = strokePositionPoint(g.line, sp, w.t);
|
|
4062
|
+
if (!at2) return;
|
|
4063
|
+
const n = { x: at2.tangent[1], y: -at2.tangent[0] };
|
|
4064
|
+
const c = { x: at2.point[0], y: at2.point[1] };
|
|
4065
|
+
const p = applyMatrix(m, c);
|
|
4066
|
+
const l = applyMatrix(m, { x: c.x + n.x * w.left * g.unit, y: c.y + n.y * w.left * g.unit });
|
|
4067
|
+
const r = applyMatrix(m, { x: c.x - n.x * w.right * g.unit, y: c.y - n.y * w.right * g.unit });
|
|
4068
|
+
const sel = state.selectedWidthPoint;
|
|
4069
|
+
out.push({
|
|
4070
|
+
ref: { nodeId: id, index, subpath: sp },
|
|
4071
|
+
x: p.x,
|
|
4072
|
+
y: p.y,
|
|
4073
|
+
left: l,
|
|
4074
|
+
right: r,
|
|
4075
|
+
t: w.t,
|
|
4076
|
+
leftScale: w.left,
|
|
4077
|
+
rightScale: w.right,
|
|
4078
|
+
selected: !!sel && sel.nodeId === id && sel.index === index
|
|
4079
|
+
});
|
|
4080
|
+
});
|
|
3228
4081
|
}
|
|
3229
4082
|
}
|
|
3230
4083
|
return out;
|
|
3231
4084
|
}
|
|
3232
4085
|
function getAnchor(doc, ref) {
|
|
3233
4086
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
3234
|
-
return _optionalChain([node, 'optionalAccess',
|
|
4087
|
+
return _optionalChain([node, 'optionalAccess', _80 => _80.type]) === "path" ? _optionalChain([node, 'access', _81 => _81.subpaths, 'access', _82 => _82[ref.subpath], 'optionalAccess', _83 => _83.anchors, 'access', _84 => _84[ref.index]]) : void 0;
|
|
3235
4088
|
}
|
|
3236
4089
|
function getAnchorWorld(doc, ref) {
|
|
3237
4090
|
const a = getAnchor(doc, ref);
|
|
@@ -3299,9 +4152,28 @@ var TOOL_LABELS = {
|
|
|
3299
4152
|
line: "Line",
|
|
3300
4153
|
scissors: "Scissors",
|
|
3301
4154
|
knife: "Knife",
|
|
3302
|
-
eraser: "Eraser"
|
|
4155
|
+
eraser: "Eraser",
|
|
4156
|
+
width: "Width",
|
|
4157
|
+
shapeBuilder: "Shape Builder",
|
|
4158
|
+
paintBucket: "Paint Bucket"
|
|
4159
|
+
};
|
|
4160
|
+
var TOOL_KEYS = {
|
|
4161
|
+
v: "select",
|
|
4162
|
+
a: "direct",
|
|
4163
|
+
p: "pen",
|
|
4164
|
+
n: "pencil",
|
|
4165
|
+
r: "rect",
|
|
4166
|
+
o: "ellipse",
|
|
4167
|
+
y: "polygon",
|
|
4168
|
+
s: "star",
|
|
4169
|
+
l: "line",
|
|
4170
|
+
c: "scissors",
|
|
4171
|
+
k: "knife",
|
|
4172
|
+
e: "eraser",
|
|
4173
|
+
w: "width",
|
|
4174
|
+
m: "shapeBuilder",
|
|
4175
|
+
b: "paintBucket"
|
|
3303
4176
|
};
|
|
3304
|
-
var TOOL_KEYS = { v: "select", a: "direct", p: "pen", n: "pencil", r: "rect", o: "ellipse", y: "polygon", s: "star", l: "line", c: "scissors", k: "knife", e: "eraser" };
|
|
3305
4177
|
function vectorToolLabel(tool) {
|
|
3306
4178
|
return TOOL_LABELS[tool];
|
|
3307
4179
|
}
|
|
@@ -3317,7 +4189,10 @@ var VECTOR_TOOL_SHORTCUTS = {
|
|
|
3317
4189
|
line: "L",
|
|
3318
4190
|
scissors: "C",
|
|
3319
4191
|
knife: "K",
|
|
3320
|
-
eraser: "E"
|
|
4192
|
+
eraser: "E",
|
|
4193
|
+
width: "W",
|
|
4194
|
+
shapeBuilder: "M",
|
|
4195
|
+
paintBucket: "B"
|
|
3321
4196
|
};
|
|
3322
4197
|
var VECTOR_TOOL_GLYPHS = {
|
|
3323
4198
|
select: "\u2196",
|
|
@@ -3331,7 +4206,10 @@ var VECTOR_TOOL_GLYPHS = {
|
|
|
3331
4206
|
line: "\u2571",
|
|
3332
4207
|
scissors: "\u2702",
|
|
3333
4208
|
knife: "\u27CB",
|
|
3334
|
-
eraser: "\u232B"
|
|
4209
|
+
eraser: "\u232B",
|
|
4210
|
+
width: "\u21F9",
|
|
4211
|
+
shapeBuilder: "\u2295",
|
|
4212
|
+
paintBucket: "\u25CD"
|
|
3335
4213
|
};
|
|
3336
4214
|
var SHAPE_TOOLS = /* @__PURE__ */ new Set(["rect", "ellipse", "polygon", "star", "line"]);
|
|
3337
4215
|
var BOOLEAN_OPS = {
|
|
@@ -3341,6 +4219,14 @@ var BOOLEAN_OPS = {
|
|
|
3341
4219
|
exclude: "xor"
|
|
3342
4220
|
};
|
|
3343
4221
|
var BOOLEAN_LABELS = { union: "Union", subtract: "Subtract", intersect: "Intersect", exclude: "Exclude" };
|
|
4222
|
+
var VECTOR_PATHFINDER_LABELS = {
|
|
4223
|
+
divide: "Divide",
|
|
4224
|
+
trim: "Trim",
|
|
4225
|
+
merge: "Merge",
|
|
4226
|
+
crop: "Crop",
|
|
4227
|
+
outline: "Outline",
|
|
4228
|
+
minusBack: "Minus Back"
|
|
4229
|
+
};
|
|
3344
4230
|
function mapTree(nodes, fn) {
|
|
3345
4231
|
let changed = false;
|
|
3346
4232
|
const out = [];
|
|
@@ -3385,35 +4271,43 @@ var VectorEditorController = (_class3 = class {
|
|
|
3385
4271
|
|
|
3386
4272
|
__init9() {this.selection = []}
|
|
3387
4273
|
__init10() {this.anchors = []}
|
|
3388
|
-
__init11() {this.
|
|
3389
|
-
__init12() {this.
|
|
4274
|
+
__init11() {this.widthPoint = null}
|
|
4275
|
+
__init12() {this.editingId = null}
|
|
4276
|
+
__init13() {this.pen = null}
|
|
3390
4277
|
|
|
3391
4278
|
|
|
3392
4279
|
|
|
3393
4280
|
|
|
3394
4281
|
|
|
3395
4282
|
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
4283
|
+
__init14() {this.hover = null}
|
|
4284
|
+
__init15() {this.pointer = null}
|
|
4285
|
+
__init16() {this.drag = null}
|
|
4286
|
+
__init17() {this.interaction = null}
|
|
4287
|
+
__init18() {this.guides = null}
|
|
3401
4288
|
/** Whether the last `snapDrawn` landed on an object (guides may be hidden). */
|
|
3402
|
-
|
|
4289
|
+
__init19() {this.snappedToObject = false}
|
|
3403
4290
|
/** Drawing targets for hovering the pen and shape tools, kept while the document and the excluded path stay the same. */
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
4291
|
+
__init20() {this.hoverTargets = null}
|
|
4292
|
+
__init21() {this.spaceHeld = false}
|
|
4293
|
+
__init22() {this.clipboard = null}
|
|
4294
|
+
/** Shape Builder map of the selection, kept while the document and the selection stay the same. */
|
|
4295
|
+
__init23() {this.builderCache = null}
|
|
4296
|
+
/** Paint bucket map of the visible outlines. */
|
|
4297
|
+
__init24() {this.fillCache = null}
|
|
4298
|
+
__init25() {this.builderPreview = null}
|
|
4299
|
+
/** What the highlight shows, to skip notifying when the pointer stays over the same face. */
|
|
4300
|
+
__init26() {this.builderHoverKey = null}
|
|
3407
4301
|
|
|
3408
4302
|
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
4303
|
+
__init27() {this.listeners = /* @__PURE__ */ new Set()}
|
|
4304
|
+
__init28() {this.cleanups = []}
|
|
4305
|
+
__init29() {this.applying = false}
|
|
3412
4306
|
/** Set while a commit records a change that was already applied, so `restore` still reports it. */
|
|
3413
|
-
|
|
3414
|
-
|
|
4307
|
+
__init30() {this.committing = false}
|
|
4308
|
+
__init31() {this.revision = 0}
|
|
3415
4309
|
|
|
3416
|
-
constructor(options = {}) {;_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);_class3.prototype.__init21.call(this);_class3.prototype.__init22.call(this);_class3.prototype.__init23.call(this);_class3.prototype.__init24.call(this);_class3.prototype.__init25.call(this);_class3.prototype.__init26.call(this);_class3.prototype.__init27.call(this);_class3.prototype.__init28.call(this);
|
|
4310
|
+
constructor(options = {}) {;_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);_class3.prototype.__init11.call(this);_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);_class3.prototype.__init15.call(this);_class3.prototype.__init16.call(this);_class3.prototype.__init17.call(this);_class3.prototype.__init18.call(this);_class3.prototype.__init19.call(this);_class3.prototype.__init20.call(this);_class3.prototype.__init21.call(this);_class3.prototype.__init22.call(this);_class3.prototype.__init23.call(this);_class3.prototype.__init24.call(this);_class3.prototype.__init25.call(this);_class3.prototype.__init26.call(this);_class3.prototype.__init27.call(this);_class3.prototype.__init28.call(this);_class3.prototype.__init29.call(this);_class3.prototype.__init30.call(this);_class3.prototype.__init31.call(this);_class3.prototype.__init32.call(this);_class3.prototype.__init33.call(this);
|
|
3417
4311
|
this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkQKLRAA4Tcjs.HistoryManager)()));
|
|
3418
4312
|
this.doc = options.document ? cloneVectorDocument(options.document) : { width: 800, height: 600, nodes: [] };
|
|
3419
4313
|
this.tool = _nullishCoalesce(options.tool, () => ( "select"));
|
|
@@ -3442,9 +4336,9 @@ var VectorEditorController = (_class3 = class {
|
|
|
3442
4336
|
// State
|
|
3443
4337
|
// -------------------------------------------------------------------------
|
|
3444
4338
|
/** The current snapshot (stable until the next change). */
|
|
3445
|
-
|
|
4339
|
+
__init32() {this.getState = () => this.state}
|
|
3446
4340
|
/** Calls `listener` after every change. Returns an unsubscribe function. */
|
|
3447
|
-
|
|
4341
|
+
__init33() {this.subscribe = (listener) => {
|
|
3448
4342
|
this.listeners.add(listener);
|
|
3449
4343
|
return () => {
|
|
3450
4344
|
this.listeners.delete(listener);
|
|
@@ -3463,6 +4357,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3463
4357
|
tool: this.tool,
|
|
3464
4358
|
selection: this.selection,
|
|
3465
4359
|
selectedAnchors: this.anchors,
|
|
4360
|
+
selectedWidthPoint: this.widthPoint,
|
|
3466
4361
|
editingId: this.editingId,
|
|
3467
4362
|
selectionBounds: this.boundsOf(this.selection),
|
|
3468
4363
|
selectionFrame: this.frameOf(this.selectedRoots()),
|
|
@@ -3477,6 +4372,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3477
4372
|
interaction: this.interaction,
|
|
3478
4373
|
pen: this.pen,
|
|
3479
4374
|
pointer: this.pointer,
|
|
4375
|
+
builder: this.builderPreview,
|
|
3480
4376
|
canUndo: h.canUndo,
|
|
3481
4377
|
canRedo: h.canRedo,
|
|
3482
4378
|
undoLabel: h.undoName,
|
|
@@ -3487,7 +4383,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3487
4383
|
notify(docChanged = false) {
|
|
3488
4384
|
this.revision++;
|
|
3489
4385
|
this.state = this.computeState();
|
|
3490
|
-
if (docChanged) _optionalChain([this, 'access',
|
|
4386
|
+
if (docChanged) _optionalChain([this, 'access', _85 => _85.onChange, 'optionalCall', _86 => _86(this.doc)]);
|
|
3491
4387
|
const state = this.state;
|
|
3492
4388
|
this.listeners.forEach((listener) => {
|
|
3493
4389
|
try {
|
|
@@ -3517,20 +4413,29 @@ var VectorEditorController = (_class3 = class {
|
|
|
3517
4413
|
return applyMatrix(invertMatrix(this.worldOf(id, doc)), p);
|
|
3518
4414
|
}
|
|
3519
4415
|
cursorFor() {
|
|
3520
|
-
if (_optionalChain([this, 'access',
|
|
3521
|
-
if (_optionalChain([this, 'access',
|
|
3522
|
-
if (_optionalChain([this, 'access',
|
|
4416
|
+
if (_optionalChain([this, 'access', _87 => _87.drag, 'optionalAccess', _88 => _88.kind]) === "pan" || this.spaceHeld) return this.drag ? "grabbing" : "grab";
|
|
4417
|
+
if (_optionalChain([this, 'access', _89 => _89.drag, 'optionalAccess', _90 => _90.kind]) === "rotate") return "grabbing";
|
|
4418
|
+
if (_optionalChain([this, 'access', _91 => _91.drag, 'optionalAccess', _92 => _92.kind]) === "move") return "move";
|
|
3523
4419
|
const h = this.hover;
|
|
3524
4420
|
switch (this.tool) {
|
|
3525
4421
|
case "select":
|
|
3526
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
3527
|
-
return _optionalChain([h, 'optionalAccess',
|
|
4422
|
+
if (_optionalChain([h, 'optionalAccess', _93 => _93.transformHandle])) return vectorResizeCursor(h.transformHandle, _nullishCoalesce(_optionalChain([this, 'access', _94 => _94.frameOf, 'call', _95 => _95(this.selectedRoots()), 'optionalAccess', _96 => _96.angle]), () => ( 0)));
|
|
4423
|
+
return _optionalChain([h, 'optionalAccess', _97 => _97.nodeId]) ? "move" : "default";
|
|
3528
4424
|
case "direct":
|
|
3529
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
3530
|
-
if (_optionalChain([h, 'optionalAccess',
|
|
3531
|
-
return _optionalChain([h, 'optionalAccess',
|
|
4425
|
+
if (_optionalChain([h, 'optionalAccess', _98 => _98.anchor]) || _optionalChain([h, 'optionalAccess', _99 => _99.handle]) || _optionalChain([h, 'optionalAccess', _100 => _100.corner])) return "pointer";
|
|
4426
|
+
if (_optionalChain([h, 'optionalAccess', _101 => _101.segment])) return "copy";
|
|
4427
|
+
return _optionalChain([h, 'optionalAccess', _102 => _102.nodeId]) ? "move" : "default";
|
|
3532
4428
|
case "pen":
|
|
3533
|
-
return _optionalChain([h, 'optionalAccess',
|
|
4429
|
+
return _optionalChain([h, 'optionalAccess', _103 => _103.anchor]) ? "pointer" : "crosshair";
|
|
4430
|
+
case "width":
|
|
4431
|
+
if (_optionalChain([this, 'access', _104 => _104.drag, 'optionalAccess', _105 => _105.kind]) === "width") return this.drag.mode === "move" ? "grabbing" : "ew-resize";
|
|
4432
|
+
if (_optionalChain([h, 'optionalAccess', _106 => _106.widthPoint])) return h.widthPoint.part === "center" ? "grab" : "ew-resize";
|
|
4433
|
+
return _optionalChain([h, 'optionalAccess', _107 => _107.strokeSpot]) ? "copy" : "default";
|
|
4434
|
+
case "shapeBuilder":
|
|
4435
|
+
if (!_optionalChain([this, 'access', _108 => _108.builderPreview, 'optionalAccess', _109 => _109.faces, 'access', _110 => _110.length]) && !_optionalChain([this, 'access', _111 => _111.builderPreview, 'optionalAccess', _112 => _112.lines, 'access', _113 => _113.length])) return "crosshair";
|
|
4436
|
+
return this.builderPreview.mode === "erase" ? "not-allowed" : "cell";
|
|
4437
|
+
case "paintBucket":
|
|
4438
|
+
return this.builderPreview ? "cell" : "crosshair";
|
|
3534
4439
|
default:
|
|
3535
4440
|
return "crosshair";
|
|
3536
4441
|
}
|
|
@@ -3550,7 +4455,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3550
4455
|
this.selection = s.selection.filter((id) => this.getNode(id));
|
|
3551
4456
|
this.anchors = s.anchors.filter((r) => getAnchor(this.doc, r));
|
|
3552
4457
|
this.editingId = s.editingId && this.getNode(s.editingId) ? s.editingId : null;
|
|
3553
|
-
this.pen = s.pen && _optionalChain([this, 'access',
|
|
4458
|
+
this.pen = s.pen && _optionalChain([this, 'access', _114 => _114.getNode, 'call', _115 => _115(s.pen.nodeId), 'optionalAccess', _116 => _116.subpaths, 'optionalAccess', _117 => _117[s.pen.subpath]]) ? s.pen : null;
|
|
3554
4459
|
} finally {
|
|
3555
4460
|
this.applying = false;
|
|
3556
4461
|
}
|
|
@@ -3656,6 +4561,9 @@ var VectorEditorController = (_class3 = class {
|
|
|
3656
4561
|
this.tool = tool;
|
|
3657
4562
|
this.hover = null;
|
|
3658
4563
|
this.guides = null;
|
|
4564
|
+
this.widthPoint = null;
|
|
4565
|
+
this.builderPreview = null;
|
|
4566
|
+
this.builderHoverKey = null;
|
|
3659
4567
|
if (tool !== "direct") {
|
|
3660
4568
|
this.anchors = [];
|
|
3661
4569
|
this.editingId = null;
|
|
@@ -3714,7 +4622,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3714
4622
|
if (res.kind) {
|
|
3715
4623
|
this.snappedToObject = true;
|
|
3716
4624
|
this.setGuides(res);
|
|
3717
|
-
return _optionalChain([leave, 'optionalAccess',
|
|
4625
|
+
return _optionalChain([leave, 'optionalAccess', _118 => _118.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) };
|
|
3718
4626
|
}
|
|
3719
4627
|
}
|
|
3720
4628
|
this.setGuides(null);
|
|
@@ -3732,14 +4640,14 @@ var VectorEditorController = (_class3 = class {
|
|
|
3732
4640
|
/** Where the pointer at `p` would place a point with the pen or a shape tool (and the guides showing why). */
|
|
3733
4641
|
hoverSnap(p, input) {
|
|
3734
4642
|
if (this.tool === "pen") {
|
|
3735
|
-
const sp = this.pen ? _optionalChain([this, 'access',
|
|
3736
|
-
if (this.pen && sp && _optionalChain([this, 'access',
|
|
4643
|
+
const sp = this.pen ? _optionalChain([this, 'access', _119 => _119.getNode, 'call', _120 => _120(this.pen.nodeId), 'optionalAccess', _121 => _121.subpaths, 'access', _122 => _122[this.pen.subpath]]) : void 0;
|
|
4644
|
+
if (this.pen && sp && _optionalChain([this, 'access', _123 => _123.hover, 'optionalAccess', _124 => _124.anchor])) {
|
|
3737
4645
|
this.setGuides(null);
|
|
3738
4646
|
return p;
|
|
3739
4647
|
}
|
|
3740
4648
|
const last = this.pen && sp ? getAnchorWorld(this.doc, { nodeId: this.pen.nodeId, subpath: this.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
|
|
3741
4649
|
const leave = last ? { at: { x: last.x, y: last.y }, constrain: input.shift ? "angle" : null } : null;
|
|
3742
|
-
return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access',
|
|
4650
|
+
return this.snapDrawn(p, leave, input, () => this.drawingTargets(_nullishCoalesce(_optionalChain([this, 'access', _125 => _125.pen, 'optionalAccess', _126 => _126.nodeId]), () => ( null))));
|
|
3743
4651
|
}
|
|
3744
4652
|
if (SHAPE_TOOLS.has(this.tool)) return this.snapDrawn(p, null, input, () => this.drawingTargets(null));
|
|
3745
4653
|
this.setGuides(null);
|
|
@@ -3887,6 +4795,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3887
4795
|
if (d.fillRule) out.fillRule = d.fillRule;
|
|
3888
4796
|
if (d.strokeAlign && d.strokeAlign !== "center") out.strokeAlign = d.strokeAlign;
|
|
3889
4797
|
for (const key of ["startArrow", "endArrow", "arrowAlign", "startArrowScale", "endArrowScale"]) if (d[key]) out[key] = d[key];
|
|
4798
|
+
if (_optionalChain([d, 'access', _127 => _127.strokeWidthProfile, 'optionalAccess', _128 => _128.length])) out.strokeWidthProfile = d.strokeWidthProfile.map((p) => ({ ...p }));
|
|
3890
4799
|
return out;
|
|
3891
4800
|
}
|
|
3892
4801
|
/** Merges `patch` into a node (paths take style and geometry; groups name / visibility / opacity). */
|
|
@@ -3907,10 +4816,39 @@ var VectorEditorController = (_class3 = class {
|
|
|
3907
4816
|
}
|
|
3908
4817
|
if (!targets.size) return { ok: false, message: "Nothing is selected." };
|
|
3909
4818
|
this.change(_nullishCoalesce(options.label, () => ( "Change Style")), () => {
|
|
3910
|
-
this.setDoc(mapTree(this.doc.nodes, (n) => targets.has(n.id) ?
|
|
4819
|
+
this.setDoc(mapTree(this.doc.nodes, (n) => targets.has(n.id) ? withStyle(n, style) : n));
|
|
3911
4820
|
});
|
|
3912
4821
|
return { ok: true };
|
|
3913
4822
|
}
|
|
4823
|
+
/**
|
|
4824
|
+
* Sets the variable-width profile of the selected (or given) paths: a preset id
|
|
4825
|
+
* (`uniform` removes the profile), points, or a parametric taper / wave. Returns an error for
|
|
4826
|
+
* an unknown preset.
|
|
4827
|
+
*/
|
|
4828
|
+
setWidthProfile(profile, options = {}) {
|
|
4829
|
+
let points;
|
|
4830
|
+
if (profile === null) points = [];
|
|
4831
|
+
else if (typeof profile === "string") {
|
|
4832
|
+
const preset = widthProfilePreset(profile);
|
|
4833
|
+
if (!preset) return { ok: false, message: `There is no width profile "${profile}".` };
|
|
4834
|
+
points = preset;
|
|
4835
|
+
} else if (Array.isArray(profile)) points = sanitizeWidthProfile(profile);
|
|
4836
|
+
else {
|
|
4837
|
+
const p = profile;
|
|
4838
|
+
points = p.taper || p.wave ? generateWidthProfile(p) : [];
|
|
4839
|
+
}
|
|
4840
|
+
this.widthPoint = null;
|
|
4841
|
+
return this.setStyle({ strokeWidthProfile: points.length ? points : null }, _nullishCoalesce(options.ids, () => ( this.selection)), { label: points.length ? "Width Profile" : "Uniform Width" });
|
|
4842
|
+
}
|
|
4843
|
+
/** Removes one width point of a path's profile (the width tool's Delete). */
|
|
4844
|
+
removeWidthPoint(ref) {
|
|
4845
|
+
const node = this.getNode(ref.nodeId);
|
|
4846
|
+
if (_optionalChain([node, 'optionalAccess', _129 => _129.type]) !== "path" || !_optionalChain([node, 'access', _130 => _130.strokeWidthProfile, 'optionalAccess', _131 => _131[ref.index]])) return { ok: false, message: "There is no such width point." };
|
|
4847
|
+
const rest = removeWidthPoints(sanitizeWidthProfile(node.strokeWidthProfile), [ref.index]);
|
|
4848
|
+
this.widthPoint = null;
|
|
4849
|
+
this.change("Delete Width Point", () => this.replaceNode(node.id, withStyle(node, { strokeWidthProfile: rest.length ? rest : null })));
|
|
4850
|
+
return { ok: true };
|
|
4851
|
+
}
|
|
3914
4852
|
/**
|
|
3915
4853
|
* Sets the live corner radius (and optionally the kind) of anchors: `refs`, else the selected
|
|
3916
4854
|
* anchors (direct tool), else every anchor of the `ids` / selected paths. Radius 0 makes the
|
|
@@ -3930,7 +4868,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3930
4868
|
const refs = this.cornerTargets(options);
|
|
3931
4869
|
if (!refs.length) return { ok: false, message: "Nothing is selected." };
|
|
3932
4870
|
this.change("Corner Kind", () => {
|
|
3933
|
-
this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access',
|
|
4871
|
+
this.doc = this.updateAnchors(this.doc, refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _132 => _132.corner, 'optionalAccess', _133 => _133.radius]), () => ( 0)), kind));
|
|
3934
4872
|
});
|
|
3935
4873
|
return { ok: true };
|
|
3936
4874
|
}
|
|
@@ -3981,6 +4919,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
3981
4919
|
arrowAlign: _al,
|
|
3982
4920
|
startArrowScale: _ss,
|
|
3983
4921
|
endArrowScale: _es,
|
|
4922
|
+
strokeWidthProfile: _wp,
|
|
3984
4923
|
...rest
|
|
3985
4924
|
} = cloneVectorNode(p);
|
|
3986
4925
|
const id = this.newId();
|
|
@@ -4068,10 +5007,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
4068
5007
|
return this.selection.filter((id) => {
|
|
4069
5008
|
let covered = false;
|
|
4070
5009
|
const loc = locateVectorNode(this.doc.nodes, id);
|
|
4071
|
-
let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess',
|
|
5010
|
+
let parent = _nullishCoalesce(_optionalChain([loc, 'optionalAccess', _134 => _134.parent]), () => ( null));
|
|
4072
5011
|
while (parent) {
|
|
4073
5012
|
if (this.selection.includes(parent.id)) covered = true;
|
|
4074
|
-
parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call',
|
|
5013
|
+
parent = _nullishCoalesce(_optionalChain([locateVectorNode, 'call', _135 => _135(this.doc.nodes, parent.id), 'optionalAccess', _136 => _136.parent]), () => ( null));
|
|
4075
5014
|
}
|
|
4076
5015
|
return !covered;
|
|
4077
5016
|
});
|
|
@@ -4254,8 +5193,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
4254
5193
|
if (!ids.length) return null;
|
|
4255
5194
|
const locs = ids.map((id2) => locateVectorNode(this.doc.nodes, id2));
|
|
4256
5195
|
if (locs.some((l) => !l)) return null;
|
|
4257
|
-
const parent = _nullishCoalesce(_optionalChain([locs, 'access',
|
|
4258
|
-
if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access',
|
|
5196
|
+
const parent = _nullishCoalesce(_optionalChain([locs, 'access', _137 => _137[0], 'access', _138 => _138.parent, 'optionalAccess', _139 => _139.id]), () => ( null));
|
|
5197
|
+
if (locs.some((l) => (_nullishCoalesce(_optionalChain([l, 'access', _140 => _140.parent, 'optionalAccess', _141 => _141.id]), () => ( null))) !== parent)) return null;
|
|
4259
5198
|
const id = this.newId();
|
|
4260
5199
|
this.change("Group", () => {
|
|
4261
5200
|
const set = new Set(ids);
|
|
@@ -4278,11 +5217,11 @@ var VectorEditorController = (_class3 = class {
|
|
|
4278
5217
|
}
|
|
4279
5218
|
/** Replaces selected groups with their children. */
|
|
4280
5219
|
ungroup(options = {}) {
|
|
4281
|
-
const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess',
|
|
5220
|
+
const groups = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _142 => _142.type]) === "group");
|
|
4282
5221
|
if (!groups.length) return { ok: false, message: "Select a group to ungroup." };
|
|
4283
5222
|
const set = new Set(groups.map((g) => g.id));
|
|
4284
5223
|
this.change("Ungroup", () => {
|
|
4285
|
-
const
|
|
5224
|
+
const flatten2 = (list) => {
|
|
4286
5225
|
const out = [];
|
|
4287
5226
|
let changed = false;
|
|
4288
5227
|
for (const n of list) {
|
|
@@ -4294,14 +5233,14 @@ var VectorEditorController = (_class3 = class {
|
|
|
4294
5233
|
...n.children.map((c) => n.transform ? transformVectorNode(c, m) : c).map((c) => opacity !== void 0 && opacity < 1 ? { ...c, opacity: (_nullishCoalesce(c.opacity, () => ( 1))) * opacity } : c)
|
|
4295
5234
|
);
|
|
4296
5235
|
} else if (n.type === "group") {
|
|
4297
|
-
const children =
|
|
5236
|
+
const children = flatten2(n.children);
|
|
4298
5237
|
if (children !== n.children) changed = true;
|
|
4299
5238
|
out.push(children !== n.children ? { ...n, children } : n);
|
|
4300
5239
|
} else out.push(n);
|
|
4301
5240
|
}
|
|
4302
5241
|
return changed ? out : list;
|
|
4303
5242
|
};
|
|
4304
|
-
this.setDoc(
|
|
5243
|
+
this.setDoc(flatten2(this.doc.nodes));
|
|
4305
5244
|
this.selection = groups.flatMap((g) => g.children.map((c) => c.id));
|
|
4306
5245
|
});
|
|
4307
5246
|
return { ok: true };
|
|
@@ -4338,7 +5277,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4338
5277
|
});
|
|
4339
5278
|
const paths = [...new Set(order)].map((id2) => this.getNode(id2));
|
|
4340
5279
|
if (paths.length < 2) return null;
|
|
4341
|
-
const result =
|
|
5280
|
+
const result = _chunk7EDLVBOOcjs.pathBoolean.call(void 0,
|
|
4342
5281
|
BOOLEAN_OPS[op],
|
|
4343
5282
|
paths.map((p) => ({
|
|
4344
5283
|
path: vectorPathWorldBezier(
|
|
@@ -4388,11 +5327,11 @@ var VectorEditorController = (_class3 = class {
|
|
|
4388
5327
|
/** A document-space path mapped into the parent space of node `id`. */
|
|
4389
5328
|
intoParentSpace(id, path) {
|
|
4390
5329
|
const parent = _nullishCoalesce(vectorParentMatrix(this.doc.nodes, id), () => ( IDENTITY_MATRIX));
|
|
4391
|
-
return isRoot(parent) ? path :
|
|
5330
|
+
return isRoot(parent) ? path : _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, path, invertMatrix(parent));
|
|
4392
5331
|
}
|
|
4393
5332
|
/** Splits selected compound paths into one path per subpath. */
|
|
4394
5333
|
breakApart(options = {}) {
|
|
4395
|
-
const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess',
|
|
5334
|
+
const paths = (_nullishCoalesce(options.ids, () => ( this.selection))).map((id) => this.getNode(id)).filter((n) => _optionalChain([n, 'optionalAccess', _143 => _143.type]) === "path" && n.subpaths.length > 1);
|
|
4396
5335
|
if (!paths.length) return { ok: false, message: "Select a compound path to break apart." };
|
|
4397
5336
|
const created = [];
|
|
4398
5337
|
const set = new Set(paths.map((p) => p.id));
|
|
@@ -4412,6 +5351,248 @@ var VectorEditorController = (_class3 = class {
|
|
|
4412
5351
|
return { ok: true };
|
|
4413
5352
|
}
|
|
4414
5353
|
// -------------------------------------------------------------------------
|
|
5354
|
+
// Pathfinder, Shape Builder and paint bucket
|
|
5355
|
+
// -------------------------------------------------------------------------
|
|
5356
|
+
/**
|
|
5357
|
+
* Pathfinder: Divide, Trim, Merge, Crop, Outline or Minus Back over the selected (or given)
|
|
5358
|
+
* paths, in document space (rotated nodes and groups included, live corners cut). Unfilled
|
|
5359
|
+
* stroked paths take part as the area their stroke paints (Divide: open ones cut instead).
|
|
5360
|
+
* The results replace the operands at the place of the top-most one, grouped when there are
|
|
5361
|
+
* several; each keeps the style of the operand whose area it is. Returns the new path ids,
|
|
5362
|
+
* or an empty list when nothing came out.
|
|
5363
|
+
*/
|
|
5364
|
+
pathfinder(op, options = {}) {
|
|
5365
|
+
const roots = _nullishCoalesce(options.ids, () => ( this.selectedRoots()));
|
|
5366
|
+
const entries = vectorPathEntries(this.doc, roots);
|
|
5367
|
+
if (entries.length < (op === "divide" || op === "outline" ? 1 : 2)) return [];
|
|
5368
|
+
const shapes = entries.map((e) => vectorPathfinderShape(e, op));
|
|
5369
|
+
const result = _chunk7EDLVBOOcjs.pathfinder.call(void 0, op, shapes);
|
|
5370
|
+
if (result.error || !result.pieces.length) return [];
|
|
5371
|
+
const last = entries[entries.length - 1].node.id;
|
|
5372
|
+
const topRoot = _nullishCoalesce([...roots].reverse().find((r) => {
|
|
5373
|
+
const n = this.getNode(r);
|
|
5374
|
+
return !!n && !!findVectorNode([n], last);
|
|
5375
|
+
}), () => ( last));
|
|
5376
|
+
const nodes = [];
|
|
5377
|
+
for (const piece of result.pieces) {
|
|
5378
|
+
const subpaths = bezierToSubpaths(this.intoParentSpace(topRoot, piece.path)).map((sp) => piece.open ? { ...sp, closed: false } : sp);
|
|
5379
|
+
if (!subpaths.length) continue;
|
|
5380
|
+
const source = entries[piece.source].node;
|
|
5381
|
+
const style = vectorResultStyle(source, shapes[piece.source].paint, op === "outline");
|
|
5382
|
+
nodes.push({ ...style, type: "path", id: this.newId(), name: _nullishCoalesce(source.name, () => ( "Path")), subpaths });
|
|
5383
|
+
}
|
|
5384
|
+
if (!nodes.length) return [];
|
|
5385
|
+
const label = VECTOR_PATHFINDER_LABELS[op];
|
|
5386
|
+
const container = nodes.length > 1 ? { id: this.newId(), type: "group", name: label, children: nodes } : nodes[0];
|
|
5387
|
+
const drop = /* @__PURE__ */ new Set([...entries.map((e) => e.node.id), ...roots]);
|
|
5388
|
+
this.change(label, () => {
|
|
5389
|
+
this.setDoc(mapTree(this.doc.nodes, (n) => n.id === topRoot ? container : drop.has(n.id) ? null : n));
|
|
5390
|
+
this.selection = [container.id];
|
|
5391
|
+
this.anchors = [];
|
|
5392
|
+
this.editingId = null;
|
|
5393
|
+
});
|
|
5394
|
+
return nodes.map((n) => n.id);
|
|
5395
|
+
}
|
|
5396
|
+
/** The Shape Builder map of the selected (or given) paths, cached per document and selection. */
|
|
5397
|
+
shapeBuilderMap(ids) {
|
|
5398
|
+
const roots = _nullishCoalesce(ids, () => ( this.selectedRoots()));
|
|
5399
|
+
const key = roots.join("\0");
|
|
5400
|
+
if (_optionalChain([this, 'access', _144 => _144.builderCache, 'optionalAccess', _145 => _145.doc]) === this.doc && this.builderCache.key === key) return this.builderCache.map;
|
|
5401
|
+
const entries = roots.length ? vectorPathEntries(this.doc, roots) : [];
|
|
5402
|
+
const map = entries.length ? vectorShapeBuilderMap(entries) : null;
|
|
5403
|
+
this.builderCache = { doc: this.doc, key, map };
|
|
5404
|
+
return map;
|
|
5405
|
+
}
|
|
5406
|
+
/** The faces the Shape Builder offers for the selected (or given) paths (document units). */
|
|
5407
|
+
getShapeBuilderFaces(options = {}) {
|
|
5408
|
+
const m = this.shapeBuilderMap(options.ids);
|
|
5409
|
+
if (!m) return [];
|
|
5410
|
+
return m.map.faces.map((f, index) => {
|
|
5411
|
+
const p = m.map.faceInterior(index);
|
|
5412
|
+
return {
|
|
5413
|
+
index,
|
|
5414
|
+
d: _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, f.path, { precision: 3 }),
|
|
5415
|
+
area: f.area,
|
|
5416
|
+
sources: m.map.faceSources(index).map((i) => m.entries[i].node.id),
|
|
5417
|
+
point: p ? { x: p[0], y: p[1] } : null
|
|
5418
|
+
};
|
|
5419
|
+
});
|
|
5420
|
+
}
|
|
5421
|
+
/** Pick distance of the Shape Builder's erase for line pieces (document units). */
|
|
5422
|
+
builderLineTolerance() {
|
|
5423
|
+
return Math.max(this.hitRadius, 4) / this.viewport.zoom;
|
|
5424
|
+
}
|
|
5425
|
+
/**
|
|
5426
|
+
* Shape Builder gesture along `points` (document units; one point is a click) over the faces
|
|
5427
|
+
* the selected (or given) paths make. Merges the faces touched into one shape styled like the
|
|
5428
|
+
* top-most shape over the first face (the current fill for a face only outlines enclose);
|
|
5429
|
+
* with `erase` deletes them, and the pieces of unfilled open paths within `tolerance`. Every
|
|
5430
|
+
* shape covering a touched face loses that area. One undo step.
|
|
5431
|
+
*/
|
|
5432
|
+
shapeBuilder(points, options = {}) {
|
|
5433
|
+
const none = (message) => ({ ok: false, message, merged: null, faces: 0, lines: 0 });
|
|
5434
|
+
if (!points.length || !points.every((p) => Number.isFinite(p.x) && Number.isFinite(p.y))) return none("Give the points of the gesture.");
|
|
5435
|
+
const m = this.shapeBuilderMap(options.ids);
|
|
5436
|
+
if (!m) return none("Select paths that make faces.");
|
|
5437
|
+
const erase = !!options.erase;
|
|
5438
|
+
const tol = erase ? _nullishCoalesce(options.tolerance, () => ( this.builderLineTolerance())) : null;
|
|
5439
|
+
const touched = { faces: [], lines: [] };
|
|
5440
|
+
const size = m.map.faces.reduce((s, f) => Math.max(s, f.bounds.maxX - f.bounds.minX, f.bounds.maxY - f.bounds.minY), 1);
|
|
5441
|
+
for (const p of samplePolyline(points, Math.max(size / 2e3, 0.25 / this.viewport.zoom))) addBuilderHit(touched, vectorShapeBuilderHit(m, p, tol));
|
|
5442
|
+
if (!touched.faces.length && !touched.lines.length) return none("There is no face under the pointer.");
|
|
5443
|
+
return this.applyShapeBuilder(m, touched, erase);
|
|
5444
|
+
}
|
|
5445
|
+
applyShapeBuilder(m, touched, erase) {
|
|
5446
|
+
const plan = planShapeBuilder(m, touched, erase);
|
|
5447
|
+
let mergedId = null;
|
|
5448
|
+
const created = /* @__PURE__ */ new Map();
|
|
5449
|
+
this.change(erase ? "Shape Builder Delete" : "Shape Builder", () => {
|
|
5450
|
+
let nodes = this.doc.nodes;
|
|
5451
|
+
m.entries.forEach((entry, i) => {
|
|
5452
|
+
const node = entry.node;
|
|
5453
|
+
const toLocal = (path) => _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, path, invertMatrix(multiplyMatrices(nodeMatrix(node), entry.parent)));
|
|
5454
|
+
const list = [];
|
|
5455
|
+
const r = plan.replace.get(i);
|
|
5456
|
+
if (r === void 0) list.push(node);
|
|
5457
|
+
else if (_optionalChain([r, 'optionalAccess', _146 => _146.kind]) === "fill") list.push({ ...node, fillRule: "nonzero", subpaths: bezierToSubpaths(toLocal(r.path)) });
|
|
5458
|
+
else if (_optionalChain([r, 'optionalAccess', _147 => _147.kind]) === "pieces") {
|
|
5459
|
+
r.paths.forEach(
|
|
5460
|
+
(path, k) => list.push({ ...node, id: k === 0 ? node.id : this.newId(), subpaths: bezierToSubpaths(toLocal(path)).map((sp) => ({ ...sp, closed: false })) })
|
|
5461
|
+
);
|
|
5462
|
+
}
|
|
5463
|
+
if (plan.merged && plan.merged.style === i) {
|
|
5464
|
+
mergedId = this.newId();
|
|
5465
|
+
const merged = {
|
|
5466
|
+
...vectorResultStyle(node, "fill"),
|
|
5467
|
+
type: "path",
|
|
5468
|
+
id: mergedId,
|
|
5469
|
+
name: "Shape",
|
|
5470
|
+
...node.transform ? { transform: node.transform } : {},
|
|
5471
|
+
subpaths: bezierToSubpaths(toLocal(plan.merged.path))
|
|
5472
|
+
};
|
|
5473
|
+
if (plan.merged.currentFill || !hasPaint(merged.fill)) merged.fill = hasPaint(this.defaults.fill) ? this.defaults.fill : "#808080";
|
|
5474
|
+
list.push(merged);
|
|
5475
|
+
}
|
|
5476
|
+
if (r === void 0 && list.length === 1) return;
|
|
5477
|
+
created.set(node.id, list.map((n) => n.id));
|
|
5478
|
+
nodes = spliceTree(nodes, node.id, list);
|
|
5479
|
+
});
|
|
5480
|
+
this.setDoc(nodes);
|
|
5481
|
+
const selection = this.selection.flatMap((id) => _nullishCoalesce(created.get(id), () => ( [id])));
|
|
5482
|
+
if (mergedId && !selection.includes(mergedId)) selection.push(mergedId);
|
|
5483
|
+
this.selection = selection.filter((id, k) => !!this.getNode(id) && selection.indexOf(id) === k);
|
|
5484
|
+
this.anchors = [];
|
|
5485
|
+
this.editingId = null;
|
|
5486
|
+
});
|
|
5487
|
+
this.builderCache = null;
|
|
5488
|
+
return { ok: true, merged: mergedId, faces: touched.faces.length, lines: touched.lines.length };
|
|
5489
|
+
}
|
|
5490
|
+
/** The paint bucket's map of the visible outlines, cached per document and gap. */
|
|
5491
|
+
fillMap(gap) {
|
|
5492
|
+
if (_optionalChain([this, 'access', _148 => _148.fillCache, 'optionalAccess', _149 => _149.doc]) === this.doc && this.fillCache.gap === gap) return this.fillCache.map;
|
|
5493
|
+
const map = vectorFillMap(this.doc, gap);
|
|
5494
|
+
this.fillCache = { doc: this.doc, gap, map };
|
|
5495
|
+
return map;
|
|
5496
|
+
}
|
|
5497
|
+
/**
|
|
5498
|
+
* Paint bucket: the region the visible outlines enclose around `point` (document units),
|
|
5499
|
+
* crossings split and islands left as holes, becomes a new path filled with the current fill
|
|
5500
|
+
* default, placed just below the selection (or on top when nothing is selected). `gap`
|
|
5501
|
+
* (default `editing.fillGap`) closes gaps up to that size between loose ends. Returns the new
|
|
5502
|
+
* path's id, or null when nothing encloses the point.
|
|
5503
|
+
*/
|
|
5504
|
+
fillRegion(point, options = {}) {
|
|
5505
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) return null;
|
|
5506
|
+
const region = _optionalChain([this, 'access', _150 => _150.fillMap, 'call', _151 => _151(_nullishCoalesce(options.gap, () => ( this.editing.fillGap))), 'optionalAccess', _152 => _152.regionAt, 'call', _153 => _153([point.x, point.y])]);
|
|
5507
|
+
if (!_optionalChain([region, 'optionalAccess', _154 => _154.length])) return null;
|
|
5508
|
+
let below = null;
|
|
5509
|
+
const roots = new Set(this.selectedRoots());
|
|
5510
|
+
walkVectorNodes(this.doc.nodes, (n) => {
|
|
5511
|
+
if (!below && roots.has(n.id)) below = n.id;
|
|
5512
|
+
});
|
|
5513
|
+
const subpaths = bezierToSubpaths(below ? this.intoParentSpace(below, region) : region);
|
|
5514
|
+
if (!subpaths.length) return null;
|
|
5515
|
+
const id = this.newId();
|
|
5516
|
+
const node = { id, type: "path", name: "Fill", ...this.styleFor(false), stroke: null, fillRule: "nonzero", subpaths };
|
|
5517
|
+
if (!hasPaint(node.fill)) node.fill = "#808080";
|
|
5518
|
+
const target = below;
|
|
5519
|
+
this.change("Fill Region", () => {
|
|
5520
|
+
if (target) {
|
|
5521
|
+
const current = this.getNode(target);
|
|
5522
|
+
this.setDoc(spliceTree(this.doc.nodes, target, [node, current]));
|
|
5523
|
+
} else this.setDoc([...this.doc.nodes, node]);
|
|
5524
|
+
if (!target) this.selection = [id];
|
|
5525
|
+
this.anchors = [];
|
|
5526
|
+
this.editingId = null;
|
|
5527
|
+
});
|
|
5528
|
+
return id;
|
|
5529
|
+
}
|
|
5530
|
+
/** Updates the Shape Builder / paint bucket highlight for the pointer at `p`; true when it changed. */
|
|
5531
|
+
hoverBuilder(p, alt) {
|
|
5532
|
+
if (this.tool === "paintBucket") {
|
|
5533
|
+
const region = _nullishCoalesce(_optionalChain([this, 'access', _155 => _155.fillMap, 'call', _156 => _156(this.editing.fillGap), 'optionalAccess', _157 => _157.regionAt, 'call', _158 => _158([p.x, p.y])]), () => ( null));
|
|
5534
|
+
const key2 = region ? _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, region, { precision: 2 }) : null;
|
|
5535
|
+
if (key2 === this.builderHoverKey) return false;
|
|
5536
|
+
this.builderHoverKey = key2;
|
|
5537
|
+
this.builderPreview = region ? { mode: "fill", faces: [region], lines: [], trail: null } : null;
|
|
5538
|
+
return true;
|
|
5539
|
+
}
|
|
5540
|
+
const m = this.selectedRoots().length ? this.shapeBuilderMap() : null;
|
|
5541
|
+
const hit = m ? vectorShapeBuilderHit(m, p, alt ? this.builderLineTolerance() : null) : null;
|
|
5542
|
+
const key = hit ? `${alt ? "erase" : "merge"}:${JSON.stringify(hit)}` : null;
|
|
5543
|
+
if (key === this.builderHoverKey) return false;
|
|
5544
|
+
this.builderHoverKey = key;
|
|
5545
|
+
this.builderPreview = hit && m ? this.builderPreviewOf(m, "face" in hit ? { faces: [hit.face], lines: [] } : { faces: [], lines: [hit.line] }, alt, null) : null;
|
|
5546
|
+
return true;
|
|
5547
|
+
}
|
|
5548
|
+
builderPreviewOf(m, touched, erase, trail) {
|
|
5549
|
+
const faces = m.map.faces;
|
|
5550
|
+
return {
|
|
5551
|
+
mode: erase ? "erase" : "merge",
|
|
5552
|
+
faces: touched.faces.map((f) => faces[f].path),
|
|
5553
|
+
lines: touched.lines.map((k) => m.pieces[k].path),
|
|
5554
|
+
trail
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
downBuilder(p, input) {
|
|
5558
|
+
this.builderHoverKey = null;
|
|
5559
|
+
if (this.tool === "paintBucket") {
|
|
5560
|
+
this.fillRegion(p);
|
|
5561
|
+
this.builderPreview = null;
|
|
5562
|
+
this.hoverBuilder(p, false);
|
|
5563
|
+
this.notify();
|
|
5564
|
+
return;
|
|
5565
|
+
}
|
|
5566
|
+
const m = this.selectedRoots().length ? this.shapeBuilderMap() : null;
|
|
5567
|
+
if (!m) return;
|
|
5568
|
+
const erase = !!input.alt;
|
|
5569
|
+
const touched = { faces: [], lines: [] };
|
|
5570
|
+
addBuilderHit(touched, vectorShapeBuilderHit(m, p, erase ? this.builderLineTolerance() : null));
|
|
5571
|
+
this.drag = { kind: "builder", erase, points: [p], touched, map: m };
|
|
5572
|
+
this.interaction = { type: "builder", mode: erase ? "erase" : "merge", points: [p] };
|
|
5573
|
+
this.builderPreview = this.builderPreviewOf(m, touched, erase, [p]);
|
|
5574
|
+
this.notify();
|
|
5575
|
+
}
|
|
5576
|
+
moveBuilder(drag, p) {
|
|
5577
|
+
const last = drag.points[drag.points.length - 1];
|
|
5578
|
+
if (Math.hypot(p.x - last.x, p.y - last.y) * this.viewport.zoom < 1) return;
|
|
5579
|
+
const tol = drag.erase ? this.builderLineTolerance() : null;
|
|
5580
|
+
for (const q of samplePolyline([last, p], 2 / this.viewport.zoom)) addBuilderHit(drag.touched, vectorShapeBuilderHit(drag.map, q, tol));
|
|
5581
|
+
drag.points.push(p);
|
|
5582
|
+
this.interaction = { type: "builder", mode: drag.erase ? "erase" : "merge", points: drag.points.slice() };
|
|
5583
|
+
this.builderPreview = this.builderPreviewOf(drag.map, drag.touched, drag.erase, drag.points.slice());
|
|
5584
|
+
this.notify();
|
|
5585
|
+
}
|
|
5586
|
+
upBuilder(drag) {
|
|
5587
|
+
this.builderPreview = null;
|
|
5588
|
+
this.builderHoverKey = null;
|
|
5589
|
+
if (!drag.touched.faces.length && !drag.touched.lines.length) {
|
|
5590
|
+
this.notify();
|
|
5591
|
+
return;
|
|
5592
|
+
}
|
|
5593
|
+
this.applyShapeBuilder(drag.map, drag.touched, drag.erase);
|
|
5594
|
+
}
|
|
5595
|
+
// -------------------------------------------------------------------------
|
|
4415
5596
|
// Anchor editing
|
|
4416
5597
|
// -------------------------------------------------------------------------
|
|
4417
5598
|
updateAnchors(doc, refs, fn) {
|
|
@@ -4454,7 +5635,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4454
5635
|
/** `doc` with anchor `ref` moved to document point `to` by a Curvature-tool move. */
|
|
4455
5636
|
curvatureMoved(doc, ref, to) {
|
|
4456
5637
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
4457
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5638
|
+
if (_optionalChain([node, 'optionalAccess', _159 => _159.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
|
|
4458
5639
|
const q = this.toLocal(ref.nodeId, to, doc);
|
|
4459
5640
|
const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? curvatureMoveAnchor(sp, ref.index, q) : sp);
|
|
4460
5641
|
const nodes = mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n);
|
|
@@ -4463,7 +5644,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4463
5644
|
/** `doc` with segment `ref` bent through document point `p` at parameter `t`. */
|
|
4464
5645
|
bent(doc, ref, t, p) {
|
|
4465
5646
|
const node = findVectorNode(doc.nodes, ref.nodeId);
|
|
4466
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5647
|
+
if (_optionalChain([node, 'optionalAccess', _160 => _160.type]) !== "path" || node.locked || !node.subpaths[ref.subpath]) return doc;
|
|
4467
5648
|
const q = this.toLocal(ref.nodeId, p, doc);
|
|
4468
5649
|
const subpaths = node.subpaths.map((sp, i) => i === ref.subpath ? bendSegment(sp, ref.segment, t, q) : sp);
|
|
4469
5650
|
return { ...doc, nodes: mapTree(doc.nodes, (n) => n.id === ref.nodeId ? { ...node, subpaths } : n) };
|
|
@@ -4474,7 +5655,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4474
5655
|
*/
|
|
4475
5656
|
bendSegment(ref, to, t = 0.5) {
|
|
4476
5657
|
const node = this.getNode(ref.nodeId);
|
|
4477
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
5658
|
+
const sp = _optionalChain([node, 'optionalAccess', _161 => _161.type]) === "path" ? node.subpaths[ref.subpath] : void 0;
|
|
4478
5659
|
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." };
|
|
4479
5660
|
if (node.locked) return { ok: false, message: "The path is locked." };
|
|
4480
5661
|
this.change("Bend Segment", () => {
|
|
@@ -4509,7 +5690,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4509
5690
|
/** Adds an anchor on the nearest segment of `nodeId` to document point `point` (shape unchanged). */
|
|
4510
5691
|
insertAnchorAt(nodeId, point) {
|
|
4511
5692
|
const node = this.getNode(nodeId);
|
|
4512
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5693
|
+
if (_optionalChain([node, 'optionalAccess', _162 => _162.type]) !== "path") return null;
|
|
4513
5694
|
const hit = nearestSegment(node, this.toLocal(nodeId, point));
|
|
4514
5695
|
if (!hit) return null;
|
|
4515
5696
|
const { subpath, index } = insertAnchor(node.subpaths[hit.subpath], hit.segment, hit.t);
|
|
@@ -4553,7 +5734,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4553
5734
|
setClosed(closed, nodeId) {
|
|
4554
5735
|
const targets = nodeId ? (() => {
|
|
4555
5736
|
const n = this.getNode(nodeId);
|
|
4556
|
-
return _optionalChain([n, 'optionalAccess',
|
|
5737
|
+
return _optionalChain([n, 'optionalAccess', _163 => _163.type]) === "path" ? n.subpaths.map((_, s) => ({ nodeId, subpath: s })) : [];
|
|
4557
5738
|
})() : this.anchors.map((r) => ({ nodeId: r.nodeId, subpath: r.subpath }));
|
|
4558
5739
|
if (!targets.length) return { ok: false, message: "Select a path or points." };
|
|
4559
5740
|
this.change(closed ? "Close Path" : "Open Path", () => {
|
|
@@ -4571,7 +5752,12 @@ var VectorEditorController = (_class3 = class {
|
|
|
4571
5752
|
const set = new Set(ids.flatMap((id) => this.getNode(id) ? collectPathNodes(this.getNode(id)) : []).map((p) => p.id));
|
|
4572
5753
|
if (!set.size) return { ok: false, message: "Select a path." };
|
|
4573
5754
|
this.change("Reverse Path", () => {
|
|
4574
|
-
this.setDoc(
|
|
5755
|
+
this.setDoc(
|
|
5756
|
+
mapTree(
|
|
5757
|
+
this.doc.nodes,
|
|
5758
|
+
(n) => n.type === "path" && set.has(n.id) ? { ...n, subpaths: n.subpaths.map(reverseSubpath), ..._optionalChain([n, 'access', _164 => _164.strokeWidthProfile, 'optionalAccess', _165 => _165.length]) ? { strokeWidthProfile: reverseWidthProfile(n.strokeWidthProfile) } : {} } : n
|
|
5759
|
+
)
|
|
5760
|
+
);
|
|
4575
5761
|
this.anchors = [];
|
|
4576
5762
|
});
|
|
4577
5763
|
return { ok: true };
|
|
@@ -4652,9 +5838,9 @@ var VectorEditorController = (_class3 = class {
|
|
|
4652
5838
|
const cx = points.reduce((s, p) => s + p.at.x, 0) / points.length;
|
|
4653
5839
|
const cy = points.reduce((s, p) => s + p.at.y, 0) / points.length;
|
|
4654
5840
|
this.change("Average", () => {
|
|
4655
|
-
for (const { ref, at } of points) {
|
|
4656
|
-
const dx = axis === "horizontal" ? 0 : cx -
|
|
4657
|
-
const dy = axis === "vertical" ? 0 : cy -
|
|
5841
|
+
for (const { ref, at: at2 } of points) {
|
|
5842
|
+
const dx = axis === "horizontal" ? 0 : cx - at2.x;
|
|
5843
|
+
const dy = axis === "vertical" ? 0 : cy - at2.y;
|
|
4658
5844
|
if (dx || dy) this.doc = this.movedAnchors(this.doc, [ref], dx, dy);
|
|
4659
5845
|
}
|
|
4660
5846
|
});
|
|
@@ -4707,7 +5893,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4707
5893
|
*/
|
|
4708
5894
|
cutPathAt(nodeId, point) {
|
|
4709
5895
|
const node = this.getNode(nodeId);
|
|
4710
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
5896
|
+
if (_optionalChain([node, 'optionalAccess', _166 => _166.type]) !== "path" || node.locked) return null;
|
|
4711
5897
|
const local = this.toLocal(nodeId, point);
|
|
4712
5898
|
const hit = nearestSegment(node, local);
|
|
4713
5899
|
if (!hit) return null;
|
|
@@ -4738,8 +5924,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
4738
5924
|
const node = this.getNode(id);
|
|
4739
5925
|
if (node.locked) continue;
|
|
4740
5926
|
const ids = this.applyCuts(node, (sp, i) => {
|
|
4741
|
-
const
|
|
4742
|
-
const pieces =
|
|
5927
|
+
const at2 = list.filter((r) => r.subpath === i).map((r) => r.index);
|
|
5928
|
+
const pieces = at2.length ? cutSubpathAt(sp, at2) : null;
|
|
4743
5929
|
return pieces && !(pieces.length === 1 && pieces[0].closed === sp.closed) ? pieces : null;
|
|
4744
5930
|
});
|
|
4745
5931
|
if (ids) created.push(...ids);
|
|
@@ -4757,7 +5943,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4757
5943
|
if (n.visible === false || n.locked || parent && blocked.has(parent.id)) blocked.add(n.id);
|
|
4758
5944
|
});
|
|
4759
5945
|
const visible = (p) => !blocked.has(p.id);
|
|
4760
|
-
if (_optionalChain([ids, 'optionalAccess',
|
|
5946
|
+
if (_optionalChain([ids, 'optionalAccess', _167 => _167.length]) || this.selection.length) return this.pathTargets(_nullishCoalesce(ids, () => ( this.selection))).filter(visible);
|
|
4761
5947
|
const box = polylineBounds(points.map(toPoint2), pad);
|
|
4762
5948
|
if (!box) return [];
|
|
4763
5949
|
const out = [];
|
|
@@ -4813,10 +5999,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
4813
5999
|
const region = eraserRegion(pts, width);
|
|
4814
6000
|
if (!region.length) return [];
|
|
4815
6001
|
const plan = [];
|
|
4816
|
-
const rb =
|
|
6002
|
+
const rb = _chunk7EDLVBOOcjs.bezierPathBounds.call(void 0, region);
|
|
4817
6003
|
const reach = rb ? [{ x: rb.minX, y: rb.minY }, { x: rb.maxX, y: rb.maxY }] : points;
|
|
4818
6004
|
for (const node of this.strokeTargets(reach, options.ids, 0)) {
|
|
4819
|
-
const local =
|
|
6005
|
+
const local = _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, region, invertMatrix(this.worldOf(node.id)));
|
|
4820
6006
|
const live = node.subpaths.filter((sp) => sp.anchors.length > 1);
|
|
4821
6007
|
if (!live.length) continue;
|
|
4822
6008
|
if (hasPaint(node.fill) && live.every((sp) => sp.closed)) {
|
|
@@ -4843,7 +6029,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
4843
6029
|
finishPath() {
|
|
4844
6030
|
if (!this.pen) return;
|
|
4845
6031
|
const node = this.getNode(this.pen.nodeId);
|
|
4846
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
6032
|
+
const sp = _optionalChain([node, 'optionalAccess', _168 => _168.subpaths, 'access', _169 => _169[this.pen.subpath]]);
|
|
4847
6033
|
const pen = this.pen;
|
|
4848
6034
|
this.pen = null;
|
|
4849
6035
|
this.pointer = null;
|
|
@@ -4887,19 +6073,19 @@ var VectorEditorController = (_class3 = class {
|
|
|
4887
6073
|
if (trimmed.startsWith("{")) {
|
|
4888
6074
|
try {
|
|
4889
6075
|
const data = JSON.parse(trimmed);
|
|
4890
|
-
if (_optionalChain([data, 'optionalAccess',
|
|
4891
|
-
} catch (
|
|
6076
|
+
if (_optionalChain([data, 'optionalAccess', _170 => _170.type]) === VECTOR_CLIPBOARD_TYPE && Array.isArray(data.nodes)) nodes = data.nodes;
|
|
6077
|
+
} catch (e3) {
|
|
4892
6078
|
nodes = null;
|
|
4893
6079
|
}
|
|
4894
6080
|
} else if (/<svg[\s>]/i.test(trimmed)) {
|
|
4895
6081
|
try {
|
|
4896
6082
|
nodes = parseVectorSvg(trimmed).nodes;
|
|
4897
|
-
} catch (
|
|
6083
|
+
} catch (e4) {
|
|
4898
6084
|
nodes = null;
|
|
4899
6085
|
}
|
|
4900
6086
|
}
|
|
4901
6087
|
} else nodes = this.clipboard;
|
|
4902
|
-
if (!_optionalChain([nodes, 'optionalAccess',
|
|
6088
|
+
if (!_optionalChain([nodes, 'optionalAccess', _171 => _171.length])) return [];
|
|
4903
6089
|
const offset = _nullishCoalesce(options.offset, () => ( (text && !text.trim().startsWith("{") ? { x: 0, y: 0 } : { x: 10, y: 10 })));
|
|
4904
6090
|
const copies = nodes.map((n) => transformVectorNode(this.freshIds(n), translateMatrix(offset.x, offset.y)));
|
|
4905
6091
|
this.change("Paste", () => {
|
|
@@ -4943,14 +6129,14 @@ var VectorEditorController = (_class3 = class {
|
|
|
4943
6129
|
if (!frame) return null;
|
|
4944
6130
|
const { box, handles } = getVectorSelectionBoxGeometry(frame, this.viewport);
|
|
4945
6131
|
const r = this.hitRadius + 2;
|
|
4946
|
-
const
|
|
4947
|
-
for (const h of
|
|
6132
|
+
const usable2 = box.width < 2 * r || box.height < 2 * r ? handles.filter((h) => h.handle.length === 2 || h.handle === "rotate") : handles;
|
|
6133
|
+
for (const h of usable2) if (Math.hypot(h.screen.x - screen.x, h.screen.y - screen.y) <= r * Math.SQRT2) return h.handle;
|
|
4948
6134
|
return null;
|
|
4949
6135
|
}
|
|
4950
6136
|
hitHandle(screen) {
|
|
4951
6137
|
for (const ref of getVisibleHandles(this.view()).reverse()) {
|
|
4952
6138
|
const a = getAnchorWorld(this.doc, ref);
|
|
4953
|
-
const h = _optionalChain([a, 'optionalAccess',
|
|
6139
|
+
const h = _optionalChain([a, 'optionalAccess', _172 => _172[ref.handle]]);
|
|
4954
6140
|
if (!h) continue;
|
|
4955
6141
|
const s = this.documentToScreen(h);
|
|
4956
6142
|
if (Math.hypot(s.x - screen.x, s.y - screen.y) <= this.hitRadius) return ref;
|
|
@@ -5053,10 +6239,131 @@ var VectorEditorController = (_class3 = class {
|
|
|
5053
6239
|
const seg = this.nearestOutline(p);
|
|
5054
6240
|
return seg ? { nodeId: seg.nodeId, segment: seg } : null;
|
|
5055
6241
|
}
|
|
6242
|
+
case "width": {
|
|
6243
|
+
const hit = this.hitWidthHandle(screen);
|
|
6244
|
+
if (hit) return { nodeId: hit.ref.nodeId, widthPoint: hit.ref };
|
|
6245
|
+
const spot = this.strokeSpotAt(p);
|
|
6246
|
+
return spot ? { nodeId: spot.nodeId, strokeSpot: spot } : null;
|
|
6247
|
+
}
|
|
5056
6248
|
default:
|
|
5057
6249
|
return null;
|
|
5058
6250
|
}
|
|
5059
6251
|
}
|
|
6252
|
+
widthView() {
|
|
6253
|
+
return { document: this.doc, selection: this.selection, tool: this.tool, hover: this.hover, interaction: this.interaction, selectedWidthPoint: this.widthPoint };
|
|
6254
|
+
}
|
|
6255
|
+
/** The width point centre or side end under `screen` (width tool). */
|
|
6256
|
+
hitWidthHandle(screen) {
|
|
6257
|
+
let best = null;
|
|
6258
|
+
let bestD = Infinity;
|
|
6259
|
+
for (const h of getVectorWidthHandles(this.widthView())) {
|
|
6260
|
+
for (const [part, q] of [["center", h], ["left", h.left], ["right", h.right]]) {
|
|
6261
|
+
const s = this.documentToScreen(q);
|
|
6262
|
+
const d = Math.hypot(s.x - screen.x, s.y - screen.y);
|
|
6263
|
+
if (d <= this.hitRadius && d < bestD - 1e-9) {
|
|
6264
|
+
best = { ref: { ...h.ref, part } };
|
|
6265
|
+
bestD = d;
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
}
|
|
6269
|
+
return best;
|
|
6270
|
+
}
|
|
6271
|
+
/** The nearest stroked, unlocked visible path whose stroke is under document point `p` (width tool). */
|
|
6272
|
+
strokeSpotAt(p) {
|
|
6273
|
+
let best = null;
|
|
6274
|
+
const tol = this.tolerance();
|
|
6275
|
+
walkVectorNodes(this.doc.nodes, (n) => {
|
|
6276
|
+
if (n.type !== "path" || n.visible === false || n.locked) return;
|
|
6277
|
+
if (hiddenOrLocked(this.doc.nodes, n.id)) return;
|
|
6278
|
+
const g = vectorStrokeWidthGeometry(n);
|
|
6279
|
+
if (!g) return;
|
|
6280
|
+
const m = this.worldOf(n.id);
|
|
6281
|
+
const local = applyMatrix(invertMatrix(m), p);
|
|
6282
|
+
const near2 = nearestStrokePosition(g.line, [local.x, local.y]);
|
|
6283
|
+
if (!near2) return;
|
|
6284
|
+
const profile = strokeWidthProfileOf(n);
|
|
6285
|
+
const w = widthProfileAt(profile, near2.t);
|
|
6286
|
+
const reach = Math.max(near2.side === "left" ? w.left : w.right, 0) * g.unit + tol;
|
|
6287
|
+
if (near2.distance > reach || near2.distance > widthProfileMaxScale(profile) * g.unit + tol) return;
|
|
6288
|
+
if (best && near2.distance >= best.distance) return;
|
|
6289
|
+
const nx = near2.tangent[1];
|
|
6290
|
+
const ny = -near2.tangent[0];
|
|
6291
|
+
const [cx, cy] = near2.point;
|
|
6292
|
+
best = {
|
|
6293
|
+
nodeId: n.id,
|
|
6294
|
+
subpath: near2.contour,
|
|
6295
|
+
t: near2.t,
|
|
6296
|
+
point: applyMatrix(m, { x: cx, y: cy }),
|
|
6297
|
+
left: applyMatrix(m, { x: cx + nx * w.left * g.unit, y: cy + ny * w.left * g.unit }),
|
|
6298
|
+
right: applyMatrix(m, { x: cx - nx * w.right * g.unit, y: cy - ny * w.right * g.unit }),
|
|
6299
|
+
distance: near2.distance
|
|
6300
|
+
};
|
|
6301
|
+
});
|
|
6302
|
+
if (!best) return null;
|
|
6303
|
+
const { distance: _d, ...spot } = best;
|
|
6304
|
+
return spot;
|
|
6305
|
+
}
|
|
6306
|
+
downWidth(screen, p, input) {
|
|
6307
|
+
const hit = this.hitWidthHandle(screen);
|
|
6308
|
+
const spot = hit ? null : this.strokeSpotAt(p);
|
|
6309
|
+
const nodeId = _nullishCoalesce(_optionalChain([hit, 'optionalAccess', _173 => _173.ref, 'access', _174 => _174.nodeId]), () => ( _optionalChain([spot, 'optionalAccess', _175 => _175.nodeId])));
|
|
6310
|
+
const node = nodeId ? this.getNode(nodeId) : void 0;
|
|
6311
|
+
const g = _optionalChain([node, 'optionalAccess', _176 => _176.type]) === "path" ? vectorStrokeWidthGeometry(node) : null;
|
|
6312
|
+
if (!node || node.type !== "path" || !g) {
|
|
6313
|
+
if (this.widthPoint) {
|
|
6314
|
+
this.widthPoint = null;
|
|
6315
|
+
this.notify();
|
|
6316
|
+
}
|
|
6317
|
+
return;
|
|
6318
|
+
}
|
|
6319
|
+
const before = this.snapshot();
|
|
6320
|
+
const local = this.toLocal(node.id, p);
|
|
6321
|
+
let profile;
|
|
6322
|
+
let ref;
|
|
6323
|
+
let mode = "width";
|
|
6324
|
+
let side = "both";
|
|
6325
|
+
let t;
|
|
6326
|
+
let subpath;
|
|
6327
|
+
if (hit) {
|
|
6328
|
+
profile = sanitizeWidthProfile(node.strokeWidthProfile);
|
|
6329
|
+
ref = { nodeId: node.id, index: hit.ref.index, subpath: hit.ref.subpath };
|
|
6330
|
+
t = _nullishCoalesce(_optionalChain([profile, 'access', _177 => _177[ref.index], 'optionalAccess', _178 => _178.t]), () => ( 0));
|
|
6331
|
+
subpath = hit.ref.subpath;
|
|
6332
|
+
if (hit.ref.part === "center") mode = "move";
|
|
6333
|
+
else if (input.alt) side = hit.ref.part;
|
|
6334
|
+
} else {
|
|
6335
|
+
const near2 = nearestStrokePosition(g.line, [local.x, local.y]);
|
|
6336
|
+
const inserted = insertWidthPoint(strokeWidthProfileOf(node), near2.t);
|
|
6337
|
+
profile = inserted.points;
|
|
6338
|
+
subpath = near2.contour;
|
|
6339
|
+
t = near2.t;
|
|
6340
|
+
ref = { nodeId: node.id, index: inserted.index, subpath };
|
|
6341
|
+
if (input.alt) side = near2.side;
|
|
6342
|
+
}
|
|
6343
|
+
const at2 = strokePositionPoint(g.line, subpath, t);
|
|
6344
|
+
if (!at2) return;
|
|
6345
|
+
const base = { ...this.doc, nodes: mapTree(this.doc.nodes, (n) => n.id === node.id ? { ...n, strokeWidthProfile: profile } : n) };
|
|
6346
|
+
this.doc = base;
|
|
6347
|
+
this.widthPoint = { nodeId: node.id, index: ref.index, subpath };
|
|
6348
|
+
this.drag = {
|
|
6349
|
+
kind: "width",
|
|
6350
|
+
ref,
|
|
6351
|
+
mode,
|
|
6352
|
+
side,
|
|
6353
|
+
origin: { x: at2.point[0], y: at2.point[1] },
|
|
6354
|
+
normal: { x: at2.tangent[1], y: -at2.tangent[0] },
|
|
6355
|
+
unit: g.unit,
|
|
6356
|
+
profile,
|
|
6357
|
+
before,
|
|
6358
|
+
base,
|
|
6359
|
+
start: p,
|
|
6360
|
+
moved: false,
|
|
6361
|
+
created: !hit
|
|
6362
|
+
};
|
|
6363
|
+
const w = profile[ref.index];
|
|
6364
|
+
this.interaction = { type: "width", ref, mode, width: (w.left + w.right) * g.unit };
|
|
6365
|
+
this.notify(!hit);
|
|
6366
|
+
}
|
|
5060
6367
|
/** The nearest outline point of any visible, unlocked path within the pick distance of document point `p`. */
|
|
5061
6368
|
nearestOutline(p) {
|
|
5062
6369
|
let best = null;
|
|
@@ -5104,7 +6411,12 @@ var VectorEditorController = (_class3 = class {
|
|
|
5104
6411
|
case "pen":
|
|
5105
6412
|
return this.downPen(screen, p, input);
|
|
5106
6413
|
case "pencil":
|
|
5107
|
-
return this.downPencil(p);
|
|
6414
|
+
return this.downPencil(p, input);
|
|
6415
|
+
case "width":
|
|
6416
|
+
return this.downWidth(screen, p, input);
|
|
6417
|
+
case "shapeBuilder":
|
|
6418
|
+
case "paintBucket":
|
|
6419
|
+
return this.downBuilder(p, input);
|
|
5108
6420
|
case "scissors": {
|
|
5109
6421
|
const seg = this.nearestOutline(p);
|
|
5110
6422
|
if (seg) this.cutPathAt(seg.nodeId, seg.point);
|
|
@@ -5240,7 +6552,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5240
6552
|
}
|
|
5241
6553
|
downPen(screen, p, input) {
|
|
5242
6554
|
const before = this.snapshot();
|
|
5243
|
-
const sp = this.pen ? _optionalChain([this, 'access',
|
|
6555
|
+
const sp = this.pen ? _optionalChain([this, 'access', _179 => _179.getNode, 'call', _180 => _180(this.pen.nodeId), 'optionalAccess', _181 => _181.subpaths, 'access', _182 => _182[this.pen.subpath]]) : void 0;
|
|
5244
6556
|
if (this.pen && sp) {
|
|
5245
6557
|
const pen = this.pen;
|
|
5246
6558
|
const first = { nodeId: pen.nodeId, subpath: pen.subpath, index: 0 };
|
|
@@ -5297,7 +6609,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5297
6609
|
this.interaction = { type: "pen", nodeId: node.id };
|
|
5298
6610
|
this.notify(true);
|
|
5299
6611
|
}
|
|
5300
|
-
downPencil(p) {
|
|
6612
|
+
downPencil(p, input = {}) {
|
|
5301
6613
|
const before = this.snapshot();
|
|
5302
6614
|
const node = {
|
|
5303
6615
|
id: this.newId(),
|
|
@@ -5311,7 +6623,11 @@ var VectorEditorController = (_class3 = class {
|
|
|
5311
6623
|
this.setDoc([...this.doc.nodes, node]);
|
|
5312
6624
|
const lazy = new LazyMouse(this.editing.pencilSmoothing * VECTOR_PENCIL_STRING_PX / this.viewport.zoom);
|
|
5313
6625
|
lazy.push([p.x, p.y]);
|
|
5314
|
-
|
|
6626
|
+
const mode = this.editing.pencilPressure;
|
|
6627
|
+
const hasPressure = typeof input.pressure === "number" && Number.isFinite(input.pressure);
|
|
6628
|
+
const record = hasPressure && (mode === "all" || mode === "pen" && input.pointerType === "pen");
|
|
6629
|
+
const pressure = hasPressure ? input.pressure : 0.5;
|
|
6630
|
+
this.drag = { kind: "pencil", nodeId: node.id, points: [[p.x, p.y]], before, lazy, pressures: record ? [pressure] : null, pressure };
|
|
5315
6631
|
this.interaction = { type: "draw", tool: "pencil", nodeId: node.id, bounds: { x: p.x, y: p.y, width: 0, height: 0 } };
|
|
5316
6632
|
this.notify(true);
|
|
5317
6633
|
}
|
|
@@ -5330,6 +6646,11 @@ var VectorEditorController = (_class3 = class {
|
|
|
5330
6646
|
pointerMove(screen, input = {}) {
|
|
5331
6647
|
const p = this.screenToDocument(screen);
|
|
5332
6648
|
const drag = this.drag;
|
|
6649
|
+
if (!drag && (this.tool === "shapeBuilder" || this.tool === "paintBucket")) {
|
|
6650
|
+
this.pointer = p;
|
|
6651
|
+
if (this.hoverBuilder(p, !!input.alt)) this.notify();
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
5333
6654
|
if (!drag) {
|
|
5334
6655
|
const hover = this.computeHover(screen);
|
|
5335
6656
|
const pointerMatters = this.tool === "pen" && !!this.pen;
|
|
@@ -5461,6 +6782,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
5461
6782
|
this.notify(true);
|
|
5462
6783
|
return;
|
|
5463
6784
|
}
|
|
6785
|
+
case "builder":
|
|
6786
|
+
return this.moveBuilder(drag, p);
|
|
5464
6787
|
case "stroke": {
|
|
5465
6788
|
const last = drag.points[drag.points.length - 1];
|
|
5466
6789
|
if (Math.hypot(p.x - last.x, p.y - last.y) * this.viewport.zoom < 1.5) return;
|
|
@@ -5491,7 +6814,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5491
6814
|
}
|
|
5492
6815
|
case "shape": {
|
|
5493
6816
|
const node = this.getNode(drag.nodeId);
|
|
5494
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
6817
|
+
if (_optionalChain([node, 'optionalAccess', _183 => _183.type]) !== "path") return;
|
|
5495
6818
|
const leave = { at: drag.start, constrain: input.shift ? drag.tool === "line" ? "angle" : "square" : null, curves: false };
|
|
5496
6819
|
let end = this.snapDrawn(p, leave, input, () => drag.targets ??= this.drawingTargets(null));
|
|
5497
6820
|
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);
|
|
@@ -5520,19 +6843,43 @@ var VectorEditorController = (_class3 = class {
|
|
|
5520
6843
|
this.notify(true);
|
|
5521
6844
|
return;
|
|
5522
6845
|
}
|
|
6846
|
+
case "width": {
|
|
6847
|
+
if (!drag.moved && Math.hypot(p.x - drag.start.x, p.y - drag.start.y) * this.viewport.zoom < 2) return;
|
|
6848
|
+
drag.moved = true;
|
|
6849
|
+
const node = findVectorNode(drag.base.nodes, drag.ref.nodeId);
|
|
6850
|
+
const local = this.toLocal(node.id, p, drag.base);
|
|
6851
|
+
let profile;
|
|
6852
|
+
if (drag.mode === "move") {
|
|
6853
|
+
const g = vectorStrokeWidthGeometry(node);
|
|
6854
|
+
const near2 = g ? nearestStrokePosition(g.line, [local.x, local.y], drag.ref.subpath) : null;
|
|
6855
|
+
if (!near2) return;
|
|
6856
|
+
profile = setWidthPoint(drag.profile, drag.ref.index, { t: near2.t });
|
|
6857
|
+
} else {
|
|
6858
|
+
const off = ((local.x - drag.origin.x) * drag.normal.x + (local.y - drag.origin.y) * drag.normal.y) / drag.unit;
|
|
6859
|
+
const patch = drag.side === "both" ? { left: Math.abs(off), right: Math.abs(off) } : drag.side === "left" ? { left: Math.max(0, off) } : { right: Math.max(0, -off) };
|
|
6860
|
+
profile = setWidthPoint(drag.profile, drag.ref.index, patch);
|
|
6861
|
+
}
|
|
6862
|
+
this.doc = { ...drag.base, nodes: mapTree(drag.base.nodes, (n) => n.id === node.id ? { ...n, strokeWidthProfile: profile } : n) };
|
|
6863
|
+
const w = profile[drag.ref.index];
|
|
6864
|
+
this.interaction = { type: "width", ref: drag.ref, mode: drag.mode, width: (w.left + w.right) * drag.unit };
|
|
6865
|
+
this.notify(true);
|
|
6866
|
+
return;
|
|
6867
|
+
}
|
|
5523
6868
|
case "pencil": {
|
|
5524
6869
|
const last = drag.points[drag.points.length - 1];
|
|
5525
6870
|
let moved = false;
|
|
6871
|
+
if (typeof input.pressure === "number" && Number.isFinite(input.pressure)) drag.pressure = input.pressure;
|
|
5526
6872
|
for (const q of drag.lazy.push([p.x, p.y])) {
|
|
5527
6873
|
if (Math.hypot(q[0] - last[0], q[1] - last[1]) * this.viewport.zoom < 1.5) continue;
|
|
5528
6874
|
drag.points.push(q);
|
|
6875
|
+
_optionalChain([drag, 'access', _184 => _184.pressures, 'optionalAccess', _185 => _185.push, 'call', _186 => _186(drag.pressure)]);
|
|
5529
6876
|
moved = true;
|
|
5530
6877
|
}
|
|
5531
6878
|
const string = drag.lazy.string();
|
|
5532
6879
|
const node = this.getNode(drag.nodeId);
|
|
5533
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
6880
|
+
if (_optionalChain([node, 'optionalAccess', _187 => _187.type]) !== "path") return;
|
|
5534
6881
|
if (!moved) {
|
|
5535
|
-
if (string && _optionalChain([this, 'access',
|
|
6882
|
+
if (string && _optionalChain([this, 'access', _188 => _188.interaction, 'optionalAccess', _189 => _189.type]) === "draw") {
|
|
5536
6883
|
this.interaction = { ...this.interaction, string: [{ x: string[0][0], y: string[0][1] }, { x: string[1][0], y: string[1][1] }] };
|
|
5537
6884
|
this.notify();
|
|
5538
6885
|
}
|
|
@@ -5568,8 +6915,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
5568
6915
|
}
|
|
5569
6916
|
this.setGuides(res);
|
|
5570
6917
|
return {
|
|
5571
|
-
dx: _optionalChain([res, 'optionalAccess',
|
|
5572
|
-
dy: _optionalChain([res, 'optionalAccess',
|
|
6918
|
+
dx: _optionalChain([res, 'optionalAccess', _190 => _190.x]) ? dx + res.dx : axes.x ? this.gridValue(origin.x + dx) - origin.x : dx,
|
|
6919
|
+
dy: _optionalChain([res, 'optionalAccess', _191 => _191.y]) ? dy + res.dy : axes.y ? this.gridValue(origin.y + dy) - origin.y : dy
|
|
5573
6920
|
};
|
|
5574
6921
|
}
|
|
5575
6922
|
/** The anchor a point drag snaps by, where it started: the grabbed one, else the moving one nearest the press. */
|
|
@@ -5606,7 +6953,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5606
6953
|
}
|
|
5607
6954
|
/** Primary button released. */
|
|
5608
6955
|
pointerUp(screen, input = {}) {
|
|
5609
|
-
if (screen && this.drag && this.drag.kind !== "pan") this.pointerMove(screen, input);
|
|
6956
|
+
if (screen && this.drag && this.drag.kind !== "pan") this.pointerMove(screen, { ...input, pressure: void 0 });
|
|
5610
6957
|
const drag = this.drag;
|
|
5611
6958
|
this.drag = null;
|
|
5612
6959
|
this.interaction = null;
|
|
@@ -5648,7 +6995,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5648
6995
|
if (drag.moved) return this.commit("Corner Radius", drag.before);
|
|
5649
6996
|
if (drag.alt) {
|
|
5650
6997
|
const kind = nextVectorCornerKind(drag.widget.kind);
|
|
5651
|
-
this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access',
|
|
6998
|
+
this.doc = this.updateAnchors(drag.base, drag.refs, (a) => setAnchorCorner(a, _nullishCoalesce(_optionalChain([a, 'access', _192 => _192.corner, 'optionalAccess', _193 => _193.radius]), () => ( 0)), kind));
|
|
5652
6999
|
return this.commit("Corner Kind", drag.before);
|
|
5653
7000
|
}
|
|
5654
7001
|
const ref = drag.widget.ref;
|
|
@@ -5658,6 +7005,17 @@ var VectorEditorController = (_class3 = class {
|
|
|
5658
7005
|
this.notify();
|
|
5659
7006
|
return;
|
|
5660
7007
|
}
|
|
7008
|
+
case "width": {
|
|
7009
|
+
if (drag.moved) return this.commit(drag.mode === "move" ? "Move Width Point" : "Width Point", drag.before);
|
|
7010
|
+
if (drag.created) {
|
|
7011
|
+
this.doc = drag.before.doc;
|
|
7012
|
+
this.widthPoint = null;
|
|
7013
|
+
this.notify(true);
|
|
7014
|
+
} else this.notify();
|
|
7015
|
+
return;
|
|
7016
|
+
}
|
|
7017
|
+
case "builder":
|
|
7018
|
+
return this.upBuilder(drag);
|
|
5661
7019
|
case "stroke": {
|
|
5662
7020
|
this.notify();
|
|
5663
7021
|
if (drag.tool === "knife") this.knife(drag.points);
|
|
@@ -5683,19 +7041,22 @@ var VectorEditorController = (_class3 = class {
|
|
|
5683
7041
|
}
|
|
5684
7042
|
case "pencil": {
|
|
5685
7043
|
const node = this.getNode(drag.nodeId);
|
|
5686
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
7044
|
+
if (_optionalChain([node, 'optionalAccess', _194 => _194.type]) !== "path" || drag.points.length < 2) {
|
|
5687
7045
|
this.doc = drag.before.doc;
|
|
5688
7046
|
this.notify(true);
|
|
5689
7047
|
return;
|
|
5690
7048
|
}
|
|
5691
|
-
for (const q of drag.lazy.finish())
|
|
7049
|
+
for (const q of drag.lazy.finish()) {
|
|
7050
|
+
drag.points.push(q);
|
|
7051
|
+
_optionalChain([drag, 'access', _195 => _195.pressures, 'optionalAccess', _196 => _196.push, 'call', _197 => _197(drag.pressure)]);
|
|
7052
|
+
}
|
|
5692
7053
|
const shape = this.editing.recognizeShapes ? recognizeInkShape(drag.points, { minSize: 6 / this.viewport.zoom }) : null;
|
|
5693
7054
|
if (shape) {
|
|
5694
7055
|
this.replaceNode(drag.nodeId, { ...node, name: inkShapeLabel(shape), subpaths: [inkShapeSubpath(shape)] });
|
|
5695
7056
|
this.selection = [drag.nodeId];
|
|
5696
7057
|
return this.commit(`Draw ${inkShapeLabel(shape)}`, drag.before);
|
|
5697
7058
|
}
|
|
5698
|
-
const fitted =
|
|
7059
|
+
const fitted = _chunk7EDLVBOOcjs.fitCubics.call(void 0, drag.points, 1.5 / this.viewport.zoom, { cornerAngleDeg: 60 });
|
|
5699
7060
|
const anchors = [];
|
|
5700
7061
|
for (const c of fitted) {
|
|
5701
7062
|
if (!anchors.length) anchors.push({ x: c.p0[0], y: c.p0[1] });
|
|
@@ -5703,7 +7064,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
5703
7064
|
anchors.push({ x: c.p3[0], y: c.p3[1], in: { x: c.p2[0], y: c.p2[1] } });
|
|
5704
7065
|
}
|
|
5705
7066
|
const subpaths = anchors.length > 1 ? bezierToSubpaths(subpathsToBezier([{ anchors, closed: false }])) : node.subpaths;
|
|
5706
|
-
|
|
7067
|
+
const profile = drag.pressures ? pencilPressureProfile(drag.points, drag.pressures) : [];
|
|
7068
|
+
this.replaceNode(drag.nodeId, { ...node, subpaths, ...profile.length ? { strokeWidthProfile: profile } : {} });
|
|
5707
7069
|
this.selection = [drag.nodeId];
|
|
5708
7070
|
return this.commit("Draw", drag.before);
|
|
5709
7071
|
}
|
|
@@ -5725,7 +7087,8 @@ var VectorEditorController = (_class3 = class {
|
|
|
5725
7087
|
this.drag = null;
|
|
5726
7088
|
this.interaction = null;
|
|
5727
7089
|
this.guides = null;
|
|
5728
|
-
if (drag.kind === "pan") {
|
|
7090
|
+
if (drag.kind === "pan" || drag.kind === "builder") {
|
|
7091
|
+
if (drag.kind === "builder") this.builderPreview = null;
|
|
5729
7092
|
this.notify();
|
|
5730
7093
|
return;
|
|
5731
7094
|
}
|
|
@@ -5757,7 +7120,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5757
7120
|
this.convertAnchors(a.in || a.out ? "corner" : "smooth", [anchor]);
|
|
5758
7121
|
return;
|
|
5759
7122
|
}
|
|
5760
|
-
const id = _nullishCoalesce(_optionalChain([this, 'access',
|
|
7123
|
+
const id = _nullishCoalesce(_optionalChain([this, 'access', _198 => _198.hover, 'optionalAccess', _199 => _199.segment, 'optionalAccess', _200 => _200.nodeId]), () => ( this.editingId));
|
|
5761
7124
|
if (id) {
|
|
5762
7125
|
const node = this.getNode(id);
|
|
5763
7126
|
const seg = node ? nearestSegment(node, this.toLocal(id, p)) : null;
|
|
@@ -5825,7 +7188,10 @@ var VectorEditorController = (_class3 = class {
|
|
|
5825
7188
|
switch (key) {
|
|
5826
7189
|
case "Escape":
|
|
5827
7190
|
if (this.drag) this.cancelDrag();
|
|
5828
|
-
else if (this.
|
|
7191
|
+
else if (this.tool === "width" && this.widthPoint) {
|
|
7192
|
+
this.widthPoint = null;
|
|
7193
|
+
this.notify();
|
|
7194
|
+
} else if (this.pen) this.finishPath();
|
|
5829
7195
|
else if (this.tool === "direct" && this.anchors.length) {
|
|
5830
7196
|
this.anchors = [];
|
|
5831
7197
|
this.notify();
|
|
@@ -5837,7 +7203,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5837
7203
|
this.finishPath();
|
|
5838
7204
|
return true;
|
|
5839
7205
|
}
|
|
5840
|
-
if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access',
|
|
7206
|
+
if (this.tool === "select" && this.selection.length === 1 && _optionalChain([this, 'access', _201 => _201.getNode, 'call', _202 => _202(this.selection[0]), 'optionalAccess', _203 => _203.type]) === "path") {
|
|
5841
7207
|
this.tool = "direct";
|
|
5842
7208
|
this.editingId = this.selection[0];
|
|
5843
7209
|
this.notify();
|
|
@@ -5846,6 +7212,7 @@ var VectorEditorController = (_class3 = class {
|
|
|
5846
7212
|
return false;
|
|
5847
7213
|
case "Delete":
|
|
5848
7214
|
case "Backspace":
|
|
7215
|
+
if (this.tool === "width" && this.widthPoint) return this.removeWidthPoint(this.widthPoint).ok;
|
|
5849
7216
|
if (this.pen) {
|
|
5850
7217
|
const node = this.getNode(this.pen.nodeId);
|
|
5851
7218
|
const sp = node.subpaths[this.pen.subpath];
|
|
@@ -5927,6 +7294,31 @@ function scaleFor(handle, b, p, mods = {}) {
|
|
|
5927
7294
|
}
|
|
5928
7295
|
return { sx, sy, origin };
|
|
5929
7296
|
}
|
|
7297
|
+
function withStyle(node, style) {
|
|
7298
|
+
const next = { ...node, ...style };
|
|
7299
|
+
if ("strokeWidthProfile" in style) {
|
|
7300
|
+
const p = style.strokeWidthProfile ? sanitizeWidthProfile(style.strokeWidthProfile) : [];
|
|
7301
|
+
if (p.length) next.strokeWidthProfile = p;
|
|
7302
|
+
else delete next.strokeWidthProfile;
|
|
7303
|
+
}
|
|
7304
|
+
return next;
|
|
7305
|
+
}
|
|
7306
|
+
function hiddenOrLocked(nodes, id) {
|
|
7307
|
+
const loc = locateVectorNode(nodes, id);
|
|
7308
|
+
if (!loc) return false;
|
|
7309
|
+
const n = loc.list[loc.index];
|
|
7310
|
+
if (n.locked || n.visible === false) return true;
|
|
7311
|
+
return loc.parent ? hiddenOrLocked(nodes, loc.parent.id) : false;
|
|
7312
|
+
}
|
|
7313
|
+
function pencilPressureProfile(points, pressures) {
|
|
7314
|
+
const n = Math.min(points.length, pressures.length);
|
|
7315
|
+
if (n < 2) return [];
|
|
7316
|
+
const s = [0];
|
|
7317
|
+
for (let i = 1; i < n; i++) s.push(s[i - 1] + Math.hypot(points[i][0] - points[i - 1][0], points[i][1] - points[i - 1][1]));
|
|
7318
|
+
const total = s[n - 1];
|
|
7319
|
+
if (!(total > 0)) return [];
|
|
7320
|
+
return pressureWidthProfile(s.map((d, i) => ({ t: d / total, pressure: pressures[i] })));
|
|
7321
|
+
}
|
|
5930
7322
|
|
|
5931
7323
|
// src/vector/render.ts
|
|
5932
7324
|
var fmt = (n) => Math.round(n * 100) / 100;
|
|
@@ -5953,7 +7345,7 @@ function renderNode(node, defs, idPrefix) {
|
|
|
5953
7345
|
strokeWidth: _nullishCoalesce(node.strokeWidth, () => ( 1)),
|
|
5954
7346
|
...node.strokeLinecap ? { strokeLinecap: node.strokeLinecap } : {},
|
|
5955
7347
|
...node.strokeLinejoin ? { strokeLinejoin: node.strokeLinejoin } : {},
|
|
5956
|
-
..._optionalChain([node, 'access',
|
|
7348
|
+
..._optionalChain([node, 'access', _204 => _204.strokeDasharray, 'optionalAccess', _205 => _205.length]) ? { strokeDasharray: node.strokeDasharray.join(" ") } : {},
|
|
5957
7349
|
fillRule: _nullishCoalesce(node.fillRule, () => ( "nonzero")),
|
|
5958
7350
|
opacity: _nullishCoalesce(node.opacity, () => ( 1))
|
|
5959
7351
|
};
|
|
@@ -5977,7 +7369,7 @@ function screenOutline(state, node) {
|
|
|
5977
7369
|
const v2 = state.viewport;
|
|
5978
7370
|
const view = [v2.zoom, 0, 0, v2.zoom, v2.x, v2.y];
|
|
5979
7371
|
const parent = _nullishCoalesce(vectorParentMatrix(state.document.nodes, node.id), () => ( IDENTITY_MATRIX));
|
|
5980
|
-
return collectWithMatrix(node, parent).map(({ path, parent: m }) =>
|
|
7372
|
+
return collectWithMatrix(node, parent).map(({ path, parent: m }) => _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, vectorPathWorldBezier(path, m), view), { precision: 2 })).join(" ");
|
|
5981
7373
|
}
|
|
5982
7374
|
function collectWithMatrix(node, parent) {
|
|
5983
7375
|
if (node.type === "path") return [{ path: node, parent }];
|
|
@@ -6002,9 +7394,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
6002
7394
|
};
|
|
6003
7395
|
for (const id of state.selection) outline(id, true);
|
|
6004
7396
|
if (state.editingId) outline(state.editingId, true);
|
|
6005
|
-
if (_optionalChain([state, 'access',
|
|
7397
|
+
if (_optionalChain([state, 'access', _206 => _206.hover, 'optionalAccess', _207 => _207.nodeId]) && !state.interaction) outline(state.hover.nodeId, false);
|
|
6006
7398
|
let selectionBox = null;
|
|
6007
|
-
if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access',
|
|
7399
|
+
if (state.tool === "select" && state.selectionFrame && _optionalChain([state, 'access', _208 => _208.interaction, 'optionalAccess', _209 => _209.type]) !== "marquee") {
|
|
6008
7400
|
const g = getVectorSelectionBoxGeometry(state.selectionFrame, state.viewport);
|
|
6009
7401
|
selectionBox = { ...g.box, angle: g.angle, transform: g.transform, corners: g.corners, handles: g.handles };
|
|
6010
7402
|
}
|
|
@@ -6014,9 +7406,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
6014
7406
|
const a = getAnchorWorld(doc, ref);
|
|
6015
7407
|
const s = toScreen(state, a);
|
|
6016
7408
|
const closes = !!state.pen && state.pen.nodeId === ref.nodeId && state.pen.subpath === ref.subpath && ref.index === 0;
|
|
6017
|
-
return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access',
|
|
7409
|
+
return { ref, x: s.x, y: s.y, type: _nullishCoalesce(a.type, () => ( inferAnchorType(a))), selected: selected(ref), hovered: sameAnchor(_optionalChain([state, 'access', _210 => _210.hover, 'optionalAccess', _211 => _211.anchor]), ref), closes };
|
|
6018
7410
|
});
|
|
6019
|
-
if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access',
|
|
7411
|
+
if (state.tool === "pen" && !state.pen && _optionalChain([state, 'access', _212 => _212.hover, 'optionalAccess', _213 => _213.anchor])) {
|
|
6020
7412
|
const a = getAnchorWorld(doc, state.hover.anchor);
|
|
6021
7413
|
if (a) {
|
|
6022
7414
|
const s = toScreen(state, a);
|
|
@@ -6025,15 +7417,15 @@ function getVectorOverlayRenderData(state) {
|
|
|
6025
7417
|
}
|
|
6026
7418
|
const handles = getVisibleHandles(state).flatMap((ref) => {
|
|
6027
7419
|
const a = getAnchorWorld(doc, ref);
|
|
6028
|
-
const h = _optionalChain([a, 'optionalAccess',
|
|
7420
|
+
const h = _optionalChain([a, 'optionalAccess', _214 => _214[ref.handle]]);
|
|
6029
7421
|
if (!a || !h) return [];
|
|
6030
7422
|
const s = toScreen(state, h);
|
|
6031
7423
|
const sa = toScreen(state, a);
|
|
6032
|
-
const hovered = !!_optionalChain([state, 'access',
|
|
7424
|
+
const hovered = !!_optionalChain([state, 'access', _215 => _215.hover, 'optionalAccess', _216 => _216.handle]) && sameAnchor(state.hover.handle, ref) && state.hover.handle.handle === ref.handle;
|
|
6033
7425
|
return [{ ref, x: s.x, y: s.y, anchorX: sa.x, anchorY: sa.y, hovered }];
|
|
6034
7426
|
});
|
|
6035
7427
|
let marquee = null;
|
|
6036
|
-
if (_optionalChain([state, 'access',
|
|
7428
|
+
if (_optionalChain([state, 'access', _217 => _217.interaction, 'optionalAccess', _218 => _218.type]) === "marquee") {
|
|
6037
7429
|
const b = state.interaction.bounds;
|
|
6038
7430
|
const tl = toScreen(state, b);
|
|
6039
7431
|
marquee = { x: tl.x, y: tl.y, width: b.width * z, height: b.height * z };
|
|
@@ -6041,7 +7433,7 @@ function getVectorOverlayRenderData(state) {
|
|
|
6041
7433
|
let penPreview = null;
|
|
6042
7434
|
if (state.tool === "pen" && state.pen && state.pointer && !state.interaction) {
|
|
6043
7435
|
const node = findVectorNode(doc.nodes, state.pen.nodeId);
|
|
6044
|
-
const sp = _optionalChain([node, 'optionalAccess',
|
|
7436
|
+
const sp = _optionalChain([node, 'optionalAccess', _219 => _219.type]) === "path" ? node.subpaths[state.pen.subpath] : void 0;
|
|
6045
7437
|
const last = sp ? getAnchorWorld(doc, { nodeId: state.pen.nodeId, subpath: state.pen.subpath, index: sp.anchors.length - 1 }) : void 0;
|
|
6046
7438
|
if (last) {
|
|
6047
7439
|
const a = toScreen(state, last);
|
|
@@ -6054,9 +7446,9 @@ function getVectorOverlayRenderData(state) {
|
|
|
6054
7446
|
const artboard = { x: origin.x, y: origin.y, width: doc.width * z, height: doc.height * z };
|
|
6055
7447
|
let status = null;
|
|
6056
7448
|
const it = state.interaction;
|
|
6057
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
6058
|
-
else if (_optionalChain([it, 'optionalAccess',
|
|
6059
|
-
else if (_optionalChain([it, 'optionalAccess',
|
|
7449
|
+
if (_optionalChain([it, 'optionalAccess', _220 => _220.type]) === "rotate") status = `${Math.round(it.angle)}\xB0`;
|
|
7450
|
+
else if (_optionalChain([it, 'optionalAccess', _221 => _221.type]) === "move" || _optionalChain([it, 'optionalAccess', _222 => _222.type]) === "anchors") status = `\u0394 ${fmt(it.dx)}, ${fmt(it.dy)}`;
|
|
7451
|
+
else if (_optionalChain([it, 'optionalAccess', _223 => _223.type]) === "scale" || _optionalChain([it, 'optionalAccess', _224 => _224.type]) === "draw") {
|
|
6060
7452
|
const b = it.type === "draw" ? findVectorNode(doc.nodes, it.nodeId) ? vectorNodeBounds(findVectorNode(doc.nodes, it.nodeId)) : null : state.selectionFrame;
|
|
6061
7453
|
if (b) status = `W ${fmt(b.width)} \xD7 H ${fmt(b.height)}`;
|
|
6062
7454
|
}
|
|
@@ -6073,25 +7465,51 @@ function getVectorOverlayRenderData(state) {
|
|
|
6073
7465
|
}
|
|
6074
7466
|
}
|
|
6075
7467
|
let toolStroke = null;
|
|
6076
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
7468
|
+
if (_optionalChain([it, 'optionalAccess', _225 => _225.type]) === "stroke") {
|
|
6077
7469
|
const pts = it.points.map((q) => toScreen(state, q));
|
|
6078
7470
|
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)}` : "");
|
|
6079
7471
|
toolStroke = { tool: it.tool, d, width: fmt(it.width * z) };
|
|
6080
7472
|
}
|
|
6081
7473
|
let pencilString = null;
|
|
6082
|
-
if (_optionalChain([it, 'optionalAccess',
|
|
7474
|
+
if (_optionalChain([it, 'optionalAccess', _226 => _226.type]) === "draw" && it.string) {
|
|
6083
7475
|
const a = toScreen(state, it.string[0]);
|
|
6084
7476
|
const b = toScreen(state, it.string[1]);
|
|
6085
7477
|
pencilString = { x1: fmt(a.x), y1: fmt(a.y), x2: fmt(b.x), y2: fmt(b.y) };
|
|
6086
7478
|
}
|
|
6087
|
-
const dragged = _optionalChain([it, 'optionalAccess',
|
|
7479
|
+
const dragged = _optionalChain([it, 'optionalAccess', _227 => _227.type]) === "corner" ? it.ref : null;
|
|
6088
7480
|
const cornerWidgets = getVectorCornerWidgets(state).map((w) => {
|
|
6089
7481
|
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',
|
|
7482
|
+
return { ref: w.ref, x: fmt(s.x), y: fmt(s.y), radius: w.radius, kind: w.kind, hovered: sameAnchor(_optionalChain([state, 'access', _228 => _228.hover, 'optionalAccess', _229 => _229.corner]), w.ref), active: !!dragged };
|
|
7483
|
+
});
|
|
7484
|
+
if (_optionalChain([it, 'optionalAccess', _230 => _230.type]) === "corner") status = `R ${fmt(it.radius)}`;
|
|
7485
|
+
const cutPoint = state.tool === "scissors" && _optionalChain([state, 'access', _231 => _231.hover, 'optionalAccess', _232 => _232.segment]) && !it ? (({ x, y }) => ({ x: fmt(x), y: fmt(y) }))(toScreen(state, state.hover.segment.point)) : null;
|
|
7486
|
+
const sc = (p) => {
|
|
7487
|
+
const q = toScreen(state, p);
|
|
7488
|
+
return { x: fmt(q.x), y: fmt(q.y) };
|
|
7489
|
+
};
|
|
7490
|
+
const sameWidth = (a, b) => !!a && a.nodeId === b.nodeId && a.index === b.index;
|
|
7491
|
+
const widthPoints = getVectorWidthHandles(state).map((h) => {
|
|
7492
|
+
const c = sc(h);
|
|
7493
|
+
const hw = _optionalChain([state, 'access', _233 => _233.hover, 'optionalAccess', _234 => _234.widthPoint]);
|
|
7494
|
+
const hovered = hw && sameWidth(hw, h.ref) && hw.subpath === h.ref.subpath ? hw.part : null;
|
|
7495
|
+
return { ref: h.ref, x: c.x, y: c.y, left: sc(h.left), right: sc(h.right), selected: h.selected, hovered, active: _optionalChain([it, 'optionalAccess', _235 => _235.type]) === "width" && sameWidth(it.ref, h.ref) };
|
|
6091
7496
|
});
|
|
6092
|
-
|
|
6093
|
-
const
|
|
6094
|
-
|
|
7497
|
+
const spot = state.tool === "width" && !it ? _optionalChain([state, 'access', _236 => _236.hover, 'optionalAccess', _237 => _237.strokeSpot]) : null;
|
|
7498
|
+
const widthSpot = spot ? { ...sc(spot.point), left: sc(spot.left), right: sc(spot.right) } : null;
|
|
7499
|
+
if (_optionalChain([it, 'optionalAccess', _238 => _238.type]) === "width") status = it.mode === "move" ? "Move width point" : `W ${fmt(it.width)}`;
|
|
7500
|
+
let builder = null;
|
|
7501
|
+
if (state.builder) {
|
|
7502
|
+
const v2 = state.viewport;
|
|
7503
|
+
const view = [v2.zoom, 0, 0, v2.zoom, v2.x, v2.y];
|
|
7504
|
+
const d = (path) => _chunk7EDLVBOOcjs.bezierPathToSvg.call(void 0, _chunk7EDLVBOOcjs.transformBezierPath.call(void 0, path, view), { precision: 2 });
|
|
7505
|
+
const trail = state.builder.trail && state.builder.trail.length > 1 ? state.builder.trail.map((q, i) => `${i ? "L" : "M"}${sc(q).x} ${sc(q).y}`).join("") : null;
|
|
7506
|
+
builder = { mode: state.builder.mode, faces: state.builder.faces.map(d), lines: state.builder.lines.map(d), trail };
|
|
7507
|
+
if (state.builder.mode !== "fill" && _optionalChain([it, 'optionalAccess', _239 => _239.type]) === "builder") {
|
|
7508
|
+
const n = state.builder.faces.length;
|
|
7509
|
+
status = state.builder.mode === "erase" ? `Delete ${n} ${n === 1 ? "face" : "faces"}` : `Merge ${n} ${n === 1 ? "face" : "faces"}`;
|
|
7510
|
+
}
|
|
7511
|
+
}
|
|
7512
|
+
return { outlines, selectionBox, anchors, handles, marquee, penPreview, artboard, guides, status, toolStroke, pencilString, cutPoint, cornerWidgets, widthPoints, widthSpot, builder };
|
|
6095
7513
|
}
|
|
6096
7514
|
var VECTOR_OVERLAY_THEME = {
|
|
6097
7515
|
accent: "#0ea5e9",
|
|
@@ -6105,13 +7523,28 @@ var VECTOR_OVERLAY_THEME = {
|
|
|
6105
7523
|
anchorSize: 7,
|
|
6106
7524
|
handleRadius: 3.5,
|
|
6107
7525
|
/** Radius of a live corner widget (a ring with a dot). */
|
|
6108
|
-
cornerWidgetRadius: 4
|
|
7526
|
+
cornerWidgetRadius: 4,
|
|
7527
|
+
/** Half the diagonal of a width point's diamond. */
|
|
7528
|
+
widthPointSize: 5,
|
|
7529
|
+
/** Shape Builder faces to merge and paint bucket regions. */
|
|
7530
|
+
builderFill: "rgba(14, 165, 233, 0.22)",
|
|
7531
|
+
/** Shape Builder faces and line pieces an Alt gesture deletes. */
|
|
7532
|
+
builderErase: "#ef4444",
|
|
7533
|
+
builderEraseFill: "rgba(239, 68, 68, 0.22)"
|
|
6109
7534
|
};
|
|
7535
|
+
function vectorDiamondPath(x, y, r = VECTOR_OVERLAY_THEME.widthPointSize) {
|
|
7536
|
+
return `M${fmt(x)} ${fmt(y - r)}L${fmt(x + r)} ${fmt(y)}L${fmt(x)} ${fmt(y + r)}L${fmt(x - r)} ${fmt(y)}Z`;
|
|
7537
|
+
}
|
|
6110
7538
|
function toVectorModifiers(event) {
|
|
6111
7539
|
return { shift: !!event.shiftKey, alt: !!event.altKey, mod: !!(event.metaKey || event.ctrlKey) };
|
|
6112
7540
|
}
|
|
6113
7541
|
function toVectorPointerInput(event) {
|
|
6114
|
-
return {
|
|
7542
|
+
return {
|
|
7543
|
+
...toVectorModifiers(event),
|
|
7544
|
+
button: event.button,
|
|
7545
|
+
...typeof event.pressure === "number" ? { pressure: event.pressure } : {},
|
|
7546
|
+
...event.pointerType ? { pointerType: event.pointerType } : {}
|
|
7547
|
+
};
|
|
6115
7548
|
}
|
|
6116
7549
|
function toVectorKeyInput(event) {
|
|
6117
7550
|
return { key: event.key, ...toVectorModifiers(event) };
|
|
@@ -6121,7 +7554,7 @@ function isVectorTextTarget(target) {
|
|
|
6121
7554
|
if (!el || typeof el !== "object") return false;
|
|
6122
7555
|
const tag = (_nullishCoalesce(el.tagName, () => ( ""))).toUpperCase();
|
|
6123
7556
|
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
|
|
6124
|
-
return !!el.isContentEditable || _optionalChain([el, 'access',
|
|
7557
|
+
return !!el.isContentEditable || _optionalChain([el, 'access', _240 => _240.getAttribute, 'optionalCall', _241 => _241("contenteditable")]) === "true";
|
|
6125
7558
|
}
|
|
6126
7559
|
function getVectorSelectionStyle(state) {
|
|
6127
7560
|
const paths = [];
|
|
@@ -6129,12 +7562,12 @@ function getVectorSelectionStyle(state) {
|
|
|
6129
7562
|
const node = findVectorNode(state.document.nodes, id);
|
|
6130
7563
|
if (node) paths.push(...collect(node));
|
|
6131
7564
|
}
|
|
6132
|
-
const anchorMode = state.tool === "direct" && !!_optionalChain([state, 'access',
|
|
7565
|
+
const anchorMode = state.tool === "direct" && !!_optionalChain([state, 'access', _242 => _242.selectedAnchors, 'optionalAccess', _243 => _243.length]);
|
|
6133
7566
|
if (anchorMode) {
|
|
6134
7567
|
for (const r of state.selectedAnchors) {
|
|
6135
7568
|
if (paths.some((p) => p.id === r.nodeId)) continue;
|
|
6136
7569
|
const node = findVectorNode(state.document.nodes, r.nodeId);
|
|
6137
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
7570
|
+
if (_optionalChain([node, 'optionalAccess', _244 => _244.type]) === "path") paths.push(node);
|
|
6138
7571
|
}
|
|
6139
7572
|
}
|
|
6140
7573
|
if (!paths.length) return null;
|
|
@@ -6145,7 +7578,7 @@ function getVectorSelectionStyle(state) {
|
|
|
6145
7578
|
for (const c of vectorCorners(p.subpaths)) {
|
|
6146
7579
|
if (anchorMode && !state.selectedAnchors.some((r) => r.nodeId === p.id && r.subpath === c.subpath && r.index === c.index)) continue;
|
|
6147
7580
|
const corner = p.subpaths[c.subpath].anchors[c.index].corner;
|
|
6148
|
-
corners2.push({ radius: _nullishCoalesce(_optionalChain([corner, 'optionalAccess',
|
|
7581
|
+
corners2.push({ radius: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _245 => _245.radius]), () => ( 0)), kind: _nullishCoalesce(_optionalChain([corner, 'optionalAccess', _246 => _246.kind]), () => ( "round")) });
|
|
6149
7582
|
}
|
|
6150
7583
|
}
|
|
6151
7584
|
const c0 = _nullishCoalesce(corners2[0], () => ( { radius: 0, kind: "round" }));
|
|
@@ -6160,6 +7593,8 @@ function getVectorSelectionStyle(state) {
|
|
|
6160
7593
|
arrowAlign: _nullishCoalesce(first.arrowAlign, () => ( "extend")),
|
|
6161
7594
|
startArrowScale: _nullishCoalesce(first.startArrowScale, () => ( 1)),
|
|
6162
7595
|
endArrowScale: _nullishCoalesce(first.endArrowScale, () => ( 1)),
|
|
7596
|
+
strokeWidthProfile: profileOf(first),
|
|
7597
|
+
widthProfile: widthProfilePresetId(profileOf(first)),
|
|
6163
7598
|
cornerRadius: c0.radius,
|
|
6164
7599
|
cornerKind: c0.kind,
|
|
6165
7600
|
corners: corners2.length,
|
|
@@ -6175,12 +7610,17 @@ function getVectorSelectionStyle(state) {
|
|
|
6175
7610
|
arrowAlign: !same((p) => _nullishCoalesce(p.arrowAlign, () => ( "extend"))),
|
|
6176
7611
|
startArrowScale: !same((p) => _nullishCoalesce(p.startArrowScale, () => ( 1))),
|
|
6177
7612
|
endArrowScale: !same((p) => _nullishCoalesce(p.endArrowScale, () => ( 1))),
|
|
7613
|
+
widthProfile: !same(profileOf),
|
|
6178
7614
|
cornerRadius: corners2.some((c) => c.radius !== c0.radius),
|
|
6179
7615
|
cornerKind: corners2.some((c) => c.kind !== c0.kind)
|
|
6180
7616
|
},
|
|
6181
7617
|
pathIds: paths.map((p) => p.id)
|
|
6182
7618
|
};
|
|
6183
7619
|
}
|
|
7620
|
+
function profileOf(p) {
|
|
7621
|
+
const points = sanitizeWidthProfile(p.strokeWidthProfile);
|
|
7622
|
+
return points.length && widthProfilePresetId(points) !== "uniform" ? points : null;
|
|
7623
|
+
}
|
|
6184
7624
|
var VECTOR_STROKE_ALIGN_LABELS = { center: "Center", inside: "Inside", outside: "Outside" };
|
|
6185
7625
|
var VECTOR_CORNER_KIND_LABELS = { round: "Round", inverted: "Inverted", chamfer: "Chamfer" };
|
|
6186
7626
|
var VECTOR_ARROWHEAD_LABELS = {
|
|
@@ -6206,6 +7646,14 @@ var VECTOR_PATH_ACTIONS = [
|
|
|
6206
7646
|
{ id: "smooth", label: "\u223F", title: "Smooth", enabled: (s, p) => s + p > 0, run: (c) => c.smoothPaths() },
|
|
6207
7647
|
{ id: "outline", label: "\u22A1", title: "Outline Stroke", enabled: (s) => s > 0, run: (c) => c.outlineStroke() }
|
|
6208
7648
|
];
|
|
7649
|
+
var VECTOR_PATHFINDER_ACTIONS = [
|
|
7650
|
+
{ id: "divide", label: "\u229E", title: "Divide", min: 1 },
|
|
7651
|
+
{ id: "trim", label: "\u29C9", title: "Trim", min: 2 },
|
|
7652
|
+
{ id: "merge", label: "\u29C8", title: "Merge", min: 2 },
|
|
7653
|
+
{ id: "crop", label: "\u2317", title: "Crop", min: 2 },
|
|
7654
|
+
{ id: "outline", label: "\u2B1A", title: "Outline", min: 1 },
|
|
7655
|
+
{ id: "minusBack", label: "\u2296", title: "Minus Back", min: 2 }
|
|
7656
|
+
];
|
|
6209
7657
|
var VECTOR_EDIT_TOGGLES = [
|
|
6210
7658
|
{ key: "keepShapeOnDelete", label: "Keep", title: "Keep shape when deleting points" },
|
|
6211
7659
|
{ key: "curvatureMoves", label: "Curv", title: "Curvature point moves (Alt flips while dragging)" },
|
|
@@ -6232,6 +7680,19 @@ var POINTS = {
|
|
|
6232
7680
|
minItems: 1,
|
|
6233
7681
|
description: "Polyline [[x, y], \u2026] in document units."
|
|
6234
7682
|
};
|
|
7683
|
+
var WIDTH_POINTS = {
|
|
7684
|
+
type: ["array", "null"],
|
|
7685
|
+
items: {
|
|
7686
|
+
type: "object",
|
|
7687
|
+
properties: {
|
|
7688
|
+
t: { type: "number", minimum: 0, maximum: 1, description: "Position along each subpath by length (0 start, 1 end)." },
|
|
7689
|
+
left: { type: "number", minimum: 0, description: "Left side as a multiple of half the stroke width (1 = uniform)." },
|
|
7690
|
+
right: { type: "number", minimum: 0, description: "Right side (looking along the path, y down)." }
|
|
7691
|
+
},
|
|
7692
|
+
required: ["t", "left", "right"]
|
|
7693
|
+
},
|
|
7694
|
+
description: "Variable-width profile points, interpolated smoothly (monotone cubic); two points at one `t` make a step. `null` or `[]` strokes at a uniform width."
|
|
7695
|
+
};
|
|
6235
7696
|
var PAINT = {
|
|
6236
7697
|
description: 'A CSS colour, `null` for none, or a gradient `{ type: "linear", angle, stops: [{ offset, color }] }`.'
|
|
6237
7698
|
};
|
|
@@ -6248,7 +7709,8 @@ var STYLE_PROPS = {
|
|
|
6248
7709
|
endArrow: { type: ["string", "null"], enum: [...VECTOR_ARROWHEADS, null], description: "Head at the end of an open path, or null for none." },
|
|
6249
7710
|
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
7711
|
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)." }
|
|
7712
|
+
endArrowScale: { type: "number", exclusiveMinimum: 0, description: "End head size as a multiple of the stroke width (default 1)." },
|
|
7713
|
+
strokeWidthProfile: WIDTH_POINTS
|
|
6252
7714
|
};
|
|
6253
7715
|
var pickStyle = (params) => {
|
|
6254
7716
|
const out = {};
|
|
@@ -6264,17 +7726,17 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6264
7726
|
const base = { group, ...options.scope ? { scope: options.scope } : {} };
|
|
6265
7727
|
const hasSelection = () => controller.getState().selection.length ? true : "Nothing is selected.";
|
|
6266
7728
|
const ids = (params) => {
|
|
6267
|
-
const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess',
|
|
7729
|
+
const list2 = _nullishCoalesce(_optionalChain([params, 'optionalAccess', _247 => _247.ids]), () => ( controller.getState().selection));
|
|
6268
7730
|
for (const id of list2) if (!controller.getNode(id)) fail(`There is no node "${id}".`);
|
|
6269
7731
|
if (!list2.length) fail("Nothing is selected; pass ids.");
|
|
6270
7732
|
return list2;
|
|
6271
7733
|
};
|
|
6272
|
-
const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess',
|
|
7734
|
+
const enabledFor = (_, params) => _optionalChain([params, 'optionalAccess', _248 => _248.ids, 'optionalAccess', _249 => _249.length]) ? true : hasSelection();
|
|
6273
7735
|
const anchorsOf = (refs) => {
|
|
6274
7736
|
if (!refs) return [...controller.getState().selectedAnchors];
|
|
6275
7737
|
for (const r of refs) {
|
|
6276
7738
|
const node = controller.getNode(r.nodeId);
|
|
6277
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
7739
|
+
if (_optionalChain([node, 'optionalAccess', _250 => _250.type]) !== "path" || !_optionalChain([node, 'access', _251 => _251.subpaths, 'access', _252 => _252[r.subpath], 'optionalAccess', _253 => _253.anchors, 'access', _254 => _254[r.index]])) fail(`There is no anchor ${r.index} on subpath ${r.subpath} of "${r.nodeId}".`);
|
|
6278
7740
|
}
|
|
6279
7741
|
return refs;
|
|
6280
7742
|
};
|
|
@@ -6365,7 +7827,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6365
7827
|
run: (_ctx, params) => {
|
|
6366
7828
|
const id = controller.addPath(params.d, { ...pickStyle(params), ...params.name ? { name: params.name } : {} });
|
|
6367
7829
|
const node = controller.getNode(id);
|
|
6368
|
-
if (_optionalChain([node, 'optionalAccess',
|
|
7830
|
+
if (_optionalChain([node, 'optionalAccess', _255 => _255.type]) === "path" && !node.subpaths.length) {
|
|
6369
7831
|
controller.undo();
|
|
6370
7832
|
fail("The path data has no points.");
|
|
6371
7833
|
}
|
|
@@ -6397,14 +7859,52 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6397
7859
|
params: { type: "object", properties: { radius: { type: "number", minimum: 0 }, kind: { type: "string", enum: VECTOR_CORNER_KINDS }, ids: IDS, anchors: ANCHORS } },
|
|
6398
7860
|
undoable: true,
|
|
6399
7861
|
run: (_ctx, params) => {
|
|
6400
|
-
const refs = _optionalChain([params, 'optionalAccess',
|
|
6401
|
-
const target = { refs, ids: _optionalChain([params, 'optionalAccess',
|
|
6402
|
-
if (_optionalChain([params, 'optionalAccess',
|
|
6403
|
-
else if (_optionalChain([params, 'optionalAccess',
|
|
7862
|
+
const refs = _optionalChain([params, 'optionalAccess', _256 => _256.anchors]) ? anchorsOf(params.anchors) : void 0;
|
|
7863
|
+
const target = { refs, ids: _optionalChain([params, 'optionalAccess', _257 => _257.ids]) ? ids(params) : void 0 };
|
|
7864
|
+
if (_optionalChain([params, 'optionalAccess', _258 => _258.radius]) !== void 0) check(controller.setCornerRadius(params.radius, { ...target, kind: params.kind }));
|
|
7865
|
+
else if (_optionalChain([params, 'optionalAccess', _259 => _259.kind])) check(controller.setCornerKind(params.kind, target));
|
|
6404
7866
|
else fail("Pass `radius` and / or `kind`.");
|
|
6405
7867
|
return { ok: true };
|
|
6406
7868
|
}
|
|
6407
7869
|
},
|
|
7870
|
+
{
|
|
7871
|
+
...base,
|
|
7872
|
+
id: `${prefix}setWidthProfile`,
|
|
7873
|
+
label: "Width Profile\u2026",
|
|
7874
|
+
keywords: ["variable width", "taper", "tapered", "pressure", "profile", "brush", "calligraphy", "bulge", "thick", "thin"],
|
|
7875
|
+
description: "Gives the stroke of paths a variable width: a `preset` (`uniform` removes the profile), explicit `points` ({ t, left, right }: side scales along each subpath), or a parametric `taper` (startLength / endLength as fractions of the path, startWidth / endWidth 0\u20131, startEase / endEase 0\u20131) and / or `wave` (amount 0\u20131, cycles, phase in degrees). Profiled strokes draw as filled outlines; Outline Stroke bakes them.",
|
|
7876
|
+
params: {
|
|
7877
|
+
type: "object",
|
|
7878
|
+
properties: {
|
|
7879
|
+
ids: IDS,
|
|
7880
|
+
preset: { type: "string", enum: VECTOR_WIDTH_PRESET_IDS },
|
|
7881
|
+
points: WIDTH_POINTS,
|
|
7882
|
+
taper: {
|
|
7883
|
+
type: "object",
|
|
7884
|
+
properties: {
|
|
7885
|
+
startLength: { type: "number", minimum: 0, maximum: 1 },
|
|
7886
|
+
endLength: { type: "number", minimum: 0, maximum: 1 },
|
|
7887
|
+
startWidth: { type: "number", minimum: 0, maximum: 1 },
|
|
7888
|
+
endWidth: { type: "number", minimum: 0, maximum: 1 },
|
|
7889
|
+
startEase: { type: "number", minimum: 0, maximum: 1 },
|
|
7890
|
+
endEase: { type: "number", minimum: 0, maximum: 1 }
|
|
7891
|
+
}
|
|
7892
|
+
},
|
|
7893
|
+
wave: { type: "object", properties: { amount: { type: "number", minimum: 0, maximum: 1 }, cycles: { type: "number", exclusiveMinimum: 0 }, phase: { type: "number" } } }
|
|
7894
|
+
}
|
|
7895
|
+
},
|
|
7896
|
+
enabled: enabledFor,
|
|
7897
|
+
undoable: true,
|
|
7898
|
+
run: (_ctx, params) => {
|
|
7899
|
+
const target = { ids: ids(params) };
|
|
7900
|
+
if (_optionalChain([params, 'optionalAccess', _260 => _260.preset])) check(controller.setWidthProfile(params.preset, target));
|
|
7901
|
+
else if (_optionalChain([params, 'optionalAccess', _261 => _261.points]) !== void 0) check(controller.setWidthProfile(_nullishCoalesce(params.points, () => ( null)), target));
|
|
7902
|
+
else if (_optionalChain([params, 'optionalAccess', _262 => _262.taper]) || _optionalChain([params, 'optionalAccess', _263 => _263.wave])) check(controller.setWidthProfile({ taper: params.taper, wave: params.wave }, target));
|
|
7903
|
+
else fail("Pass `preset`, `points`, `taper` or `wave`.");
|
|
7904
|
+
const node = controller.getNode(target.ids[0]);
|
|
7905
|
+
return { ok: true, points: _optionalChain([node, 'optionalAccess', _264 => _264.type]) === "path" ? _nullishCoalesce(node.strokeWidthProfile, () => ( [])) : [] };
|
|
7906
|
+
}
|
|
7907
|
+
},
|
|
6408
7908
|
{
|
|
6409
7909
|
...base,
|
|
6410
7910
|
id: `${prefix}outlineStroke`,
|
|
@@ -6415,7 +7915,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6415
7915
|
enabled: enabledFor,
|
|
6416
7916
|
undoable: true,
|
|
6417
7917
|
run: (_ctx, params) => {
|
|
6418
|
-
const created = controller.outlineStroke({ ids: _optionalChain([params, 'optionalAccess',
|
|
7918
|
+
const created = controller.outlineStroke({ ids: _optionalChain([params, 'optionalAccess', _265 => _265.ids]) ? ids(params) : void 0 });
|
|
6419
7919
|
if (!created.length) fail("No selected path has a stroke.");
|
|
6420
7920
|
return { ids: created };
|
|
6421
7921
|
}
|
|
@@ -6477,6 +7977,62 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6477
7977
|
return { id };
|
|
6478
7978
|
}
|
|
6479
7979
|
},
|
|
7980
|
+
{
|
|
7981
|
+
...base,
|
|
7982
|
+
id: `${prefix}pathfinder`,
|
|
7983
|
+
label: "Pathfinder\u2026",
|
|
7984
|
+
keywords: ["divide", "trim", "merge", "crop", "outline", "minus back", "split", "faces"],
|
|
7985
|
+
description: "Pathfinder over the given paths (bottom to top): divide (every face its own shape, painted like the top-most shape over it; open unfilled paths cut), trim (hidden parts removed), merge (trim, then touching parts of one fill joined), crop (the top shape crops the others), outline (outlines cut into open strokes where they meet) or minusBack (the top shape minus everything below). Results replace the paths, grouped when there are several.",
|
|
7986
|
+
params: { type: "object", properties: { operation: { type: "string", enum: [...VECTOR_PATHFINDER_OPERATIONS] }, ids: IDS }, required: ["operation"] },
|
|
7987
|
+
undoable: true,
|
|
7988
|
+
run: (_ctx, params) => {
|
|
7989
|
+
if (!VECTOR_PATHFINDER_OPERATIONS.includes(params.operation)) fail(`Unknown Pathfinder operation "${params.operation}".`);
|
|
7990
|
+
const created = controller.pathfinder(params.operation, { ids: ids(params) });
|
|
7991
|
+
if (!created.length) fail("Nothing came out: select paths that overlap (two or more, except for divide and outline).");
|
|
7992
|
+
return { ids: created, selection: [...controller.getState().selection] };
|
|
7993
|
+
}
|
|
7994
|
+
},
|
|
7995
|
+
{
|
|
7996
|
+
...base,
|
|
7997
|
+
id: `${prefix}shapeBuilderFaces`,
|
|
7998
|
+
label: "List Shape Builder Faces",
|
|
7999
|
+
keywords: ["shape builder", "regions", "faces", "planar"],
|
|
8000
|
+
description: "Lists the faces the given paths divide the plane into: path data, area, a point inside and the ids of the paths filling each (empty when only outlines enclose it).",
|
|
8001
|
+
params: { type: "object", properties: { ids: IDS } },
|
|
8002
|
+
run: (_ctx, params) => ({ faces: controller.getShapeBuilderFaces({ ids: ids(params) }) })
|
|
8003
|
+
},
|
|
8004
|
+
{
|
|
8005
|
+
...base,
|
|
8006
|
+
id: `${prefix}shapeBuilder`,
|
|
8007
|
+
label: "Shape Builder",
|
|
8008
|
+
keywords: ["merge faces", "build shape", "combine regions", "delete region"],
|
|
8009
|
+
description: "Shape Builder gesture over the faces of the given paths: `points` is the pointer path in document units (one point is a click; [[x, y], \u2026]; use the points from shapeBuilderFaces). Merges the faces it touches into one shape, or with `erase: true` deletes them and the pieces of unfilled open paths within `tolerance`. Shapes covering those faces lose that area.",
|
|
8010
|
+
params: {
|
|
8011
|
+
type: "object",
|
|
8012
|
+
properties: { points: POINTS, erase: { type: "boolean" }, tolerance: { type: "number", minimum: 0 }, ids: IDS },
|
|
8013
|
+
required: ["points"]
|
|
8014
|
+
},
|
|
8015
|
+
undoable: true,
|
|
8016
|
+
run: (_ctx, params) => {
|
|
8017
|
+
const result = controller.shapeBuilder(params.points.map(([x, y]) => ({ x, y })), { ids: ids(params), erase: params.erase, tolerance: params.tolerance });
|
|
8018
|
+
check(result);
|
|
8019
|
+
return { merged: result.merged, faces: result.faces, lines: result.lines };
|
|
8020
|
+
}
|
|
8021
|
+
},
|
|
8022
|
+
{
|
|
8023
|
+
...base,
|
|
8024
|
+
id: `${prefix}fillRegion`,
|
|
8025
|
+
label: "Fill Region",
|
|
8026
|
+
keywords: ["paint bucket", "live paint", "fill area", "enclosed"],
|
|
8027
|
+
description: "Paint bucket: fills the area the visible outlines enclose around `point` (crossings split, nested shapes left as holes) with a new path in the current fill, below the selection or on top. `gap` closes gaps up to that size between loose ends.",
|
|
8028
|
+
params: { type: "object", properties: { point: { type: "array", items: { type: "number" }, minItems: 2, maxItems: 2, description: "[x, y] in document units." }, gap: { type: "number", minimum: 0 } }, required: ["point"] },
|
|
8029
|
+
undoable: true,
|
|
8030
|
+
run: (_ctx, params) => {
|
|
8031
|
+
const id = controller.fillRegion({ x: params.point[0], y: params.point[1] }, { gap: params.gap });
|
|
8032
|
+
if (!id) fail("No closed region surrounds that point.");
|
|
8033
|
+
return { id };
|
|
8034
|
+
}
|
|
8035
|
+
},
|
|
6480
8036
|
{
|
|
6481
8037
|
...base,
|
|
6482
8038
|
id: `${prefix}align`,
|
|
@@ -6530,7 +8086,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6530
8086
|
enabled: enabledFor,
|
|
6531
8087
|
undoable: true,
|
|
6532
8088
|
run: (_ctx, params) => {
|
|
6533
|
-
const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess',
|
|
8089
|
+
const id = controller.group({ ids: ids(params), name: _optionalChain([params, 'optionalAccess', _266 => _266.name]) });
|
|
6534
8090
|
if (!id) fail("Only nodes that share a parent can be grouped.");
|
|
6535
8091
|
return { id };
|
|
6536
8092
|
}
|
|
@@ -6558,7 +8114,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6558
8114
|
params: { type: "object", properties: { anchors: ANCHORS, keepShape: { type: "boolean" } } },
|
|
6559
8115
|
undoable: true,
|
|
6560
8116
|
run: (_ctx, params) => {
|
|
6561
|
-
check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess',
|
|
8117
|
+
check(controller.deleteAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _267 => _267.anchors])), { keepShape: _optionalChain([params, 'optionalAccess', _268 => _268.keepShape]) }));
|
|
6562
8118
|
return { ok: true };
|
|
6563
8119
|
}
|
|
6564
8120
|
},
|
|
@@ -6613,7 +8169,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6613
8169
|
params: { type: "object", properties: { ids: IDS, tolerance: { type: "number", minimum: 0 } } },
|
|
6614
8170
|
undoable: true,
|
|
6615
8171
|
run: (_ctx, params) => {
|
|
6616
|
-
check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess',
|
|
8172
|
+
check(controller.joinPaths({ ids: _optionalChain([params, 'optionalAccess', _269 => _269.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _270 => _270.tolerance]) }));
|
|
6617
8173
|
return { selection: controller.getState().selection };
|
|
6618
8174
|
}
|
|
6619
8175
|
},
|
|
@@ -6627,7 +8183,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6627
8183
|
params: { type: "object", properties: { axis: { type: "string", enum: ["horizontal", "vertical", "both"] }, anchors: ANCHORS } },
|
|
6628
8184
|
undoable: true,
|
|
6629
8185
|
run: (_ctx, params) => {
|
|
6630
|
-
check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess',
|
|
8186
|
+
check(controller.averageAnchors(_nullishCoalesce(_optionalChain([params, 'optionalAccess', _271 => _271.axis]), () => ( "both")), anchorsOf(_optionalChain([params, 'optionalAccess', _272 => _272.anchors]))));
|
|
6631
8187
|
return { ok: true };
|
|
6632
8188
|
}
|
|
6633
8189
|
},
|
|
@@ -6641,7 +8197,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6641
8197
|
enabled: enabledFor,
|
|
6642
8198
|
undoable: true,
|
|
6643
8199
|
run: (_ctx, params) => {
|
|
6644
|
-
check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess',
|
|
8200
|
+
check(controller.removeRedundantPoints({ ids: _optionalChain([params, 'optionalAccess', _273 => _273.ids]) ? ids(params) : void 0, tolerance: _optionalChain([params, 'optionalAccess', _274 => _274.tolerance]) }));
|
|
6645
8201
|
return { ok: true };
|
|
6646
8202
|
}
|
|
6647
8203
|
},
|
|
@@ -6654,7 +8210,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6654
8210
|
params: { type: "object", properties: { ids: IDS, amount: { type: "number", minimum: 0, maximum: 1 }, anchors: ANCHORS } },
|
|
6655
8211
|
undoable: true,
|
|
6656
8212
|
run: (_ctx, params) => {
|
|
6657
|
-
check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess',
|
|
8213
|
+
check(controller.smoothPaths({ ids: _optionalChain([params, 'optionalAccess', _275 => _275.ids]) ? ids(params) : void 0, amount: _optionalChain([params, 'optionalAccess', _276 => _276.amount]), refs: _optionalChain([params, 'optionalAccess', _277 => _277.anchors]) }));
|
|
6658
8214
|
return { ok: true };
|
|
6659
8215
|
}
|
|
6660
8216
|
},
|
|
@@ -6667,14 +8223,14 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6667
8223
|
params: { type: "object", properties: { nodeId: { type: "string" }, x: { type: "number" }, y: { type: "number" }, anchors: ANCHORS } },
|
|
6668
8224
|
undoable: true,
|
|
6669
8225
|
run: (_ctx, params) => {
|
|
6670
|
-
if (_optionalChain([params, 'optionalAccess',
|
|
8226
|
+
if (_optionalChain([params, 'optionalAccess', _278 => _278.nodeId]) !== void 0) {
|
|
6671
8227
|
if (!controller.getNode(params.nodeId)) fail(`There is no node "${params.nodeId}".`);
|
|
6672
8228
|
if (params.x === void 0 || params.y === void 0) fail("Pass x and y with nodeId.");
|
|
6673
8229
|
const created = controller.cutPathAt(params.nodeId, { x: params.x, y: params.y });
|
|
6674
8230
|
if (!created) fail("Nothing to cut there (the end of an open path, or a locked path).");
|
|
6675
8231
|
return { ids: created };
|
|
6676
8232
|
}
|
|
6677
|
-
check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess',
|
|
8233
|
+
check(controller.cutAtAnchors(anchorsOf(_optionalChain([params, 'optionalAccess', _279 => _279.anchors]))));
|
|
6678
8234
|
return { ids: controller.getState().selection };
|
|
6679
8235
|
}
|
|
6680
8236
|
},
|
|
@@ -6711,7 +8267,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6711
8267
|
id: `${prefix}setEditing`,
|
|
6712
8268
|
label: "Path Editing Options\u2026",
|
|
6713
8269
|
keywords: ["settings", "curvature", "pencil", "smoothing", "lazy mouse", "shapes", "eraser"],
|
|
6714
|
-
description: "Sets how editing behaves: `keepShapeOnDelete`, `curvatureMoves` (anchor drags bend like the Curvature tool), `pencilSmoothing` (lazy mouse, 0\u20131), `recognizeShapes` (pencil scribbles become lines, rectangles, ellipses, polygons) and `
|
|
8270
|
+
description: "Sets how editing behaves: `keepShapeOnDelete`, `curvatureMoves` (anchor drags bend like the Curvature tool), `pencilSmoothing` (lazy mouse, 0\u20131), `recognizeShapes` (pencil scribbles become lines, rectangles, ellipses, polygons), `eraserSize` and `pencilPressure` (`pen`: record pen pressure on pencil strokes as a width profile, `all`: any pointer reporting pressure, `off`).",
|
|
6715
8271
|
params: {
|
|
6716
8272
|
type: "object",
|
|
6717
8273
|
properties: {
|
|
@@ -6719,12 +8275,13 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6719
8275
|
curvatureMoves: { type: "boolean" },
|
|
6720
8276
|
pencilSmoothing: { type: "number", minimum: 0, maximum: 1 },
|
|
6721
8277
|
recognizeShapes: { type: "boolean" },
|
|
6722
|
-
eraserSize: { type: "number", exclusiveMinimum: 0 }
|
|
8278
|
+
eraserSize: { type: "number", exclusiveMinimum: 0 },
|
|
8279
|
+
pencilPressure: { type: "string", enum: ["pen", "all", "off"] }
|
|
6723
8280
|
}
|
|
6724
8281
|
},
|
|
6725
8282
|
run: (_ctx, params) => {
|
|
6726
8283
|
const patch = {};
|
|
6727
|
-
for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize"]) if (_optionalChain([params, 'optionalAccess',
|
|
8284
|
+
for (const key of ["keepShapeOnDelete", "curvatureMoves", "pencilSmoothing", "recognizeShapes", "eraserSize", "pencilPressure"]) if (_optionalChain([params, 'optionalAccess', _280 => _280[key]]) !== void 0) patch[key] = params[key];
|
|
6728
8285
|
controller.setEditing(patch);
|
|
6729
8286
|
return { editing: controller.getState().editing };
|
|
6730
8287
|
}
|
|
@@ -6749,7 +8306,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6749
8306
|
keywords: ["download", "save", "markup"],
|
|
6750
8307
|
description: "Returns the document as SVG markup.",
|
|
6751
8308
|
params: { type: "object", properties: { precision: { type: "integer", minimum: 0, maximum: 8 } } },
|
|
6752
|
-
run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess',
|
|
8309
|
+
run: (_ctx, params) => ({ svg: controller.toSvg({ precision: _optionalChain([params, 'optionalAccess', _281 => _281.precision]) }) })
|
|
6753
8310
|
},
|
|
6754
8311
|
{
|
|
6755
8312
|
...base,
|
|
@@ -6915,5 +8472,51 @@ function createVectorCommands(controller, options = {}) {
|
|
|
6915
8472
|
|
|
6916
8473
|
|
|
6917
8474
|
|
|
6918
|
-
|
|
8475
|
+
|
|
8476
|
+
|
|
8477
|
+
|
|
8478
|
+
|
|
8479
|
+
|
|
8480
|
+
|
|
8481
|
+
|
|
8482
|
+
|
|
8483
|
+
|
|
8484
|
+
|
|
8485
|
+
|
|
8486
|
+
|
|
8487
|
+
|
|
8488
|
+
|
|
8489
|
+
|
|
8490
|
+
|
|
8491
|
+
|
|
8492
|
+
|
|
8493
|
+
|
|
8494
|
+
|
|
8495
|
+
|
|
8496
|
+
|
|
8497
|
+
|
|
8498
|
+
|
|
8499
|
+
|
|
8500
|
+
|
|
8501
|
+
|
|
8502
|
+
|
|
8503
|
+
|
|
8504
|
+
|
|
8505
|
+
|
|
8506
|
+
|
|
8507
|
+
|
|
8508
|
+
|
|
8509
|
+
|
|
8510
|
+
|
|
8511
|
+
|
|
8512
|
+
|
|
8513
|
+
|
|
8514
|
+
|
|
8515
|
+
|
|
8516
|
+
|
|
8517
|
+
|
|
8518
|
+
|
|
8519
|
+
|
|
8520
|
+
|
|
8521
|
+
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_FILL_GAP = VECTOR_FILL_GAP; exports.VECTOR_INK_MAX_CORNERS = VECTOR_INK_MAX_CORNERS; exports.VECTOR_OVERLAY_THEME = VECTOR_OVERLAY_THEME; exports.VECTOR_PATHFINDER_ACTIONS = VECTOR_PATHFINDER_ACTIONS; exports.VECTOR_PATHFINDER_LABELS = VECTOR_PATHFINDER_LABELS; exports.VECTOR_PATHFINDER_OPERATIONS = VECTOR_PATHFINDER_OPERATIONS; exports.VECTOR_PATH_ACTIONS = VECTOR_PATH_ACTIONS; exports.VECTOR_PENCIL_STRING_PX = VECTOR_PENCIL_STRING_PX; exports.VECTOR_PRESSURE_NOMINAL = VECTOR_PRESSURE_NOMINAL; 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.VECTOR_WIDTH_PRESETS = VECTOR_WIDTH_PRESETS; exports.VECTOR_WIDTH_PRESET_IDS = VECTOR_WIDTH_PRESET_IDS; exports.VECTOR_WIDTH_PROFILE_MAX_POINTS = VECTOR_WIDTH_PROFILE_MAX_POINTS; exports.VECTOR_WIDTH_PROFILE_MAX_SCALE = VECTOR_WIDTH_PROFILE_MAX_SCALE; exports.VECTOR_WIDTH_SAME_T = VECTOR_WIDTH_SAME_T; exports.VectorEditorController = VectorEditorController; exports.VectorSnapTargets = VectorSnapTargets; exports.addBuilderHit = addBuilderHit; 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.dashIntervals = dashIntervals; 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.generateWidthProfile = generateWidthProfile; 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.getVectorWidthHandles = getVectorWidthHandles; 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.insertWidthPoint = insertWidthPoint; exports.invertMatrix = invertMatrix; exports.isClosedBezierShape = isClosedBezierShape; exports.isIdentityMatrix = isIdentityMatrix; exports.isUniformWidthProfile = isUniformWidthProfile; exports.isVectorTextTarget = isVectorTextTarget; exports.joinSubpaths = joinSubpaths; exports.knifePath = knifePath; exports.lineSubpath = lineSubpath; exports.locateVectorNode = locateVectorNode; exports.matrixRotation = matrixRotation; exports.mirrorWidthProfile = mirrorWidthProfile; exports.moveAnchorHandle = moveAnchorHandle; exports.multiplyMatrices = multiplyMatrices; exports.nearestSegment = nearestSegment; exports.nearestStrokePosition = nearestStrokePosition; exports.nextVectorCornerKind = nextVectorCornerKind; exports.nodeMatrix = nodeMatrix; exports.parseSvgTransform = parseSvgTransform; exports.parseVectorSvg = parseVectorSvg; exports.planShapeBuilder = planShapeBuilder; exports.polygonSubpath = polygonSubpath; exports.polylineBounds = polylineBounds; exports.pressureWidthProfile = pressureWidthProfile; exports.recognizeInkShape = recognizeInkShape; exports.rectSubpath = rectSubpath; exports.removeAnchorKeepingShape = removeAnchorKeepingShape; exports.removeAnchors = removeAnchors; exports.removeAnchorsKeepingShape = removeAnchorsKeepingShape; exports.removeRedundantPoints = removeRedundantPoints; exports.removeWidthPoints = removeWidthPoints; exports.reverseSubpath = reverseSubpath; exports.reverseWidthProfile = reverseWidthProfile; exports.rotateMatrix = rotateMatrix; exports.roundSubpaths = roundSubpaths; exports.samplePolyline = samplePolyline; exports.sanitizeWidthProfile = sanitizeWidthProfile; exports.scaleFor = scaleFor; exports.scaleMatrix = scaleMatrix; exports.setAnchorCorner = setAnchorCorner; exports.setSubpathCorners = setSubpathCorners; exports.setWidthPoint = setWidthPoint; exports.simplifyPolyline = simplifyPolyline; exports.smoothSubpath = smoothSubpath; exports.splitIntoFaces = splitIntoFaces; exports.splitSubpathAt = splitSubpathAt; exports.starSubpath = starSubpath; exports.strokePositionPoint = strokePositionPoint; exports.strokeWidthProfileOf = strokeWidthProfileOf; exports.subpathEnclosesArea = subpathEnclosesArea; exports.subpathPointAt = subpathPointAt; exports.subpathSegment = subpathSegment; exports.subpathSegmentCount = subpathSegmentCount; exports.subpathsToBezier = subpathsToBezier; exports.taperWaveFactor = taperWaveFactor; exports.toVectorKeyInput = toVectorKeyInput; exports.toVectorModifiers = toVectorModifiers; exports.toVectorPointerInput = toVectorPointerInput; exports.transformVectorNode = transformVectorNode; exports.translateAnchor = translateAnchor; exports.translateMatrix = translateMatrix; exports.unionBounds = unionBounds; exports.variableStrokeOutline = variableStrokeOutline; exports.variableStrokeRings = variableStrokeRings; exports.vectorCornerAt = vectorCornerAt; exports.vectorCorners = vectorCorners; exports.vectorCornersAttribute = vectorCornersAttribute; exports.vectorDiamondPath = vectorDiamondPath; exports.vectorDocumentToSvg = vectorDocumentToSvg; exports.vectorFillMap = vectorFillMap; 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.vectorPathEntries = vectorPathEntries; exports.vectorPathWorldBezier = vectorPathWorldBezier; exports.vectorPathfinderShape = vectorPathfinderShape; exports.vectorResizeCursor = vectorResizeCursor; exports.vectorResultStyle = vectorResultStyle; exports.vectorShapeBuilderHit = vectorShapeBuilderHit; exports.vectorShapeBuilderMap = vectorShapeBuilderMap; exports.vectorStrokeLineArea = vectorStrokeLineArea; exports.vectorStrokeOutline = vectorStrokeOutline; exports.vectorStrokeOutlinePath = vectorStrokeOutlinePath; exports.vectorStrokeParts = vectorStrokeParts; exports.vectorStrokeReach = vectorStrokeReach; exports.vectorStrokeSvgParts = vectorStrokeSvgParts; exports.vectorStrokeWidthGeometry = vectorStrokeWidthGeometry; exports.vectorToolLabel = vectorToolLabel; exports.vectorWorldMatrix = vectorWorldMatrix; exports.walkVectorNodes = walkVectorNodes; exports.widthProfileAt = widthProfileAt; exports.widthProfileFromAttribute = widthProfileFromAttribute; exports.widthProfileMaxScale = widthProfileMaxScale; exports.widthProfilePreset = widthProfilePreset; exports.widthProfilePresetId = widthProfilePresetId; exports.widthProfileToAttribute = widthProfileToAttribute;
|
|
6919
8522
|
//# sourceMappingURL=index.cjs.map
|