modern-path2d 1.2.19 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +208 -220
- package/dist/index.d.cts +16 -1
- package/dist/index.d.mts +16 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +2 -2
- package/dist/index.mjs +208 -222
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -62,6 +62,11 @@ class Vector2 {
|
|
|
62
62
|
get array() {
|
|
63
63
|
return [this.x, this.y];
|
|
64
64
|
}
|
|
65
|
+
finite() {
|
|
66
|
+
this.x = Number.isFinite(this.x) ? this.x : 0;
|
|
67
|
+
this.y = Number.isFinite(this.y) ? this.y : 0;
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
65
70
|
set(x, y) {
|
|
66
71
|
this.x = x;
|
|
67
72
|
this.y = y;
|
|
@@ -1752,7 +1757,7 @@ class Curve {
|
|
|
1752
1757
|
min.min(p);
|
|
1753
1758
|
max.max(p);
|
|
1754
1759
|
}
|
|
1755
|
-
return { min, max };
|
|
1760
|
+
return { min: min.finite(), max: max.finite() };
|
|
1756
1761
|
}
|
|
1757
1762
|
getBoundingBox() {
|
|
1758
1763
|
const { min, max } = this.getMinMax();
|
|
@@ -1788,7 +1793,7 @@ class Curve {
|
|
|
1788
1793
|
const p1 = getPoint(indices[i]);
|
|
1789
1794
|
const p2 = getPoint(indices[i + 1]);
|
|
1790
1795
|
const p3 = getPoint(indices[i + 2]);
|
|
1791
|
-
polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="none" stroke="black" />`;
|
|
1796
|
+
polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="none" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" />`;
|
|
1792
1797
|
}
|
|
1793
1798
|
const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
|
|
1794
1799
|
return `<svg width="${viewBox[2]}" height="${viewBox[3]}" viewBox="${viewBox.join(" ")}" xmlns="http://www.w3.org/2000/svg">${polygonStr}</svg>`;
|
|
@@ -1971,76 +1976,24 @@ class RoundCurve extends Curve {
|
|
|
1971
1976
|
return [this._center];
|
|
1972
1977
|
}
|
|
1973
1978
|
getAdaptivePointArray(output = []) {
|
|
1974
|
-
const { cx, cy, rx, ry,
|
|
1975
|
-
if (!(rx >= 0 && ry >= 0
|
|
1976
|
-
return output;
|
|
1977
|
-
}
|
|
1978
|
-
const n = Math.ceil(2.3 * Math.sqrt(rx + ry));
|
|
1979
|
-
const x = cx;
|
|
1980
|
-
const y = cy;
|
|
1981
|
-
const m = n * 8 + (dx ? 4 : 0) + (dy ? 4 : 0);
|
|
1982
|
-
if (m === 0) {
|
|
1979
|
+
const { cx, cy, rx, ry, startAngle, endAngle, clockwise } = this;
|
|
1980
|
+
if (!(rx >= 0 && ry >= 0)) {
|
|
1983
1981
|
return output;
|
|
1984
1982
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
return output;
|
|
1991
|
-
}
|
|
1992
|
-
let j1 = 0;
|
|
1993
|
-
let j2 = n * 4 + (dx ? 2 : 0) + 2;
|
|
1994
|
-
let j3 = j2;
|
|
1995
|
-
let j4 = m;
|
|
1996
|
-
let x0 = dx + rx;
|
|
1997
|
-
let y0 = dy;
|
|
1998
|
-
let x1 = x + x0;
|
|
1999
|
-
let x2 = x - x0;
|
|
2000
|
-
let y1 = y + y0;
|
|
2001
|
-
output[j1++] = x1;
|
|
2002
|
-
output[j1++] = y1;
|
|
2003
|
-
output[--j2] = y1;
|
|
2004
|
-
output[--j2] = x2;
|
|
2005
|
-
if (dy) {
|
|
2006
|
-
const y22 = y - y0;
|
|
2007
|
-
output[j3++] = x2;
|
|
2008
|
-
output[j3++] = y22;
|
|
2009
|
-
output[--j4] = y22;
|
|
2010
|
-
output[--j4] = x1;
|
|
1983
|
+
let deltaAngle = endAngle - startAngle;
|
|
1984
|
+
if (!clockwise && deltaAngle > 0) {
|
|
1985
|
+
deltaAngle -= 2 * Math.PI;
|
|
1986
|
+
} else if (clockwise && deltaAngle < 0) {
|
|
1987
|
+
deltaAngle += 2 * Math.PI;
|
|
2011
1988
|
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
const
|
|
2016
|
-
const
|
|
2017
|
-
const
|
|
2018
|
-
const
|
|
2019
|
-
|
|
2020
|
-
output[j1++] = x12;
|
|
2021
|
-
output[j1++] = y12;
|
|
2022
|
-
output[--j2] = y12;
|
|
2023
|
-
output[--j2] = x22;
|
|
2024
|
-
output[j3++] = x22;
|
|
2025
|
-
output[j3++] = y22;
|
|
2026
|
-
output[--j4] = y22;
|
|
2027
|
-
output[--j4] = x12;
|
|
2028
|
-
}
|
|
2029
|
-
x0 = dx;
|
|
2030
|
-
y0 = dy + ry;
|
|
2031
|
-
x1 = x + x0;
|
|
2032
|
-
x2 = x - x0;
|
|
2033
|
-
y1 = y + y0;
|
|
2034
|
-
const y2 = y - y0;
|
|
2035
|
-
output[j1++] = x1;
|
|
2036
|
-
output[j1++] = y1;
|
|
2037
|
-
output[--j4] = y2;
|
|
2038
|
-
output[--j4] = x1;
|
|
2039
|
-
if (dx) {
|
|
2040
|
-
output[j1++] = x2;
|
|
2041
|
-
output[j1++] = y1;
|
|
2042
|
-
output[--j4] = y2;
|
|
2043
|
-
output[--j4] = x2;
|
|
1989
|
+
const arcLength = Math.abs(deltaAngle);
|
|
1990
|
+
const n = Math.max(1, Math.ceil(arcLength / (Math.PI / 16)));
|
|
1991
|
+
for (let i = 0; i <= n; i++) {
|
|
1992
|
+
const t = i / n;
|
|
1993
|
+
const angle = startAngle + deltaAngle * t;
|
|
1994
|
+
const x = cx + Math.cos(angle) * rx;
|
|
1995
|
+
const y = cy + Math.sin(angle) * ry;
|
|
1996
|
+
output.push(x, y);
|
|
2044
1997
|
}
|
|
2045
1998
|
return output;
|
|
2046
1999
|
}
|
|
@@ -2100,7 +2053,7 @@ class RoundCurve extends Curve {
|
|
|
2100
2053
|
min.y = Math.min(min.y, cy - halfHeight);
|
|
2101
2054
|
max.x = Math.max(max.x, cx + halfWidth);
|
|
2102
2055
|
max.y = Math.max(max.y, cy + halfHeight);
|
|
2103
|
-
return { min, max };
|
|
2056
|
+
return { min: min.finite(), max: max.finite() };
|
|
2104
2057
|
}
|
|
2105
2058
|
copy(source) {
|
|
2106
2059
|
super.copy(source);
|
|
@@ -2306,121 +2259,6 @@ class ArcCurve extends RoundCurve {
|
|
|
2306
2259
|
}
|
|
2307
2260
|
}
|
|
2308
2261
|
|
|
2309
|
-
class LineCurve extends Curve {
|
|
2310
|
-
constructor(p1 = new Vector2(), p2 = new Vector2()) {
|
|
2311
|
-
super();
|
|
2312
|
-
this.p1 = p1;
|
|
2313
|
-
this.p2 = p2;
|
|
2314
|
-
}
|
|
2315
|
-
static from(p1x, p1y, p2x, p2y) {
|
|
2316
|
-
return new LineCurve(
|
|
2317
|
-
new Vector2(p1x, p1y),
|
|
2318
|
-
new Vector2(p2x, p2y)
|
|
2319
|
-
);
|
|
2320
|
-
}
|
|
2321
|
-
getPoint(t, output = new Vector2()) {
|
|
2322
|
-
if (t === 1) {
|
|
2323
|
-
output.copy(this.p2);
|
|
2324
|
-
} else {
|
|
2325
|
-
output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
|
|
2326
|
-
}
|
|
2327
|
-
return output;
|
|
2328
|
-
}
|
|
2329
|
-
getPointAt(u, output = new Vector2()) {
|
|
2330
|
-
return this.getPoint(u, output);
|
|
2331
|
-
}
|
|
2332
|
-
getTangent(_t, output = new Vector2()) {
|
|
2333
|
-
return output.subVectors(this.p2, this.p1).normalize();
|
|
2334
|
-
}
|
|
2335
|
-
getTangentAt(u, output = new Vector2()) {
|
|
2336
|
-
return this.getTangent(u, output);
|
|
2337
|
-
}
|
|
2338
|
-
getControlPointRefs() {
|
|
2339
|
-
return [this.p1, this.p2];
|
|
2340
|
-
}
|
|
2341
|
-
getAdaptivePointArray(output = []) {
|
|
2342
|
-
output.push(
|
|
2343
|
-
this.p1.x,
|
|
2344
|
-
this.p1.y,
|
|
2345
|
-
this.p2.x,
|
|
2346
|
-
this.p2.y
|
|
2347
|
-
);
|
|
2348
|
-
return output;
|
|
2349
|
-
}
|
|
2350
|
-
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
2351
|
-
const { p1, p2 } = this;
|
|
2352
|
-
min.x = Math.min(min.x, p1.x, p2.x);
|
|
2353
|
-
min.y = Math.min(min.y, p1.y, p2.y);
|
|
2354
|
-
max.x = Math.max(max.x, p1.x, p2.x);
|
|
2355
|
-
max.y = Math.max(max.y, p1.y, p2.y);
|
|
2356
|
-
return { min, max };
|
|
2357
|
-
}
|
|
2358
|
-
toCommands() {
|
|
2359
|
-
const { p1, p2 } = this;
|
|
2360
|
-
return [
|
|
2361
|
-
{ type: "M", x: p1.x, y: p1.y },
|
|
2362
|
-
{ type: "L", x: p2.x, y: p2.y }
|
|
2363
|
-
];
|
|
2364
|
-
}
|
|
2365
|
-
fillTriangulate(options = {}) {
|
|
2366
|
-
let {
|
|
2367
|
-
vertices = [],
|
|
2368
|
-
indices = [],
|
|
2369
|
-
verticesStride = 2,
|
|
2370
|
-
verticesOffset = vertices.length / verticesStride,
|
|
2371
|
-
indicesOffset = indices.length
|
|
2372
|
-
} = options;
|
|
2373
|
-
const x = this.p1.x;
|
|
2374
|
-
const y = this.p1.y;
|
|
2375
|
-
const width = this.p2.x - this.p1.x || 1;
|
|
2376
|
-
const height = this.p2.y - this.p2.y || 1;
|
|
2377
|
-
const points = [
|
|
2378
|
-
x,
|
|
2379
|
-
y,
|
|
2380
|
-
x + width,
|
|
2381
|
-
y,
|
|
2382
|
-
x + width,
|
|
2383
|
-
y + height,
|
|
2384
|
-
x,
|
|
2385
|
-
y + height
|
|
2386
|
-
];
|
|
2387
|
-
let count = 0;
|
|
2388
|
-
verticesOffset *= verticesStride;
|
|
2389
|
-
vertices[verticesOffset + count] = points[0];
|
|
2390
|
-
vertices[verticesOffset + count + 1] = points[1];
|
|
2391
|
-
count += verticesStride;
|
|
2392
|
-
vertices[verticesOffset + count] = points[2];
|
|
2393
|
-
vertices[verticesOffset + count + 1] = points[3];
|
|
2394
|
-
count += verticesStride;
|
|
2395
|
-
vertices[verticesOffset + count] = points[6];
|
|
2396
|
-
vertices[verticesOffset + count + 1] = points[7];
|
|
2397
|
-
count += verticesStride;
|
|
2398
|
-
vertices[verticesOffset + count] = points[4];
|
|
2399
|
-
vertices[verticesOffset + count + 1] = points[5];
|
|
2400
|
-
count += verticesStride;
|
|
2401
|
-
const verticesIndex = verticesOffset / verticesStride;
|
|
2402
|
-
indices[indicesOffset++] = verticesIndex;
|
|
2403
|
-
indices[indicesOffset++] = verticesIndex + 1;
|
|
2404
|
-
indices[indicesOffset++] = verticesIndex + 2;
|
|
2405
|
-
indices[indicesOffset++] = verticesIndex + 1;
|
|
2406
|
-
indices[indicesOffset++] = verticesIndex + 3;
|
|
2407
|
-
indices[indicesOffset++] = verticesIndex + 2;
|
|
2408
|
-
return { vertices, indices };
|
|
2409
|
-
}
|
|
2410
|
-
drawTo(ctx) {
|
|
2411
|
-
const { p1, p2 } = this;
|
|
2412
|
-
ctx.lineTo(p1.x, p1.y);
|
|
2413
|
-
ctx.lineTo(p2.x, p2.y);
|
|
2414
|
-
return this;
|
|
2415
|
-
}
|
|
2416
|
-
copy(source) {
|
|
2417
|
-
super.copy(source);
|
|
2418
|
-
this.p1.copy(source.p1);
|
|
2419
|
-
this.p2.copy(source.p2);
|
|
2420
|
-
return this;
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
2262
|
class CompositeCurve extends Curve {
|
|
2425
2263
|
constructor(curves = []) {
|
|
2426
2264
|
super();
|
|
@@ -2498,39 +2336,13 @@ class CompositeCurve extends Curve {
|
|
|
2498
2336
|
fillTriangulate(options) {
|
|
2499
2337
|
const indices = options?.indices ?? [];
|
|
2500
2338
|
const vertices = options?.vertices ?? [];
|
|
2501
|
-
const lines = [];
|
|
2502
|
-
const fillLines = () => {
|
|
2503
|
-
if (lines.length) {
|
|
2504
|
-
const pointArray = [];
|
|
2505
|
-
lines.forEach((line) => {
|
|
2506
|
-
const x = line.p1.x;
|
|
2507
|
-
const y = line.p1.y;
|
|
2508
|
-
if (pointArray[pointArray.length - 2] !== x || pointArray[pointArray.length - 1] !== y) {
|
|
2509
|
-
pointArray.push(x, y);
|
|
2510
|
-
}
|
|
2511
|
-
pointArray.push(line.p2.x, line.p2.y);
|
|
2512
|
-
});
|
|
2513
|
-
fillTriangulate(pointArray, {
|
|
2514
|
-
...options,
|
|
2515
|
-
indices,
|
|
2516
|
-
vertices
|
|
2517
|
-
});
|
|
2518
|
-
lines.length = 0;
|
|
2519
|
-
}
|
|
2520
|
-
};
|
|
2521
2339
|
this.curves.forEach((curve) => {
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
...options,
|
|
2528
|
-
indices,
|
|
2529
|
-
vertices
|
|
2530
|
-
});
|
|
2531
|
-
}
|
|
2340
|
+
curve.fillTriangulate({
|
|
2341
|
+
...options,
|
|
2342
|
+
indices,
|
|
2343
|
+
vertices
|
|
2344
|
+
});
|
|
2532
2345
|
});
|
|
2533
|
-
fillLines();
|
|
2534
2346
|
return { indices, vertices };
|
|
2535
2347
|
}
|
|
2536
2348
|
applyTransform(transform) {
|
|
@@ -2539,7 +2351,7 @@ class CompositeCurve extends Curve {
|
|
|
2539
2351
|
}
|
|
2540
2352
|
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
2541
2353
|
this.curves.forEach((curve) => curve.getMinMax(min, max));
|
|
2542
|
-
return { min, max };
|
|
2354
|
+
return { min: min.finite(), max: max.finite() };
|
|
2543
2355
|
}
|
|
2544
2356
|
getBoundingBox() {
|
|
2545
2357
|
const { min, max } = this.getMinMax();
|
|
@@ -2639,7 +2451,7 @@ class CubicBezierCurve extends Curve {
|
|
|
2639
2451
|
}
|
|
2640
2452
|
};
|
|
2641
2453
|
samplePoints(tValues, 10);
|
|
2642
|
-
return { min, max };
|
|
2454
|
+
return { min: min.finite(), max: max.finite() };
|
|
2643
2455
|
}
|
|
2644
2456
|
toCommands() {
|
|
2645
2457
|
const { p1, cp1, cp2, p2 } = this;
|
|
@@ -2691,6 +2503,125 @@ class EllipseCurve extends RoundCurve {
|
|
|
2691
2503
|
}
|
|
2692
2504
|
}
|
|
2693
2505
|
|
|
2506
|
+
class LineCurve extends Curve {
|
|
2507
|
+
constructor(p1 = new Vector2(), p2 = new Vector2()) {
|
|
2508
|
+
super();
|
|
2509
|
+
this.p1 = p1;
|
|
2510
|
+
this.p2 = p2;
|
|
2511
|
+
}
|
|
2512
|
+
static from(p1x, p1y, p2x, p2y) {
|
|
2513
|
+
return new LineCurve(
|
|
2514
|
+
new Vector2(p1x, p1y),
|
|
2515
|
+
new Vector2(p2x, p2y)
|
|
2516
|
+
);
|
|
2517
|
+
}
|
|
2518
|
+
getPoint(t, output = new Vector2()) {
|
|
2519
|
+
if (t === 1) {
|
|
2520
|
+
output.copy(this.p2);
|
|
2521
|
+
} else {
|
|
2522
|
+
output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
|
|
2523
|
+
}
|
|
2524
|
+
return output;
|
|
2525
|
+
}
|
|
2526
|
+
getPointAt(u, output = new Vector2()) {
|
|
2527
|
+
return this.getPoint(u, output);
|
|
2528
|
+
}
|
|
2529
|
+
getTangent(_t, output = new Vector2()) {
|
|
2530
|
+
return output.subVectors(this.p2, this.p1).normalize();
|
|
2531
|
+
}
|
|
2532
|
+
getTangentAt(u, output = new Vector2()) {
|
|
2533
|
+
return this.getTangent(u, output);
|
|
2534
|
+
}
|
|
2535
|
+
getControlPointRefs() {
|
|
2536
|
+
return [this.p1, this.p2];
|
|
2537
|
+
}
|
|
2538
|
+
getAdaptivePointArray(output = []) {
|
|
2539
|
+
output.push(
|
|
2540
|
+
this.p1.x,
|
|
2541
|
+
this.p1.y,
|
|
2542
|
+
this.p2.x,
|
|
2543
|
+
this.p2.y
|
|
2544
|
+
);
|
|
2545
|
+
return output;
|
|
2546
|
+
}
|
|
2547
|
+
getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
|
|
2548
|
+
const { p1, p2 } = this;
|
|
2549
|
+
min.x = Math.min(min.x, p1.x, p2.x);
|
|
2550
|
+
min.y = Math.min(min.y, p1.y, p2.y);
|
|
2551
|
+
max.x = Math.max(max.x, p1.x, p2.x);
|
|
2552
|
+
max.y = Math.max(max.y, p1.y, p2.y);
|
|
2553
|
+
return { min: min.finite(), max: max.finite() };
|
|
2554
|
+
}
|
|
2555
|
+
toCommands() {
|
|
2556
|
+
const { p1, p2 } = this;
|
|
2557
|
+
return [
|
|
2558
|
+
{ type: "M", x: p1.x, y: p1.y },
|
|
2559
|
+
{ type: "L", x: p2.x, y: p2.y }
|
|
2560
|
+
];
|
|
2561
|
+
}
|
|
2562
|
+
fillTriangulate(options = {}) {
|
|
2563
|
+
let {
|
|
2564
|
+
vertices = [],
|
|
2565
|
+
indices = [],
|
|
2566
|
+
verticesStride = 2,
|
|
2567
|
+
verticesOffset = vertices.length / verticesStride,
|
|
2568
|
+
indicesOffset = indices.length
|
|
2569
|
+
} = options;
|
|
2570
|
+
const minX = Math.min(this.p1.x, this.p2.x);
|
|
2571
|
+
const maxX = Math.max(this.p1.x, this.p2.x);
|
|
2572
|
+
const minY = Math.min(this.p1.y, this.p2.y);
|
|
2573
|
+
const maxY = Math.max(this.p1.y, this.p2.y);
|
|
2574
|
+
const x = minX;
|
|
2575
|
+
const y = minY;
|
|
2576
|
+
const width = maxX - minX;
|
|
2577
|
+
const height = maxY - minY;
|
|
2578
|
+
const points = [
|
|
2579
|
+
x,
|
|
2580
|
+
y,
|
|
2581
|
+
x + width,
|
|
2582
|
+
y,
|
|
2583
|
+
x + width,
|
|
2584
|
+
y + height,
|
|
2585
|
+
x,
|
|
2586
|
+
y + height
|
|
2587
|
+
];
|
|
2588
|
+
let count = 0;
|
|
2589
|
+
verticesOffset *= verticesStride;
|
|
2590
|
+
vertices[verticesOffset + count] = points[0];
|
|
2591
|
+
vertices[verticesOffset + count + 1] = points[1];
|
|
2592
|
+
count += verticesStride;
|
|
2593
|
+
vertices[verticesOffset + count] = points[2];
|
|
2594
|
+
vertices[verticesOffset + count + 1] = points[3];
|
|
2595
|
+
count += verticesStride;
|
|
2596
|
+
vertices[verticesOffset + count] = points[6];
|
|
2597
|
+
vertices[verticesOffset + count + 1] = points[7];
|
|
2598
|
+
count += verticesStride;
|
|
2599
|
+
vertices[verticesOffset + count] = points[4];
|
|
2600
|
+
vertices[verticesOffset + count + 1] = points[5];
|
|
2601
|
+
count += verticesStride;
|
|
2602
|
+
const verticesIndex = verticesOffset / verticesStride;
|
|
2603
|
+
indices[indicesOffset++] = verticesIndex;
|
|
2604
|
+
indices[indicesOffset++] = verticesIndex + 1;
|
|
2605
|
+
indices[indicesOffset++] = verticesIndex + 2;
|
|
2606
|
+
indices[indicesOffset++] = verticesIndex + 1;
|
|
2607
|
+
indices[indicesOffset++] = verticesIndex + 3;
|
|
2608
|
+
indices[indicesOffset++] = verticesIndex + 2;
|
|
2609
|
+
return { vertices, indices };
|
|
2610
|
+
}
|
|
2611
|
+
drawTo(ctx) {
|
|
2612
|
+
const { p1, p2 } = this;
|
|
2613
|
+
ctx.lineTo(p1.x, p1.y);
|
|
2614
|
+
ctx.lineTo(p2.x, p2.y);
|
|
2615
|
+
return this;
|
|
2616
|
+
}
|
|
2617
|
+
copy(source) {
|
|
2618
|
+
super.copy(source);
|
|
2619
|
+
this.p1.copy(source.p1);
|
|
2620
|
+
this.p2.copy(source.p2);
|
|
2621
|
+
return this;
|
|
2622
|
+
}
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2694
2625
|
class PloygonCurve extends CompositeCurve {
|
|
2695
2626
|
//
|
|
2696
2627
|
}
|
|
@@ -2786,7 +2717,7 @@ class QuadraticBezierCurve extends Curve {
|
|
|
2786
2717
|
min.y = Math.min(min.y, p1.y, p2.y, y1, y2);
|
|
2787
2718
|
max.x = Math.max(max.x, p1.x, p2.x, x1, x2);
|
|
2788
2719
|
max.y = Math.max(max.y, p1.y, p2.y, y1, y2);
|
|
2789
|
-
return { min, max };
|
|
2720
|
+
return { min: min.finite(), max: max.finite() };
|
|
2790
2721
|
}
|
|
2791
2722
|
toCommands() {
|
|
2792
2723
|
const { p1, cp, p2 } = this;
|
|
@@ -3428,7 +3359,7 @@ class Path2D extends CompositeCurve {
|
|
|
3428
3359
|
}
|
|
3429
3360
|
}
|
|
3430
3361
|
});
|
|
3431
|
-
return { min, max };
|
|
3362
|
+
return { min: min.finite(), max: max.finite() };
|
|
3432
3363
|
}
|
|
3433
3364
|
strokeTriangulate(options) {
|
|
3434
3365
|
const indices = options?.indices ?? [];
|
|
@@ -3564,6 +3495,61 @@ class Path2DSet {
|
|
|
3564
3495
|
}
|
|
3565
3496
|
}
|
|
3566
3497
|
|
|
3498
|
+
class FFDControlGrid {
|
|
3499
|
+
constructor(rows, cols, width = 1, height = 1) {
|
|
3500
|
+
this.rows = rows;
|
|
3501
|
+
this.cols = cols;
|
|
3502
|
+
this.width = width;
|
|
3503
|
+
this.height = height;
|
|
3504
|
+
for (let i = 0; i < rows; i++) {
|
|
3505
|
+
this.controlPoints[i] = [];
|
|
3506
|
+
for (let j = 0; j < cols; j++) {
|
|
3507
|
+
this.controlPoints[i][j] = {
|
|
3508
|
+
x: j / (cols - 1) * width,
|
|
3509
|
+
y: i / (rows - 1) * height
|
|
3510
|
+
};
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
controlPoints = [];
|
|
3515
|
+
moveControlPoint(i, j, dx, dy) {
|
|
3516
|
+
this.controlPoints[i][j].x += dx;
|
|
3517
|
+
this.controlPoints[i][j].y += dy;
|
|
3518
|
+
return this;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
function bsplineBasis(t) {
|
|
3522
|
+
const B = [];
|
|
3523
|
+
B[0] = (1 - t) ** 3 / 6;
|
|
3524
|
+
B[1] = (3 * t ** 3 - 6 * t ** 2 + 4) / 6;
|
|
3525
|
+
B[2] = (-3 * t ** 3 + 3 * t ** 2 + 3 * t + 1) / 6;
|
|
3526
|
+
B[3] = t ** 3 / 6;
|
|
3527
|
+
return B;
|
|
3528
|
+
}
|
|
3529
|
+
function applyFFD(point, grid, width = grid.width, height = grid.height) {
|
|
3530
|
+
const s = point.x / width * (grid.cols - 1);
|
|
3531
|
+
const t = point.y / height * (grid.rows - 1);
|
|
3532
|
+
const i = Math.floor(s);
|
|
3533
|
+
const j = Math.floor(t);
|
|
3534
|
+
const u = s - i;
|
|
3535
|
+
const v = t - j;
|
|
3536
|
+
const bu = bsplineBasis(u);
|
|
3537
|
+
const bv = bsplineBasis(v);
|
|
3538
|
+
let x = 0;
|
|
3539
|
+
let y = 0;
|
|
3540
|
+
for (let m = 0; m < 4; m++) {
|
|
3541
|
+
for (let n = 0; n < 4; n++) {
|
|
3542
|
+
const row = Math.min(Math.max(j - 1 + m, 0), grid.rows - 1);
|
|
3543
|
+
const col = Math.min(Math.max(i - 1 + n, 0), grid.cols - 1);
|
|
3544
|
+
const cp = grid.controlPoints[row][col];
|
|
3545
|
+
const weight = bu[n] * bv[m];
|
|
3546
|
+
x += cp.x * weight;
|
|
3547
|
+
y += cp.y * weight;
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
point.set(x, y);
|
|
3551
|
+
}
|
|
3552
|
+
|
|
3567
3553
|
const dataUri = "data:image/svg+xml;";
|
|
3568
3554
|
const base64DataUri = `${dataUri}base64,`;
|
|
3569
3555
|
const utf8DataUri = `${dataUri}charset=utf8,`;
|
|
@@ -4101,6 +4087,7 @@ exports.Curve = Curve;
|
|
|
4101
4087
|
exports.CurvePath = CurvePath;
|
|
4102
4088
|
exports.EllipseCurve = EllipseCurve;
|
|
4103
4089
|
exports.EquilateralPloygonCurve = EquilateralPloygonCurve;
|
|
4090
|
+
exports.FFDControlGrid = FFDControlGrid;
|
|
4104
4091
|
exports.LineCurve = LineCurve;
|
|
4105
4092
|
exports.Matrix3 = Matrix3;
|
|
4106
4093
|
exports.Path2D = Path2D;
|
|
@@ -4111,6 +4098,7 @@ exports.RectangleCurve = RectangleCurve;
|
|
|
4111
4098
|
exports.RoundRectangleCurve = RoundRectangleCurve;
|
|
4112
4099
|
exports.SplineCurve = SplineCurve;
|
|
4113
4100
|
exports.Vector2 = Vector2;
|
|
4101
|
+
exports.applyFFD = applyFFD;
|
|
4114
4102
|
exports.catmullRom = catmullRom;
|
|
4115
4103
|
exports.cubicBezier = cubicBezier;
|
|
4116
4104
|
exports.drawPoint = drawPoint;
|
package/dist/index.d.cts
CHANGED
|
@@ -81,6 +81,7 @@ declare class Vector2 {
|
|
|
81
81
|
static get MIN(): Vector2;
|
|
82
82
|
get array(): [number, number];
|
|
83
83
|
constructor(x?: number, y?: number);
|
|
84
|
+
finite(): this;
|
|
84
85
|
set(x: number, y: number): this;
|
|
85
86
|
add(vec: VectorLike): this;
|
|
86
87
|
sub(vec: VectorLike): this;
|
|
@@ -521,6 +522,20 @@ declare class Path2DSet {
|
|
|
521
522
|
|
|
522
523
|
declare function setCanvasContext(ctx: CanvasRenderingContext2D, style: Partial<Path2DStyle>): void;
|
|
523
524
|
|
|
525
|
+
declare class FFDControlGrid {
|
|
526
|
+
rows: number;
|
|
527
|
+
cols: number;
|
|
528
|
+
width: number;
|
|
529
|
+
height: number;
|
|
530
|
+
controlPoints: {
|
|
531
|
+
x: number;
|
|
532
|
+
y: number;
|
|
533
|
+
}[][];
|
|
534
|
+
constructor(rows: number, cols: number, width?: number, height?: number);
|
|
535
|
+
moveControlPoint(i: number, j: number, dx: number, dy: number): this;
|
|
536
|
+
}
|
|
537
|
+
declare function applyFFD(point: Vector2, grid: FFDControlGrid, width?: number, height?: number): void;
|
|
538
|
+
|
|
524
539
|
/**
|
|
525
540
|
* @link https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
|
526
541
|
* @link https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ Appendix: Endpoint to center arc conversion
|
|
@@ -549,4 +564,4 @@ declare function svgToDOM(svg: string | SVGElement): SVGElement;
|
|
|
549
564
|
|
|
550
565
|
declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
|
|
551
566
|
|
|
552
|
-
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|
|
567
|
+
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|
package/dist/index.d.mts
CHANGED
|
@@ -81,6 +81,7 @@ declare class Vector2 {
|
|
|
81
81
|
static get MIN(): Vector2;
|
|
82
82
|
get array(): [number, number];
|
|
83
83
|
constructor(x?: number, y?: number);
|
|
84
|
+
finite(): this;
|
|
84
85
|
set(x: number, y: number): this;
|
|
85
86
|
add(vec: VectorLike): this;
|
|
86
87
|
sub(vec: VectorLike): this;
|
|
@@ -521,6 +522,20 @@ declare class Path2DSet {
|
|
|
521
522
|
|
|
522
523
|
declare function setCanvasContext(ctx: CanvasRenderingContext2D, style: Partial<Path2DStyle>): void;
|
|
523
524
|
|
|
525
|
+
declare class FFDControlGrid {
|
|
526
|
+
rows: number;
|
|
527
|
+
cols: number;
|
|
528
|
+
width: number;
|
|
529
|
+
height: number;
|
|
530
|
+
controlPoints: {
|
|
531
|
+
x: number;
|
|
532
|
+
y: number;
|
|
533
|
+
}[][];
|
|
534
|
+
constructor(rows: number, cols: number, width?: number, height?: number);
|
|
535
|
+
moveControlPoint(i: number, j: number, dx: number, dy: number): this;
|
|
536
|
+
}
|
|
537
|
+
declare function applyFFD(point: Vector2, grid: FFDControlGrid, width?: number, height?: number): void;
|
|
538
|
+
|
|
524
539
|
/**
|
|
525
540
|
* @link https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
|
526
541
|
* @link https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ Appendix: Endpoint to center arc conversion
|
|
@@ -549,4 +564,4 @@ declare function svgToDOM(svg: string | SVGElement): SVGElement;
|
|
|
549
564
|
|
|
550
565
|
declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
|
|
551
566
|
|
|
552
|
-
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|
|
567
|
+
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|
package/dist/index.d.ts
CHANGED
|
@@ -81,6 +81,7 @@ declare class Vector2 {
|
|
|
81
81
|
static get MIN(): Vector2;
|
|
82
82
|
get array(): [number, number];
|
|
83
83
|
constructor(x?: number, y?: number);
|
|
84
|
+
finite(): this;
|
|
84
85
|
set(x: number, y: number): this;
|
|
85
86
|
add(vec: VectorLike): this;
|
|
86
87
|
sub(vec: VectorLike): this;
|
|
@@ -521,6 +522,20 @@ declare class Path2DSet {
|
|
|
521
522
|
|
|
522
523
|
declare function setCanvasContext(ctx: CanvasRenderingContext2D, style: Partial<Path2DStyle>): void;
|
|
523
524
|
|
|
525
|
+
declare class FFDControlGrid {
|
|
526
|
+
rows: number;
|
|
527
|
+
cols: number;
|
|
528
|
+
width: number;
|
|
529
|
+
height: number;
|
|
530
|
+
controlPoints: {
|
|
531
|
+
x: number;
|
|
532
|
+
y: number;
|
|
533
|
+
}[][];
|
|
534
|
+
constructor(rows: number, cols: number, width?: number, height?: number);
|
|
535
|
+
moveControlPoint(i: number, j: number, dx: number, dy: number): this;
|
|
536
|
+
}
|
|
537
|
+
declare function applyFFD(point: Vector2, grid: FFDControlGrid, width?: number, height?: number): void;
|
|
538
|
+
|
|
524
539
|
/**
|
|
525
540
|
* @link https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
|
|
526
541
|
* @link https://mortoray.com/2017/02/16/rendering-an-svg-elliptical-arc-as-bezier-curves/ Appendix: Endpoint to center arc conversion
|
|
@@ -549,4 +564,4 @@ declare function svgToDOM(svg: string | SVGElement): SVGElement;
|
|
|
549
564
|
|
|
550
565
|
declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
|
|
551
566
|
|
|
552
|
-
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|
|
567
|
+
export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, type DrawPointOptions, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, type FillRule, type FillTriangulateOptions, type FillTriangulatedResult, type LineCap, LineCurve, type LineJoin, type LineStyle, Matrix3, Path2D, type Path2DCommand, type Path2DData, type Path2DDrawStyle, Path2DSet, type Path2DStyle, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, type StrokeLinecap, type StrokeLinejoin, type StrokeTriangulateOptions, type StrokeTriangulatedResult, Vector2, type VectorLike, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
|