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