modern-path2d 0.0.5 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -1
- package/dist/index.cjs +1597 -140
- package/dist/index.d.cts +181 -131
- package/dist/index.d.mts +181 -131
- package/dist/index.d.ts +181 -131
- package/dist/index.js +1 -1
- package/dist/index.mjs +1596 -138
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,207 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var __defProp$6 = Object.defineProperty;
|
|
4
|
+
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
+
var __publicField$6 = (obj, key, value) => {
|
|
6
|
+
__defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
+
return value;
|
|
8
|
+
};
|
|
9
|
+
class Matrix3 {
|
|
10
|
+
constructor(n11 = 1, n12 = 0, n13 = 0, n21 = 0, n22 = 1, n23 = 0, n31 = 0, n32 = 0, n33 = 1) {
|
|
11
|
+
__publicField$6(this, "elements", []);
|
|
12
|
+
this.set(n11, n12, n13, n21, n22, n23, n31, n32, n33);
|
|
13
|
+
}
|
|
14
|
+
set(n11, n12, n13, n21, n22, n23, n31, n32, n33) {
|
|
15
|
+
const te = this.elements;
|
|
16
|
+
te[0] = n11;
|
|
17
|
+
te[1] = n21;
|
|
18
|
+
te[2] = n31;
|
|
19
|
+
te[3] = n12;
|
|
20
|
+
te[4] = n22;
|
|
21
|
+
te[5] = n32;
|
|
22
|
+
te[6] = n13;
|
|
23
|
+
te[7] = n23;
|
|
24
|
+
te[8] = n33;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
identity() {
|
|
28
|
+
this.set(
|
|
29
|
+
1,
|
|
30
|
+
0,
|
|
31
|
+
0,
|
|
32
|
+
0,
|
|
33
|
+
1,
|
|
34
|
+
0,
|
|
35
|
+
0,
|
|
36
|
+
0,
|
|
37
|
+
1
|
|
38
|
+
);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
copy(m) {
|
|
42
|
+
const te = this.elements;
|
|
43
|
+
const me = m.elements;
|
|
44
|
+
te[0] = me[0];
|
|
45
|
+
te[1] = me[1];
|
|
46
|
+
te[2] = me[2];
|
|
47
|
+
te[3] = me[3];
|
|
48
|
+
te[4] = me[4];
|
|
49
|
+
te[5] = me[5];
|
|
50
|
+
te[6] = me[6];
|
|
51
|
+
te[7] = me[7];
|
|
52
|
+
te[8] = me[8];
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
multiply(m) {
|
|
56
|
+
return this.multiplyMatrices(this, m);
|
|
57
|
+
}
|
|
58
|
+
premultiply(m) {
|
|
59
|
+
return this.multiplyMatrices(m, this);
|
|
60
|
+
}
|
|
61
|
+
multiplyMatrices(a, b) {
|
|
62
|
+
const ae = a.elements;
|
|
63
|
+
const be = b.elements;
|
|
64
|
+
const te = this.elements;
|
|
65
|
+
const a11 = ae[0];
|
|
66
|
+
const a12 = ae[3];
|
|
67
|
+
const a13 = ae[6];
|
|
68
|
+
const a21 = ae[1];
|
|
69
|
+
const a22 = ae[4];
|
|
70
|
+
const a23 = ae[7];
|
|
71
|
+
const a31 = ae[2];
|
|
72
|
+
const a32 = ae[5];
|
|
73
|
+
const a33 = ae[8];
|
|
74
|
+
const b11 = be[0];
|
|
75
|
+
const b12 = be[3];
|
|
76
|
+
const b13 = be[6];
|
|
77
|
+
const b21 = be[1];
|
|
78
|
+
const b22 = be[4];
|
|
79
|
+
const b23 = be[7];
|
|
80
|
+
const b31 = be[2];
|
|
81
|
+
const b32 = be[5];
|
|
82
|
+
const b33 = be[8];
|
|
83
|
+
te[0] = a11 * b11 + a12 * b21 + a13 * b31;
|
|
84
|
+
te[3] = a11 * b12 + a12 * b22 + a13 * b32;
|
|
85
|
+
te[6] = a11 * b13 + a12 * b23 + a13 * b33;
|
|
86
|
+
te[1] = a21 * b11 + a22 * b21 + a23 * b31;
|
|
87
|
+
te[4] = a21 * b12 + a22 * b22 + a23 * b32;
|
|
88
|
+
te[7] = a21 * b13 + a22 * b23 + a23 * b33;
|
|
89
|
+
te[2] = a31 * b11 + a32 * b21 + a33 * b31;
|
|
90
|
+
te[5] = a31 * b12 + a32 * b22 + a33 * b32;
|
|
91
|
+
te[8] = a31 * b13 + a32 * b23 + a33 * b33;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
invert() {
|
|
95
|
+
const te = this.elements;
|
|
96
|
+
const n11 = te[0];
|
|
97
|
+
const n21 = te[1];
|
|
98
|
+
const n31 = te[2];
|
|
99
|
+
const n12 = te[3];
|
|
100
|
+
const n22 = te[4];
|
|
101
|
+
const n32 = te[5];
|
|
102
|
+
const n13 = te[6];
|
|
103
|
+
const n23 = te[7];
|
|
104
|
+
const n33 = te[8];
|
|
105
|
+
const t11 = n33 * n22 - n32 * n23;
|
|
106
|
+
const t12 = n32 * n13 - n33 * n12;
|
|
107
|
+
const t13 = n23 * n12 - n22 * n13;
|
|
108
|
+
const det = n11 * t11 + n21 * t12 + n31 * t13;
|
|
109
|
+
if (det === 0)
|
|
110
|
+
return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
111
|
+
const detInv = 1 / det;
|
|
112
|
+
te[0] = t11 * detInv;
|
|
113
|
+
te[1] = (n31 * n23 - n33 * n21) * detInv;
|
|
114
|
+
te[2] = (n32 * n21 - n31 * n22) * detInv;
|
|
115
|
+
te[3] = t12 * detInv;
|
|
116
|
+
te[4] = (n33 * n11 - n31 * n13) * detInv;
|
|
117
|
+
te[5] = (n31 * n12 - n32 * n11) * detInv;
|
|
118
|
+
te[6] = t13 * detInv;
|
|
119
|
+
te[7] = (n21 * n13 - n23 * n11) * detInv;
|
|
120
|
+
te[8] = (n22 * n11 - n21 * n12) * detInv;
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
transpose() {
|
|
124
|
+
let tmp;
|
|
125
|
+
const m = this.elements;
|
|
126
|
+
tmp = m[1];
|
|
127
|
+
m[1] = m[3];
|
|
128
|
+
m[3] = tmp;
|
|
129
|
+
tmp = m[2];
|
|
130
|
+
m[2] = m[6];
|
|
131
|
+
m[6] = tmp;
|
|
132
|
+
tmp = m[5];
|
|
133
|
+
m[5] = m[7];
|
|
134
|
+
m[7] = tmp;
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
scale(sx, sy) {
|
|
138
|
+
this.premultiply(_m3.makeScale(sx, sy));
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
rotate(theta) {
|
|
142
|
+
this.premultiply(_m3.makeRotation(-theta));
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
translate(tx, ty) {
|
|
146
|
+
this.premultiply(_m3.makeTranslation(tx, ty));
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
makeTranslation(x, y) {
|
|
150
|
+
this.set(
|
|
151
|
+
1,
|
|
152
|
+
0,
|
|
153
|
+
x,
|
|
154
|
+
0,
|
|
155
|
+
1,
|
|
156
|
+
y,
|
|
157
|
+
0,
|
|
158
|
+
0,
|
|
159
|
+
1
|
|
160
|
+
);
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
makeRotation(theta) {
|
|
164
|
+
const c = Math.cos(theta);
|
|
165
|
+
const s = Math.sin(theta);
|
|
166
|
+
this.set(
|
|
167
|
+
c,
|
|
168
|
+
-s,
|
|
169
|
+
0,
|
|
170
|
+
s,
|
|
171
|
+
c,
|
|
172
|
+
0,
|
|
173
|
+
0,
|
|
174
|
+
0,
|
|
175
|
+
1
|
|
176
|
+
);
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
makeScale(x, y) {
|
|
180
|
+
this.set(
|
|
181
|
+
x,
|
|
182
|
+
0,
|
|
183
|
+
0,
|
|
184
|
+
0,
|
|
185
|
+
y,
|
|
186
|
+
0,
|
|
187
|
+
0,
|
|
188
|
+
0,
|
|
189
|
+
1
|
|
190
|
+
);
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
fromArray(array, offset = 0) {
|
|
194
|
+
for (let i = 0; i < 9; i++) {
|
|
195
|
+
this.elements[i] = array[i + offset];
|
|
196
|
+
}
|
|
197
|
+
return this;
|
|
198
|
+
}
|
|
199
|
+
clone() {
|
|
200
|
+
return new this.constructor().fromArray(this.elements);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const _m3 = /* @__PURE__ */ new Matrix3();
|
|
204
|
+
|
|
3
205
|
class Point2D {
|
|
4
206
|
constructor(x = 0, y = 0) {
|
|
5
207
|
this.x = x;
|
|
@@ -61,6 +263,15 @@ class Point2D {
|
|
|
61
263
|
equals(point) {
|
|
62
264
|
return this.x === point.x && this.y === point.y;
|
|
63
265
|
}
|
|
266
|
+
applyMatrix3(matrix3) {
|
|
267
|
+
const [a, c, tx, b, d, ty] = matrix3.elements;
|
|
268
|
+
const { x, y } = this;
|
|
269
|
+
this.set(
|
|
270
|
+
a * x + c * y + tx,
|
|
271
|
+
b * x + d * y + ty
|
|
272
|
+
);
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
64
275
|
copy(point) {
|
|
65
276
|
this.x = point.x;
|
|
66
277
|
this.y = point.y;
|
|
@@ -71,6 +282,574 @@ class Point2D {
|
|
|
71
282
|
}
|
|
72
283
|
}
|
|
73
284
|
|
|
285
|
+
function svgAngle(ux, uy, vx, vy) {
|
|
286
|
+
const dot = ux * vx + uy * vy;
|
|
287
|
+
const len = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
|
|
288
|
+
let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));
|
|
289
|
+
if (ux * vy - uy * vx < 0)
|
|
290
|
+
ang = -ang;
|
|
291
|
+
return ang;
|
|
292
|
+
}
|
|
293
|
+
function parseArcCommand(path, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, start, end) {
|
|
294
|
+
if (rx === 0 || ry === 0) {
|
|
295
|
+
path.lineTo(end.x, end.y);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
xAxisRotation = xAxisRotation * Math.PI / 180;
|
|
299
|
+
rx = Math.abs(rx);
|
|
300
|
+
ry = Math.abs(ry);
|
|
301
|
+
const dx2 = (start.x - end.x) / 2;
|
|
302
|
+
const dy2 = (start.y - end.y) / 2;
|
|
303
|
+
const x1p = Math.cos(xAxisRotation) * dx2 + Math.sin(xAxisRotation) * dy2;
|
|
304
|
+
const y1p = -Math.sin(xAxisRotation) * dx2 + Math.cos(xAxisRotation) * dy2;
|
|
305
|
+
let rxs = rx * rx;
|
|
306
|
+
let rys = ry * ry;
|
|
307
|
+
const x1ps = x1p * x1p;
|
|
308
|
+
const y1ps = y1p * y1p;
|
|
309
|
+
const cr = x1ps / rxs + y1ps / rys;
|
|
310
|
+
if (cr > 1) {
|
|
311
|
+
const s = Math.sqrt(cr);
|
|
312
|
+
rx = s * rx;
|
|
313
|
+
ry = s * ry;
|
|
314
|
+
rxs = rx * rx;
|
|
315
|
+
rys = ry * ry;
|
|
316
|
+
}
|
|
317
|
+
const dq = rxs * y1ps + rys * x1ps;
|
|
318
|
+
const pq = (rxs * rys - dq) / dq;
|
|
319
|
+
let q = Math.sqrt(Math.max(0, pq));
|
|
320
|
+
if (largeArcFlag === sweepFlag)
|
|
321
|
+
q = -q;
|
|
322
|
+
const cxp = q * rx * y1p / ry;
|
|
323
|
+
const cyp = -q * ry * x1p / rx;
|
|
324
|
+
const cx = Math.cos(xAxisRotation) * cxp - Math.sin(xAxisRotation) * cyp + (start.x + end.x) / 2;
|
|
325
|
+
const cy = Math.sin(xAxisRotation) * cxp + Math.cos(xAxisRotation) * cyp + (start.y + end.y) / 2;
|
|
326
|
+
const theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
|
|
327
|
+
const delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry) % (Math.PI * 2);
|
|
328
|
+
path.currentPath.absellipse(cx, cy, rx, ry, theta, theta + delta, sweepFlag === 0, xAxisRotation);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function getReflection(a, b) {
|
|
332
|
+
return a - (b - a);
|
|
333
|
+
}
|
|
334
|
+
function addPathCommandsToPath2D(commands, path) {
|
|
335
|
+
const point = new Point2D();
|
|
336
|
+
const control = new Point2D();
|
|
337
|
+
const firstPoint = new Point2D();
|
|
338
|
+
let isFirstPoint = true;
|
|
339
|
+
let doSetFirstPoint = false;
|
|
340
|
+
for (let i = 0, l = commands.length; i < l; i++) {
|
|
341
|
+
const command = commands[i];
|
|
342
|
+
if (isFirstPoint) {
|
|
343
|
+
doSetFirstPoint = true;
|
|
344
|
+
isFirstPoint = false;
|
|
345
|
+
}
|
|
346
|
+
if (command.type === "m" || command.type === "M") {
|
|
347
|
+
if (command.type === "m") {
|
|
348
|
+
point.x += command.x;
|
|
349
|
+
point.y += command.y;
|
|
350
|
+
} else {
|
|
351
|
+
point.x = command.x;
|
|
352
|
+
point.y = command.y;
|
|
353
|
+
}
|
|
354
|
+
control.x = point.x;
|
|
355
|
+
control.y = point.y;
|
|
356
|
+
path.moveTo(point.x, point.y);
|
|
357
|
+
if (i === 0)
|
|
358
|
+
firstPoint.copy(point);
|
|
359
|
+
} else if (command.type === "h" || command.type === "H") {
|
|
360
|
+
if (command.type === "h") {
|
|
361
|
+
point.x += command.x;
|
|
362
|
+
} else {
|
|
363
|
+
point.x = command.x;
|
|
364
|
+
}
|
|
365
|
+
control.x = point.x;
|
|
366
|
+
control.y = point.y;
|
|
367
|
+
path.lineTo(point.x, point.y);
|
|
368
|
+
if (doSetFirstPoint)
|
|
369
|
+
firstPoint.copy(point);
|
|
370
|
+
} else if (command.type === "v" || command.type === "V") {
|
|
371
|
+
if (command.type === "v") {
|
|
372
|
+
point.y += command.y;
|
|
373
|
+
} else {
|
|
374
|
+
point.y = command.y;
|
|
375
|
+
}
|
|
376
|
+
control.x = point.x;
|
|
377
|
+
control.y = point.y;
|
|
378
|
+
path.lineTo(point.x, point.y);
|
|
379
|
+
if (doSetFirstPoint)
|
|
380
|
+
firstPoint.copy(point);
|
|
381
|
+
} else if (command.type === "l" || command.type === "L") {
|
|
382
|
+
if (command.type === "l") {
|
|
383
|
+
point.x += command.x;
|
|
384
|
+
point.y += command.y;
|
|
385
|
+
} else {
|
|
386
|
+
point.x = command.x;
|
|
387
|
+
point.y = command.y;
|
|
388
|
+
}
|
|
389
|
+
control.x = point.x;
|
|
390
|
+
control.y = point.y;
|
|
391
|
+
path.lineTo(point.x, point.y);
|
|
392
|
+
if (doSetFirstPoint)
|
|
393
|
+
firstPoint.copy(point);
|
|
394
|
+
} else if (command.type === "c" || command.type === "C") {
|
|
395
|
+
if (command.type === "c") {
|
|
396
|
+
path.bezierCurveTo(
|
|
397
|
+
point.x + command.x1,
|
|
398
|
+
point.y + command.y1,
|
|
399
|
+
point.x + command.x2,
|
|
400
|
+
point.y + command.y2,
|
|
401
|
+
point.x + command.x,
|
|
402
|
+
point.y + command.y
|
|
403
|
+
);
|
|
404
|
+
control.x = point.x + command.x2;
|
|
405
|
+
control.y = point.y + command.y2;
|
|
406
|
+
point.x += command.x;
|
|
407
|
+
point.y += command.y;
|
|
408
|
+
} else {
|
|
409
|
+
path.bezierCurveTo(
|
|
410
|
+
command.x1,
|
|
411
|
+
command.y1,
|
|
412
|
+
command.x2,
|
|
413
|
+
command.y2,
|
|
414
|
+
command.x,
|
|
415
|
+
command.y
|
|
416
|
+
);
|
|
417
|
+
control.x = command.x2;
|
|
418
|
+
control.y = command.y2;
|
|
419
|
+
point.x = command.x;
|
|
420
|
+
point.y = command.y;
|
|
421
|
+
}
|
|
422
|
+
if (doSetFirstPoint)
|
|
423
|
+
firstPoint.copy(point);
|
|
424
|
+
} else if (command.type === "s" || command.type === "S") {
|
|
425
|
+
if (command.type === "s") {
|
|
426
|
+
path.bezierCurveTo(
|
|
427
|
+
getReflection(point.x, control.x),
|
|
428
|
+
getReflection(point.y, control.y),
|
|
429
|
+
point.x + command.x2,
|
|
430
|
+
point.y + command.y2,
|
|
431
|
+
point.x + command.x,
|
|
432
|
+
point.y + command.y
|
|
433
|
+
);
|
|
434
|
+
control.x = point.x + command.x2;
|
|
435
|
+
control.y = point.y + command.y2;
|
|
436
|
+
point.x += command.x;
|
|
437
|
+
point.y += command.y;
|
|
438
|
+
} else {
|
|
439
|
+
path.bezierCurveTo(
|
|
440
|
+
getReflection(point.x, control.x),
|
|
441
|
+
getReflection(point.y, control.y),
|
|
442
|
+
command.x2,
|
|
443
|
+
command.y2,
|
|
444
|
+
command.x,
|
|
445
|
+
command.y
|
|
446
|
+
);
|
|
447
|
+
control.x = command.x2;
|
|
448
|
+
control.y = command.y2;
|
|
449
|
+
point.x = command.x;
|
|
450
|
+
point.y = command.y;
|
|
451
|
+
}
|
|
452
|
+
if (doSetFirstPoint)
|
|
453
|
+
firstPoint.copy(point);
|
|
454
|
+
} else if (command.type === "q" || command.type === "Q") {
|
|
455
|
+
if (command.type === "q") {
|
|
456
|
+
path.quadraticCurveTo(
|
|
457
|
+
point.x + command.x1,
|
|
458
|
+
point.y + command.y1,
|
|
459
|
+
point.x + command.x,
|
|
460
|
+
point.y + command.y
|
|
461
|
+
);
|
|
462
|
+
control.x = point.x + command.x1;
|
|
463
|
+
control.y = point.y + command.y1;
|
|
464
|
+
point.x += command.x;
|
|
465
|
+
point.y += command.y;
|
|
466
|
+
} else {
|
|
467
|
+
path.quadraticCurveTo(
|
|
468
|
+
command.x1,
|
|
469
|
+
command.y1,
|
|
470
|
+
command.x,
|
|
471
|
+
command.y
|
|
472
|
+
);
|
|
473
|
+
control.x = command.x1;
|
|
474
|
+
control.y = command.y1;
|
|
475
|
+
point.x = command.x;
|
|
476
|
+
point.y = command.y;
|
|
477
|
+
}
|
|
478
|
+
if (doSetFirstPoint)
|
|
479
|
+
firstPoint.copy(point);
|
|
480
|
+
} else if (command.type === "t" || command.type === "T") {
|
|
481
|
+
const rx = getReflection(point.x, control.x);
|
|
482
|
+
const ry = getReflection(point.y, control.y);
|
|
483
|
+
control.x = rx;
|
|
484
|
+
control.y = ry;
|
|
485
|
+
if (command.type === "t") {
|
|
486
|
+
path.quadraticCurveTo(
|
|
487
|
+
rx,
|
|
488
|
+
ry,
|
|
489
|
+
point.x + command.x,
|
|
490
|
+
point.y + command.y
|
|
491
|
+
);
|
|
492
|
+
point.x += command.x;
|
|
493
|
+
point.y += command.y;
|
|
494
|
+
} else {
|
|
495
|
+
path.quadraticCurveTo(
|
|
496
|
+
rx,
|
|
497
|
+
ry,
|
|
498
|
+
command.x,
|
|
499
|
+
command.y
|
|
500
|
+
);
|
|
501
|
+
point.x = command.x;
|
|
502
|
+
point.y = command.y;
|
|
503
|
+
}
|
|
504
|
+
if (doSetFirstPoint)
|
|
505
|
+
firstPoint.copy(point);
|
|
506
|
+
} else if (command.type === "a" || command.type === "A") {
|
|
507
|
+
if (command.type === "a") {
|
|
508
|
+
if (command.x === 0 && command.y === 0)
|
|
509
|
+
continue;
|
|
510
|
+
point.x += command.x;
|
|
511
|
+
point.y += command.y;
|
|
512
|
+
} else {
|
|
513
|
+
if (command.x === point.x && command.y === point.y)
|
|
514
|
+
continue;
|
|
515
|
+
point.x = command.x;
|
|
516
|
+
point.y = command.y;
|
|
517
|
+
}
|
|
518
|
+
const start = point.clone();
|
|
519
|
+
control.x = point.x;
|
|
520
|
+
control.y = point.y;
|
|
521
|
+
parseArcCommand(
|
|
522
|
+
path,
|
|
523
|
+
command.rx,
|
|
524
|
+
command.ry,
|
|
525
|
+
command.angle,
|
|
526
|
+
command.largeArcFlag,
|
|
527
|
+
command.sweepFlag,
|
|
528
|
+
start,
|
|
529
|
+
point
|
|
530
|
+
);
|
|
531
|
+
if (doSetFirstPoint)
|
|
532
|
+
firstPoint.copy(point);
|
|
533
|
+
} else if (command.type === "z" || command.type === "Z") {
|
|
534
|
+
path.currentPath.autoClose = true;
|
|
535
|
+
if (path.currentPath.curves.length > 0) {
|
|
536
|
+
point.copy(firstPoint);
|
|
537
|
+
path.currentPath.currentPoint.copy(point);
|
|
538
|
+
isFirstPoint = true;
|
|
539
|
+
}
|
|
540
|
+
} else {
|
|
541
|
+
console.warn(command);
|
|
542
|
+
}
|
|
543
|
+
doSetFirstPoint = false;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
const RE$3 = {
|
|
548
|
+
SEPARATOR: /[ \t\r\n,.\-+]/,
|
|
549
|
+
WHITESPACE: /[ \t\r\n]/,
|
|
550
|
+
DIGIT: /\d/,
|
|
551
|
+
SIGN: /[-+]/,
|
|
552
|
+
POINT: /\./,
|
|
553
|
+
COMMA: /,/,
|
|
554
|
+
EXP: /e/i,
|
|
555
|
+
FLAGS: /[01]/
|
|
556
|
+
};
|
|
557
|
+
function parsePathDataArgs(input, flags, stride = 0) {
|
|
558
|
+
const SEP = 0;
|
|
559
|
+
const INT = 1;
|
|
560
|
+
const FLOAT = 2;
|
|
561
|
+
const EXP = 3;
|
|
562
|
+
let state = SEP;
|
|
563
|
+
let seenComma = true;
|
|
564
|
+
let number = "";
|
|
565
|
+
let exponent = "";
|
|
566
|
+
const result = [];
|
|
567
|
+
function throwSyntaxError(current2, i, partial) {
|
|
568
|
+
const error = new SyntaxError(`Unexpected character "${current2}" at index ${i}.`);
|
|
569
|
+
error.partial = partial;
|
|
570
|
+
throw error;
|
|
571
|
+
}
|
|
572
|
+
function newNumber() {
|
|
573
|
+
if (number !== "") {
|
|
574
|
+
if (exponent === "")
|
|
575
|
+
result.push(Number(number));
|
|
576
|
+
else
|
|
577
|
+
result.push(Number(number) * 10 ** Number(exponent));
|
|
578
|
+
}
|
|
579
|
+
number = "";
|
|
580
|
+
exponent = "";
|
|
581
|
+
}
|
|
582
|
+
let current;
|
|
583
|
+
const length = input.length;
|
|
584
|
+
for (let i = 0; i < length; i++) {
|
|
585
|
+
current = input[i];
|
|
586
|
+
if (Array.isArray(flags) && flags.includes(result.length % stride) && RE$3.FLAGS.test(current)) {
|
|
587
|
+
state = INT;
|
|
588
|
+
number = current;
|
|
589
|
+
newNumber();
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
if (state === SEP) {
|
|
593
|
+
if (RE$3.WHITESPACE.test(current)) {
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (RE$3.DIGIT.test(current) || RE$3.SIGN.test(current)) {
|
|
597
|
+
state = INT;
|
|
598
|
+
number = current;
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
if (RE$3.POINT.test(current)) {
|
|
602
|
+
state = FLOAT;
|
|
603
|
+
number = current;
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
if (RE$3.COMMA.test(current)) {
|
|
607
|
+
if (seenComma) {
|
|
608
|
+
throwSyntaxError(current, i, result);
|
|
609
|
+
}
|
|
610
|
+
seenComma = true;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
if (state === INT) {
|
|
614
|
+
if (RE$3.DIGIT.test(current)) {
|
|
615
|
+
number += current;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (RE$3.POINT.test(current)) {
|
|
619
|
+
number += current;
|
|
620
|
+
state = FLOAT;
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (RE$3.EXP.test(current)) {
|
|
624
|
+
state = EXP;
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
if (RE$3.SIGN.test(current) && number.length === 1 && RE$3.SIGN.test(number[0])) {
|
|
628
|
+
throwSyntaxError(current, i, result);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (state === FLOAT) {
|
|
632
|
+
if (RE$3.DIGIT.test(current)) {
|
|
633
|
+
number += current;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (RE$3.EXP.test(current)) {
|
|
637
|
+
state = EXP;
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (RE$3.POINT.test(current) && number[number.length - 1] === ".") {
|
|
641
|
+
throwSyntaxError(current, i, result);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
if (state === EXP) {
|
|
645
|
+
if (RE$3.DIGIT.test(current)) {
|
|
646
|
+
exponent += current;
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (RE$3.SIGN.test(current)) {
|
|
650
|
+
if (exponent === "") {
|
|
651
|
+
exponent += current;
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
if (exponent.length === 1 && RE$3.SIGN.test(exponent)) {
|
|
655
|
+
throwSyntaxError(current, i, result);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (RE$3.WHITESPACE.test(current)) {
|
|
660
|
+
newNumber();
|
|
661
|
+
state = SEP;
|
|
662
|
+
seenComma = false;
|
|
663
|
+
} else if (RE$3.COMMA.test(current)) {
|
|
664
|
+
newNumber();
|
|
665
|
+
state = SEP;
|
|
666
|
+
seenComma = true;
|
|
667
|
+
} else if (RE$3.SIGN.test(current)) {
|
|
668
|
+
newNumber();
|
|
669
|
+
state = INT;
|
|
670
|
+
number = current;
|
|
671
|
+
} else if (RE$3.POINT.test(current)) {
|
|
672
|
+
newNumber();
|
|
673
|
+
state = FLOAT;
|
|
674
|
+
number = current;
|
|
675
|
+
} else {
|
|
676
|
+
throwSyntaxError(current, i, result);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
newNumber();
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
function commandToData(cmd) {
|
|
684
|
+
switch (cmd.type) {
|
|
685
|
+
case "m":
|
|
686
|
+
case "M":
|
|
687
|
+
return `${cmd.type} ${cmd.x} ${cmd.y}`;
|
|
688
|
+
case "h":
|
|
689
|
+
case "H":
|
|
690
|
+
return `${cmd.type} ${cmd.x}`;
|
|
691
|
+
case "v":
|
|
692
|
+
case "V":
|
|
693
|
+
return `${cmd.type} ${cmd.y}`;
|
|
694
|
+
case "l":
|
|
695
|
+
case "L":
|
|
696
|
+
return `${cmd.type} ${cmd.x} ${cmd.y}`;
|
|
697
|
+
case "c":
|
|
698
|
+
case "C":
|
|
699
|
+
return `${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`;
|
|
700
|
+
case "s":
|
|
701
|
+
case "S":
|
|
702
|
+
return `${cmd.type} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`;
|
|
703
|
+
case "q":
|
|
704
|
+
case "Q":
|
|
705
|
+
return `${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x} ${cmd.y}`;
|
|
706
|
+
case "t":
|
|
707
|
+
case "T":
|
|
708
|
+
return `${cmd.type} ${cmd.x} ${cmd.y}`;
|
|
709
|
+
case "a":
|
|
710
|
+
case "A":
|
|
711
|
+
return `${cmd.type} ${cmd.rx} ${cmd.ry} ${cmd.angle} ${cmd.largeArcFlag} ${cmd.sweepFlag} ${cmd.x} ${cmd.y}`;
|
|
712
|
+
case "z":
|
|
713
|
+
case "Z":
|
|
714
|
+
return cmd.type;
|
|
715
|
+
default:
|
|
716
|
+
return "";
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function pathCommandsToPathData(commands) {
|
|
720
|
+
let data = "";
|
|
721
|
+
for (let i = 0, len = commands.length; i < len; i++) {
|
|
722
|
+
data += `${commandToData(commands[i])} `;
|
|
723
|
+
}
|
|
724
|
+
return data;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
const RE$2 = /[a-df-z][^a-df-z]*/gi;
|
|
728
|
+
function pathDataToPathCommands(d) {
|
|
729
|
+
const commands = [];
|
|
730
|
+
const matched = d.match(RE$2);
|
|
731
|
+
if (!matched) {
|
|
732
|
+
return commands;
|
|
733
|
+
}
|
|
734
|
+
for (let i = 0, len = matched.length; i < len; i++) {
|
|
735
|
+
const command = matched[i];
|
|
736
|
+
const type = command.charAt(0);
|
|
737
|
+
const data = command.slice(1).trim();
|
|
738
|
+
let args;
|
|
739
|
+
switch (type) {
|
|
740
|
+
case "m":
|
|
741
|
+
case "M":
|
|
742
|
+
args = parsePathDataArgs(data);
|
|
743
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
|
|
744
|
+
if (i2 === 0) {
|
|
745
|
+
commands.push({ type, x: args[i2], y: args[i2 + 1] });
|
|
746
|
+
} else {
|
|
747
|
+
commands.push({ type: type === "m" ? "l" : "L", x: args[i2], y: args[i2 + 1] });
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
break;
|
|
751
|
+
case "h":
|
|
752
|
+
case "H":
|
|
753
|
+
args = parsePathDataArgs(data);
|
|
754
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
|
|
755
|
+
commands.push({ type, x: args[i2] });
|
|
756
|
+
}
|
|
757
|
+
break;
|
|
758
|
+
case "v":
|
|
759
|
+
case "V":
|
|
760
|
+
args = parsePathDataArgs(data);
|
|
761
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
|
|
762
|
+
commands.push({ type, y: args[i2] });
|
|
763
|
+
}
|
|
764
|
+
break;
|
|
765
|
+
case "l":
|
|
766
|
+
case "L":
|
|
767
|
+
args = parsePathDataArgs(data);
|
|
768
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
|
|
769
|
+
commands.push({ type, x: args[i2], y: args[i2 + 1] });
|
|
770
|
+
}
|
|
771
|
+
break;
|
|
772
|
+
case "c":
|
|
773
|
+
case "C":
|
|
774
|
+
args = parsePathDataArgs(data);
|
|
775
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 6) {
|
|
776
|
+
commands.push({
|
|
777
|
+
type,
|
|
778
|
+
x1: args[i2],
|
|
779
|
+
y1: args[i2 + 1],
|
|
780
|
+
x2: args[i2 + 2],
|
|
781
|
+
y2: args[i2 + 3],
|
|
782
|
+
x: args[i2 + 4],
|
|
783
|
+
y: args[i2 + 5]
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
break;
|
|
787
|
+
case "s":
|
|
788
|
+
case "S":
|
|
789
|
+
args = parsePathDataArgs(data);
|
|
790
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
|
|
791
|
+
commands.push({
|
|
792
|
+
type,
|
|
793
|
+
x2: args[i2],
|
|
794
|
+
y2: args[i2 + 1],
|
|
795
|
+
x: args[i2 + 2],
|
|
796
|
+
y: args[i2 + 3]
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
break;
|
|
800
|
+
case "q":
|
|
801
|
+
case "Q":
|
|
802
|
+
args = parsePathDataArgs(data);
|
|
803
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
|
|
804
|
+
commands.push({
|
|
805
|
+
type,
|
|
806
|
+
x1: args[i2],
|
|
807
|
+
y1: args[i2 + 1],
|
|
808
|
+
x: args[i2 + 2],
|
|
809
|
+
y: args[i2 + 3]
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
break;
|
|
813
|
+
case "t":
|
|
814
|
+
case "T":
|
|
815
|
+
args = parsePathDataArgs(data);
|
|
816
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
|
|
817
|
+
commands.push({
|
|
818
|
+
type,
|
|
819
|
+
x: args[i2],
|
|
820
|
+
y: args[i2 + 1]
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
case "a":
|
|
825
|
+
case "A":
|
|
826
|
+
args = parsePathDataArgs(data, [3, 4], 7);
|
|
827
|
+
for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 7) {
|
|
828
|
+
commands.push({
|
|
829
|
+
type,
|
|
830
|
+
rx: args[i2],
|
|
831
|
+
ry: args[i2 + 1],
|
|
832
|
+
angle: args[i2 + 2],
|
|
833
|
+
largeArcFlag: args[i2 + 3],
|
|
834
|
+
sweepFlag: args[i2 + 4],
|
|
835
|
+
x: args[i2 + 5],
|
|
836
|
+
y: args[i2 + 6]
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
break;
|
|
840
|
+
case "z":
|
|
841
|
+
case "Z":
|
|
842
|
+
commands.push({
|
|
843
|
+
type
|
|
844
|
+
});
|
|
845
|
+
break;
|
|
846
|
+
default:
|
|
847
|
+
console.warn(command);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
return commands;
|
|
851
|
+
}
|
|
852
|
+
|
|
74
853
|
var __defProp$5 = Object.defineProperty;
|
|
75
854
|
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
76
855
|
var __publicField$5 = (obj, key, value) => {
|
|
@@ -83,12 +862,6 @@ class Curve {
|
|
|
83
862
|
__publicField$5(this, "_cacheArcLengths");
|
|
84
863
|
__publicField$5(this, "_needsUpdate", false);
|
|
85
864
|
}
|
|
86
|
-
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
87
|
-
return { min, max };
|
|
88
|
-
}
|
|
89
|
-
getDivisions(divisions) {
|
|
90
|
-
return divisions;
|
|
91
|
-
}
|
|
92
865
|
getPointAt(u, output = new Point2D()) {
|
|
93
866
|
return this.getPoint(this.getUtoTmapping(u), output);
|
|
94
867
|
}
|
|
@@ -181,33 +954,38 @@ class Curve {
|
|
|
181
954
|
getTangentAt(u, output = new Point2D()) {
|
|
182
955
|
return this.getTangent(this.getUtoTmapping(u), output);
|
|
183
956
|
}
|
|
957
|
+
/** overrideable */
|
|
958
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
959
|
+
transform(matrix) {
|
|
960
|
+
return this;
|
|
961
|
+
}
|
|
962
|
+
/** overrideable */
|
|
963
|
+
getDivisions(divisions) {
|
|
964
|
+
return divisions;
|
|
965
|
+
}
|
|
966
|
+
/** overrideable */
|
|
967
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
968
|
+
return { min, max };
|
|
969
|
+
}
|
|
970
|
+
/** overrideable */
|
|
971
|
+
getCommands() {
|
|
972
|
+
return [];
|
|
973
|
+
}
|
|
184
974
|
getData() {
|
|
185
|
-
return this.getCommands()
|
|
186
|
-
switch (cmd.type) {
|
|
187
|
-
case "M":
|
|
188
|
-
return `M ${cmd.x} ${cmd.y}`;
|
|
189
|
-
case "L":
|
|
190
|
-
return `L ${cmd.x} ${cmd.y}`;
|
|
191
|
-
case "C":
|
|
192
|
-
return `C ${cmd.x1} ${cmd.y1} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`;
|
|
193
|
-
case "Q":
|
|
194
|
-
return `Q ${cmd.x1} ${cmd.y1} ${cmd.x} ${cmd.y}`;
|
|
195
|
-
case "A":
|
|
196
|
-
return `A ${cmd.rx} ${cmd.ry} ${cmd.xAxisRotation} ${cmd.largeArcFlag} ${cmd.sweepFlag} ${cmd.x} ${cmd.y}`;
|
|
197
|
-
case "Z":
|
|
198
|
-
return "Z";
|
|
199
|
-
default:
|
|
200
|
-
return "";
|
|
201
|
-
}
|
|
202
|
-
}).join(" ");
|
|
975
|
+
return pathCommandsToPathData(this.getCommands());
|
|
203
976
|
}
|
|
204
|
-
|
|
205
|
-
|
|
977
|
+
/** overrideable */
|
|
978
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
979
|
+
drawTo(ctx) {
|
|
980
|
+
return this;
|
|
206
981
|
}
|
|
207
982
|
copy(source) {
|
|
208
983
|
this.arcLengthDivisions = source.arcLengthDivisions;
|
|
209
984
|
return this;
|
|
210
985
|
}
|
|
986
|
+
clone() {
|
|
987
|
+
return new this.constructor().copy(this);
|
|
988
|
+
}
|
|
211
989
|
}
|
|
212
990
|
|
|
213
991
|
class CircleCurve extends Curve {
|
|
@@ -218,13 +996,6 @@ class CircleCurve extends Curve {
|
|
|
218
996
|
this.start = start;
|
|
219
997
|
this.end = end;
|
|
220
998
|
}
|
|
221
|
-
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
222
|
-
min.x = Math.min(min.x, this.center.x - this.radius);
|
|
223
|
-
min.y = Math.min(min.y, this.center.y - this.radius);
|
|
224
|
-
max.x = Math.max(max.x, this.center.x + this.radius);
|
|
225
|
-
max.y = Math.max(max.y, this.center.y + this.radius);
|
|
226
|
-
return { min, max };
|
|
227
|
-
}
|
|
228
999
|
getPoint(t) {
|
|
229
1000
|
const { radius, center } = this;
|
|
230
1001
|
return center.clone().add(this.getNormal(t).clone().multiplyScalar(radius));
|
|
@@ -238,10 +1009,12 @@ class CircleCurve extends Curve {
|
|
|
238
1009
|
const _t = t * (end - start) + start - 0.5 * Math.PI;
|
|
239
1010
|
return new Point2D(Math.cos(_t), Math.sin(_t));
|
|
240
1011
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
1012
|
+
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
1013
|
+
min.x = Math.min(min.x, this.center.x - this.radius);
|
|
1014
|
+
min.y = Math.min(min.y, this.center.y - this.radius);
|
|
1015
|
+
max.x = Math.max(max.x, this.center.x + this.radius);
|
|
1016
|
+
max.y = Math.max(max.y, this.center.y + this.radius);
|
|
1017
|
+
return { min, max };
|
|
245
1018
|
}
|
|
246
1019
|
}
|
|
247
1020
|
|
|
@@ -299,6 +1072,13 @@ class CubicBezierCurve extends Curve {
|
|
|
299
1072
|
);
|
|
300
1073
|
return output;
|
|
301
1074
|
}
|
|
1075
|
+
transform(matrix) {
|
|
1076
|
+
this.v0.applyMatrix3(matrix);
|
|
1077
|
+
this.v1.applyMatrix3(matrix);
|
|
1078
|
+
this.v2.applyMatrix3(matrix);
|
|
1079
|
+
this.v3.applyMatrix3(matrix);
|
|
1080
|
+
return this;
|
|
1081
|
+
}
|
|
302
1082
|
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
303
1083
|
const { v0, v1, v2, v3 } = this;
|
|
304
1084
|
min.x = Math.min(min.x, v0.x, v1.x, v2.x, v3.x);
|
|
@@ -318,6 +1098,7 @@ class CubicBezierCurve extends Curve {
|
|
|
318
1098
|
const { v0, v1, v2, v3 } = this;
|
|
319
1099
|
ctx.moveTo(v0.x, v0.y);
|
|
320
1100
|
ctx.bezierCurveTo(v1.x, v1.y, v2.x, v2.y, v3.x, v3.y);
|
|
1101
|
+
return this;
|
|
321
1102
|
}
|
|
322
1103
|
copy(source) {
|
|
323
1104
|
super.copy(source);
|
|
@@ -329,21 +1110,22 @@ class CubicBezierCurve extends Curve {
|
|
|
329
1110
|
}
|
|
330
1111
|
}
|
|
331
1112
|
|
|
1113
|
+
const tempTransform0$1 = new Matrix3();
|
|
1114
|
+
const tempTransform1$1 = new Matrix3();
|
|
1115
|
+
const tempTransform2$1 = new Matrix3();
|
|
1116
|
+
const tempV2 = new Point2D();
|
|
332
1117
|
class EllipseCurve extends Curve {
|
|
333
|
-
constructor(x = 0, y = 0,
|
|
1118
|
+
constructor(x = 0, y = 0, radiusX = 1, radiusY = 1, startAngle = 0, endAngle = Math.PI * 2, clockwise = false, rotation = 0) {
|
|
334
1119
|
super();
|
|
335
1120
|
this.x = x;
|
|
336
1121
|
this.y = y;
|
|
337
|
-
this.
|
|
338
|
-
this.
|
|
1122
|
+
this.radiusX = radiusX;
|
|
1123
|
+
this.radiusY = radiusY;
|
|
339
1124
|
this.startAngle = startAngle;
|
|
340
1125
|
this.endAngle = endAngle;
|
|
341
1126
|
this.clockwise = clockwise;
|
|
342
1127
|
this.rotation = rotation;
|
|
343
1128
|
}
|
|
344
|
-
getDivisions(divisions = 12) {
|
|
345
|
-
return divisions * 2;
|
|
346
|
-
}
|
|
347
1129
|
getPoint(t, output = new Point2D()) {
|
|
348
1130
|
const twoPi = Math.PI * 2;
|
|
349
1131
|
let deltaAngle = this.endAngle - this.startAngle;
|
|
@@ -367,8 +1149,8 @@ class EllipseCurve extends Curve {
|
|
|
367
1149
|
}
|
|
368
1150
|
}
|
|
369
1151
|
const angle = this.startAngle + t * deltaAngle;
|
|
370
|
-
let _x = this.x + this.
|
|
371
|
-
let _y = this.y + this.
|
|
1152
|
+
let _x = this.x + this.radiusX * Math.cos(angle);
|
|
1153
|
+
let _y = this.y + this.radiusY * Math.sin(angle);
|
|
372
1154
|
if (this.rotation !== 0) {
|
|
373
1155
|
const cos = Math.cos(this.rotation);
|
|
374
1156
|
const sin = Math.sin(this.rotation);
|
|
@@ -379,51 +1161,69 @@ class EllipseCurve extends Curve {
|
|
|
379
1161
|
}
|
|
380
1162
|
return output.set(_x, _y);
|
|
381
1163
|
}
|
|
1164
|
+
getDivisions(divisions = 12) {
|
|
1165
|
+
return divisions * 2;
|
|
1166
|
+
}
|
|
382
1167
|
getCommands() {
|
|
383
|
-
const { x, y,
|
|
1168
|
+
const { x, y, radiusX, radiusY, startAngle, endAngle, clockwise } = this;
|
|
384
1169
|
const anticlockwise = !clockwise;
|
|
385
|
-
const startX = x +
|
|
386
|
-
const startY = y +
|
|
387
|
-
const endX = x +
|
|
388
|
-
const endY = y +
|
|
1170
|
+
const startX = x + radiusX * Math.cos(startAngle);
|
|
1171
|
+
const startY = y + radiusY * Math.sin(startAngle);
|
|
1172
|
+
const endX = x + radiusX * Math.cos(endAngle);
|
|
1173
|
+
const endY = y + radiusY * Math.sin(endAngle);
|
|
389
1174
|
const angleDiff = Math.abs(startAngle - endAngle);
|
|
390
1175
|
const largeArcFlag = angleDiff > Math.PI ? 1 : 0;
|
|
391
1176
|
const sweepFlag = anticlockwise ? 0 : 1;
|
|
392
|
-
const midX = x +
|
|
393
|
-
const midY = y +
|
|
1177
|
+
const midX = x + radiusX * Math.cos(startAngle + (endAngle - startAngle) / 2);
|
|
1178
|
+
const midY = y + radiusY * Math.sin(startAngle + (endAngle - startAngle) / 2);
|
|
394
1179
|
if (angleDiff >= 2 * Math.PI) {
|
|
395
1180
|
return [
|
|
396
1181
|
{ type: "M", x: startX, y: startY },
|
|
397
|
-
{ type: "A", rx, ry,
|
|
398
|
-
{ type: "A", rx, ry,
|
|
1182
|
+
{ type: "A", rx: radiusX, ry: radiusY, angle: 0, largeArcFlag: 1, sweepFlag, x: midX, y: midY },
|
|
1183
|
+
{ type: "A", rx: radiusX, ry: radiusY, angle: 0, largeArcFlag: 1, sweepFlag, x: startX, y: startY }
|
|
399
1184
|
];
|
|
400
1185
|
} else {
|
|
401
1186
|
return [
|
|
402
1187
|
{ type: "M", x: startX, y: startY },
|
|
403
|
-
{ type: "A", rx, ry,
|
|
1188
|
+
{ type: "A", rx: radiusX, ry: radiusY, angle: 0, largeArcFlag, sweepFlag, x: endX, y: endY }
|
|
404
1189
|
];
|
|
405
1190
|
}
|
|
406
1191
|
}
|
|
407
1192
|
drawTo(ctx) {
|
|
408
|
-
const { x, y,
|
|
409
|
-
const startX = x +
|
|
410
|
-
const startY = y +
|
|
1193
|
+
const { x, y, radiusX, radiusY, rotation, startAngle, endAngle, clockwise } = this;
|
|
1194
|
+
const startX = x + radiusX * Math.cos(startAngle);
|
|
1195
|
+
const startY = y + radiusY * Math.sin(startAngle);
|
|
411
1196
|
ctx.moveTo(startX, startY);
|
|
412
|
-
ctx.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
1197
|
+
ctx.ellipse(
|
|
1198
|
+
x,
|
|
1199
|
+
y,
|
|
1200
|
+
radiusX,
|
|
1201
|
+
radiusY,
|
|
1202
|
+
rotation,
|
|
1203
|
+
startAngle,
|
|
1204
|
+
endAngle,
|
|
1205
|
+
!clockwise
|
|
419
1206
|
);
|
|
1207
|
+
return this;
|
|
1208
|
+
}
|
|
1209
|
+
transform(matrix) {
|
|
1210
|
+
tempV2.set(this.x, this.y);
|
|
1211
|
+
tempV2.applyMatrix3(matrix);
|
|
1212
|
+
this.x = tempV2.x;
|
|
1213
|
+
this.y = tempV2.y;
|
|
1214
|
+
if (isTransformSkewed(matrix)) {
|
|
1215
|
+
transfEllipseGeneric(this, matrix);
|
|
1216
|
+
} else {
|
|
1217
|
+
transfEllipseNoSkew(this, matrix);
|
|
1218
|
+
}
|
|
1219
|
+
return this;
|
|
420
1220
|
}
|
|
421
1221
|
copy(source) {
|
|
422
1222
|
super.copy(source);
|
|
423
1223
|
this.x = source.x;
|
|
424
1224
|
this.y = source.y;
|
|
425
|
-
this.
|
|
426
|
-
this.
|
|
1225
|
+
this.radiusX = source.radiusX;
|
|
1226
|
+
this.radiusY = source.radiusY;
|
|
427
1227
|
this.startAngle = source.startAngle;
|
|
428
1228
|
this.endAngle = source.endAngle;
|
|
429
1229
|
this.clockwise = source.clockwise;
|
|
@@ -431,6 +1231,145 @@ class EllipseCurve extends Curve {
|
|
|
431
1231
|
return this;
|
|
432
1232
|
}
|
|
433
1233
|
}
|
|
1234
|
+
function transfEllipseGeneric(curve, m) {
|
|
1235
|
+
const a = curve.radiusX;
|
|
1236
|
+
const b = curve.radiusY;
|
|
1237
|
+
const cosTheta = Math.cos(curve.rotation);
|
|
1238
|
+
const sinTheta = Math.sin(curve.rotation);
|
|
1239
|
+
const v1 = new Point2D(a * cosTheta, a * sinTheta);
|
|
1240
|
+
const v2 = new Point2D(-b * sinTheta, b * cosTheta);
|
|
1241
|
+
const f1 = v1.applyMatrix3(m);
|
|
1242
|
+
const f2 = v2.applyMatrix3(m);
|
|
1243
|
+
const mF = tempTransform0$1.set(
|
|
1244
|
+
f1.x,
|
|
1245
|
+
f2.x,
|
|
1246
|
+
0,
|
|
1247
|
+
f1.y,
|
|
1248
|
+
f2.y,
|
|
1249
|
+
0,
|
|
1250
|
+
0,
|
|
1251
|
+
0,
|
|
1252
|
+
1
|
|
1253
|
+
);
|
|
1254
|
+
const mFInv = tempTransform1$1.copy(mF).invert();
|
|
1255
|
+
const mFInvT = tempTransform2$1.copy(mFInv).transpose();
|
|
1256
|
+
const mQ = mFInvT.multiply(mFInv);
|
|
1257
|
+
const mQe = mQ.elements;
|
|
1258
|
+
const ed = eigenDecomposition(mQe[0], mQe[1], mQe[4]);
|
|
1259
|
+
const rt1sqrt = Math.sqrt(ed.rt1);
|
|
1260
|
+
const rt2sqrt = Math.sqrt(ed.rt2);
|
|
1261
|
+
curve.radiusX = 1 / rt1sqrt;
|
|
1262
|
+
curve.radiusY = 1 / rt2sqrt;
|
|
1263
|
+
curve.rotation = Math.atan2(ed.sn, ed.cs);
|
|
1264
|
+
const isFullEllipse = (curve.endAngle - curve.startAngle) % (2 * Math.PI) < Number.EPSILON;
|
|
1265
|
+
if (!isFullEllipse) {
|
|
1266
|
+
const mDsqrt = tempTransform1$1.set(
|
|
1267
|
+
rt1sqrt,
|
|
1268
|
+
0,
|
|
1269
|
+
0,
|
|
1270
|
+
0,
|
|
1271
|
+
rt2sqrt,
|
|
1272
|
+
0,
|
|
1273
|
+
0,
|
|
1274
|
+
0,
|
|
1275
|
+
1
|
|
1276
|
+
);
|
|
1277
|
+
const mRT = tempTransform2$1.set(
|
|
1278
|
+
ed.cs,
|
|
1279
|
+
ed.sn,
|
|
1280
|
+
0,
|
|
1281
|
+
-ed.sn,
|
|
1282
|
+
ed.cs,
|
|
1283
|
+
0,
|
|
1284
|
+
0,
|
|
1285
|
+
0,
|
|
1286
|
+
1
|
|
1287
|
+
);
|
|
1288
|
+
const mDRF = mDsqrt.multiply(mRT).multiply(mF);
|
|
1289
|
+
const transformAngle = (phi) => {
|
|
1290
|
+
const { x: cosR, y: sinR } = new Point2D(Math.cos(phi), Math.sin(phi)).applyMatrix3(mDRF);
|
|
1291
|
+
return Math.atan2(sinR, cosR);
|
|
1292
|
+
};
|
|
1293
|
+
curve.startAngle = transformAngle(curve.startAngle);
|
|
1294
|
+
curve.endAngle = transformAngle(curve.endAngle);
|
|
1295
|
+
if (isTransformFlipped(m)) {
|
|
1296
|
+
curve.clockwise = !curve.clockwise;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function transfEllipseNoSkew(curve, m) {
|
|
1301
|
+
const sx = getTransformScaleX(m);
|
|
1302
|
+
const sy = getTransformScaleY(m);
|
|
1303
|
+
curve.radiusX *= sx;
|
|
1304
|
+
curve.radiusY *= sy;
|
|
1305
|
+
const theta = sx > Number.EPSILON ? Math.atan2(m.elements[1], m.elements[0]) : Math.atan2(-m.elements[3], m.elements[4]);
|
|
1306
|
+
curve.rotation += theta;
|
|
1307
|
+
if (isTransformFlipped(m)) {
|
|
1308
|
+
curve.startAngle *= -1;
|
|
1309
|
+
curve.endAngle *= -1;
|
|
1310
|
+
curve.clockwise = !curve.clockwise;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
function isTransformFlipped(m) {
|
|
1314
|
+
const te = m.elements;
|
|
1315
|
+
return te[0] * te[4] - te[1] * te[3] < 0;
|
|
1316
|
+
}
|
|
1317
|
+
function isTransformSkewed(m) {
|
|
1318
|
+
const te = m.elements;
|
|
1319
|
+
const basisDot = te[0] * te[3] + te[1] * te[4];
|
|
1320
|
+
if (basisDot === 0)
|
|
1321
|
+
return false;
|
|
1322
|
+
const sx = getTransformScaleX(m);
|
|
1323
|
+
const sy = getTransformScaleY(m);
|
|
1324
|
+
return Math.abs(basisDot / (sx * sy)) > Number.EPSILON;
|
|
1325
|
+
}
|
|
1326
|
+
function getTransformScaleX(m) {
|
|
1327
|
+
const te = m.elements;
|
|
1328
|
+
return Math.sqrt(te[0] * te[0] + te[1] * te[1]);
|
|
1329
|
+
}
|
|
1330
|
+
function getTransformScaleY(m) {
|
|
1331
|
+
const te = m.elements;
|
|
1332
|
+
return Math.sqrt(te[3] * te[3] + te[4] * te[4]);
|
|
1333
|
+
}
|
|
1334
|
+
function eigenDecomposition(A, B, C) {
|
|
1335
|
+
let rt1, rt2, cs, sn, t;
|
|
1336
|
+
const sm = A + C;
|
|
1337
|
+
const df = A - C;
|
|
1338
|
+
const rt = Math.sqrt(df * df + 4 * B * B);
|
|
1339
|
+
if (sm > 0) {
|
|
1340
|
+
rt1 = 0.5 * (sm + rt);
|
|
1341
|
+
t = 1 / rt1;
|
|
1342
|
+
rt2 = A * t * C - B * t * B;
|
|
1343
|
+
} else if (sm < 0) {
|
|
1344
|
+
rt2 = 0.5 * (sm - rt);
|
|
1345
|
+
} else {
|
|
1346
|
+
rt1 = 0.5 * rt;
|
|
1347
|
+
rt2 = -0.5 * rt;
|
|
1348
|
+
}
|
|
1349
|
+
if (df > 0) {
|
|
1350
|
+
cs = df + rt;
|
|
1351
|
+
} else {
|
|
1352
|
+
cs = df - rt;
|
|
1353
|
+
}
|
|
1354
|
+
if (Math.abs(cs) > 2 * Math.abs(B)) {
|
|
1355
|
+
t = -2 * B / cs;
|
|
1356
|
+
sn = 1 / Math.sqrt(1 + t * t);
|
|
1357
|
+
cs = t * sn;
|
|
1358
|
+
} else if (Math.abs(B) === 0) {
|
|
1359
|
+
cs = 1;
|
|
1360
|
+
sn = 0;
|
|
1361
|
+
} else {
|
|
1362
|
+
t = -0.5 * cs / B;
|
|
1363
|
+
cs = 1 / Math.sqrt(1 + t * t);
|
|
1364
|
+
sn = t * cs;
|
|
1365
|
+
}
|
|
1366
|
+
if (df > 0) {
|
|
1367
|
+
t = cs;
|
|
1368
|
+
cs = -sn;
|
|
1369
|
+
sn = t;
|
|
1370
|
+
}
|
|
1371
|
+
return { rt1, rt2, cs, sn };
|
|
1372
|
+
}
|
|
434
1373
|
|
|
435
1374
|
class LineCurve extends Curve {
|
|
436
1375
|
constructor(v1 = new Point2D(), v2 = new Point2D()) {
|
|
@@ -438,9 +1377,6 @@ class LineCurve extends Curve {
|
|
|
438
1377
|
this.v1 = v1;
|
|
439
1378
|
this.v2 = v2;
|
|
440
1379
|
}
|
|
441
|
-
getDivisions() {
|
|
442
|
-
return 1;
|
|
443
|
-
}
|
|
444
1380
|
getPoint(t, output = new Point2D()) {
|
|
445
1381
|
if (t === 1) {
|
|
446
1382
|
output.copy(this.v2);
|
|
@@ -459,12 +1395,13 @@ class LineCurve extends Curve {
|
|
|
459
1395
|
getTangentAt(u, output = new Point2D()) {
|
|
460
1396
|
return this.getTangent(u, output);
|
|
461
1397
|
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
1398
|
+
transform(matrix) {
|
|
1399
|
+
this.v1.applyMatrix3(matrix);
|
|
1400
|
+
this.v2.applyMatrix3(matrix);
|
|
1401
|
+
return this;
|
|
1402
|
+
}
|
|
1403
|
+
getDivisions() {
|
|
1404
|
+
return 1;
|
|
468
1405
|
}
|
|
469
1406
|
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
470
1407
|
const { v1, v2 } = this;
|
|
@@ -474,10 +1411,18 @@ class LineCurve extends Curve {
|
|
|
474
1411
|
max.y = Math.max(max.y, v1.y, v2.y);
|
|
475
1412
|
return { min, max };
|
|
476
1413
|
}
|
|
1414
|
+
getCommands() {
|
|
1415
|
+
const { v1, v2 } = this;
|
|
1416
|
+
return [
|
|
1417
|
+
{ type: "M", x: v1.x, y: v1.y },
|
|
1418
|
+
{ type: "L", x: v2.x, y: v2.y }
|
|
1419
|
+
];
|
|
1420
|
+
}
|
|
477
1421
|
drawTo(ctx) {
|
|
478
1422
|
const { v1, v2 } = this;
|
|
479
1423
|
ctx.moveTo(v1.x, v1.y);
|
|
480
1424
|
ctx.lineTo(v2.x, v2.y);
|
|
1425
|
+
return this;
|
|
481
1426
|
}
|
|
482
1427
|
copy(source) {
|
|
483
1428
|
super.copy(source);
|
|
@@ -560,6 +1505,7 @@ class HeartCurve extends Curve {
|
|
|
560
1505
|
}
|
|
561
1506
|
drawTo(ctx) {
|
|
562
1507
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
1508
|
+
return this;
|
|
563
1509
|
}
|
|
564
1510
|
}
|
|
565
1511
|
|
|
@@ -622,6 +1568,7 @@ class PloygonCurve extends Curve {
|
|
|
622
1568
|
}
|
|
623
1569
|
drawTo(ctx) {
|
|
624
1570
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
1571
|
+
return this;
|
|
625
1572
|
}
|
|
626
1573
|
}
|
|
627
1574
|
|
|
@@ -640,12 +1587,11 @@ class QuadraticBezierCurve extends Curve {
|
|
|
640
1587
|
);
|
|
641
1588
|
return output;
|
|
642
1589
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
];
|
|
1590
|
+
transform(matrix) {
|
|
1591
|
+
this.v0.applyMatrix3(matrix);
|
|
1592
|
+
this.v1.applyMatrix3(matrix);
|
|
1593
|
+
this.v2.applyMatrix3(matrix);
|
|
1594
|
+
return this;
|
|
649
1595
|
}
|
|
650
1596
|
getMinMax(min = Point2D.MAX, max = Point2D.MIN) {
|
|
651
1597
|
const { v0, v1, v2 } = this;
|
|
@@ -659,10 +1605,18 @@ class QuadraticBezierCurve extends Curve {
|
|
|
659
1605
|
max.y = Math.max(max.y, v0.y, v2.y, y1, y2);
|
|
660
1606
|
return { min, max };
|
|
661
1607
|
}
|
|
1608
|
+
getCommands() {
|
|
1609
|
+
const { v0, v1, v2 } = this;
|
|
1610
|
+
return [
|
|
1611
|
+
{ type: "M", x: v0.x, y: v0.y },
|
|
1612
|
+
{ type: "Q", x1: v1.x, y1: v1.y, x: v2.x, y: v2.y }
|
|
1613
|
+
];
|
|
1614
|
+
}
|
|
662
1615
|
drawTo(ctx) {
|
|
663
1616
|
const { v0, v1, v2 } = this;
|
|
664
1617
|
ctx.moveTo(v0.x, v0.y);
|
|
665
1618
|
ctx.quadraticCurveTo(v1.x, v1.y, v2.x, v2.y);
|
|
1619
|
+
return this;
|
|
666
1620
|
}
|
|
667
1621
|
copy(source) {
|
|
668
1622
|
super.copy(source);
|
|
@@ -756,6 +1710,7 @@ class RectangularCurve extends Curve {
|
|
|
756
1710
|
}
|
|
757
1711
|
drawTo(ctx) {
|
|
758
1712
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
1713
|
+
return this;
|
|
759
1714
|
}
|
|
760
1715
|
}
|
|
761
1716
|
|
|
@@ -782,11 +1737,6 @@ class SplineCurve extends Curve {
|
|
|
782
1737
|
);
|
|
783
1738
|
return output;
|
|
784
1739
|
}
|
|
785
|
-
getCommands() {
|
|
786
|
-
return [];
|
|
787
|
-
}
|
|
788
|
-
drawTo(_ctx) {
|
|
789
|
-
}
|
|
790
1740
|
copy(source) {
|
|
791
1741
|
super.copy(source);
|
|
792
1742
|
this.points = [];
|
|
@@ -958,13 +1908,13 @@ class CurvePath extends Curve {
|
|
|
958
1908
|
this.absellipse(x, y, radius, radius, startAngle, endAngle, clockwise);
|
|
959
1909
|
return this;
|
|
960
1910
|
}
|
|
961
|
-
ellipse(x, y,
|
|
1911
|
+
ellipse(x, y, radiusX, radiusY, startAngle, endAngle, clockwise = false, rotation = 0) {
|
|
962
1912
|
const point = this.currentPoint;
|
|
963
|
-
this.absellipse(x + point.x, y + point.y,
|
|
1913
|
+
this.absellipse(x + point.x, y + point.y, radiusX, radiusY, startAngle, endAngle, clockwise, rotation);
|
|
964
1914
|
return this;
|
|
965
1915
|
}
|
|
966
|
-
absellipse(x, y,
|
|
967
|
-
const curve = new EllipseCurve(x, y,
|
|
1916
|
+
absellipse(x, y, radiusX, radiusY, startAngle, endAngle, clockwise = false, rotation = 0) {
|
|
1917
|
+
const curve = new EllipseCurve(x, y, radiusX, radiusY, startAngle, endAngle, clockwise, rotation);
|
|
968
1918
|
if (this.curves.length > 0) {
|
|
969
1919
|
const firstPoint = curve.getPoint(0);
|
|
970
1920
|
if (!firstPoint.equals(this.currentPoint)) {
|
|
@@ -984,13 +1934,13 @@ class CurvePath extends Curve {
|
|
|
984
1934
|
}
|
|
985
1935
|
drawTo(ctx) {
|
|
986
1936
|
this.curves.forEach((curve) => curve.drawTo(ctx));
|
|
1937
|
+
return this;
|
|
987
1938
|
}
|
|
988
1939
|
copy(source) {
|
|
989
1940
|
super.copy(source);
|
|
990
1941
|
this.curves = [];
|
|
991
|
-
for (let i = 0,
|
|
992
|
-
|
|
993
|
-
this.curves.push(curve.clone());
|
|
1942
|
+
for (let i = 0, len = source.curves.length; i < len; i++) {
|
|
1943
|
+
this.curves.push(source.curves[i].clone());
|
|
994
1944
|
}
|
|
995
1945
|
this.autoClose = source.autoClose;
|
|
996
1946
|
this.currentPoint.copy(source.currentPoint);
|
|
@@ -1008,6 +1958,7 @@ class Path2D {
|
|
|
1008
1958
|
constructor(path) {
|
|
1009
1959
|
__publicField(this, "currentPath", new CurvePath());
|
|
1010
1960
|
__publicField(this, "paths", [this.currentPath]);
|
|
1961
|
+
__publicField(this, "userData");
|
|
1011
1962
|
if (path) {
|
|
1012
1963
|
if (path instanceof Path2D) {
|
|
1013
1964
|
this.addPath(path);
|
|
@@ -1019,38 +1970,13 @@ class Path2D {
|
|
|
1019
1970
|
}
|
|
1020
1971
|
}
|
|
1021
1972
|
addPath(path) {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
for (let i = 0, len = commands.length; i < len; i++) {
|
|
1027
|
-
const cmd = commands[i];
|
|
1028
|
-
switch (cmd.type) {
|
|
1029
|
-
case "M":
|
|
1030
|
-
this.moveTo(cmd.x, cmd.y);
|
|
1031
|
-
break;
|
|
1032
|
-
case "L":
|
|
1033
|
-
this.lineTo(cmd.x, cmd.y);
|
|
1034
|
-
break;
|
|
1035
|
-
case "C":
|
|
1036
|
-
this.bezierCurveTo(cmd.x2, cmd.y2, cmd.x1, cmd.y1, cmd.x, cmd.y);
|
|
1037
|
-
break;
|
|
1038
|
-
case "Q":
|
|
1039
|
-
this.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
|
|
1040
|
-
break;
|
|
1041
|
-
case "A":
|
|
1042
|
-
break;
|
|
1043
|
-
case "Z":
|
|
1044
|
-
this.closePath();
|
|
1045
|
-
break;
|
|
1046
|
-
}
|
|
1973
|
+
if (path instanceof Path2D) {
|
|
1974
|
+
this.paths.push(...path.paths.map((v) => v.clone()));
|
|
1975
|
+
} else {
|
|
1976
|
+
this.paths.push(path);
|
|
1047
1977
|
}
|
|
1048
1978
|
return this;
|
|
1049
1979
|
}
|
|
1050
|
-
addData(data) {
|
|
1051
|
-
console.error("TODO", data);
|
|
1052
|
-
return this;
|
|
1053
|
-
}
|
|
1054
1980
|
closePath() {
|
|
1055
1981
|
this.currentPath.closePath();
|
|
1056
1982
|
return this;
|
|
@@ -1115,31 +2041,49 @@ class Path2D {
|
|
|
1115
2041
|
this.currentPath.rect(x, y, w, h);
|
|
1116
2042
|
return this;
|
|
1117
2043
|
}
|
|
2044
|
+
addCommands(commands) {
|
|
2045
|
+
addPathCommandsToPath2D(commands, this);
|
|
2046
|
+
return this;
|
|
2047
|
+
}
|
|
2048
|
+
addData(data) {
|
|
2049
|
+
this.addCommands(pathDataToPathCommands(data));
|
|
2050
|
+
return this;
|
|
2051
|
+
}
|
|
1118
2052
|
splineThru(points) {
|
|
1119
2053
|
this.currentPath.splineThru(points);
|
|
1120
2054
|
return this;
|
|
1121
2055
|
}
|
|
1122
|
-
|
|
1123
|
-
this.paths.forEach((path) => path.curves.forEach((curve) => curve
|
|
1124
|
-
return
|
|
2056
|
+
forEachCurve(cb) {
|
|
2057
|
+
this.paths.forEach((path) => path.curves.forEach((curve) => cb(curve)));
|
|
2058
|
+
return this;
|
|
1125
2059
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
2060
|
+
transform(matrix) {
|
|
2061
|
+
this.forEachCurve((curve) => curve.transform(matrix));
|
|
2062
|
+
return this;
|
|
1128
2063
|
}
|
|
1129
|
-
|
|
1130
|
-
|
|
2064
|
+
getMinMax(min = new Point2D(), max = new Point2D()) {
|
|
2065
|
+
this.forEachCurve((curve) => curve.getMinMax(min, max));
|
|
2066
|
+
return { min, max };
|
|
1131
2067
|
}
|
|
1132
2068
|
getBoundingBox() {
|
|
1133
|
-
const min =
|
|
1134
|
-
const max = Point2D.MIN;
|
|
1135
|
-
this.paths.forEach((path) => path.getMinMax(min, max));
|
|
2069
|
+
const { min, max } = this.getMinMax();
|
|
1136
2070
|
return {
|
|
1137
2071
|
x: min.x,
|
|
1138
2072
|
y: min.y,
|
|
2073
|
+
left: min.x,
|
|
2074
|
+
top: min.y,
|
|
2075
|
+
right: max.x,
|
|
2076
|
+
bottom: max.y,
|
|
1139
2077
|
width: max.x - min.x,
|
|
1140
2078
|
height: max.y - min.y
|
|
1141
2079
|
};
|
|
1142
2080
|
}
|
|
2081
|
+
getCommands() {
|
|
2082
|
+
return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.getCommands()));
|
|
2083
|
+
}
|
|
2084
|
+
getData() {
|
|
2085
|
+
return this.paths.map((path) => path.getData()).join(" ");
|
|
2086
|
+
}
|
|
1143
2087
|
getSvgString() {
|
|
1144
2088
|
const { x, y, width, height } = this.getBoundingBox();
|
|
1145
2089
|
return `<svg viewBox="${x} ${y} ${width} ${height}" xmlns="http://www.w3.org/2000/svg"><path fill="none" stroke="currentColor" d="${this.getData()}"></path></svg>`;
|
|
@@ -1148,10 +2092,8 @@ class Path2D {
|
|
|
1148
2092
|
return `data:image/svg+xml;base64,${btoa(this.getSvgString())}`;
|
|
1149
2093
|
}
|
|
1150
2094
|
drawTo(ctx) {
|
|
1151
|
-
this.
|
|
1152
|
-
|
|
1153
|
-
curve.drawTo(ctx);
|
|
1154
|
-
});
|
|
2095
|
+
this.forEachCurve((curve) => {
|
|
2096
|
+
curve.drawTo(ctx);
|
|
1155
2097
|
});
|
|
1156
2098
|
}
|
|
1157
2099
|
strokeTo(ctx) {
|
|
@@ -1162,6 +2104,522 @@ class Path2D {
|
|
|
1162
2104
|
this.drawTo(ctx);
|
|
1163
2105
|
ctx.fill();
|
|
1164
2106
|
}
|
|
2107
|
+
copy(source) {
|
|
2108
|
+
source.currentPath = this.currentPath.clone();
|
|
2109
|
+
source.paths = this.paths.map((path) => path.clone());
|
|
2110
|
+
source.userData = this.userData;
|
|
2111
|
+
return this;
|
|
2112
|
+
}
|
|
2113
|
+
clone() {
|
|
2114
|
+
return new Path2D().copy(this);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
const defaultUnit = "px";
|
|
2119
|
+
const defaultDPI = 90;
|
|
2120
|
+
const units = ["mm", "cm", "in", "pt", "pc", "px"];
|
|
2121
|
+
const unitConversion = {
|
|
2122
|
+
mm: {
|
|
2123
|
+
mm: 1,
|
|
2124
|
+
cm: 0.1,
|
|
2125
|
+
in: 1 / 25.4,
|
|
2126
|
+
pt: 72 / 25.4,
|
|
2127
|
+
pc: 6 / 25.4,
|
|
2128
|
+
px: -1
|
|
2129
|
+
},
|
|
2130
|
+
cm: {
|
|
2131
|
+
mm: 10,
|
|
2132
|
+
cm: 1,
|
|
2133
|
+
in: 1 / 2.54,
|
|
2134
|
+
pt: 72 / 2.54,
|
|
2135
|
+
pc: 6 / 2.54,
|
|
2136
|
+
px: -1
|
|
2137
|
+
},
|
|
2138
|
+
in: {
|
|
2139
|
+
mm: 25.4,
|
|
2140
|
+
cm: 2.54,
|
|
2141
|
+
in: 1,
|
|
2142
|
+
pt: 72,
|
|
2143
|
+
pc: 6,
|
|
2144
|
+
px: -1
|
|
2145
|
+
},
|
|
2146
|
+
pt: {
|
|
2147
|
+
mm: 25.4 / 72,
|
|
2148
|
+
cm: 2.54 / 72,
|
|
2149
|
+
in: 1 / 72,
|
|
2150
|
+
pt: 1,
|
|
2151
|
+
pc: 6 / 72,
|
|
2152
|
+
px: -1
|
|
2153
|
+
},
|
|
2154
|
+
pc: {
|
|
2155
|
+
mm: 25.4 / 6,
|
|
2156
|
+
cm: 2.54 / 6,
|
|
2157
|
+
in: 1 / 6,
|
|
2158
|
+
pt: 72 / 6,
|
|
2159
|
+
pc: 1,
|
|
2160
|
+
px: -1
|
|
2161
|
+
},
|
|
2162
|
+
px: {
|
|
2163
|
+
px: 1
|
|
2164
|
+
}
|
|
2165
|
+
};
|
|
2166
|
+
function parseFloatWithUnits(string) {
|
|
2167
|
+
let theUnit = "px";
|
|
2168
|
+
if (typeof string === "string" || string instanceof String) {
|
|
2169
|
+
for (let i = 0, n = units.length; i < n; i++) {
|
|
2170
|
+
const u = units[i];
|
|
2171
|
+
if (string.endsWith(u)) {
|
|
2172
|
+
theUnit = u;
|
|
2173
|
+
string = string.substring(0, string.length - u.length);
|
|
2174
|
+
break;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
let scale;
|
|
2179
|
+
if (theUnit === "px" && defaultUnit !== "px") {
|
|
2180
|
+
scale = unitConversion.in[defaultUnit] / defaultDPI;
|
|
2181
|
+
} else {
|
|
2182
|
+
scale = unitConversion[theUnit][defaultUnit];
|
|
2183
|
+
if (scale < 0) {
|
|
2184
|
+
scale = unitConversion[theUnit].in * defaultDPI;
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
return scale * Number.parseFloat(string);
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
const tempTransform0 = new Matrix3();
|
|
2191
|
+
const tempTransform1 = new Matrix3();
|
|
2192
|
+
const tempTransform2 = new Matrix3();
|
|
2193
|
+
const tempTransform3 = new Matrix3();
|
|
2194
|
+
function getNodeTransform(node, currentTransform, transformStack) {
|
|
2195
|
+
if (!(node.hasAttribute("transform") || node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y")))) {
|
|
2196
|
+
return null;
|
|
2197
|
+
}
|
|
2198
|
+
const transform = parseNodeTransform(node);
|
|
2199
|
+
if (transformStack.length > 0) {
|
|
2200
|
+
transform.premultiply(transformStack[transformStack.length - 1]);
|
|
2201
|
+
}
|
|
2202
|
+
currentTransform.copy(transform);
|
|
2203
|
+
transformStack.push(transform);
|
|
2204
|
+
return transform;
|
|
2205
|
+
}
|
|
2206
|
+
function parseNodeTransform(node) {
|
|
2207
|
+
const transform = new Matrix3();
|
|
2208
|
+
const currentTransform = tempTransform0;
|
|
2209
|
+
if (node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y"))) {
|
|
2210
|
+
transform.translate(
|
|
2211
|
+
parseFloatWithUnits(node.getAttribute("x")),
|
|
2212
|
+
parseFloatWithUnits(node.getAttribute("y"))
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
if (node.hasAttribute("transform")) {
|
|
2216
|
+
const transformsTexts = node.getAttribute("transform").split(")");
|
|
2217
|
+
for (let tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex--) {
|
|
2218
|
+
const transformText = transformsTexts[tIndex].trim();
|
|
2219
|
+
if (transformText === "")
|
|
2220
|
+
continue;
|
|
2221
|
+
const openParPos = transformText.indexOf("(");
|
|
2222
|
+
const closeParPos = transformText.length;
|
|
2223
|
+
if (openParPos > 0 && openParPos < closeParPos) {
|
|
2224
|
+
const transformType = transformText.slice(0, openParPos);
|
|
2225
|
+
const array = parsePathDataArgs(transformText.slice(openParPos + 1));
|
|
2226
|
+
currentTransform.identity();
|
|
2227
|
+
switch (transformType) {
|
|
2228
|
+
case "translate":
|
|
2229
|
+
if (array.length >= 1) {
|
|
2230
|
+
const tx = array[0];
|
|
2231
|
+
let ty = 0;
|
|
2232
|
+
if (array.length >= 2) {
|
|
2233
|
+
ty = array[1];
|
|
2234
|
+
}
|
|
2235
|
+
currentTransform.translate(tx, ty);
|
|
2236
|
+
}
|
|
2237
|
+
break;
|
|
2238
|
+
case "rotate":
|
|
2239
|
+
if (array.length >= 1) {
|
|
2240
|
+
let angle = 0;
|
|
2241
|
+
let cx = 0;
|
|
2242
|
+
let cy = 0;
|
|
2243
|
+
angle = array[0] * Math.PI / 180;
|
|
2244
|
+
if (array.length >= 3) {
|
|
2245
|
+
cx = array[1];
|
|
2246
|
+
cy = array[2];
|
|
2247
|
+
}
|
|
2248
|
+
tempTransform1.makeTranslation(-cx, -cy);
|
|
2249
|
+
tempTransform2.makeRotation(angle);
|
|
2250
|
+
tempTransform3.multiplyMatrices(tempTransform2, tempTransform1);
|
|
2251
|
+
tempTransform1.makeTranslation(cx, cy);
|
|
2252
|
+
currentTransform.multiplyMatrices(tempTransform1, tempTransform3);
|
|
2253
|
+
}
|
|
2254
|
+
break;
|
|
2255
|
+
case "scale":
|
|
2256
|
+
if (array.length >= 1) {
|
|
2257
|
+
currentTransform.scale(
|
|
2258
|
+
array[0],
|
|
2259
|
+
array[1] ?? array[0]
|
|
2260
|
+
);
|
|
2261
|
+
}
|
|
2262
|
+
break;
|
|
2263
|
+
case "skewX":
|
|
2264
|
+
if (array.length === 1) {
|
|
2265
|
+
currentTransform.set(
|
|
2266
|
+
1,
|
|
2267
|
+
Math.tan(array[0] * Math.PI / 180),
|
|
2268
|
+
0,
|
|
2269
|
+
0,
|
|
2270
|
+
1,
|
|
2271
|
+
0,
|
|
2272
|
+
0,
|
|
2273
|
+
0,
|
|
2274
|
+
1
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
break;
|
|
2278
|
+
case "skewY":
|
|
2279
|
+
if (array.length === 1) {
|
|
2280
|
+
currentTransform.set(
|
|
2281
|
+
1,
|
|
2282
|
+
0,
|
|
2283
|
+
0,
|
|
2284
|
+
Math.tan(array[0] * Math.PI / 180),
|
|
2285
|
+
1,
|
|
2286
|
+
0,
|
|
2287
|
+
0,
|
|
2288
|
+
0,
|
|
2289
|
+
1
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
break;
|
|
2293
|
+
case "matrix":
|
|
2294
|
+
if (array.length === 6) {
|
|
2295
|
+
currentTransform.set(
|
|
2296
|
+
array[0],
|
|
2297
|
+
array[2],
|
|
2298
|
+
array[4],
|
|
2299
|
+
array[1],
|
|
2300
|
+
array[3],
|
|
2301
|
+
array[5],
|
|
2302
|
+
0,
|
|
2303
|
+
0,
|
|
2304
|
+
1
|
|
2305
|
+
);
|
|
2306
|
+
}
|
|
2307
|
+
break;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
transform.premultiply(currentTransform);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
return transform;
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
function parseCircleNode(node) {
|
|
2317
|
+
return new Path2D().addPath(
|
|
2318
|
+
new CurvePath().absarc(
|
|
2319
|
+
parseFloatWithUnits(node.getAttribute("cx") || 0),
|
|
2320
|
+
parseFloatWithUnits(node.getAttribute("cy") || 0),
|
|
2321
|
+
parseFloatWithUnits(node.getAttribute("r") || 0),
|
|
2322
|
+
0,
|
|
2323
|
+
Math.PI * 2
|
|
2324
|
+
)
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
function parseCSSStylesheet(node, stylesheets) {
|
|
2329
|
+
if (!node.sheet || !node.sheet.cssRules || !node.sheet.cssRules.length)
|
|
2330
|
+
return;
|
|
2331
|
+
for (let i = 0; i < node.sheet.cssRules.length; i++) {
|
|
2332
|
+
const stylesheet = node.sheet.cssRules[i];
|
|
2333
|
+
if (stylesheet.type !== 1)
|
|
2334
|
+
continue;
|
|
2335
|
+
const selectorList = stylesheet.selectorText.split(/,/g).filter(Boolean).map((i2) => i2.trim());
|
|
2336
|
+
for (let j = 0; j < selectorList.length; j++) {
|
|
2337
|
+
const definitions = Object.fromEntries(
|
|
2338
|
+
Object.entries(stylesheet.style).filter(([, v]) => v !== "")
|
|
2339
|
+
);
|
|
2340
|
+
stylesheets[selectorList[j]] = Object.assign(
|
|
2341
|
+
stylesheets[selectorList[j]] || {},
|
|
2342
|
+
definitions
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
function parseEllipseNode(node) {
|
|
2349
|
+
return new Path2D().addPath(
|
|
2350
|
+
new CurvePath().absellipse(
|
|
2351
|
+
parseFloatWithUnits(node.getAttribute("cx") || 0),
|
|
2352
|
+
parseFloatWithUnits(node.getAttribute("cy") || 0),
|
|
2353
|
+
parseFloatWithUnits(node.getAttribute("rx") || 0),
|
|
2354
|
+
parseFloatWithUnits(node.getAttribute("ry") || 0),
|
|
2355
|
+
0,
|
|
2356
|
+
Math.PI * 2
|
|
2357
|
+
)
|
|
2358
|
+
);
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
function parseLineNode(node) {
|
|
2362
|
+
return new Path2D().moveTo(
|
|
2363
|
+
parseFloatWithUnits(node.getAttribute("x1") || 0),
|
|
2364
|
+
parseFloatWithUnits(node.getAttribute("y1") || 0)
|
|
2365
|
+
).lineTo(
|
|
2366
|
+
parseFloatWithUnits(node.getAttribute("x2") || 0),
|
|
2367
|
+
parseFloatWithUnits(node.getAttribute("y2") || 0)
|
|
2368
|
+
);
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
function parsePathNode(node) {
|
|
2372
|
+
const path = new Path2D();
|
|
2373
|
+
const d = node.getAttribute("d");
|
|
2374
|
+
if (!d || d === "none")
|
|
2375
|
+
return null;
|
|
2376
|
+
path.addData(d);
|
|
2377
|
+
return path;
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
const RE$1 = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
|
2381
|
+
function parsePolygonNode(node) {
|
|
2382
|
+
const path = new Path2D();
|
|
2383
|
+
let index = 0;
|
|
2384
|
+
node.getAttribute("points")?.replace(RE$1, (match, a, b) => {
|
|
2385
|
+
const x = parseFloatWithUnits(a);
|
|
2386
|
+
const y = parseFloatWithUnits(b);
|
|
2387
|
+
if (index === 0) {
|
|
2388
|
+
path.moveTo(x, y);
|
|
2389
|
+
} else {
|
|
2390
|
+
path.lineTo(x, y);
|
|
2391
|
+
}
|
|
2392
|
+
index++;
|
|
2393
|
+
return match;
|
|
2394
|
+
});
|
|
2395
|
+
path.currentPath.autoClose = true;
|
|
2396
|
+
return path;
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
const RE = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
|
2400
|
+
function parsePolylineNode(node) {
|
|
2401
|
+
const path = new Path2D();
|
|
2402
|
+
let index = 0;
|
|
2403
|
+
node.getAttribute("points")?.replace(RE, (match, a, b) => {
|
|
2404
|
+
const x = parseFloatWithUnits(a);
|
|
2405
|
+
const y = parseFloatWithUnits(b);
|
|
2406
|
+
if (index === 0) {
|
|
2407
|
+
path.moveTo(x, y);
|
|
2408
|
+
} else {
|
|
2409
|
+
path.lineTo(x, y);
|
|
2410
|
+
}
|
|
2411
|
+
index++;
|
|
2412
|
+
return match;
|
|
2413
|
+
});
|
|
2414
|
+
path.currentPath.autoClose = false;
|
|
2415
|
+
return path;
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2418
|
+
function parseRectNode(node) {
|
|
2419
|
+
const x = parseFloatWithUnits(node.getAttribute("x") || 0);
|
|
2420
|
+
const y = parseFloatWithUnits(node.getAttribute("y") || 0);
|
|
2421
|
+
const rx = parseFloatWithUnits(node.getAttribute("rx") || node.getAttribute("ry") || 0);
|
|
2422
|
+
const ry = parseFloatWithUnits(node.getAttribute("ry") || node.getAttribute("rx") || 0);
|
|
2423
|
+
const w = parseFloatWithUnits(node.getAttribute("width"));
|
|
2424
|
+
const h = parseFloatWithUnits(node.getAttribute("height"));
|
|
2425
|
+
const bci = 1 - 0.551915024494;
|
|
2426
|
+
const path = new Path2D();
|
|
2427
|
+
path.moveTo(x + rx, y);
|
|
2428
|
+
path.lineTo(x + w - rx, y);
|
|
2429
|
+
if (rx !== 0 || ry !== 0) {
|
|
2430
|
+
path.bezierCurveTo(
|
|
2431
|
+
x + w - rx * bci,
|
|
2432
|
+
y,
|
|
2433
|
+
x + w,
|
|
2434
|
+
y + ry * bci,
|
|
2435
|
+
x + w,
|
|
2436
|
+
y + ry
|
|
2437
|
+
);
|
|
2438
|
+
}
|
|
2439
|
+
path.lineTo(x + w, y + h - ry);
|
|
2440
|
+
if (rx !== 0 || ry !== 0) {
|
|
2441
|
+
path.bezierCurveTo(
|
|
2442
|
+
x + w,
|
|
2443
|
+
y + h - ry * bci,
|
|
2444
|
+
x + w - rx * bci,
|
|
2445
|
+
y + h,
|
|
2446
|
+
x + w - rx,
|
|
2447
|
+
y + h
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
path.lineTo(x + rx, y + h);
|
|
2451
|
+
if (rx !== 0 || ry !== 0) {
|
|
2452
|
+
path.bezierCurveTo(
|
|
2453
|
+
x + rx * bci,
|
|
2454
|
+
y + h,
|
|
2455
|
+
x,
|
|
2456
|
+
y + h - ry * bci,
|
|
2457
|
+
x,
|
|
2458
|
+
y + h - ry
|
|
2459
|
+
);
|
|
2460
|
+
}
|
|
2461
|
+
path.lineTo(x, y + ry);
|
|
2462
|
+
if (rx !== 0 || ry !== 0) {
|
|
2463
|
+
path.bezierCurveTo(x, y + ry * bci, x + rx * bci, y, x + rx, y);
|
|
2464
|
+
}
|
|
2465
|
+
return path;
|
|
2466
|
+
}
|
|
2467
|
+
|
|
2468
|
+
function parseStyle(node, style, stylesheets) {
|
|
2469
|
+
style = Object.assign({}, style);
|
|
2470
|
+
let stylesheetStyles = {};
|
|
2471
|
+
if (node.hasAttribute("class")) {
|
|
2472
|
+
const classSelectors = node.getAttribute("class").split(/\s/).filter(Boolean).map((i) => i.trim());
|
|
2473
|
+
for (let i = 0; i < classSelectors.length; i++) {
|
|
2474
|
+
stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`.${classSelectors[i]}`]);
|
|
2475
|
+
}
|
|
2476
|
+
}
|
|
2477
|
+
if (node.hasAttribute("id")) {
|
|
2478
|
+
stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`#${node.getAttribute("id")}`]);
|
|
2479
|
+
}
|
|
2480
|
+
function addStyle(svgName, jsName, adjustFunction) {
|
|
2481
|
+
if (adjustFunction === void 0) {
|
|
2482
|
+
adjustFunction = function copy(v) {
|
|
2483
|
+
if (v.startsWith("url"))
|
|
2484
|
+
console.warn("url access in attributes is not implemented.");
|
|
2485
|
+
return v;
|
|
2486
|
+
};
|
|
2487
|
+
}
|
|
2488
|
+
if (node.hasAttribute(svgName))
|
|
2489
|
+
style[jsName] = adjustFunction(node.getAttribute(svgName));
|
|
2490
|
+
if (stylesheetStyles[svgName])
|
|
2491
|
+
style[jsName] = adjustFunction(stylesheetStyles[svgName]);
|
|
2492
|
+
if (node.style && node.style[svgName] !== "")
|
|
2493
|
+
style[jsName] = adjustFunction(node.style[svgName]);
|
|
2494
|
+
}
|
|
2495
|
+
function clamp(v) {
|
|
2496
|
+
return Math.max(0, Math.min(1, parseFloatWithUnits(v)));
|
|
2497
|
+
}
|
|
2498
|
+
function positive(v) {
|
|
2499
|
+
return Math.max(0, parseFloatWithUnits(v));
|
|
2500
|
+
}
|
|
2501
|
+
addStyle("fill", "fill");
|
|
2502
|
+
addStyle("fill-opacity", "fillOpacity", clamp);
|
|
2503
|
+
addStyle("fill-rule", "fillRule");
|
|
2504
|
+
addStyle("opacity", "opacity", clamp);
|
|
2505
|
+
addStyle("stroke", "stroke");
|
|
2506
|
+
addStyle("stroke-dashoffset", "strokeDashoffset");
|
|
2507
|
+
addStyle("stroke-dasharray", "strokeDasharray");
|
|
2508
|
+
addStyle("stroke-linecap", "strokeLineCap");
|
|
2509
|
+
addStyle("stroke-linejoin", "strokeLineJoin");
|
|
2510
|
+
addStyle("stroke-miterlimit", "strokeMiterLimit", positive);
|
|
2511
|
+
addStyle("stroke-opacity", "strokeOpacity", clamp);
|
|
2512
|
+
addStyle("stroke-width", "strokeWidth", positive);
|
|
2513
|
+
addStyle("visibility", "visibility");
|
|
2514
|
+
return style;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
function parseNode(node, style, paths = []) {
|
|
2518
|
+
if (node.nodeType !== 1)
|
|
2519
|
+
return paths;
|
|
2520
|
+
let isDefsNode = false;
|
|
2521
|
+
let path = null;
|
|
2522
|
+
const stylesheets = {};
|
|
2523
|
+
switch (node.nodeName) {
|
|
2524
|
+
case "svg":
|
|
2525
|
+
style = parseStyle(node, style, stylesheets);
|
|
2526
|
+
break;
|
|
2527
|
+
case "style":
|
|
2528
|
+
parseCSSStylesheet(node, stylesheets);
|
|
2529
|
+
break;
|
|
2530
|
+
case "g":
|
|
2531
|
+
style = parseStyle(node, style, stylesheets);
|
|
2532
|
+
break;
|
|
2533
|
+
case "path":
|
|
2534
|
+
style = parseStyle(node, style, stylesheets);
|
|
2535
|
+
if (node.hasAttribute("d"))
|
|
2536
|
+
path = parsePathNode(node);
|
|
2537
|
+
break;
|
|
2538
|
+
case "rect":
|
|
2539
|
+
style = parseStyle(node, style, stylesheets);
|
|
2540
|
+
path = parseRectNode(node);
|
|
2541
|
+
break;
|
|
2542
|
+
case "polygon":
|
|
2543
|
+
style = parseStyle(node, style, stylesheets);
|
|
2544
|
+
path = parsePolygonNode(node);
|
|
2545
|
+
break;
|
|
2546
|
+
case "polyline":
|
|
2547
|
+
style = parseStyle(node, style, stylesheets);
|
|
2548
|
+
path = parsePolylineNode(node);
|
|
2549
|
+
break;
|
|
2550
|
+
case "circle":
|
|
2551
|
+
style = parseStyle(node, style, stylesheets);
|
|
2552
|
+
path = parseCircleNode(node);
|
|
2553
|
+
break;
|
|
2554
|
+
case "ellipse":
|
|
2555
|
+
style = parseStyle(node, style, stylesheets);
|
|
2556
|
+
path = parseEllipseNode(node);
|
|
2557
|
+
break;
|
|
2558
|
+
case "line":
|
|
2559
|
+
style = parseStyle(node, style, stylesheets);
|
|
2560
|
+
path = parseLineNode(node);
|
|
2561
|
+
break;
|
|
2562
|
+
case "defs":
|
|
2563
|
+
isDefsNode = true;
|
|
2564
|
+
break;
|
|
2565
|
+
case "use": {
|
|
2566
|
+
style = parseStyle(node, style, stylesheets);
|
|
2567
|
+
const href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "";
|
|
2568
|
+
const usedNodeId = href.substring(1);
|
|
2569
|
+
const usedNode = node.viewportElement?.getElementById(usedNodeId);
|
|
2570
|
+
if (usedNode) {
|
|
2571
|
+
parseNode(usedNode, style, paths);
|
|
2572
|
+
} else {
|
|
2573
|
+
console.warn(`'use node' references non-existent node id: ${usedNodeId}`);
|
|
2574
|
+
}
|
|
2575
|
+
break;
|
|
2576
|
+
}
|
|
2577
|
+
default:
|
|
2578
|
+
console.warn(node);
|
|
2579
|
+
break;
|
|
2580
|
+
}
|
|
2581
|
+
const currentTransform = new Matrix3();
|
|
2582
|
+
const transformStack = [];
|
|
2583
|
+
const transform = getNodeTransform(node, currentTransform, transformStack);
|
|
2584
|
+
if (path) {
|
|
2585
|
+
path.transform(currentTransform);
|
|
2586
|
+
paths.push(path);
|
|
2587
|
+
path.userData = { node, style };
|
|
2588
|
+
}
|
|
2589
|
+
const childNodes = node.childNodes;
|
|
2590
|
+
for (let i = 0, len = childNodes.length; i < len; i++) {
|
|
2591
|
+
const node2 = childNodes[i];
|
|
2592
|
+
if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs")
|
|
2593
|
+
continue;
|
|
2594
|
+
parseNode(node2, style, paths);
|
|
2595
|
+
}
|
|
2596
|
+
if (transform) {
|
|
2597
|
+
transformStack.pop();
|
|
2598
|
+
if (transformStack.length > 0) {
|
|
2599
|
+
currentTransform.copy(transformStack[transformStack.length - 1]);
|
|
2600
|
+
} else {
|
|
2601
|
+
currentTransform.identity();
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2604
|
+
return paths;
|
|
2605
|
+
}
|
|
2606
|
+
|
|
2607
|
+
function parseSvg(svg) {
|
|
2608
|
+
let node;
|
|
2609
|
+
if (typeof svg === "string") {
|
|
2610
|
+
node = new DOMParser().parseFromString(svg, "image/svg+xml").documentElement;
|
|
2611
|
+
} else {
|
|
2612
|
+
node = svg;
|
|
2613
|
+
}
|
|
2614
|
+
return parseNode(node, {
|
|
2615
|
+
fill: "#000",
|
|
2616
|
+
fillOpacity: 1,
|
|
2617
|
+
strokeOpacity: 1,
|
|
2618
|
+
strokeWidth: 1,
|
|
2619
|
+
strokeLineJoin: "miter",
|
|
2620
|
+
strokeLineCap: "butt",
|
|
2621
|
+
strokeMiterLimit: 4
|
|
2622
|
+
});
|
|
1165
2623
|
}
|
|
1166
2624
|
|
|
1167
2625
|
exports.CircleCurve = CircleCurve;
|
|
@@ -1171,12 +2629,11 @@ exports.CurvePath = CurvePath;
|
|
|
1171
2629
|
exports.EllipseCurve = EllipseCurve;
|
|
1172
2630
|
exports.HeartCurve = HeartCurve;
|
|
1173
2631
|
exports.LineCurve = LineCurve;
|
|
2632
|
+
exports.Matrix3 = Matrix3;
|
|
1174
2633
|
exports.Path2D = Path2D;
|
|
1175
2634
|
exports.PloygonCurve = PloygonCurve;
|
|
1176
2635
|
exports.Point2D = Point2D;
|
|
1177
2636
|
exports.QuadraticBezierCurve = QuadraticBezierCurve;
|
|
1178
2637
|
exports.RectangularCurve = RectangularCurve;
|
|
1179
2638
|
exports.SplineCurve = SplineCurve;
|
|
1180
|
-
exports.
|
|
1181
|
-
exports.cubicBezier = cubicBezier;
|
|
1182
|
-
exports.quadraticBezier = quadraticBezier;
|
|
2639
|
+
exports.parseSvg = parseSvg;
|