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/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().map((cmd) => {
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
- clone() {
205
- return new this.constructor().copy(this);
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
- getCommands() {
242
- return [];
243
- }
244
- drawTo(_ctx) {
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, rx = 1, ry = 1, startAngle = 0, endAngle = Math.PI * 2, clockwise = false, rotation = 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.rx = rx;
338
- this.ry = ry;
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.rx * Math.cos(angle);
371
- let _y = this.y + this.ry * Math.sin(angle);
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, rx, ry, startAngle, endAngle, clockwise } = this;
1168
+ const { x, y, radiusX, radiusY, startAngle, endAngle, clockwise } = this;
384
1169
  const anticlockwise = !clockwise;
385
- const startX = x + rx * Math.cos(startAngle);
386
- const startY = y + ry * Math.sin(startAngle);
387
- const endX = x + rx * Math.cos(endAngle);
388
- const endY = y + ry * Math.sin(endAngle);
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 + rx * Math.cos(startAngle + (endAngle - startAngle) / 2);
393
- const midY = y + ry * Math.sin(startAngle + (endAngle - startAngle) / 2);
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, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: midX, y: midY },
398
- { type: "A", rx, ry, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: startX, y: startY }
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, xAxisRotation: 0, largeArcFlag, sweepFlag, x: endX, y: endY }
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, rx, ry, startAngle } = this;
409
- const startX = x + rx * Math.cos(startAngle);
410
- const startY = y + ry * Math.sin(startAngle);
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.arc(
413
- this.x,
414
- this.y,
415
- this.rx,
416
- this.startAngle,
417
- this.endAngle,
418
- !this.clockwise
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.rx = source.rx;
426
- this.ry = source.ry;
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
- getCommands() {
463
- const { v1, v2 } = this;
464
- return [
465
- { type: "M", x: v1.x, y: v1.y },
466
- { type: "L", x: v2.x, y: v2.y }
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
- getCommands() {
644
- const { v0, v1, v2 } = this;
645
- return [
646
- { type: "M", x: v0.x, y: v0.y },
647
- { type: "Q", x1: v1.x, y1: v1.y, x: v2.x, y: v2.y }
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, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
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, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
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, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
967
- const curve = new EllipseCurve(x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
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, l = source.curves.length; i < l; i++) {
992
- const curve = source.curves[i];
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
- this.paths.push(...path.paths.map((v) => v.clone()));
1023
- return this;
1024
- }
1025
- addCommands(commands) {
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
- getMinMax(min = new Point2D(), max = new Point2D()) {
1123
- this.paths.forEach((path) => path.curves.forEach((curve) => curve.getMinMax(min, max)));
1124
- return { min, max };
2056
+ forEachCurve(cb) {
2057
+ this.paths.forEach((path) => path.curves.forEach((curve) => cb(curve)));
2058
+ return this;
1125
2059
  }
1126
- getCommands() {
1127
- return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.getCommands()));
2060
+ transform(matrix) {
2061
+ this.forEachCurve((curve) => curve.transform(matrix));
2062
+ return this;
1128
2063
  }
1129
- getData() {
1130
- return this.paths.map((path) => path.getData()).join(" ");
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 = Point2D.MAX;
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.paths.forEach((path) => {
1152
- path.curves.forEach((curve) => {
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.catmullRom = catmullRom;
1181
- exports.cubicBezier = cubicBezier;
1182
- exports.quadraticBezier = quadraticBezier;
2639
+ exports.parseSvg = parseSvg;