toosoon-utils 4.2.2 → 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.
- package/README.md +499 -575
- package/lib/colors.d.ts +147 -66
- package/lib/colors.js +149 -63
- package/lib/constants.js +1 -1
- package/lib/dom.d.ts +1 -1
- package/lib/dom.js +1 -1
- package/lib/extras/colors/Color.d.ts +406 -0
- package/lib/extras/colors/Color.js +546 -0
- package/lib/extras/colors/ColorPalette.d.ts +105 -0
- package/lib/extras/colors/ColorPalette.js +124 -0
- package/lib/extras/colors/ColorScale.d.ts +257 -0
- package/lib/extras/colors/ColorScale.js +347 -0
- package/lib/extras/colors/_ColorScale.d.ts +62 -0
- package/lib/extras/colors/_ColorScale.js +156 -0
- package/lib/extras/colors/index.d.ts +3 -0
- package/lib/extras/colors/index.js +3 -0
- package/lib/extras/frame-rate/FrameRate.d.ts +1 -1
- package/lib/extras/frame-rate/FrameRate.js +2 -2
- package/lib/extras/geometry/Vector.d.ts +1 -1
- package/lib/extras/geometry/Vector2.d.ts +24 -11
- package/lib/extras/geometry/Vector2.js +41 -23
- package/lib/extras/geometry/Vector3.d.ts +12 -5
- package/lib/extras/geometry/Vector3.js +23 -10
- package/lib/extras/paths/Path.d.ts +3 -3
- package/lib/extras/paths/Path.js +10 -10
- package/lib/extras/paths/PathContext.d.ts +7 -17
- package/lib/extras/paths/PathContext.js +122 -144
- package/lib/extras/paths/PathSVG.d.ts +31 -25
- package/lib/extras/paths/PathSVG.js +36 -39
- package/lib/extras/paths/index.d.ts +1 -1
- package/lib/geometry.js +1 -1
- package/lib/maths.d.ts +19 -13
- package/lib/maths.js +23 -17
- package/lib/prng.d.ts +4 -4
- package/lib/prng.js +4 -4
- package/lib/random.d.ts +4 -4
- package/lib/random.js +4 -4
- package/lib/strings.d.ts +14 -8
- package/lib/strings.js +14 -8
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types.d.ts +15 -8
- package/package.json +14 -14
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { EPSILON
|
|
2
|
-
import {
|
|
1
|
+
import { EPSILON } from '../../constants';
|
|
2
|
+
import { toDegrees } from '../../geometry';
|
|
3
3
|
import { LineCurve, PolylineCurve, QuadraticBezierCurve, CubicBezierCurve, CatmullRomCurve, SplineCurve, EllipseCurve, ArcCurve } from '../curves';
|
|
4
4
|
import { Vector2 } from '../geometry';
|
|
5
5
|
import Path from './Path';
|
|
@@ -12,14 +12,8 @@ import Path from './Path';
|
|
|
12
12
|
* @implements CanvasRenderingContext2D
|
|
13
13
|
*/
|
|
14
14
|
export default class PathContext extends Path {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*/
|
|
18
|
-
currentPosition = new Vector2(NaN, NaN);
|
|
19
|
-
/**
|
|
20
|
-
* Path current transformation matrix
|
|
21
|
-
*/
|
|
22
|
-
currentTransform = new DOMMatrix();
|
|
15
|
+
_currentPosition = new Vector2(NaN, NaN);
|
|
16
|
+
_currentTransform = new DOMMatrix();
|
|
23
17
|
_transformStack = [];
|
|
24
18
|
/**
|
|
25
19
|
* Create a path from a given list of points
|
|
@@ -50,8 +44,8 @@ export default class PathContext extends Path {
|
|
|
50
44
|
* @return {this}
|
|
51
45
|
*/
|
|
52
46
|
closePath() {
|
|
53
|
-
const startPoint = this.
|
|
54
|
-
const endPoint = this.
|
|
47
|
+
const startPoint = this.curves[0]?.getPoint(0);
|
|
48
|
+
const endPoint = this.curves[this.curves.length - 1]?.getPoint(1);
|
|
55
49
|
if (!startPoint.equals(endPoint)) {
|
|
56
50
|
const curve = new LineCurve(endPoint.x, endPoint.y, startPoint.x, startPoint.y);
|
|
57
51
|
this.add(curve);
|
|
@@ -66,8 +60,8 @@ export default class PathContext extends Path {
|
|
|
66
60
|
* @return {this}
|
|
67
61
|
*/
|
|
68
62
|
moveTo(x, y) {
|
|
69
|
-
|
|
70
|
-
this._setCurrentPosition(
|
|
63
|
+
[x, y] = this._transformPoint([x, y]);
|
|
64
|
+
this._setCurrentPosition(x, y);
|
|
71
65
|
return this;
|
|
72
66
|
}
|
|
73
67
|
/**
|
|
@@ -79,12 +73,12 @@ export default class PathContext extends Path {
|
|
|
79
73
|
* @return {this}
|
|
80
74
|
*/
|
|
81
75
|
lineTo(x, y) {
|
|
82
|
-
|
|
76
|
+
[x, y] = this._transformPoint([x, y]);
|
|
83
77
|
if (!this._hasCurrentPosition())
|
|
84
|
-
return this._setCurrentPosition(
|
|
85
|
-
const curve = new LineCurve(this.
|
|
78
|
+
return this._setCurrentPosition(x, y);
|
|
79
|
+
const curve = new LineCurve(this._currentPosition.x, this._currentPosition.y, x, y);
|
|
86
80
|
this.add(curve);
|
|
87
|
-
this._setCurrentPosition(
|
|
81
|
+
this._setCurrentPosition(x, y);
|
|
88
82
|
return this;
|
|
89
83
|
}
|
|
90
84
|
/**
|
|
@@ -95,12 +89,12 @@ export default class PathContext extends Path {
|
|
|
95
89
|
* @returns {this}
|
|
96
90
|
*/
|
|
97
91
|
polylineTo(points) {
|
|
98
|
-
|
|
92
|
+
points = this._transformPoints(points);
|
|
99
93
|
if (!this._hasCurrentPosition())
|
|
100
|
-
this._setCurrentPosition(...
|
|
101
|
-
const curve = new PolylineCurve([this.
|
|
94
|
+
this._setCurrentPosition(...points[0]);
|
|
95
|
+
const curve = new PolylineCurve([this._currentPosition.toArray()].concat(points));
|
|
102
96
|
this.add(curve);
|
|
103
|
-
this._setCurrentPosition(...
|
|
97
|
+
this._setCurrentPosition(...points[points.length - 1]);
|
|
104
98
|
return this;
|
|
105
99
|
}
|
|
106
100
|
/**
|
|
@@ -114,13 +108,13 @@ export default class PathContext extends Path {
|
|
|
114
108
|
* @return {this}
|
|
115
109
|
*/
|
|
116
110
|
quadraticCurveTo(cpx, cpy, x2, y2) {
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
[cpx, cpy] = this._transformPoint([cpx, cpy]);
|
|
112
|
+
[x2, y2] = this._transformPoint([x2, y2]);
|
|
119
113
|
if (!this._hasCurrentPosition())
|
|
120
|
-
this._setCurrentPosition(
|
|
121
|
-
const curve = new QuadraticBezierCurve(this.
|
|
114
|
+
this._setCurrentPosition(cpx, cpy);
|
|
115
|
+
const curve = new QuadraticBezierCurve(this._currentPosition.x, this._currentPosition.y, cpx, cpy, x2, y2);
|
|
122
116
|
this.add(curve);
|
|
123
|
-
this._setCurrentPosition(
|
|
117
|
+
this._setCurrentPosition(x2, y2);
|
|
124
118
|
return this;
|
|
125
119
|
}
|
|
126
120
|
/**
|
|
@@ -136,14 +130,14 @@ export default class PathContext extends Path {
|
|
|
136
130
|
* @return {this}
|
|
137
131
|
*/
|
|
138
132
|
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
[cp1x, cp1y] = this._transformPoint([cp1x, cp1y]);
|
|
134
|
+
[cp2x, cp2y] = this._transformPoint([cp2x, cp2y]);
|
|
135
|
+
[x2, y2] = this._transformPoint([x2, y2]);
|
|
142
136
|
if (!this._hasCurrentPosition())
|
|
143
|
-
this._setCurrentPosition(
|
|
144
|
-
const curve = new CubicBezierCurve(this.
|
|
137
|
+
this._setCurrentPosition(cp1x, cp1y);
|
|
138
|
+
const curve = new CubicBezierCurve(this._currentPosition.x, this._currentPosition.y, cp1x, cp1y, cp2x, cp2y, x2, y2);
|
|
145
139
|
this.add(curve);
|
|
146
|
-
this._setCurrentPosition(
|
|
140
|
+
this._setCurrentPosition(x2, y2);
|
|
147
141
|
return this;
|
|
148
142
|
}
|
|
149
143
|
/**
|
|
@@ -159,14 +153,14 @@ export default class PathContext extends Path {
|
|
|
159
153
|
* @return {this}
|
|
160
154
|
*/
|
|
161
155
|
catmullRomCurveTo(cp1x, cp1y, cp2x, cp2y, x2, y2) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
[cp1x, cp1y] = this._transformPoint([cp1x, cp1y]);
|
|
157
|
+
[cp2x, cp2y] = this._transformPoint([cp2x, cp2y]);
|
|
158
|
+
[x2, y2] = this._transformPoint([x2, y2]);
|
|
165
159
|
if (!this._hasCurrentPosition())
|
|
166
|
-
this._setCurrentPosition(
|
|
167
|
-
const curve = new CatmullRomCurve(this.
|
|
160
|
+
this._setCurrentPosition(cp1x, cp1y);
|
|
161
|
+
const curve = new CatmullRomCurve(this._currentPosition.x, this._currentPosition.y, cp1x, cp1y, cp2x, cp2y, x2, y2);
|
|
168
162
|
this.add(curve);
|
|
169
|
-
this._setCurrentPosition(
|
|
163
|
+
this._setCurrentPosition(x2, y2);
|
|
170
164
|
return this;
|
|
171
165
|
}
|
|
172
166
|
/**
|
|
@@ -177,12 +171,12 @@ export default class PathContext extends Path {
|
|
|
177
171
|
* @return {this}
|
|
178
172
|
*/
|
|
179
173
|
splineTo(points) {
|
|
180
|
-
|
|
174
|
+
points = this._transformPoints(points);
|
|
181
175
|
if (!this._hasCurrentPosition())
|
|
182
|
-
this._setCurrentPosition(...
|
|
183
|
-
const curve = new SplineCurve([this.
|
|
176
|
+
this._setCurrentPosition(...points[0]);
|
|
177
|
+
const curve = new SplineCurve([this._currentPosition.toArray()].concat(points));
|
|
184
178
|
this.add(curve);
|
|
185
|
-
this._setCurrentPosition(...
|
|
179
|
+
this._setCurrentPosition(...points[points.length - 1]);
|
|
186
180
|
return this;
|
|
187
181
|
}
|
|
188
182
|
/**
|
|
@@ -200,18 +194,16 @@ export default class PathContext extends Path {
|
|
|
200
194
|
* @return {this}
|
|
201
195
|
*/
|
|
202
196
|
ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise) {
|
|
203
|
-
|
|
204
|
-
const start = EllipseCurve.interpolate(0,
|
|
205
|
-
const end = EllipseCurve.interpolate(1,
|
|
206
|
-
if (
|
|
207
|
-
this.
|
|
208
|
-
|
|
209
|
-
const curve = new LineCurve(this.currentPosition.x, this.currentPosition.y, ...start);
|
|
210
|
-
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);
|
|
211
203
|
}
|
|
212
|
-
if (
|
|
204
|
+
if (rx <= EPSILON && ry <= EPSILON)
|
|
213
205
|
return this;
|
|
214
|
-
const curve = new EllipseCurve(
|
|
206
|
+
const curve = new EllipseCurve(cx, cy, rx, ry, rotation, startAngle, endAngle, counterclockwise);
|
|
215
207
|
this.add(curve);
|
|
216
208
|
this._setCurrentPosition(...end);
|
|
217
209
|
return this;
|
|
@@ -232,25 +224,23 @@ export default class PathContext extends Path {
|
|
|
232
224
|
if (!this._isUniform || this._isRotated) {
|
|
233
225
|
return this.ellipse(cx, cy, radius, radius, 0, startAngle, endAngle, counterclockwise);
|
|
234
226
|
}
|
|
235
|
-
|
|
236
|
-
const start = EllipseCurve.interpolate(0,
|
|
237
|
-
const end = EllipseCurve.interpolate(1,
|
|
238
|
-
if (
|
|
239
|
-
this.
|
|
240
|
-
|
|
241
|
-
const curve = new LineCurve(this.currentPosition.x, this.currentPosition.y, ...start);
|
|
242
|
-
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);
|
|
243
233
|
}
|
|
244
|
-
if (
|
|
234
|
+
if (radius <= EPSILON)
|
|
245
235
|
return this;
|
|
246
|
-
const curve = new ArcCurve(
|
|
236
|
+
const curve = new ArcCurve(cx, cy, radius, startAngle, endAngle, counterclockwise);
|
|
247
237
|
this.add(curve);
|
|
248
238
|
this._setCurrentPosition(...end);
|
|
249
239
|
return this;
|
|
250
240
|
}
|
|
251
241
|
/**
|
|
252
242
|
* Draw an Arc curve from the current position, tangential to the 2 segments created by both control points
|
|
253
|
-
* Add an instance of {@link
|
|
243
|
+
* Add an instance of {@link EllipseCurve} to this path
|
|
254
244
|
*
|
|
255
245
|
* @param {number} x1 X-axis coordinate of the first control point
|
|
256
246
|
* @param {number} y1 Y-axis coordinate of the first control point
|
|
@@ -263,35 +253,46 @@ export default class PathContext extends Path {
|
|
|
263
253
|
if (radius < 0) {
|
|
264
254
|
throw new Error(`IndexSizeError: Failed to execute 'arcTo' on 'PathContext': The radius provided (${radius}) is negative.`);
|
|
265
255
|
}
|
|
266
|
-
const
|
|
267
|
-
|
|
256
|
+
const p0 = new Vector2(...this._currentPosition).applyMatrix(this._currentTransform.inverse());
|
|
257
|
+
const p1 = new Vector2(x1, y1);
|
|
258
|
+
const p2 = new Vector2(x2, y2);
|
|
259
|
+
if (Vector2.equals(p0, p1)) {
|
|
268
260
|
return this;
|
|
269
261
|
}
|
|
270
|
-
if (Vector2.collinear(
|
|
262
|
+
if (Vector2.collinear(p0, p1, p2) || radius === 0) {
|
|
271
263
|
return this.lineTo(x1, y1);
|
|
272
264
|
}
|
|
273
|
-
const
|
|
274
|
-
const
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
265
|
+
const v1 = p0.clone().sub(p1).normalize();
|
|
266
|
+
const v2 = p2.clone().sub(p1).normalize();
|
|
267
|
+
const n1 = new Vector2(-v1.y, v1.x);
|
|
268
|
+
const n2 = new Vector2(-v2.y, v2.x);
|
|
269
|
+
const angle = Math.acos(v1.dot(v2));
|
|
270
|
+
const tangentLength = radius / Math.tan(angle / 2);
|
|
271
|
+
const t1 = p1.clone().add(v1.clone().multiplyScalar(tangentLength));
|
|
272
|
+
const t2 = p1.clone().add(v2.clone().multiplyScalar(tangentLength));
|
|
273
|
+
const dx = t2.x - t1.x;
|
|
274
|
+
const dy = t2.y - t1.y;
|
|
275
|
+
const determinant = n2.x * n1.y - n2.y * n1.x;
|
|
276
|
+
if (Math.abs(determinant) <= EPSILON) {
|
|
277
|
+
throw new Error(`Failed to execute 'arcTo' on 'PathContext': Failed to compute arc center.`);
|
|
278
|
+
}
|
|
279
|
+
const normalLength = (n2.x * dy - n2.y * dx) / determinant;
|
|
280
|
+
const c = t1.clone().add(n1.clone().multiplyScalar(normalLength));
|
|
281
|
+
const startAngle = Math.atan2(t1.y - c.y, t1.x - c.x);
|
|
282
|
+
const endAngle = Math.atan2(t2.y - c.y, t2.x - c.x);
|
|
283
|
+
const deltaAngle = endAngle - startAngle;
|
|
292
284
|
const counterclockwise = deltaAngle < 0;
|
|
293
|
-
this.
|
|
294
|
-
this.
|
|
285
|
+
t1.applyMatrix(this._currentTransform);
|
|
286
|
+
t2.applyMatrix(this._currentTransform);
|
|
287
|
+
c.applyMatrix(this._currentTransform);
|
|
288
|
+
const rx = this._scaleX * radius;
|
|
289
|
+
const ry = this._scaleY * radius;
|
|
290
|
+
const rotation = this._rotation;
|
|
291
|
+
const line = new LineCurve(this._currentPosition.x, this._currentPosition.y, t1.x, t1.y);
|
|
292
|
+
this.add(line);
|
|
293
|
+
const ellipse = new EllipseCurve(c.x, c.y, rx, ry, rotation, startAngle, endAngle, counterclockwise);
|
|
294
|
+
this.add(ellipse);
|
|
295
|
+
this._setCurrentPosition(t2.x, t2.y);
|
|
295
296
|
return this;
|
|
296
297
|
}
|
|
297
298
|
/**
|
|
@@ -339,7 +340,6 @@ export default class PathContext extends Path {
|
|
|
339
340
|
bottomLeftRadius = Math.min(bottomLeftRadius, maxRadius);
|
|
340
341
|
const curve = new PathContext({ autoClose: true });
|
|
341
342
|
curve.setTransform(this.getTransform());
|
|
342
|
-
this.add(curve);
|
|
343
343
|
// Top-Right corner
|
|
344
344
|
if (topRightRadius > 0) {
|
|
345
345
|
curve.lineTo(x + width - topRightRadius, y);
|
|
@@ -372,19 +372,20 @@ export default class PathContext extends Path {
|
|
|
372
372
|
else {
|
|
373
373
|
curve.lineTo(x, y);
|
|
374
374
|
}
|
|
375
|
+
this.add(curve);
|
|
375
376
|
return this;
|
|
376
377
|
}
|
|
377
378
|
setTransform(a, b, c, d, e, f) {
|
|
378
379
|
if (a instanceof DOMMatrix) {
|
|
379
380
|
const matrix = a;
|
|
380
|
-
this.
|
|
381
|
+
this._currentTransform = new DOMMatrix([matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f]);
|
|
381
382
|
}
|
|
382
383
|
else {
|
|
383
|
-
this.
|
|
384
|
+
this._currentTransform = new DOMMatrix([a, b, c, d, e, f]);
|
|
384
385
|
}
|
|
385
386
|
}
|
|
386
387
|
getTransform() {
|
|
387
|
-
const { a, b, c, d, e, f } = this.
|
|
388
|
+
const { a, b, c, d, e, f } = this._currentTransform;
|
|
388
389
|
return new DOMMatrix([a, b, c, d, e, f]);
|
|
389
390
|
}
|
|
390
391
|
resetTransform() {
|
|
@@ -392,23 +393,23 @@ export default class PathContext extends Path {
|
|
|
392
393
|
}
|
|
393
394
|
transform(a, b, c, d, e, f) {
|
|
394
395
|
const matrix = new DOMMatrix([a, b, c, d, e, f]);
|
|
395
|
-
this.
|
|
396
|
+
this._currentTransform = this._currentTransform.multiply(matrix);
|
|
396
397
|
}
|
|
397
398
|
translate(x, y) {
|
|
398
|
-
this.
|
|
399
|
+
this._currentTransform = this._currentTransform.translate(x, y);
|
|
399
400
|
}
|
|
400
401
|
rotate(angle) {
|
|
401
|
-
this.
|
|
402
|
+
this._currentTransform = this._currentTransform.rotate(toDegrees(angle));
|
|
402
403
|
}
|
|
403
404
|
scale(x, y) {
|
|
404
|
-
this.
|
|
405
|
+
this._currentTransform = this._currentTransform.scale(x, y);
|
|
405
406
|
}
|
|
406
407
|
save() {
|
|
407
408
|
this._transformStack.push(this.getTransform());
|
|
408
409
|
}
|
|
409
410
|
restore() {
|
|
410
411
|
if (this._transformStack.length > 0) {
|
|
411
|
-
this.
|
|
412
|
+
this._currentTransform = this._transformStack.pop();
|
|
412
413
|
}
|
|
413
414
|
}
|
|
414
415
|
reset() {
|
|
@@ -416,79 +417,62 @@ export default class PathContext extends Path {
|
|
|
416
417
|
this._transformStack = [];
|
|
417
418
|
}
|
|
418
419
|
_hasCurrentPosition() {
|
|
419
|
-
return !isNaN(this.
|
|
420
|
+
return !isNaN(this._currentPosition.x) && !isNaN(this._currentPosition.y);
|
|
420
421
|
}
|
|
421
422
|
_setCurrentPosition(x, y) {
|
|
422
|
-
this.
|
|
423
|
+
this._currentPosition.set(x, y);
|
|
423
424
|
return this;
|
|
424
425
|
}
|
|
425
426
|
// ****************************
|
|
426
427
|
// Matrix transformations
|
|
427
428
|
// ****************************
|
|
428
|
-
_transformPoint(point
|
|
429
|
+
_transformPoint(point) {
|
|
429
430
|
if (this._isIdentity)
|
|
430
431
|
return point;
|
|
431
|
-
const { x, y } =
|
|
432
|
+
const { x, y } = this._currentTransform.transformPoint({ x: point[0], y: point[1] });
|
|
432
433
|
return [x, y];
|
|
433
434
|
}
|
|
434
|
-
_transformPoints(points
|
|
435
|
+
_transformPoints(points) {
|
|
435
436
|
if (this._isIdentity)
|
|
436
437
|
return points;
|
|
437
|
-
return points.map((point) => this._transformPoint(point
|
|
438
|
+
return points.map((point) => this._transformPoint(point));
|
|
438
439
|
}
|
|
439
|
-
_transformVector(vector
|
|
440
|
+
_transformVector(vector) {
|
|
440
441
|
if (this._isIdentity)
|
|
441
442
|
return vector;
|
|
442
|
-
const [x0, y0] = this._transformPoint([0, 0]
|
|
443
|
-
const [vx, vy] = this._transformPoint(vector
|
|
443
|
+
const [x0, y0] = this._transformPoint([0, 0]);
|
|
444
|
+
const [vx, vy] = this._transformPoint(vector);
|
|
444
445
|
return [vx - x0, vy - y0];
|
|
445
446
|
}
|
|
446
|
-
_transformEllipse(cx, cy, rx, ry, rotation
|
|
447
|
+
_transformEllipse(cx, cy, rx, ry, rotation) {
|
|
447
448
|
if (this._isIdentity)
|
|
448
449
|
return [cx, cy, rx, ry, rotation];
|
|
449
|
-
|
|
450
|
-
const [
|
|
451
|
-
const [
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
return [
|
|
456
|
-
}
|
|
457
|
-
_inversePoint(point) {
|
|
458
|
-
return this._transformPoint(point, this.currentTransform.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];
|
|
459
457
|
}
|
|
460
458
|
get _translateX() {
|
|
461
|
-
return this.
|
|
459
|
+
return this._currentTransform.e;
|
|
462
460
|
}
|
|
463
461
|
get _translateY() {
|
|
464
|
-
return this.
|
|
462
|
+
return this._currentTransform.f;
|
|
465
463
|
}
|
|
466
464
|
get _scaleX() {
|
|
467
|
-
const { a, b } = this.
|
|
465
|
+
const { a, b } = this._currentTransform;
|
|
468
466
|
return Math.hypot(a, b);
|
|
469
467
|
}
|
|
470
468
|
get _scaleY() {
|
|
471
|
-
const { c, d } = this.
|
|
469
|
+
const { c, d } = this._currentTransform;
|
|
472
470
|
return Math.hypot(c, d);
|
|
473
471
|
}
|
|
474
472
|
get _rotation() {
|
|
475
|
-
const { a, b } = this.
|
|
473
|
+
const { a, b } = this._currentTransform;
|
|
476
474
|
return Math.atan2(b, a);
|
|
477
475
|
}
|
|
478
|
-
get _skewX() {
|
|
479
|
-
const { c, d } = this.currentTransform;
|
|
480
|
-
const cos = Math.cos(this._rotation);
|
|
481
|
-
const sin = Math.sin(this._rotation);
|
|
482
|
-
const m11 = c * cos + d * sin;
|
|
483
|
-
return Math.atan(m11 / this._scaleX);
|
|
484
|
-
}
|
|
485
|
-
get _skewY() {
|
|
486
|
-
const { a, b } = this.currentTransform;
|
|
487
|
-
const cos = Math.cos(this._rotation);
|
|
488
|
-
const sin = Math.sin(this._rotation);
|
|
489
|
-
const m21 = a * sin - b * cos;
|
|
490
|
-
return Math.atan(m21 / this._scaleY);
|
|
491
|
-
}
|
|
492
476
|
get _isTranslated() {
|
|
493
477
|
return Math.abs(this._translateX) > EPSILON || Math.abs(this._translateY) > EPSILON;
|
|
494
478
|
}
|
|
@@ -496,20 +480,14 @@ export default class PathContext extends Path {
|
|
|
496
480
|
return Math.abs(this._scaleX - 1) > EPSILON || Math.abs(this._scaleY - 1) > EPSILON;
|
|
497
481
|
}
|
|
498
482
|
get _isRotated() {
|
|
499
|
-
const { b, c } = this.
|
|
483
|
+
const { b, c } = this._currentTransform;
|
|
500
484
|
return Math.abs(b) > EPSILON || Math.abs(c) > EPSILON;
|
|
501
485
|
}
|
|
502
|
-
get _isSkewed() {
|
|
503
|
-
const { a, b, c, d } = this.currentTransform;
|
|
504
|
-
const angleX = Math.atan2(b, a);
|
|
505
|
-
const angleY = Math.atan2(-c, d);
|
|
506
|
-
return Math.abs(angleX - angleY) > EPSILON;
|
|
507
|
-
}
|
|
508
486
|
get _isUniform() {
|
|
509
487
|
return Math.abs(this._scaleX - this._scaleY) <= EPSILON;
|
|
510
488
|
}
|
|
511
489
|
get _isIdentity() {
|
|
512
|
-
return this.
|
|
490
|
+
return this._currentTransform.isIdentity;
|
|
513
491
|
}
|
|
514
492
|
// ****************************
|
|
515
493
|
// Canvas 2D interface
|
|
@@ -2,9 +2,18 @@ import { Curve, LineCurve, PolylineCurve, QuadraticBezierCurve, CubicBezierCurve
|
|
|
2
2
|
import { type Vector2 } from '../geometry';
|
|
3
3
|
import PathContext from './PathContext';
|
|
4
4
|
import Path from './Path';
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Parameters used for SVG serialization of a path
|
|
7
|
+
*/
|
|
8
|
+
export type PathSVGSerializationParameters = {
|
|
9
|
+
/**
|
|
10
|
+
* Flag indicating if given curve should be approximated into straight lines
|
|
11
|
+
*/
|
|
6
12
|
approximate?: boolean;
|
|
7
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Resolution used for approximations
|
|
15
|
+
*/
|
|
16
|
+
resolution?: number;
|
|
8
17
|
};
|
|
9
18
|
/**
|
|
10
19
|
* Utility class for manipulating connected curves and generating SVG path
|
|
@@ -19,10 +28,10 @@ export default class PathSVG extends PathContext {
|
|
|
19
28
|
/**
|
|
20
29
|
* Serialize this path into a SVG path string
|
|
21
30
|
*
|
|
22
|
-
* @param {
|
|
31
|
+
* @param {PathSVGSerializationParameters} [params] Serialization parameters
|
|
23
32
|
* @returns {string}
|
|
24
33
|
*/
|
|
25
|
-
toString(params?:
|
|
34
|
+
toString(params?: PathSVGSerializationParameters): string;
|
|
26
35
|
/**
|
|
27
36
|
* Convert a {@link Curve} into spaced points
|
|
28
37
|
*
|
|
@@ -35,77 +44,74 @@ export default class PathSVG extends PathContext {
|
|
|
35
44
|
* Serialize a {@link Curve}
|
|
36
45
|
*
|
|
37
46
|
* @param {Curve} curve Curve to serialize
|
|
38
|
-
* @param {
|
|
39
|
-
* @
|
|
40
|
-
* @param {number} [params.curveResolution] Resolution used for curve approximations
|
|
41
|
-
* @returns string
|
|
47
|
+
* @param {PathSVGSerializationParameters} [params] Serialization parameters
|
|
48
|
+
* @returns {string}
|
|
42
49
|
*/
|
|
43
|
-
static serialize(curve: Curve<Vector2>, { approximate,
|
|
50
|
+
static serialize(curve: Curve<Vector2>, { approximate, resolution }?: PathSVGSerializationParameters): string;
|
|
44
51
|
/**
|
|
45
52
|
* Serialize a {@link LineCurve}
|
|
46
53
|
*
|
|
47
54
|
* @param {LineCurve} curve LineCurve to serialize
|
|
48
|
-
* @returns string
|
|
55
|
+
* @returns {string}
|
|
49
56
|
*/
|
|
50
57
|
static serializeLineCurve(curve: LineCurve): string;
|
|
51
58
|
/**
|
|
52
59
|
* Serialize a {@link PolylineCurve}
|
|
53
60
|
*
|
|
54
61
|
* @param {PolylineCurve} curve PolylineCurve to serialize
|
|
55
|
-
* @returns string
|
|
62
|
+
* @returns {string}
|
|
56
63
|
*/
|
|
57
64
|
static serializePolylineCurve(curve: PolylineCurve): string;
|
|
58
65
|
/**
|
|
59
66
|
* Serialize a {@link QuadraticBezierCurve}
|
|
60
67
|
*
|
|
61
68
|
* @param {QuadraticBezierCurve} curve QuadraticBezierCurve to serialize
|
|
62
|
-
* @returns string
|
|
69
|
+
* @returns {string}
|
|
63
70
|
*/
|
|
64
71
|
static serializeQuadraticBezierCurve(curve: QuadraticBezierCurve): string;
|
|
65
72
|
/**
|
|
66
73
|
* Serialize a {@link CubicBezierCurve}
|
|
67
74
|
*
|
|
68
75
|
* @param {CubicBezierCurve} curve CubicBezierCurve to serialize
|
|
69
|
-
* @returns string
|
|
76
|
+
* @returns {string}
|
|
70
77
|
*/
|
|
71
78
|
static serializeCubicBezierCurve(curve: CubicBezierCurve): string;
|
|
72
79
|
/**
|
|
73
80
|
* Serialize a {@link CatmullRomCurve} by approximating it into straight lines
|
|
74
81
|
*
|
|
75
82
|
* @param {CatmullRomCurve} curve CatmullRomCurve to serialize
|
|
76
|
-
* @param {number} [
|
|
77
|
-
* @returns string
|
|
83
|
+
* @param {number} [resolution] Approximation resolution
|
|
84
|
+
* @returns {string}
|
|
78
85
|
*/
|
|
79
|
-
static serializeCatmullRomCurve(curve: CatmullRomCurve,
|
|
86
|
+
static serializeCatmullRomCurve(curve: CatmullRomCurve, resolution?: number): string;
|
|
80
87
|
/**
|
|
81
88
|
* Serialize a {@link SplineCurve} by approximating it into straight lines
|
|
82
89
|
*
|
|
83
90
|
* @param {SplineCurve} curve SplineCurve to serialize
|
|
84
|
-
* @param {number} [
|
|
85
|
-
* @returns string
|
|
91
|
+
* @param {number} [resolution] Approximation resolution
|
|
92
|
+
* @returns {string}
|
|
86
93
|
*/
|
|
87
|
-
static serializeSplineCurve(curve: SplineCurve,
|
|
94
|
+
static serializeSplineCurve(curve: SplineCurve, resolution?: number): string;
|
|
88
95
|
/**
|
|
89
96
|
* Serialize an {@link EllipseCurve}
|
|
90
97
|
*
|
|
91
98
|
* @param {EllipseCurve} curve EllipseCurve to serialize
|
|
92
|
-
* @returns string
|
|
99
|
+
* @returns {string}
|
|
93
100
|
*/
|
|
94
101
|
static serializeEllipseCurve(curve: EllipseCurve): string;
|
|
95
102
|
/**
|
|
96
103
|
* Serialize an {@link ArcCurve}
|
|
97
104
|
*
|
|
98
105
|
* @param {ArcCurve} curve ArcCurve to serialize
|
|
99
|
-
* @returns string
|
|
106
|
+
* @returns {string}
|
|
100
107
|
*/
|
|
101
108
|
static serializeArcCurve(curve: ArcCurve): string;
|
|
102
109
|
/**
|
|
103
110
|
* Serialize an {@link Path}
|
|
104
111
|
*
|
|
105
112
|
* @param {Path} path Path to serialize
|
|
106
|
-
* @param {
|
|
107
|
-
* @
|
|
108
|
-
* @returns string
|
|
113
|
+
* @param {PathSVGSerializationParameters} [params] Serialization parameters
|
|
114
|
+
* @returns {string}
|
|
109
115
|
*/
|
|
110
|
-
static serializePath(path: Path<Vector2>, params?:
|
|
116
|
+
static serializePath(path: Path<Vector2>, params?: PathSVGSerializationParameters): string;
|
|
111
117
|
}
|