modern-path2d 1.4.4 → 1.4.6

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 CHANGED
@@ -1722,44 +1722,110 @@ function getDirectedArea(vertices) {
1722
1722
  return area / 2;
1723
1723
  }
1724
1724
 
1725
- function pointInPolygonEvenOdd(point, polygon) {
1726
- let inside = false;
1727
- const [x, y] = point;
1728
- const len = polygon.length / 2;
1729
- for (let i = 0, j = len - 1; i < len; j = i++) {
1730
- const xi = polygon[i * 2];
1731
- const yi = polygon[i * 2 + 1];
1732
- const xj = polygon[j * 2];
1733
- const yj = polygon[j * 2 + 1];
1734
- if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
1735
- inside = !inside;
1736
- }
1725
+ function toKebabCase(str) {
1726
+ return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
1727
+ }
1728
+ function getIntersectionPoint(p1, p2, q1, q2) {
1729
+ const r = p2.clone().sub(p1);
1730
+ const s = q2.clone().sub(q1);
1731
+ const q1p1 = q1.clone().sub(p1);
1732
+ const crossRS = r.cross(s);
1733
+ if (crossRS === 0) {
1734
+ return new Vector2(
1735
+ (p1.x + q1.x) / 2,
1736
+ (p1.y + q1.y) / 2
1737
+ );
1737
1738
  }
1738
- return inside;
1739
+ const t = q1p1.cross(s) / crossRS;
1740
+ if (Math.abs(t) > 1) {
1741
+ return new Vector2(
1742
+ (p1.x + q1.x) / 2,
1743
+ (p1.y + q1.y) / 2
1744
+ );
1745
+ }
1746
+ return new Vector2(
1747
+ p1.x + t * r.x,
1748
+ p1.y + t * r.y
1749
+ );
1739
1750
  }
1740
- function pointInPolygonNonZero(point, polygon) {
1741
- const [x, y] = point;
1742
- const len = polygon.length / 2;
1751
+
1752
+ function centroid(path) {
1753
+ let sx = 0;
1754
+ let sy = 0;
1755
+ const n = path.length / 2;
1756
+ for (let i = 0; i < path.length; i += 2) {
1757
+ sx += path[i];
1758
+ sy += path[i + 1];
1759
+ }
1760
+ return [sx / n, sy / n];
1761
+ }
1762
+ function signedArea(pts) {
1763
+ let sum = 0;
1764
+ const len = pts.length / 2;
1765
+ for (let i = 0; i < len; i++) {
1766
+ const xi = pts[2 * i];
1767
+ const yi = pts[2 * i + 1];
1768
+ const j = (i + 1) % len;
1769
+ const xj = pts[2 * j];
1770
+ const yj = pts[2 * j + 1];
1771
+ sum += (xj - xi) * (yj + yi);
1772
+ }
1773
+ return sum;
1774
+ }
1775
+ function cross(ax, ay, bx, by, cx, cy) {
1776
+ return (bx - ax) * (cy - ay) - (cx - ax) * (by - ay);
1777
+ }
1778
+ function windingNumber(px, py, path) {
1743
1779
  let wn = 0;
1744
- for (let i = 0, j = len - 1; i < len; j = i++) {
1745
- const xi = polygon[i * 2];
1746
- const yi = polygon[i * 2 + 1];
1747
- const xj = polygon[j * 2];
1748
- const yj = polygon[j * 2 + 1];
1749
- if (yi <= y) {
1750
- if (yj > y && cross([xj, yj], [xi, yi], [x, y]) > 0) {
1780
+ for (let i = 0, j = path.length - 2; i < path.length; j = i, i += 2) {
1781
+ const xi = path[i];
1782
+ const yi = path[i + 1];
1783
+ const xj = path[j];
1784
+ const yj = path[j + 1];
1785
+ if (yi <= py) {
1786
+ if (yj > py && cross(xj, yj, xi, yi, px, py) > 0)
1751
1787
  wn++;
1752
- }
1753
1788
  } else {
1754
- if (yj <= y && cross([xj, yj], [xi, yi], [x, y]) < 0) {
1789
+ if (yj <= py && cross(xj, yj, xi, yi, px, py) < 0)
1755
1790
  wn--;
1756
- }
1757
1791
  }
1758
1792
  }
1759
- return wn !== 0;
1793
+ return wn;
1760
1794
  }
1761
- function cross(p0, p1, p2) {
1762
- return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
1795
+ function nonzeroFillRule(paths) {
1796
+ const results = paths.map((_, i) => ({ index: i, parentIndex: null, wn: 0 }));
1797
+ for (let i = 0; i < paths.length; i++) {
1798
+ let best = null;
1799
+ if (signedArea(paths[i]) < 0) {
1800
+ continue;
1801
+ }
1802
+ const points = [
1803
+ paths[i][0],
1804
+ paths[i][1],
1805
+ ...centroid(paths[i])
1806
+ ];
1807
+ for (let j = 0; j < paths.length; j++) {
1808
+ if (i === j) {
1809
+ continue;
1810
+ }
1811
+ let wn0 = 0;
1812
+ for (let p = 0; p < points.length; p += 2) {
1813
+ wn0 = wn0 || windingNumber(points[p], points[p + 1], paths[j]);
1814
+ if (wn0) {
1815
+ break;
1816
+ }
1817
+ }
1818
+ const absWn = Math.abs(wn0);
1819
+ if (absWn !== 0 && (!best || absWn > Math.abs(best.wn))) {
1820
+ best = { idx: j, wn: wn0 };
1821
+ }
1822
+ }
1823
+ if (best) {
1824
+ results[i].parentIndex = best.idx;
1825
+ results[i].wn = best.wn;
1826
+ }
1827
+ }
1828
+ return results;
1763
1829
  }
1764
1830
 
1765
1831
  function quadraticBezierP0(t, p) {
@@ -2829,29 +2895,6 @@ class ArcCurve extends RoundCurve {
2829
2895
  );
2830
2896
  return this;
2831
2897
  }
2832
- getAdaptiveVertices(output = []) {
2833
- const { cx, cy, rx, startAngle, endAngle, clockwise } = this;
2834
- let dist = Math.abs(startAngle - endAngle);
2835
- if (!clockwise && startAngle > endAngle) {
2836
- dist = 2 * Math.PI - dist;
2837
- } else if (clockwise && endAngle > startAngle) {
2838
- dist = 2 * Math.PI - dist;
2839
- }
2840
- let steps = Math.max(6, Math.floor(6 * rx ** (1 / 3) * (dist / Math.PI)));
2841
- steps = Math.max(steps, 3);
2842
- let f = dist / steps;
2843
- let t = startAngle;
2844
- f *= !clockwise ? -1 : 1;
2845
- for (let i = 0; i < steps + 1; i++) {
2846
- const cs = Math.cos(t);
2847
- const sn = Math.sin(t);
2848
- const nx = cx + cs * rx;
2849
- const ny = cy + sn * rx;
2850
- output.push(nx, ny);
2851
- t += f;
2852
- }
2853
- return output;
2854
- }
2855
2898
  }
2856
2899
 
2857
2900
  class LineCurve extends Curve {
@@ -3675,33 +3718,6 @@ class CurvePath extends CompositeCurve {
3675
3718
  }
3676
3719
  }
3677
3720
 
3678
- function toKebabCase(str) {
3679
- return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
3680
- }
3681
- function getIntersectionPoint(p1, p2, q1, q2) {
3682
- const r = p2.clone().sub(p1);
3683
- const s = q2.clone().sub(q1);
3684
- const q1p1 = q1.clone().sub(p1);
3685
- const crossRS = r.cross(s);
3686
- if (crossRS === 0) {
3687
- return new Vector2(
3688
- (p1.x + q1.x) / 2,
3689
- (p1.y + q1.y) / 2
3690
- );
3691
- }
3692
- const t = q1p1.cross(s) / crossRS;
3693
- if (Math.abs(t) > 1) {
3694
- return new Vector2(
3695
- (p1.x + q1.x) / 2,
3696
- (p1.y + q1.y) / 2
3697
- );
3698
- }
3699
- return new Vector2(
3700
- p1.x + t * r.x,
3701
- p1.y + t * r.y
3702
- );
3703
- }
3704
-
3705
3721
  class Path2D extends CompositeCurve {
3706
3722
  currentCurve = new CurvePath();
3707
3723
  style;
@@ -3943,73 +3959,25 @@ class Path2D extends CompositeCurve {
3943
3959
  ...options?.style
3944
3960
  }
3945
3961
  };
3946
- function signedArea(pts) {
3947
- let sum = 0;
3948
- const len = pts.length / 2;
3949
- for (let i = 0; i < len; i++) {
3950
- const xi = pts[2 * i];
3951
- const yi = pts[2 * i + 1];
3952
- const j = (i + 1) % len;
3953
- const xj = pts[2 * j];
3954
- const yj = pts[2 * j + 1];
3955
- sum += (xj - xi) * (yj + yi);
3956
- }
3957
- return sum;
3958
- }
3959
- function isHoleFlat(pts) {
3960
- return signedArea(pts) > 0;
3961
- }
3962
3962
  const indices = _options.indices ?? [];
3963
3963
  const vertices = _options.vertices ?? [];
3964
3964
  const fillRule = _options.style.fillRule ?? "nonzero";
3965
3965
  if (fillRule === "nonzero") {
3966
- const pointArrays = this.curves.map((curve) => curve.getFillVertices(_options));
3967
- const parentMap = /* @__PURE__ */ new Map();
3968
- const parentd = /* @__PURE__ */ new Set();
3969
- for (let i = 0; i < pointArrays.length; i++) {
3970
- if (!isHoleFlat(pointArrays[i])) {
3966
+ const paths = this.curves.map((curve) => curve.getFillVertices(_options));
3967
+ const groups = nonzeroFillRule(paths);
3968
+ for (let i = 0; i < groups.length; i++) {
3969
+ const group = groups[i];
3970
+ const pointArray = paths[i];
3971
+ if (group.wn || !pointArray.length) {
3971
3972
  continue;
3972
3973
  }
3973
- const parents = [];
3974
- for (let j = 0; j < pointArrays.length; j++) {
3975
- if (i === j || isHoleFlat(pointArrays[j]))
3976
- continue;
3977
- let flag = false;
3978
- for (let k = 0; k < pointArrays[i].length; k += 2) {
3979
- flag = flag || pointInPolygonNonZero(
3980
- [pointArrays[i][k], pointArrays[i][k + 1]],
3981
- pointArrays[j]
3982
- );
3983
- if (flag) {
3984
- break;
3985
- }
3986
- }
3987
- if (flag) {
3988
- parents.push(j);
3989
- }
3990
- }
3991
- if (parents.length) {
3992
- parents.forEach((pi) => {
3993
- let set = parentMap.get(pi);
3994
- if (!set) {
3995
- set = /* @__PURE__ */ new Set();
3996
- parentMap.set(pi, set);
3997
- }
3998
- set.add(i);
3999
- });
4000
- parentd.add(i);
4001
- }
4002
- }
4003
- pointArrays.forEach((pointArray, i) => {
4004
- if (parentd.has(i) || !pointArray.length) {
4005
- return;
4006
- }
4007
3974
  const _pointArray = pointArray.slice();
4008
3975
  const holes = [];
4009
- parentMap.get(i)?.forEach((ci) => {
3976
+ const child = groups.find((v) => v.parentIndex === i);
3977
+ if (child) {
4010
3978
  holes.push(_pointArray.length / 2);
4011
- _pointArray.push(...pointArrays[ci]);
4012
- });
3979
+ _pointArray.push(...paths[child.index]);
3980
+ }
4013
3981
  fillTriangulate(_pointArray, {
4014
3982
  ...options,
4015
3983
  indices,
@@ -4017,7 +3985,7 @@ class Path2D extends CompositeCurve {
4017
3985
  holes,
4018
3986
  style: { ...this.style }
4019
3987
  });
4020
- });
3988
+ }
4021
3989
  } else {
4022
3990
  this.curves.forEach((curve) => {
4023
3991
  curve.fillTriangulate({
@@ -4140,7 +4108,7 @@ class Path2DSet {
4140
4108
  const p1 = getPoint(indices[i]);
4141
4109
  const p2 = getPoint(indices[i + 1]);
4142
4110
  const p3 = getPoint(indices[i + 2]);
4143
- polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="black" />`;
4111
+ polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" stroke="none" fill="black" />`;
4144
4112
  }
4145
4113
  });
4146
4114
  const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
@@ -4262,10 +4230,10 @@ exports.fillTriangulate = fillTriangulate;
4262
4230
  exports.getAdaptiveCubicBezierCurvePoints = getAdaptiveCubicBezierCurvePoints;
4263
4231
  exports.getAdaptiveQuadraticBezierCurvePoints = getAdaptiveQuadraticBezierCurvePoints;
4264
4232
  exports.getDirectedArea = getDirectedArea;
4233
+ exports.getIntersectionPoint = getIntersectionPoint;
4234
+ exports.nonzeroFillRule = nonzeroFillRule;
4265
4235
  exports.parseArcCommand = parseArcCommand;
4266
4236
  exports.parsePathDataArgs = parsePathDataArgs;
4267
- exports.pointInPolygonEvenOdd = pointInPolygonEvenOdd;
4268
- exports.pointInPolygonNonZero = pointInPolygonNonZero;
4269
4237
  exports.quadraticBezier = quadraticBezier;
4270
4238
  exports.setCanvasContext = setCanvasContext;
4271
4239
  exports.strokeTriangulate = strokeTriangulate;
@@ -4274,3 +4242,4 @@ exports.svgPathCommandsToData = svgPathCommandsToData;
4274
4242
  exports.svgPathDataToCommands = svgPathDataToCommands;
4275
4243
  exports.svgToDom = svgToDom;
4276
4244
  exports.svgToPath2DSet = svgToPath2DSet;
4245
+ exports.toKebabCase = toKebabCase;
package/dist/index.d.cts CHANGED
@@ -3,6 +3,93 @@ interface DrawPointOptions {
3
3
  }
4
4
  declare function drawPoint(ctx: CanvasRenderingContext2D, x: number, y: number, options?: DrawPointOptions): void;
5
5
 
6
+ /**
7
+ * @link https://developer.mozilla.org/docs/Web/SVG/Attribute/d
8
+ */
9
+ type Path2DCommand = {
10
+ type: 'm' | 'M';
11
+ x: number;
12
+ y: number;
13
+ } | {
14
+ type: 'h' | 'H';
15
+ x: number;
16
+ } | {
17
+ type: 'v' | 'V';
18
+ y: number;
19
+ } | {
20
+ type: 'l' | 'L';
21
+ x: number;
22
+ y: number;
23
+ } | {
24
+ type: 'c' | 'C';
25
+ x1: number;
26
+ y1: number;
27
+ x2: number;
28
+ y2: number;
29
+ x: number;
30
+ y: number;
31
+ } | {
32
+ type: 's' | 'S';
33
+ x2: number;
34
+ y2: number;
35
+ x: number;
36
+ y: number;
37
+ } | {
38
+ type: 'q' | 'Q';
39
+ x1: number;
40
+ y1: number;
41
+ x: number;
42
+ y: number;
43
+ } | {
44
+ type: 't' | 'T';
45
+ x: number;
46
+ y: number;
47
+ } | {
48
+ type: 'a' | 'A';
49
+ rx: number;
50
+ ry: number;
51
+ angle: number;
52
+ largeArcFlag: number;
53
+ sweepFlag: number;
54
+ x: number;
55
+ y: number;
56
+ } | {
57
+ type: 'z' | 'Z';
58
+ };
59
+ /**
60
+ * SVG path data
61
+ *
62
+ * @link https://developer.mozilla.org/docs/Web/SVG/Attribute/d
63
+ */
64
+ type Path2DData = string;
65
+ type FillRule = 'nonzero' | 'evenodd';
66
+ type StrokeLinecap = 'butt' | 'round' | 'square';
67
+ type StrokeLinejoin = 'arcs' | 'bevel' | 'miter' | 'miter-clip' | 'round';
68
+ interface Path2DDrawStyle {
69
+ fill: string | any;
70
+ stroke: string | any;
71
+ shadowColor: string;
72
+ shadowOffsetX: number;
73
+ shadowOffsetY: number;
74
+ shadowBlur: number;
75
+ }
76
+ interface Path2DStyle extends Path2DDrawStyle {
77
+ [key: string]: any;
78
+ fillOpacity: number;
79
+ fillRule: FillRule;
80
+ opacity: number;
81
+ strokeOpacity: number;
82
+ strokeWidth: number;
83
+ strokeLinecap: StrokeLinecap;
84
+ strokeLinejoin: StrokeLinejoin;
85
+ strokeMiterlimit: number;
86
+ strokeDasharray: number[];
87
+ strokeDashoffset: number;
88
+ visibility: string;
89
+ }
90
+
91
+ declare function setCanvasContext(ctx: CanvasRenderingContext2D, style: Partial<Path2DStyle>): void;
92
+
6
93
  declare class Matrix3 {
7
94
  elements: number[];
8
95
  constructor(n11?: number, n12?: number, n13?: number, n21?: number, n22?: number, n23?: number, n31?: number, n32?: number, n33?: number);
@@ -109,8 +196,15 @@ declare function getAdaptiveQuadraticBezierCurvePoints(sX: number, sY: number, x
109
196
 
110
197
  declare function getDirectedArea(vertices: number[]): number;
111
198
 
112
- declare function pointInPolygonEvenOdd(point: number[], polygon: number[]): boolean;
113
- declare function pointInPolygonNonZero(point: number[], polygon: number[]): boolean;
199
+ declare function toKebabCase(str: string): string;
200
+ declare function getIntersectionPoint(p1: Vector2, p2: Vector2, q1: Vector2, q2: Vector2): Vector2;
201
+
202
+ interface Grouping {
203
+ index: number;
204
+ parentIndex: number | null;
205
+ wn: number;
206
+ }
207
+ declare function nonzeroFillRule(paths: number[][]): Grouping[];
114
208
 
115
209
  declare function quadraticBezier(t: number, p0: number, p1: number, p2: number): number;
116
210
 
@@ -214,7 +308,6 @@ declare class RoundCurve extends Curve {
214
308
  declare class ArcCurve extends RoundCurve {
215
309
  constructor(cx?: number, cy?: number, radius?: number, startAngle?: number, endAngle?: number, clockwise?: boolean);
216
310
  drawTo(ctx: CanvasRenderingContext2D): this;
217
- getAdaptiveVertices(output?: number[]): number[];
218
311
  }
219
312
 
220
313
  declare class CompositeCurve<T extends Curve = Curve> extends Curve {
@@ -350,60 +443,6 @@ declare class SplineCurve extends Curve {
350
443
  copy(source: SplineCurve): this;
351
444
  }
352
445
 
353
- /**
354
- * @link https://developer.mozilla.org/docs/Web/SVG/Attribute/d
355
- */
356
- type Path2DCommand = {
357
- type: 'm' | 'M';
358
- x: number;
359
- y: number;
360
- } | {
361
- type: 'h' | 'H';
362
- x: number;
363
- } | {
364
- type: 'v' | 'V';
365
- y: number;
366
- } | {
367
- type: 'l' | 'L';
368
- x: number;
369
- y: number;
370
- } | {
371
- type: 'c' | 'C';
372
- x1: number;
373
- y1: number;
374
- x2: number;
375
- y2: number;
376
- x: number;
377
- y: number;
378
- } | {
379
- type: 's' | 'S';
380
- x2: number;
381
- y2: number;
382
- x: number;
383
- y: number;
384
- } | {
385
- type: 'q' | 'Q';
386
- x1: number;
387
- y1: number;
388
- x: number;
389
- y: number;
390
- } | {
391
- type: 't' | 'T';
392
- x: number;
393
- y: number;
394
- } | {
395
- type: 'a' | 'A';
396
- rx: number;
397
- ry: number;
398
- angle: number;
399
- largeArcFlag: number;
400
- sweepFlag: number;
401
- x: number;
402
- y: number;
403
- } | {
404
- type: 'z' | 'Z';
405
- };
406
-
407
446
  declare class CurvePath extends CompositeCurve {
408
447
  startPoint?: Vector2;
409
448
  currentPoint?: Vector2;
@@ -436,39 +475,6 @@ declare class CurvePath extends CompositeCurve {
436
475
  copy(source: CurvePath): this;
437
476
  }
438
477
 
439
- /**
440
- * Svg path data
441
- *
442
- * @link https://developer.mozilla.org/docs/Web/SVG/Attribute/d
443
- */
444
- type Path2DData = string;
445
-
446
- type FillRule = 'nonzero' | 'evenodd';
447
- type StrokeLinecap = 'butt' | 'round' | 'square';
448
- type StrokeLinejoin = 'arcs' | 'bevel' | 'miter' | 'miter-clip' | 'round';
449
- interface Path2DDrawStyle {
450
- fill: string | any;
451
- stroke: string | any;
452
- shadowColor: string;
453
- shadowOffsetX: number;
454
- shadowOffsetY: number;
455
- shadowBlur: number;
456
- }
457
- interface Path2DStyle extends Path2DDrawStyle {
458
- [key: string]: any;
459
- fillOpacity: number;
460
- fillRule: FillRule;
461
- opacity: number;
462
- strokeOpacity: number;
463
- strokeWidth: number;
464
- strokeLinecap: StrokeLinecap;
465
- strokeLinejoin: StrokeLinejoin;
466
- strokeMiterlimit: number;
467
- strokeDasharray: number[];
468
- strokeDashoffset: number;
469
- visibility: string;
470
- }
471
-
472
478
  /**
473
479
  * @link https://developer.mozilla.org/zh-CN/docs/Web/API/Path2D
474
480
  *
@@ -535,8 +541,6 @@ declare class Path2DSet {
535
541
  }>): HTMLCanvasElement;
536
542
  }
537
543
 
538
- declare function setCanvasContext(ctx: CanvasRenderingContext2D, style: Partial<Path2DStyle>): void;
539
-
540
544
  declare class FFDControlGrid {
541
545
  rows: number;
542
546
  cols: number;
@@ -579,5 +583,5 @@ declare function svgToDom(svg: string | SVGElement): SVGElement;
579
583
 
580
584
  declare function svgToPath2DSet(svg: string | SVGElement): Path2DSet;
581
585
 
582
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, Matrix3, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, parseArcCommand, parsePathDataArgs, pointInPolygonEvenOdd, pointInPolygonNonZero, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet };
586
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, Matrix3, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
583
587
  export type { DrawPointOptions, FillRule, FillTriangulateOptions, FillTriangulatedResult, LineCap, LineJoin, LineStyle, Path2DCommand, Path2DData, Path2DDrawStyle, Path2DStyle, StrokeLinecap, StrokeLinejoin, StrokeTriangulateOptions, StrokeTriangulatedResult, VectorLike };