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.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().map((cmd) => {
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
- clone() {
203
- return new this.constructor().copy(this);
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
- getCommands() {
240
- return [];
241
- }
242
- drawTo(_ctx) {
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, rx = 1, ry = 1, startAngle = 0, endAngle = Math.PI * 2, clockwise = false, rotation = 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.rx = rx;
336
- this.ry = ry;
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.rx * Math.cos(angle);
369
- let _y = this.y + this.ry * Math.sin(angle);
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, rx, ry, startAngle, endAngle, clockwise } = this;
1166
+ const { x, y, radiusX, radiusY, startAngle, endAngle, clockwise } = this;
382
1167
  const anticlockwise = !clockwise;
383
- const startX = x + rx * Math.cos(startAngle);
384
- const startY = y + ry * Math.sin(startAngle);
385
- const endX = x + rx * Math.cos(endAngle);
386
- const endY = y + ry * Math.sin(endAngle);
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 + rx * Math.cos(startAngle + (endAngle - startAngle) / 2);
391
- const midY = y + ry * Math.sin(startAngle + (endAngle - startAngle) / 2);
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, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: midX, y: midY },
396
- { type: "A", rx, ry, xAxisRotation: 0, largeArcFlag: 1, sweepFlag, x: startX, y: startY }
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, xAxisRotation: 0, largeArcFlag, sweepFlag, x: endX, y: endY }
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, rx, ry, startAngle } = this;
407
- const startX = x + rx * Math.cos(startAngle);
408
- const startY = y + ry * Math.sin(startAngle);
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.arc(
411
- this.x,
412
- this.y,
413
- this.rx,
414
- this.startAngle,
415
- this.endAngle,
416
- !this.clockwise
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.rx = source.rx;
424
- this.ry = source.ry;
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
- getCommands() {
461
- const { v1, v2 } = this;
462
- return [
463
- { type: "M", x: v1.x, y: v1.y },
464
- { type: "L", x: v2.x, y: v2.y }
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
- getCommands() {
642
- const { v0, v1, v2 } = this;
643
- return [
644
- { type: "M", x: v0.x, y: v0.y },
645
- { type: "Q", x1: v1.x, y1: v1.y, x: v2.x, y: v2.y }
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, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
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, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
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, xRadius, yRadius, startAngle, endAngle, clockwise = false, rotation = 0) {
965
- const curve = new EllipseCurve(x, y, xRadius, yRadius, startAngle, endAngle, clockwise, rotation);
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, l = source.curves.length; i < l; i++) {
990
- const curve = source.curves[i];
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
- this.paths.push(...path.paths.map((v) => v.clone()));
1021
- return this;
1022
- }
1023
- addCommands(commands) {
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
- getMinMax(min = new Point2D(), max = new Point2D()) {
1121
- this.paths.forEach((path) => path.curves.forEach((curve) => curve.getMinMax(min, max)));
1122
- return { min, max };
2054
+ forEachCurve(cb) {
2055
+ this.paths.forEach((path) => path.curves.forEach((curve) => cb(curve)));
2056
+ return this;
1123
2057
  }
1124
- getCommands() {
1125
- return this.paths.flatMap((path) => path.curves.flatMap((curve) => curve.getCommands()));
2058
+ transform(matrix) {
2059
+ this.forEachCurve((curve) => curve.transform(matrix));
2060
+ return this;
1126
2061
  }
1127
- getData() {
1128
- return this.paths.map((path) => path.getData()).join(" ");
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 = Point2D.MAX;
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.paths.forEach((path) => {
1150
- path.curves.forEach((curve) => {
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, catmullRom, cubicBezier, quadraticBezier };
2623
+ export { CircleCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, HeartCurve, LineCurve, Matrix3, Path2D, PloygonCurve, Point2D, QuadraticBezierCurve, RectangularCurve, SplineCurve, parseSvg };