modern-path2d 1.3.0 → 1.3.2

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.mjs CHANGED
@@ -1769,32 +1769,6 @@ class Curve {
1769
1769
  options
1770
1770
  );
1771
1771
  }
1772
- toTriangulatedSVGString(result = this.fillTriangulate(), padding = 0) {
1773
- const { vertices, indices } = result;
1774
- const min = { x: -padding, y: -padding };
1775
- const max = { x: padding, y: padding };
1776
- const getPoint = (indice) => {
1777
- const x = vertices[indice * 2];
1778
- const y = vertices[indice * 2 + 1];
1779
- min.x = Math.min(min.x, x + padding);
1780
- max.x = Math.max(max.x, x + padding);
1781
- min.y = Math.min(min.y, y + padding);
1782
- max.y = Math.max(max.y, y + padding);
1783
- return [x, y];
1784
- };
1785
- let polygonStr = "";
1786
- for (let i = 0, len = indices.length; i < len; i += 3) {
1787
- const p1 = getPoint(indices[i]);
1788
- const p2 = getPoint(indices[i + 1]);
1789
- const p3 = getPoint(indices[i + 2]);
1790
- polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="none" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" />`;
1791
- }
1792
- const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
1793
- return `<svg width="${viewBox[2]}" height="${viewBox[3]}" viewBox="${viewBox.join(" ")}" xmlns="http://www.w3.org/2000/svg">${polygonStr}</svg>`;
1794
- }
1795
- toTriangulatedSVG(result, padding) {
1796
- return new DOMParser().parseFromString(this.toTriangulatedSVGString(result, padding), "image/svg+xml").documentElement;
1797
- }
1798
1772
  toCommands() {
1799
1773
  const comds = [];
1800
1774
  const potins = this.getPoints();
@@ -1970,76 +1944,24 @@ class RoundCurve extends Curve {
1970
1944
  return [this._center];
1971
1945
  }
1972
1946
  getAdaptivePointArray(output = []) {
1973
- const { cx, cy, rx, ry, dx, dy } = this;
1974
- if (!(rx >= 0 && ry >= 0 && dx >= 0 && dy >= 0)) {
1947
+ const { cx, cy, rx, ry, startAngle, endAngle, clockwise } = this;
1948
+ if (!(rx >= 0 && ry >= 0)) {
1975
1949
  return output;
1976
1950
  }
1977
- const n = Math.ceil(2.3 * Math.sqrt(rx + ry));
1978
- const x = cx;
1979
- const y = cy;
1980
- const m = n * 8 + (dx ? 4 : 0) + (dy ? 4 : 0);
1981
- if (m === 0) {
1982
- return output;
1983
- }
1984
- if (n === 0) {
1985
- output[0] = output[6] = x + dx;
1986
- output[1] = output[3] = y + dy;
1987
- output[2] = output[4] = x - dx;
1988
- output[5] = output[7] = y - dy;
1989
- return output;
1951
+ let deltaAngle = endAngle - startAngle;
1952
+ if (!clockwise && deltaAngle > 0) {
1953
+ deltaAngle -= 2 * Math.PI;
1954
+ } else if (clockwise && deltaAngle < 0) {
1955
+ deltaAngle += 2 * Math.PI;
1990
1956
  }
1991
- let j1 = 0;
1992
- let j2 = n * 4 + (dx ? 2 : 0) + 2;
1993
- let j3 = j2;
1994
- let j4 = m;
1995
- let x0 = dx + rx;
1996
- let y0 = dy;
1997
- let x1 = x + x0;
1998
- let x2 = x - x0;
1999
- let y1 = y + y0;
2000
- output[j1++] = x1;
2001
- output[j1++] = y1;
2002
- output[--j2] = y1;
2003
- output[--j2] = x2;
2004
- if (dy) {
2005
- const y22 = y - y0;
2006
- output[j3++] = x2;
2007
- output[j3++] = y22;
2008
- output[--j4] = y22;
2009
- output[--j4] = x1;
2010
- }
2011
- for (let i = 1; i < n; i++) {
2012
- const a = Math.PI / 2 * (i / n);
2013
- const x02 = dx + Math.cos(a) * rx;
2014
- const y02 = dy + Math.sin(a) * ry;
2015
- const x12 = x + x02;
2016
- const x22 = x - x02;
2017
- const y12 = y + y02;
2018
- const y22 = y - y02;
2019
- output[j1++] = x12;
2020
- output[j1++] = y12;
2021
- output[--j2] = y12;
2022
- output[--j2] = x22;
2023
- output[j3++] = x22;
2024
- output[j3++] = y22;
2025
- output[--j4] = y22;
2026
- output[--j4] = x12;
2027
- }
2028
- x0 = dx;
2029
- y0 = dy + ry;
2030
- x1 = x + x0;
2031
- x2 = x - x0;
2032
- y1 = y + y0;
2033
- const y2 = y - y0;
2034
- output[j1++] = x1;
2035
- output[j1++] = y1;
2036
- output[--j4] = y2;
2037
- output[--j4] = x1;
2038
- if (dx) {
2039
- output[j1++] = x2;
2040
- output[j1++] = y1;
2041
- output[--j4] = y2;
2042
- output[--j4] = x2;
1957
+ const arcLength = Math.abs(deltaAngle);
1958
+ const n = Math.max(1, Math.ceil(arcLength / (Math.PI / 16)));
1959
+ for (let i = 0; i <= n; i++) {
1960
+ const t = i / n;
1961
+ const angle = startAngle + deltaAngle * t;
1962
+ const x = cx + Math.cos(angle) * rx;
1963
+ const y = cy + Math.sin(angle) * ry;
1964
+ output.push(x, y);
2043
1965
  }
2044
1966
  return output;
2045
1967
  }
@@ -2305,121 +2227,6 @@ class ArcCurve extends RoundCurve {
2305
2227
  }
2306
2228
  }
2307
2229
 
2308
- class LineCurve extends Curve {
2309
- constructor(p1 = new Vector2(), p2 = new Vector2()) {
2310
- super();
2311
- this.p1 = p1;
2312
- this.p2 = p2;
2313
- }
2314
- static from(p1x, p1y, p2x, p2y) {
2315
- return new LineCurve(
2316
- new Vector2(p1x, p1y),
2317
- new Vector2(p2x, p2y)
2318
- );
2319
- }
2320
- getPoint(t, output = new Vector2()) {
2321
- if (t === 1) {
2322
- output.copy(this.p2);
2323
- } else {
2324
- output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
2325
- }
2326
- return output;
2327
- }
2328
- getPointAt(u, output = new Vector2()) {
2329
- return this.getPoint(u, output);
2330
- }
2331
- getTangent(_t, output = new Vector2()) {
2332
- return output.subVectors(this.p2, this.p1).normalize();
2333
- }
2334
- getTangentAt(u, output = new Vector2()) {
2335
- return this.getTangent(u, output);
2336
- }
2337
- getControlPointRefs() {
2338
- return [this.p1, this.p2];
2339
- }
2340
- getAdaptivePointArray(output = []) {
2341
- output.push(
2342
- this.p1.x,
2343
- this.p1.y,
2344
- this.p2.x,
2345
- this.p2.y
2346
- );
2347
- return output;
2348
- }
2349
- getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2350
- const { p1, p2 } = this;
2351
- min.x = Math.min(min.x, p1.x, p2.x);
2352
- min.y = Math.min(min.y, p1.y, p2.y);
2353
- max.x = Math.max(max.x, p1.x, p2.x);
2354
- max.y = Math.max(max.y, p1.y, p2.y);
2355
- return { min: min.finite(), max: max.finite() };
2356
- }
2357
- toCommands() {
2358
- const { p1, p2 } = this;
2359
- return [
2360
- { type: "M", x: p1.x, y: p1.y },
2361
- { type: "L", x: p2.x, y: p2.y }
2362
- ];
2363
- }
2364
- fillTriangulate(options = {}) {
2365
- let {
2366
- vertices = [],
2367
- indices = [],
2368
- verticesStride = 2,
2369
- verticesOffset = vertices.length / verticesStride,
2370
- indicesOffset = indices.length
2371
- } = options;
2372
- const x = this.p1.x;
2373
- const y = this.p1.y;
2374
- const width = this.p2.x - this.p1.x || 1;
2375
- const height = this.p2.y - this.p2.y || 1;
2376
- const points = [
2377
- x,
2378
- y,
2379
- x + width,
2380
- y,
2381
- x + width,
2382
- y + height,
2383
- x,
2384
- y + height
2385
- ];
2386
- let count = 0;
2387
- verticesOffset *= verticesStride;
2388
- vertices[verticesOffset + count] = points[0];
2389
- vertices[verticesOffset + count + 1] = points[1];
2390
- count += verticesStride;
2391
- vertices[verticesOffset + count] = points[2];
2392
- vertices[verticesOffset + count + 1] = points[3];
2393
- count += verticesStride;
2394
- vertices[verticesOffset + count] = points[6];
2395
- vertices[verticesOffset + count + 1] = points[7];
2396
- count += verticesStride;
2397
- vertices[verticesOffset + count] = points[4];
2398
- vertices[verticesOffset + count + 1] = points[5];
2399
- count += verticesStride;
2400
- const verticesIndex = verticesOffset / verticesStride;
2401
- indices[indicesOffset++] = verticesIndex;
2402
- indices[indicesOffset++] = verticesIndex + 1;
2403
- indices[indicesOffset++] = verticesIndex + 2;
2404
- indices[indicesOffset++] = verticesIndex + 1;
2405
- indices[indicesOffset++] = verticesIndex + 3;
2406
- indices[indicesOffset++] = verticesIndex + 2;
2407
- return { vertices, indices };
2408
- }
2409
- drawTo(ctx) {
2410
- const { p1, p2 } = this;
2411
- ctx.lineTo(p1.x, p1.y);
2412
- ctx.lineTo(p2.x, p2.y);
2413
- return this;
2414
- }
2415
- copy(source) {
2416
- super.copy(source);
2417
- this.p1.copy(source.p1);
2418
- this.p2.copy(source.p2);
2419
- return this;
2420
- }
2421
- }
2422
-
2423
2230
  class CompositeCurve extends Curve {
2424
2231
  constructor(curves = []) {
2425
2232
  super();
@@ -2467,7 +2274,9 @@ class CompositeCurve extends Curve {
2467
2274
  return this.curves.flatMap((curve) => curve.getControlPointRefs());
2468
2275
  }
2469
2276
  _removeNextPointIfEqualPrevPoint(output, offset) {
2470
- if (output[offset - 1] === output[offset + 1] && output[offset] === output[offset + 2]) {
2277
+ const p1 = [output[offset - 1], output[offset]];
2278
+ const p2 = [output[offset + 1], output[offset + 2]];
2279
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
2471
2280
  output.splice(offset + 1, 2);
2472
2281
  }
2473
2282
  return output;
@@ -2494,43 +2303,19 @@ class CompositeCurve extends Curve {
2494
2303
  });
2495
2304
  return output;
2496
2305
  }
2306
+ strokeTriangulate(options) {
2307
+ if (this.curves.length === 1) {
2308
+ return this.curves[0].strokeTriangulate(options);
2309
+ } else {
2310
+ return super.strokeTriangulate(options);
2311
+ }
2312
+ }
2497
2313
  fillTriangulate(options) {
2498
- const indices = options?.indices ?? [];
2499
- const vertices = options?.vertices ?? [];
2500
- const lines = [];
2501
- const fillLines = () => {
2502
- if (lines.length) {
2503
- const pointArray = [];
2504
- lines.forEach((line) => {
2505
- const x = line.p1.x;
2506
- const y = line.p1.y;
2507
- if (pointArray[pointArray.length - 2] !== x || pointArray[pointArray.length - 1] !== y) {
2508
- pointArray.push(x, y);
2509
- }
2510
- pointArray.push(line.p2.x, line.p2.y);
2511
- });
2512
- fillTriangulate(pointArray, {
2513
- ...options,
2514
- indices,
2515
- vertices
2516
- });
2517
- lines.length = 0;
2518
- }
2519
- };
2520
- this.curves.forEach((curve) => {
2521
- if (curve instanceof LineCurve) {
2522
- lines.push(curve);
2523
- } else {
2524
- fillLines();
2525
- curve.fillTriangulate({
2526
- ...options,
2527
- indices,
2528
- vertices
2529
- });
2530
- }
2531
- });
2532
- fillLines();
2533
- return { indices, vertices };
2314
+ if (this.curves.length === 1) {
2315
+ return this.curves[0].fillTriangulate(options);
2316
+ } else {
2317
+ return super.fillTriangulate(options);
2318
+ }
2534
2319
  }
2535
2320
  applyTransform(transform) {
2536
2321
  this.curves.forEach((curve) => curve.applyTransform(transform));
@@ -2690,6 +2475,125 @@ class EllipseCurve extends RoundCurve {
2690
2475
  }
2691
2476
  }
2692
2477
 
2478
+ class LineCurve extends Curve {
2479
+ constructor(p1 = new Vector2(), p2 = new Vector2()) {
2480
+ super();
2481
+ this.p1 = p1;
2482
+ this.p2 = p2;
2483
+ }
2484
+ static from(p1x, p1y, p2x, p2y) {
2485
+ return new LineCurve(
2486
+ new Vector2(p1x, p1y),
2487
+ new Vector2(p2x, p2y)
2488
+ );
2489
+ }
2490
+ getPoint(t, output = new Vector2()) {
2491
+ if (t === 1) {
2492
+ output.copy(this.p2);
2493
+ } else {
2494
+ output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
2495
+ }
2496
+ return output;
2497
+ }
2498
+ getPointAt(u, output = new Vector2()) {
2499
+ return this.getPoint(u, output);
2500
+ }
2501
+ getTangent(_t, output = new Vector2()) {
2502
+ return output.subVectors(this.p2, this.p1).normalize();
2503
+ }
2504
+ getTangentAt(u, output = new Vector2()) {
2505
+ return this.getTangent(u, output);
2506
+ }
2507
+ getControlPointRefs() {
2508
+ return [this.p1, this.p2];
2509
+ }
2510
+ getAdaptivePointArray(output = []) {
2511
+ output.push(
2512
+ this.p1.x,
2513
+ this.p1.y,
2514
+ this.p2.x,
2515
+ this.p2.y
2516
+ );
2517
+ return output;
2518
+ }
2519
+ getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2520
+ const { p1, p2 } = this;
2521
+ min.x = Math.min(min.x, p1.x, p2.x);
2522
+ min.y = Math.min(min.y, p1.y, p2.y);
2523
+ max.x = Math.max(max.x, p1.x, p2.x);
2524
+ max.y = Math.max(max.y, p1.y, p2.y);
2525
+ return { min: min.finite(), max: max.finite() };
2526
+ }
2527
+ toCommands() {
2528
+ const { p1, p2 } = this;
2529
+ return [
2530
+ { type: "M", x: p1.x, y: p1.y },
2531
+ { type: "L", x: p2.x, y: p2.y }
2532
+ ];
2533
+ }
2534
+ fillTriangulate(options = {}) {
2535
+ let {
2536
+ vertices = [],
2537
+ indices = [],
2538
+ verticesStride = 2,
2539
+ verticesOffset = vertices.length / verticesStride,
2540
+ indicesOffset = indices.length
2541
+ } = options;
2542
+ const minX = Math.min(this.p1.x, this.p2.x);
2543
+ const maxX = Math.max(this.p1.x, this.p2.x);
2544
+ const minY = Math.min(this.p1.y, this.p2.y);
2545
+ const maxY = Math.max(this.p1.y, this.p2.y);
2546
+ const x = minX;
2547
+ const y = minY;
2548
+ const width = maxX - minX || options.style?.strokeWidth || 1;
2549
+ const height = maxY - minY || options.style?.strokeWidth || 1;
2550
+ const points = [
2551
+ x,
2552
+ y,
2553
+ x + width,
2554
+ y,
2555
+ x + width,
2556
+ y + height,
2557
+ x,
2558
+ y + height
2559
+ ];
2560
+ let count = 0;
2561
+ verticesOffset *= verticesStride;
2562
+ vertices[verticesOffset + count] = points[0];
2563
+ vertices[verticesOffset + count + 1] = points[1];
2564
+ count += verticesStride;
2565
+ vertices[verticesOffset + count] = points[2];
2566
+ vertices[verticesOffset + count + 1] = points[3];
2567
+ count += verticesStride;
2568
+ vertices[verticesOffset + count] = points[6];
2569
+ vertices[verticesOffset + count + 1] = points[7];
2570
+ count += verticesStride;
2571
+ vertices[verticesOffset + count] = points[4];
2572
+ vertices[verticesOffset + count + 1] = points[5];
2573
+ count += verticesStride;
2574
+ const verticesIndex = verticesOffset / verticesStride;
2575
+ indices[indicesOffset++] = verticesIndex;
2576
+ indices[indicesOffset++] = verticesIndex + 1;
2577
+ indices[indicesOffset++] = verticesIndex + 2;
2578
+ indices[indicesOffset++] = verticesIndex + 1;
2579
+ indices[indicesOffset++] = verticesIndex + 3;
2580
+ indices[indicesOffset++] = verticesIndex + 2;
2581
+ return { vertices, indices };
2582
+ }
2583
+ drawTo(ctx) {
2584
+ const { p1, p2 } = this;
2585
+ ctx.lineTo(p1.x, p1.y);
2586
+ ctx.lineTo(p2.x, p2.y);
2587
+ return this;
2588
+ }
2589
+ copy(source) {
2590
+ super.copy(source);
2591
+ this.p1.copy(source.p1);
2592
+ this.p2.copy(source.p2);
2593
+ return this;
2594
+ }
2595
+ }
2596
+
2693
2597
  class PloygonCurve extends CompositeCurve {
2694
2598
  //
2695
2599
  }
@@ -3436,7 +3340,21 @@ class Path2D extends CompositeCurve {
3436
3340
  curve.strokeTriangulate({
3437
3341
  ...options,
3438
3342
  indices,
3439
- vertices
3343
+ vertices,
3344
+ style: { ...this.style }
3345
+ });
3346
+ });
3347
+ return { indices, vertices };
3348
+ }
3349
+ fillTriangulate(options) {
3350
+ const indices = options?.indices ?? [];
3351
+ const vertices = options?.vertices ?? [];
3352
+ this.curves.forEach((curve) => {
3353
+ curve.fillTriangulate({
3354
+ ...options,
3355
+ indices,
3356
+ vertices,
3357
+ style: { ...this.style }
3440
3358
  });
3441
3359
  });
3442
3360
  return { indices, vertices };
@@ -3532,6 +3450,34 @@ class Path2DSet {
3532
3450
  this.paths.forEach((path) => path.getMinMax(min, max, withStyle));
3533
3451
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
3534
3452
  }
3453
+ toTriangulatedSVGString(result = this.paths.map((p) => p.fillTriangulate()), padding = 0) {
3454
+ let polygonStr = "";
3455
+ const min = { x: -padding, y: -padding };
3456
+ const max = { x: padding, y: padding };
3457
+ const results = Array.isArray(result) ? result : [result];
3458
+ results.forEach(({ vertices, indices }) => {
3459
+ const getPoint = (indice) => {
3460
+ const x = vertices[indice * 2];
3461
+ const y = vertices[indice * 2 + 1];
3462
+ min.x = Math.min(min.x, x + padding);
3463
+ max.x = Math.max(max.x, x + padding);
3464
+ min.y = Math.min(min.y, y + padding);
3465
+ max.y = Math.max(max.y, y + padding);
3466
+ return [x, y];
3467
+ };
3468
+ for (let i = 0, len = indices.length; i < len; i += 3) {
3469
+ const p1 = getPoint(indices[i]);
3470
+ const p2 = getPoint(indices[i + 1]);
3471
+ const p3 = getPoint(indices[i + 2]);
3472
+ polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="none" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" />`;
3473
+ }
3474
+ });
3475
+ const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
3476
+ return `<svg width="${viewBox[2]}" height="${viewBox[3]}" viewBox="${viewBox.join(" ")}" xmlns="http://www.w3.org/2000/svg">${polygonStr}</svg>`;
3477
+ }
3478
+ toTriangulatedSVG(result, padding) {
3479
+ return new DOMParser().parseFromString(this.toTriangulatedSVGString(result, padding), "image/svg+xml").documentElement;
3480
+ }
3535
3481
  toSVGString() {
3536
3482
  const { x, y, width, height } = this.getBoundingBox();
3537
3483
  const content = this.paths.map((path) => path.toSVGPathString()).join("");
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "modern-path2d",
3
3
  "type": "module",
4
- "version": "1.3.0",
4
+ "version": "1.3.2",
5
5
  "packageManager": "pnpm@9.15.1",
6
- "description": "A modern Path2D library, fully compatible with Web Path2D, with additional support for path animation, path deformation, path playback, etc.",
6
+ "description": "A Path2D library, fully compatible with Web Path2D, with additional support for triangulate、animationdeformation etc.",
7
7
  "author": "wxm",
8
8
  "license": "MIT",
9
9
  "homepage": "https://github.com/qq15725/modern-path2d",