toosoon-utils 4.2.3 → 4.3.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.
Files changed (42) hide show
  1. package/README.md +499 -575
  2. package/lib/colors.d.ts +147 -66
  3. package/lib/colors.js +149 -63
  4. package/lib/constants.js +1 -1
  5. package/lib/dom.d.ts +1 -1
  6. package/lib/dom.js +1 -1
  7. package/lib/extras/colors/Color.d.ts +406 -0
  8. package/lib/extras/colors/Color.js +546 -0
  9. package/lib/extras/colors/ColorPalette.d.ts +105 -0
  10. package/lib/extras/colors/ColorPalette.js +124 -0
  11. package/lib/extras/colors/ColorScale.d.ts +257 -0
  12. package/lib/extras/colors/ColorScale.js +347 -0
  13. package/lib/extras/colors/_ColorScale.d.ts +62 -0
  14. package/lib/extras/colors/_ColorScale.js +156 -0
  15. package/lib/extras/colors/index.d.ts +3 -0
  16. package/lib/extras/colors/index.js +3 -0
  17. package/lib/extras/frame-rate/FrameRate.d.ts +1 -1
  18. package/lib/extras/frame-rate/FrameRate.js +2 -2
  19. package/lib/extras/geometry/Vector.d.ts +1 -1
  20. package/lib/extras/geometry/Vector2.d.ts +17 -11
  21. package/lib/extras/geometry/Vector2.js +29 -23
  22. package/lib/extras/geometry/Vector3.d.ts +5 -5
  23. package/lib/extras/geometry/Vector3.js +10 -10
  24. package/lib/extras/paths/Path.d.ts +3 -3
  25. package/lib/extras/paths/Path.js +10 -10
  26. package/lib/extras/paths/PathContext.d.ts +5 -10
  27. package/lib/extras/paths/PathContext.js +70 -99
  28. package/lib/extras/paths/PathSVG.d.ts +31 -25
  29. package/lib/extras/paths/PathSVG.js +36 -39
  30. package/lib/extras/paths/index.d.ts +1 -1
  31. package/lib/geometry.js +1 -1
  32. package/lib/maths.d.ts +19 -13
  33. package/lib/maths.js +23 -17
  34. package/lib/prng.d.ts +4 -4
  35. package/lib/prng.js +4 -4
  36. package/lib/random.d.ts +4 -4
  37. package/lib/random.js +4 -4
  38. package/lib/strings.d.ts +14 -8
  39. package/lib/strings.js +14 -8
  40. package/lib/tsconfig.tsbuildinfo +1 -1
  41. package/lib/types.d.ts +15 -8
  42. package/package.json +14 -14
@@ -18,6 +18,10 @@ export default class Vector2 {
18
18
  * Y-axis value of this vector
19
19
  */
20
20
  y;
21
+ *[Symbol.iterator]() {
22
+ yield this.x;
23
+ yield this.y;
24
+ }
21
25
  /**
22
26
  * @param {number} [x=0] X-axis value
23
27
  * @param {number} [y=0] Y-axis value
@@ -41,7 +45,7 @@ export default class Vector2 {
41
45
  /**
42
46
  * Set a given scalar value to all values of this vector
43
47
  *
44
- * @param {number} scalar Value to set for all vector values
48
+ * @param {number} scalar Value to set for all values
45
49
  * @returns {this}
46
50
  */
47
51
  setScalar(scalar) {
@@ -306,13 +310,13 @@ export default class Vector2 {
306
310
  return this.set(...Vector2.rotate(this, center, angle));
307
311
  }
308
312
  /**
309
- * Interpolate this vector values between a given vector and this vector
313
+ * Linearly interpolate this vector values towards a given vector values
310
314
  *
311
- * @param {Vector2|Point2} vector Vector to interpolate values towards
312
315
  * @param {number} t Normalized time value to interpolate
316
+ * @param {Vector2|Point2} vector Vector to interpolate values towards
313
317
  * @returns {this}
314
318
  */
315
- lerp([x, y], t) {
319
+ lerp(t, [x, y]) {
316
320
  this.x += (x - this.x) * t;
317
321
  this.y += (y - this.y) * t;
318
322
  return this;
@@ -467,7 +471,7 @@ export default class Vector2 {
467
471
  * Set this vector values from a given array
468
472
  *
469
473
  * @param {number[]} values Values to set
470
- * @returns
474
+ * @returns {this}
471
475
  */
472
476
  fromArray([x, y]) {
473
477
  this.x = x;
@@ -503,6 +507,24 @@ export default class Vector2 {
503
507
  clone() {
504
508
  return new Vector2(this.x, this.y);
505
509
  }
510
+ /**
511
+ * X-axis value of this vector
512
+ */
513
+ set width(width) {
514
+ this.x = width;
515
+ }
516
+ get width() {
517
+ return this.x;
518
+ }
519
+ /**
520
+ * Y-axis value of this vector
521
+ */
522
+ set height(height) {
523
+ this.y = height;
524
+ }
525
+ get height() {
526
+ return this.y;
527
+ }
506
528
  /**
507
529
  * Add two vectors
508
530
  *
@@ -569,7 +591,7 @@ export default class Vector2 {
569
591
  return [x, y];
570
592
  }
571
593
  /**
572
- * Interpolate a point between two vectors
594
+ * Linearly interpolate a point between two vectors
573
595
  *
574
596
  * @param {number} t Normalized time value to interpolate
575
597
  * @param {Vector2|Point2} min Minimum boundaries
@@ -639,7 +661,7 @@ export default class Vector2 {
639
661
  * @returns {number} Computed Euclidean distance
640
662
  */
641
663
  static distance(vector1, vector2) {
642
- return Math.sqrt(Vector2.squaredDistance(vector1, vector2));
664
+ return Math.sqrt(this.squaredDistance(vector1, vector2));
643
665
  }
644
666
  /**
645
667
  * Calculate the squared distance between two vectors
@@ -702,20 +724,4 @@ export default class Vector2 {
702
724
  const y = radius * Math.sin(angle);
703
725
  return [x, y];
704
726
  }
705
- set width(width) {
706
- this.x = width;
707
- }
708
- get width() {
709
- return this.x;
710
- }
711
- set height(height) {
712
- this.y = height;
713
- }
714
- get height() {
715
- return this.y;
716
- }
717
- *[Symbol.iterator]() {
718
- yield this.x;
719
- yield this.y;
720
- }
721
727
  }
@@ -23,6 +23,7 @@ export default class Vector3 implements Vector<Vec3> {
23
23
  * Z-axis value of this vector
24
24
  */
25
25
  z: number;
26
+ [Symbol.iterator](): Iterator<number>;
26
27
  /**
27
28
  * @param {number} [x=0] X-axis value
28
29
  * @param {number} [y=0] Y-axis value
@@ -198,13 +199,13 @@ export default class Vector3 implements Vector<Vec3> {
198
199
  */
199
200
  negate(): this;
200
201
  /**
201
- * Interpolate this vector values between a given vector and this vector
202
+ * Linearly interpolate this vector values towards a given vector values
202
203
  *
203
- * @param {Vector3|Point3} vector Vector to interpolate values towards
204
204
  * @param {number} t Normalized time value to interpolate
205
+ * @param {Vector3|Point3} vector Vector to interpolate values towards
205
206
  * @returns {this}
206
207
  */
207
- lerp([x, y, z]: Vec3, t: number): this;
208
+ lerp(t: number, [x, y, z]: Vec3): this;
208
209
  /**
209
210
  * Convert this vector to a unit vector
210
211
  *
@@ -384,7 +385,7 @@ export default class Vector3 implements Vector<Vec3> {
384
385
  */
385
386
  static divide([x1, y1, z1]: Vec3, [x2, y2, z2]: Vec3): Point3;
386
387
  /**
387
- * Interpolate a point between two vectors
388
+ * Linearly interpolate a point between two vectors
388
389
  *
389
390
  * @param {number} t Normalized time value to interpolate
390
391
  * @param {Vector3|Point3} min Minimum boundaries
@@ -488,6 +489,5 @@ export default class Vector3 implements Vector<Vec3> {
488
489
  * @returns {Point3}
489
490
  */
490
491
  static fromCylindricalCoords(theta: number, y: number, radius?: number): Point3;
491
- [Symbol.iterator](): Iterator<number>;
492
492
  }
493
493
  export {};
@@ -22,6 +22,11 @@ export default class Vector3 {
22
22
  * Z-axis value of this vector
23
23
  */
24
24
  z;
25
+ *[Symbol.iterator]() {
26
+ yield this.x;
27
+ yield this.y;
28
+ yield this.z;
29
+ }
25
30
  /**
26
31
  * @param {number} [x=0] X-axis value
27
32
  * @param {number} [y=0] Y-axis value
@@ -339,13 +344,13 @@ export default class Vector3 {
339
344
  return this;
340
345
  }
341
346
  /**
342
- * Interpolate this vector values between a given vector and this vector
347
+ * Linearly interpolate this vector values towards a given vector values
343
348
  *
344
- * @param {Vector3|Point3} vector Vector to interpolate values towards
345
349
  * @param {number} t Normalized time value to interpolate
350
+ * @param {Vector3|Point3} vector Vector to interpolate values towards
346
351
  * @returns {this}
347
352
  */
348
- lerp([x, y, z], t) {
353
+ lerp(t, [x, y, z]) {
349
354
  this.x += (x - this.x) * t;
350
355
  this.y += (y - this.y) * t;
351
356
  this.z += (z - this.z) * t;
@@ -618,7 +623,7 @@ export default class Vector3 {
618
623
  return [x, y, z];
619
624
  }
620
625
  /**
621
- * Interpolate a point between two vectors
626
+ * Linearly interpolate a point between two vectors
622
627
  *
623
628
  * @param {number} t Normalized time value to interpolate
624
629
  * @param {Vector3|Point3} min Minimum boundaries
@@ -691,7 +696,7 @@ export default class Vector3 {
691
696
  * @returns {number} Computed Euclidean distance
692
697
  */
693
698
  static distance(vector1, vector2) {
694
- return Math.sqrt(Vector3.squaredDistance(vector1, vector2));
699
+ return Math.sqrt(this.squaredDistance(vector1, vector2));
695
700
  }
696
701
  /**
697
702
  * Calculate the squared distance between two vectors
@@ -770,9 +775,4 @@ export default class Vector3 {
770
775
  const z = radius * Math.cos(theta);
771
776
  return [x, y, z];
772
777
  }
773
- *[Symbol.iterator]() {
774
- yield this.x;
775
- yield this.y;
776
- yield this.z;
777
- }
778
778
  }
@@ -7,13 +7,13 @@ import { type Vector, Vector2, Vector3 } from '../geometry';
7
7
  * @class Path
8
8
  * @extends Curve
9
9
  */
10
- export default class Path<V extends Vector = Vector2 | Vector3, S extends Curve<V> = Curve<V>> extends Curve<V> {
10
+ export default class Path<V extends Vector = Vector2 | Vector3, C extends Curve<V> = Curve<V>> extends Curve<V> {
11
11
  readonly isPath = true;
12
12
  readonly type: string;
13
13
  /**
14
14
  * Array of curves composing this path
15
15
  */
16
- subpaths: S[];
16
+ curves: C[];
17
17
  /**
18
18
  * Array of points composing this path
19
19
  */
@@ -30,7 +30,7 @@ export default class Path<V extends Vector = Vector2 | Vector3, S extends Curve<
30
30
  *
31
31
  * @param {Curve} curve Curve to add
32
32
  */
33
- add(curve: S): void;
33
+ add(curve: C): void;
34
34
  /**
35
35
  * Interpolate a point on this path
36
36
  *
@@ -12,7 +12,7 @@ export default class Path extends Curve {
12
12
  /**
13
13
  * Array of curves composing this path
14
14
  */
15
- subpaths = [];
15
+ curves = [];
16
16
  /**
17
17
  * Array of points composing this path
18
18
  */
@@ -31,7 +31,7 @@ export default class Path extends Curve {
31
31
  * @param {Curve} curve Curve to add
32
32
  */
33
33
  add(curve) {
34
- this.subpaths.push(curve);
34
+ this.curves.push(curve);
35
35
  }
36
36
  /**
37
37
  * Interpolate a point on this path
@@ -46,7 +46,7 @@ export default class Path extends Curve {
46
46
  while (i < curveLengths.length) {
47
47
  if (curveLengths[i] >= d) {
48
48
  const delta = curveLengths[i] - d;
49
- const curve = this.subpaths[i];
49
+ const curve = this.curves[i];
50
50
  const segmentLength = curve.getLength();
51
51
  const u = segmentLength === 0 ? 0 : 1 - delta / segmentLength;
52
52
  return curve.getPointAt(u);
@@ -54,7 +54,7 @@ export default class Path extends Curve {
54
54
  i++;
55
55
  }
56
56
  console.warn(`Path.getPoint()`, `No point found in curve.`, this);
57
- return this.subpaths[0].getPoint(0);
57
+ return this.curves[0].getPoint(0);
58
58
  }
59
59
  /**
60
60
  * Compute the curve shape into an array of points
@@ -65,8 +65,8 @@ export default class Path extends Curve {
65
65
  getPoints(divisions = 40) {
66
66
  const points = [];
67
67
  let lastPoint = null;
68
- for (let i = 0; i < this.subpaths.length; i++) {
69
- const curve = this.subpaths[i];
68
+ for (let i = 0; i < this.curves.length; i++) {
69
+ const curve = this.curves[i];
70
70
  let resolution = divisions;
71
71
  if (curve instanceof LineCurve || curve instanceof LineCurve3) {
72
72
  resolution = 1;
@@ -80,7 +80,7 @@ export default class Path extends Curve {
80
80
  else if (curve instanceof EllipseCurve) {
81
81
  resolution *= 2;
82
82
  }
83
- const pts = this.subpaths[i].getPoints(resolution);
83
+ const pts = this.curves[i].getPoints(resolution);
84
84
  for (let j = 0; j < pts.length; j++) {
85
85
  const point = pts[j];
86
86
  if (point?.equals(lastPoint))
@@ -127,13 +127,13 @@ export default class Path extends Curve {
127
127
  * @returns {number[]}
128
128
  */
129
129
  getCurveLengths() {
130
- if (this._cacheArcLengths.length === this.subpaths.length) {
130
+ if (this._cacheArcLengths.length === this.curves.length) {
131
131
  return this._cacheArcLengths;
132
132
  }
133
133
  const lengths = [];
134
134
  let sums = 0;
135
- for (let i = 0, j = this.subpaths.length; i < j; i++) {
136
- sums += this.subpaths[i].getLength();
135
+ for (let i = 0, j = this.curves.length; i < j; i++) {
136
+ sums += this.curves[i].getLength();
137
137
  lengths.push(sums);
138
138
  }
139
139
  this._cacheArcLengths = lengths;
@@ -12,7 +12,6 @@ import Path from './Path';
12
12
  export default class PathContext extends Path<Vector2> implements CanvasRenderingContext2D {
13
13
  protected _currentPosition: Vector2;
14
14
  protected _currentTransform: DOMMatrix;
15
- protected _positionTransform: DOMMatrix;
16
15
  private _transformStack;
17
16
  /**
18
17
  * Create a path from a given list of points
@@ -134,7 +133,7 @@ export default class PathContext extends Path<Vector2> implements CanvasRenderin
134
133
  arc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): this;
135
134
  /**
136
135
  * Draw an Arc curve from the current position, tangential to the 2 segments created by both control points
137
- * Add an instance of {@link ArcCurve} to this path
136
+ * Add an instance of {@link EllipseCurve} to this path
138
137
  *
139
138
  * @param {number} x1 X-axis coordinate of the first control point
140
139
  * @param {number} y1 Y-axis coordinate of the first control point
@@ -180,22 +179,18 @@ export default class PathContext extends Path<Vector2> implements CanvasRenderin
180
179
  reset(): void;
181
180
  protected _hasCurrentPosition(): boolean;
182
181
  protected _setCurrentPosition(x: number, y: number): this;
183
- protected _transformPoint(point: Point2, matrix?: DOMMatrix): Point2;
184
- protected _transformPoints(points: Point2[], matrix?: DOMMatrix): Point2[];
185
- protected _transformVector(vector: Point2, matrix?: DOMMatrix): Point2;
186
- protected _transformEllipse(cx: number, cy: number, rx: number, ry: number, rotation: number, matrix?: DOMMatrix): [number, number, number, number, number];
187
- protected _inversePoint(point: Point2, matrix?: DOMMatrix): Point2;
182
+ protected _transformPoint(point: Point2): Point2;
183
+ protected _transformPoints(points: Point2[]): Point2[];
184
+ protected _transformVector(vector: Point2): Point2;
185
+ protected _transformEllipse(cx: number, cy: number, rx: number, ry: number, rotation: number): [number, number, number, number, number];
188
186
  protected get _translateX(): number;
189
187
  protected get _translateY(): number;
190
188
  protected get _scaleX(): number;
191
189
  protected get _scaleY(): number;
192
190
  protected get _rotation(): number;
193
- protected get _skewX(): number;
194
- protected get _skewY(): number;
195
191
  protected get _isTranslated(): boolean;
196
192
  protected get _isScaled(): boolean;
197
193
  protected get _isRotated(): boolean;
198
- protected get _isSkewed(): boolean;
199
194
  protected get _isUniform(): boolean;
200
195
  protected get _isIdentity(): boolean;
201
196
  canvas: CanvasRenderingContext2D['canvas'];
@@ -14,7 +14,6 @@ import Path from './Path';
14
14
  export default class PathContext extends Path {
15
15
  _currentPosition = new Vector2(NaN, NaN);
16
16
  _currentTransform = new DOMMatrix();
17
- _positionTransform = new DOMMatrix();
18
17
  _transformStack = [];
19
18
  /**
20
19
  * Create a path from a given list of points
@@ -45,8 +44,8 @@ export default class PathContext extends Path {
45
44
  * @return {this}
46
45
  */
47
46
  closePath() {
48
- const startPoint = this.subpaths[0]?.getPoint(0);
49
- const endPoint = this.subpaths[this.subpaths.length - 1]?.getPoint(1);
47
+ const startPoint = this.curves[0]?.getPoint(0);
48
+ const endPoint = this.curves[this.curves.length - 1]?.getPoint(1);
50
49
  if (!startPoint.equals(endPoint)) {
51
50
  const curve = new LineCurve(endPoint.x, endPoint.y, startPoint.x, startPoint.y);
52
51
  this.add(curve);
@@ -61,8 +60,8 @@ export default class PathContext extends Path {
61
60
  * @return {this}
62
61
  */
63
62
  moveTo(x, y) {
64
- const [tX, tY] = this._transformPoint([x, y]);
65
- this._setCurrentPosition(tX, tY);
63
+ [x, y] = this._transformPoint([x, y]);
64
+ this._setCurrentPosition(x, y);
66
65
  return this;
67
66
  }
68
67
  /**
@@ -74,12 +73,12 @@ export default class PathContext extends Path {
74
73
  * @return {this}
75
74
  */
76
75
  lineTo(x, y) {
77
- const [tX, tY] = this._transformPoint([x, y]);
76
+ [x, y] = this._transformPoint([x, y]);
78
77
  if (!this._hasCurrentPosition())
79
- return this._setCurrentPosition(tX, tY);
80
- const curve = new LineCurve(this._currentPosition.x, this._currentPosition.y, tX, tY);
78
+ return this._setCurrentPosition(x, y);
79
+ const curve = new LineCurve(this._currentPosition.x, this._currentPosition.y, x, y);
81
80
  this.add(curve);
82
- this._setCurrentPosition(tX, tY);
81
+ this._setCurrentPosition(x, y);
83
82
  return this;
84
83
  }
85
84
  /**
@@ -90,12 +89,12 @@ export default class PathContext extends Path {
90
89
  * @returns {this}
91
90
  */
92
91
  polylineTo(points) {
93
- const tPoints = this._transformPoints(points);
92
+ points = this._transformPoints(points);
94
93
  if (!this._hasCurrentPosition())
95
- this._setCurrentPosition(...tPoints[0]);
96
- const curve = new PolylineCurve([this._currentPosition.toArray()].concat(tPoints));
94
+ this._setCurrentPosition(...points[0]);
95
+ const curve = new PolylineCurve([this._currentPosition.toArray()].concat(points));
97
96
  this.add(curve);
98
- this._setCurrentPosition(...tPoints[tPoints.length - 1]);
97
+ this._setCurrentPosition(...points[points.length - 1]);
99
98
  return this;
100
99
  }
101
100
  /**
@@ -109,13 +108,13 @@ export default class PathContext extends Path {
109
108
  * @return {this}
110
109
  */
111
110
  quadraticCurveTo(cpx, cpy, x2, y2) {
112
- const [tCpx, tCpy] = this._transformPoint([cpx, cpy]);
113
- const [tX2, tY2] = this._transformPoint([x2, y2]);
111
+ [cpx, cpy] = this._transformPoint([cpx, cpy]);
112
+ [x2, y2] = this._transformPoint([x2, y2]);
114
113
  if (!this._hasCurrentPosition())
115
- this._setCurrentPosition(tCpx, tCpy);
116
- const curve = new QuadraticBezierCurve(this._currentPosition.x, this._currentPosition.y, tCpx, tCpy, tX2, tY2);
114
+ this._setCurrentPosition(cpx, cpy);
115
+ const curve = new QuadraticBezierCurve(this._currentPosition.x, this._currentPosition.y, cpx, cpy, x2, y2);
117
116
  this.add(curve);
118
- this._setCurrentPosition(tX2, tY2);
117
+ this._setCurrentPosition(x2, y2);
119
118
  return this;
120
119
  }
121
120
  /**
@@ -131,14 +130,14 @@ export default class PathContext extends Path {
131
130
  * @return {this}
132
131
  */
133
132
  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2) {
134
- const [tCp1x, tCp1y] = this._transformPoint([cp1x, cp1y]);
135
- const [tCp2x, tCp2y] = this._transformPoint([cp2x, cp2y]);
136
- const [tX2, tY2] = this._transformPoint([x2, y2]);
133
+ [cp1x, cp1y] = this._transformPoint([cp1x, cp1y]);
134
+ [cp2x, cp2y] = this._transformPoint([cp2x, cp2y]);
135
+ [x2, y2] = this._transformPoint([x2, y2]);
137
136
  if (!this._hasCurrentPosition())
138
- this._setCurrentPosition(tCp1x, tCp1y);
139
- const curve = new CubicBezierCurve(this._currentPosition.x, this._currentPosition.y, tCp1x, tCp1y, tCp2x, tCp2y, tX2, tY2);
137
+ this._setCurrentPosition(cp1x, cp1y);
138
+ const curve = new CubicBezierCurve(this._currentPosition.x, this._currentPosition.y, cp1x, cp1y, cp2x, cp2y, x2, y2);
140
139
  this.add(curve);
141
- this._setCurrentPosition(tX2, tY2);
140
+ this._setCurrentPosition(x2, y2);
142
141
  return this;
143
142
  }
144
143
  /**
@@ -154,14 +153,14 @@ export default class PathContext extends Path {
154
153
  * @return {this}
155
154
  */
156
155
  catmullRomCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2) {
157
- const [tCp1x, tCp1y] = this._transformPoint([cp1x, cp1y]);
158
- const [tCp2x, tCp2y] = this._transformPoint([cp2x, cp2y]);
159
- const [tX2, tY2] = this._transformPoint([x2, y2]);
156
+ [cp1x, cp1y] = this._transformPoint([cp1x, cp1y]);
157
+ [cp2x, cp2y] = this._transformPoint([cp2x, cp2y]);
158
+ [x2, y2] = this._transformPoint([x2, y2]);
160
159
  if (!this._hasCurrentPosition())
161
- this._setCurrentPosition(tCp1x, tCp1y);
162
- const curve = new CatmullRomCurve(this._currentPosition.x, this._currentPosition.y, tCp1x, tCp1y, tCp2x, tCp2y, tX2, tY2);
160
+ this._setCurrentPosition(cp1x, cp1y);
161
+ const curve = new CatmullRomCurve(this._currentPosition.x, this._currentPosition.y, cp1x, cp1y, cp2x, cp2y, x2, y2);
163
162
  this.add(curve);
164
- this._setCurrentPosition(tX2, tY2);
163
+ this._setCurrentPosition(x2, y2);
165
164
  return this;
166
165
  }
167
166
  /**
@@ -172,12 +171,12 @@ export default class PathContext extends Path {
172
171
  * @return {this}
173
172
  */
174
173
  splineTo(points) {
175
- const tPoints = this._transformPoints(points);
174
+ points = this._transformPoints(points);
176
175
  if (!this._hasCurrentPosition())
177
- this._setCurrentPosition(...tPoints[0]);
178
- const curve = new SplineCurve([this._currentPosition.toArray()].concat(tPoints));
176
+ this._setCurrentPosition(...points[0]);
177
+ const curve = new SplineCurve([this._currentPosition.toArray()].concat(points));
179
178
  this.add(curve);
180
- this._setCurrentPosition(...tPoints[tPoints.length - 1]);
179
+ this._setCurrentPosition(...points[points.length - 1]);
181
180
  return this;
182
181
  }
183
182
  /**
@@ -195,18 +194,16 @@ export default class PathContext extends Path {
195
194
  * @return {this}
196
195
  */
197
196
  ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise) {
198
- const [tCx, tCy, tRx, tRy, tRotation] = this._transformEllipse(cx, cy, rx, ry, rotation);
199
- const start = EllipseCurve.interpolate(0, tCx, tCy, tRx, tRy, tRotation, startAngle, endAngle, counterclockwise);
200
- const end = EllipseCurve.interpolate(1, tCx, tCy, tRx, tRy, tRotation, startAngle, endAngle, counterclockwise);
201
- if (!this._hasCurrentPosition())
202
- this._setCurrentPosition(...start);
203
- else if (!this._currentPosition.equals(start)) {
204
- const curve = new LineCurve(this._currentPosition.x, this._currentPosition.y, ...start);
205
- this.add(curve);
197
+ [cx, cy, rx, ry, rotation] = this._transformEllipse(cx, cy, rx, ry, rotation);
198
+ const start = EllipseCurve.interpolate(0, cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise);
199
+ const end = EllipseCurve.interpolate(1, cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise);
200
+ if (this._hasCurrentPosition() && !this._currentPosition.equals(start)) {
201
+ const line = new LineCurve(this._currentPosition.x, this._currentPosition.y, ...start);
202
+ this.add(line);
206
203
  }
207
- if (tRx <= EPSILON && tRy <= EPSILON)
204
+ if (rx <= EPSILON && ry <= EPSILON)
208
205
  return this;
209
- const curve = new EllipseCurve(tCx, tCy, tRx, tRy, tRotation, startAngle, endAngle, counterclockwise);
206
+ const curve = new EllipseCurve(cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise);
210
207
  this.add(curve);
211
208
  this._setCurrentPosition(...end);
212
209
  return this;
@@ -227,25 +224,23 @@ export default class PathContext extends Path {
227
224
  if (!this._isUniform || this._isRotated) {
228
225
  return this.ellipse(cx, cy, radius, radius, 0, startAngle, endAngle, counterclockwise);
229
226
  }
230
- const [tCx, tCy, tRadius] = this._transformEllipse(cx, cy, radius, radius, 0);
231
- const start = EllipseCurve.interpolate(0, tCx, tCy, tRadius, tRadius, 0, startAngle, endAngle, counterclockwise);
232
- const end = EllipseCurve.interpolate(1, tCx, tCy, tRadius, tRadius, 0, startAngle, endAngle, counterclockwise);
233
- if (!this._hasCurrentPosition())
234
- this._setCurrentPosition(...start);
235
- else if (!this._currentPosition.equals(start)) {
236
- const curve = new LineCurve(this._currentPosition.x, this._currentPosition.y, ...start);
237
- this.add(curve);
227
+ [cx, cy, radius] = this._transformEllipse(cx, cy, radius, radius, 0);
228
+ const start = EllipseCurve.interpolate(0, cx, cy, radius, radius, 0, startAngle, endAngle, counterclockwise);
229
+ const end = EllipseCurve.interpolate(1, cx, cy, radius, radius, 0, startAngle, endAngle, counterclockwise);
230
+ if (this._hasCurrentPosition() && !this._currentPosition.equals(start)) {
231
+ const line = new LineCurve(this._currentPosition.x, this._currentPosition.y, ...start);
232
+ this.add(line);
238
233
  }
239
- if (tRadius <= EPSILON)
234
+ if (radius <= EPSILON)
240
235
  return this;
241
- const curve = new ArcCurve(tCx, tCy, tRadius, startAngle, endAngle, counterclockwise);
236
+ const curve = new ArcCurve(cx, cy, radius, startAngle, endAngle, counterclockwise);
242
237
  this.add(curve);
243
238
  this._setCurrentPosition(...end);
244
239
  return this;
245
240
  }
246
241
  /**
247
242
  * Draw an Arc curve from the current position, tangential to the 2 segments created by both control points
248
- * Add an instance of {@link ArcCurve} to this path
243
+ * Add an instance of {@link EllipseCurve} to this path
249
244
  *
250
245
  * @param {number} x1 X-axis coordinate of the first control point
251
246
  * @param {number} y1 Y-axis coordinate of the first control point
@@ -345,7 +340,6 @@ export default class PathContext extends Path {
345
340
  bottomLeftRadius = Math.min(bottomLeftRadius, maxRadius);
346
341
  const curve = new PathContext({ autoClose: true });
347
342
  curve.setTransform(this.getTransform());
348
- this.add(curve);
349
343
  // Top-Right corner
350
344
  if (topRightRadius > 0) {
351
345
  curve.lineTo(x + width - topRightRadius, y);
@@ -378,6 +372,7 @@ export default class PathContext extends Path {
378
372
  else {
379
373
  curve.lineTo(x, y);
380
374
  }
375
+ this.add(curve);
381
376
  return this;
382
377
  }
383
378
  setTransform(a, b, c, d, e, f) {
@@ -426,43 +421,39 @@ export default class PathContext extends Path {
426
421
  }
427
422
  _setCurrentPosition(x, y) {
428
423
  this._currentPosition.set(x, y);
429
- this._positionTransform = this.getTransform();
430
424
  return this;
431
425
  }
432
426
  // ****************************
433
427
  // Matrix transformations
434
428
  // ****************************
435
- _transformPoint(point, matrix = this._currentTransform) {
436
- if (matrix.isIdentity)
429
+ _transformPoint(point) {
430
+ if (this._isIdentity)
437
431
  return point;
438
- const { x, y } = matrix.transformPoint({ x: point[0], y: point[1] });
432
+ const { x, y } = this._currentTransform.transformPoint({ x: point[0], y: point[1] });
439
433
  return [x, y];
440
434
  }
441
- _transformPoints(points, matrix = this._currentTransform) {
442
- if (matrix.isIdentity)
435
+ _transformPoints(points) {
436
+ if (this._isIdentity)
443
437
  return points;
444
- return points.map((point) => this._transformPoint(point, matrix));
438
+ return points.map((point) => this._transformPoint(point));
445
439
  }
446
- _transformVector(vector, matrix = this._currentTransform) {
447
- if (matrix.isIdentity)
440
+ _transformVector(vector) {
441
+ if (this._isIdentity)
448
442
  return vector;
449
- const [x0, y0] = this._transformPoint([0, 0], matrix);
450
- const [vx, vy] = this._transformPoint(vector, matrix);
443
+ const [x0, y0] = this._transformPoint([0, 0]);
444
+ const [vx, vy] = this._transformPoint(vector);
451
445
  return [vx - x0, vy - y0];
452
446
  }
453
- _transformEllipse(cx, cy, rx, ry, rotation, matrix = this._currentTransform) {
454
- if (matrix.isIdentity)
447
+ _transformEllipse(cx, cy, rx, ry, rotation) {
448
+ if (this._isIdentity)
455
449
  return [cx, cy, rx, ry, rotation];
456
- const [tCx, tCy] = this._transformPoint([cx, cy], matrix);
457
- const [ux1, uy1] = this._transformVector([Math.cos(rotation) * rx, Math.sin(rotation) * rx], matrix);
458
- const [ux2, uy2] = this._transformVector([-Math.sin(rotation) * ry, Math.cos(rotation) * ry], matrix);
459
- const tRx = Math.hypot(ux1, uy1);
460
- const tRy = Math.hypot(ux2, uy2);
461
- const tRotation = Math.atan2(uy1, ux1);
462
- return [tCx, tCy, tRx, tRy, tRotation];
463
- }
464
- _inversePoint(point, matrix = this._currentTransform) {
465
- return this._transformPoint(point, matrix.inverse());
450
+ [cx, cy] = this._transformPoint([cx, cy]);
451
+ const [u1x, u1y] = this._transformVector([Math.cos(rotation) * rx, Math.sin(rotation) * rx]);
452
+ const [u2x, u2y] = this._transformVector([-Math.sin(rotation) * ry, Math.cos(rotation) * ry]);
453
+ rx = Math.hypot(u1x, u1y);
454
+ ry = Math.hypot(u2x, u2y);
455
+ rotation = Math.atan2(u1y, u1x);
456
+ return [cx, cy, rx, ry, rotation];
466
457
  }
467
458
  get _translateX() {
468
459
  return this._currentTransform.e;
@@ -482,20 +473,6 @@ export default class PathContext extends Path {
482
473
  const { a, b } = this._currentTransform;
483
474
  return Math.atan2(b, a);
484
475
  }
485
- get _skewX() {
486
- const { c, d } = this._currentTransform;
487
- const cos = Math.cos(this._rotation);
488
- const sin = Math.sin(this._rotation);
489
- const m11 = c * cos + d * sin;
490
- return Math.atan(m11 / this._scaleX);
491
- }
492
- get _skewY() {
493
- const { a, b } = this._currentTransform;
494
- const cos = Math.cos(this._rotation);
495
- const sin = Math.sin(this._rotation);
496
- const m21 = a * sin - b * cos;
497
- return Math.atan(m21 / this._scaleY);
498
- }
499
476
  get _isTranslated() {
500
477
  return Math.abs(this._translateX) > EPSILON || Math.abs(this._translateY) > EPSILON;
501
478
  }
@@ -506,12 +483,6 @@ export default class PathContext extends Path {
506
483
  const { b, c } = this._currentTransform;
507
484
  return Math.abs(b) > EPSILON || Math.abs(c) > EPSILON;
508
485
  }
509
- get _isSkewed() {
510
- const { a, b, c, d } = this._currentTransform;
511
- const angleX = Math.atan2(b, a);
512
- const angleY = Math.atan2(-c, d);
513
- return Math.abs(angleX - angleY) > EPSILON;
514
- }
515
486
  get _isUniform() {
516
487
  return Math.abs(this._scaleX - this._scaleY) <= EPSILON;
517
488
  }