fabric 6.4.1 → 6.4.2

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +123 -95
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.min.js +1 -1
  5. package/dist/index.min.js.map +1 -1
  6. package/dist/index.min.mjs +1 -1
  7. package/dist/index.min.mjs.map +1 -1
  8. package/dist/index.mjs +123 -95
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/index.node.cjs +123 -95
  11. package/dist/index.node.cjs.map +1 -1
  12. package/dist/index.node.mjs +123 -95
  13. package/dist/index.node.mjs.map +1 -1
  14. package/dist/package.json.min.mjs +1 -1
  15. package/dist/package.json.mjs +1 -1
  16. package/dist/src/canvas/DOMManagers/CanvasDOMManager.min.mjs +1 -1
  17. package/dist/src/canvas/DOMManagers/CanvasDOMManager.min.mjs.map +1 -1
  18. package/dist/src/canvas/DOMManagers/CanvasDOMManager.mjs +0 -1
  19. package/dist/src/canvas/DOMManagers/CanvasDOMManager.mjs.map +1 -1
  20. package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
  21. package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
  22. package/dist/src/canvas/SelectableCanvas.mjs +0 -1
  23. package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
  24. package/dist/src/config.d.ts +5 -1
  25. package/dist/src/config.d.ts.map +1 -1
  26. package/dist/src/config.min.mjs +1 -1
  27. package/dist/src/config.min.mjs.map +1 -1
  28. package/dist/src/config.mjs +6 -2
  29. package/dist/src/config.mjs.map +1 -1
  30. package/dist/src/parser/constants.d.ts +0 -1
  31. package/dist/src/parser/constants.d.ts.map +1 -1
  32. package/dist/src/parser/constants.min.mjs +1 -1
  33. package/dist/src/parser/constants.min.mjs.map +1 -1
  34. package/dist/src/parser/constants.mjs +1 -2
  35. package/dist/src/parser/constants.mjs.map +1 -1
  36. package/dist/src/shapes/Line.min.mjs +1 -1
  37. package/dist/src/shapes/Line.min.mjs.map +1 -1
  38. package/dist/src/shapes/Line.mjs +0 -1
  39. package/dist/src/shapes/Line.mjs.map +1 -1
  40. package/dist/src/shapes/Path.min.mjs +1 -1
  41. package/dist/src/shapes/Path.min.mjs.map +1 -1
  42. package/dist/src/shapes/Path.mjs +7 -1
  43. package/dist/src/shapes/Path.mjs.map +1 -1
  44. package/dist/src/shapes/Text/StyledText.min.mjs +1 -1
  45. package/dist/src/shapes/Text/StyledText.min.mjs.map +1 -1
  46. package/dist/src/shapes/Text/StyledText.mjs +0 -1
  47. package/dist/src/shapes/Text/StyledText.mjs.map +1 -1
  48. package/dist/src/util/misc/boundingBoxFromPoints.d.ts.map +1 -1
  49. package/dist/src/util/misc/boundingBoxFromPoints.min.mjs +1 -1
  50. package/dist/src/util/misc/boundingBoxFromPoints.min.mjs.map +1 -1
  51. package/dist/src/util/misc/boundingBoxFromPoints.mjs +17 -30
  52. package/dist/src/util/misc/boundingBoxFromPoints.mjs.map +1 -1
  53. package/dist/src/util/path/index.d.ts.map +1 -1
  54. package/dist/src/util/path/index.min.mjs +1 -1
  55. package/dist/src/util/path/index.min.mjs.map +1 -1
  56. package/dist/src/util/path/index.mjs +51 -47
  57. package/dist/src/util/path/index.mjs.map +1 -1
  58. package/dist/src/util/path/regex.d.ts +2 -1
  59. package/dist/src/util/path/regex.d.ts.map +1 -1
  60. package/dist/src/util/path/regex.min.mjs +1 -1
  61. package/dist/src/util/path/regex.min.mjs.map +1 -1
  62. package/dist/src/util/path/regex.mjs +41 -16
  63. package/dist/src/util/path/regex.mjs.map +1 -1
  64. package/dist/src/util/path/typedefs.d.ts +1 -0
  65. package/dist/src/util/path/typedefs.d.ts.map +1 -1
  66. package/dist-extensions/src/config.d.ts +5 -1
  67. package/dist-extensions/src/config.d.ts.map +1 -1
  68. package/dist-extensions/src/parser/constants.d.ts +0 -1
  69. package/dist-extensions/src/parser/constants.d.ts.map +1 -1
  70. package/dist-extensions/src/util/misc/boundingBoxFromPoints.d.ts.map +1 -1
  71. package/dist-extensions/src/util/path/index.d.ts.map +1 -1
  72. package/dist-extensions/src/util/path/regex.d.ts +2 -1
  73. package/dist-extensions/src/util/path/regex.d.ts.map +1 -1
  74. package/dist-extensions/src/util/path/typedefs.d.ts +1 -0
  75. package/dist-extensions/src/util/path/typedefs.d.ts.map +1 -1
  76. package/package.json +1 -1
  77. package/src/config.ts +6 -2
  78. package/src/parser/constants.ts +0 -2
  79. package/src/shapes/Path.ts +1 -1
  80. package/src/util/misc/boundingBoxFromPoints.ts +15 -24
  81. package/src/util/path/__snapshots__/index.spec.ts.snap +462 -0
  82. package/src/util/path/index.spec.ts +107 -1
  83. package/src/util/path/index.ts +56 -51
  84. package/src/util/path/regex.ts +29 -22
  85. package/src/util/path/typedefs.ts +22 -0
@@ -1,5 +1,76 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`Path Utils fabric.util.getRegularPolygonPath 1`] = `
4
+ [
5
+ [
6
+ "M",
7
+ 0,
8
+ -50,
9
+ ],
10
+ [
11
+ "L",
12
+ 47.552825814757675,
13
+ -15.450849718747369,
14
+ ],
15
+ [
16
+ "L",
17
+ 29.389262614623657,
18
+ 40.45084971874737,
19
+ ],
20
+ [
21
+ "L",
22
+ -29.38926261462365,
23
+ 40.45084971874737,
24
+ ],
25
+ [
26
+ "L",
27
+ -47.55282581475768,
28
+ -15.450849718747364,
29
+ ],
30
+ [
31
+ "Z",
32
+ ],
33
+ ]
34
+ `;
35
+
36
+ exports[`Path Utils fabric.util.getRegularPolygonPath 2`] = `
37
+ [
38
+ [
39
+ "M",
40
+ 24.999999999999993,
41
+ -43.30127018922194,
42
+ ],
43
+ [
44
+ "L",
45
+ 50,
46
+ -1.1102230246251565e-14,
47
+ ],
48
+ [
49
+ "L",
50
+ 25.000000000000018,
51
+ 43.301270189221924,
52
+ ],
53
+ [
54
+ "L",
55
+ -24.99999999999999,
56
+ 43.30127018922194,
57
+ ],
58
+ [
59
+ "L",
60
+ -50,
61
+ 2.8327694488239898e-14,
62
+ ],
63
+ [
64
+ "L",
65
+ -25.00000000000006,
66
+ -43.301270189221896,
67
+ ],
68
+ [
69
+ "Z",
70
+ ],
71
+ ]
72
+ `;
73
+
3
74
  exports[`Path Utils getPathSegmentsInfo operates as expected 1`] = `
4
75
  [
5
76
  {
@@ -380,3 +451,394 @@ exports[`Path Utils makePathSimpler can parse paths that return NaN segments 1`]
380
451
  ],
381
452
  ]
382
453
  `;
454
+
455
+ exports[`Path Utils parsePath Path written with uncommon scenario 1`] = `
456
+ [
457
+ [
458
+ "a",
459
+ 10.56,
460
+ 10.56,
461
+ 0,
462
+ 0,
463
+ 0,
464
+ -1.484,
465
+ -0.133,
466
+ ],
467
+ [
468
+ "a",
469
+ 10.56,
470
+ 10.56,
471
+ 0,
472
+ 0,
473
+ 0,
474
+ -1.484,
475
+ -0.133,
476
+ ],
477
+ [
478
+ "a",
479
+ 10.56,
480
+ 10.56,
481
+ 0,
482
+ 0,
483
+ 0,
484
+ -1.484,
485
+ -0.133,
486
+ ],
487
+ [
488
+ "a",
489
+ 10.56,
490
+ 10.56,
491
+ 0,
492
+ 0,
493
+ 0,
494
+ -1.484,
495
+ -0.133,
496
+ ],
497
+ ]
498
+ `;
499
+
500
+ exports[`Path Utils parsePath can parse path string 1`] = `
501
+ [
502
+ [
503
+ "M",
504
+ 2,
505
+ 5,
506
+ ],
507
+ [
508
+ "l",
509
+ 2,
510
+ -2,
511
+ ],
512
+ [
513
+ "L",
514
+ 4,
515
+ 4,
516
+ ],
517
+ [
518
+ "h",
519
+ 3,
520
+ ],
521
+ [
522
+ "H",
523
+ 9,
524
+ ],
525
+ [
526
+ "C",
527
+ 8,
528
+ 3,
529
+ 10,
530
+ 3,
531
+ 10,
532
+ 3,
533
+ ],
534
+ [
535
+ "c",
536
+ 1,
537
+ -1,
538
+ 2,
539
+ 0,
540
+ 1,
541
+ 1,
542
+ ],
543
+ [
544
+ "S",
545
+ 8,
546
+ 5,
547
+ 9,
548
+ 7,
549
+ ],
550
+ [
551
+ "v",
552
+ 1,
553
+ ],
554
+ [
555
+ "s",
556
+ 2,
557
+ -1,
558
+ 1,
559
+ 2,
560
+ ],
561
+ [
562
+ "Q",
563
+ 9,
564
+ 10,
565
+ 10,
566
+ 11,
567
+ ],
568
+ [
569
+ "T",
570
+ 12,
571
+ 11,
572
+ ],
573
+ [
574
+ "t",
575
+ -1,
576
+ -1,
577
+ ],
578
+ [
579
+ "v",
580
+ 2,
581
+ ],
582
+ [
583
+ "T",
584
+ 10,
585
+ 12,
586
+ ],
587
+ [
588
+ "S",
589
+ 9,
590
+ 12,
591
+ 7,
592
+ 11,
593
+ ],
594
+ [
595
+ "c",
596
+ 0,
597
+ -1,
598
+ 0,
599
+ -1,
600
+ -2,
601
+ -2,
602
+ ],
603
+ [
604
+ "z",
605
+ ],
606
+ [
607
+ "m",
608
+ 0,
609
+ 2,
610
+ ],
611
+ [
612
+ "l",
613
+ 1,
614
+ 0,
615
+ ],
616
+ [
617
+ "l",
618
+ 0,
619
+ 1,
620
+ ],
621
+ [
622
+ "l",
623
+ -1,
624
+ 0,
625
+ ],
626
+ [
627
+ "z",
628
+ ],
629
+ [
630
+ "M",
631
+ 1,
632
+ 1,
633
+ ],
634
+ [
635
+ "a",
636
+ 1,
637
+ 1,
638
+ 30,
639
+ 1,
640
+ 0,
641
+ 2,
642
+ 2,
643
+ ],
644
+ [
645
+ "A",
646
+ 2,
647
+ 2,
648
+ 30,
649
+ 1,
650
+ 0,
651
+ 6,
652
+ 6,
653
+ ],
654
+ ]
655
+ `;
656
+
657
+ exports[`Path Utils parsePath can parse path string 2`] = `
658
+ [
659
+ [
660
+ "M",
661
+ 2,
662
+ 5,
663
+ ],
664
+ [
665
+ "L",
666
+ 4,
667
+ 3,
668
+ ],
669
+ [
670
+ "L",
671
+ 4,
672
+ 4,
673
+ ],
674
+ [
675
+ "L",
676
+ 7,
677
+ 4,
678
+ ],
679
+ [
680
+ "L",
681
+ 9,
682
+ 4,
683
+ ],
684
+ [
685
+ "C",
686
+ 8,
687
+ 3,
688
+ 10,
689
+ 3,
690
+ 10,
691
+ 3,
692
+ ],
693
+ [
694
+ "C",
695
+ 11,
696
+ 2,
697
+ 12,
698
+ 3,
699
+ 11,
700
+ 4,
701
+ ],
702
+ [
703
+ "C",
704
+ 10,
705
+ 5,
706
+ 8,
707
+ 5,
708
+ 9,
709
+ 7,
710
+ ],
711
+ [
712
+ "L",
713
+ 9,
714
+ 8,
715
+ ],
716
+ [
717
+ "C",
718
+ 9,
719
+ 8,
720
+ 11,
721
+ 7,
722
+ 10,
723
+ 10,
724
+ ],
725
+ [
726
+ "Q",
727
+ 9,
728
+ 10,
729
+ 10,
730
+ 11,
731
+ ],
732
+ [
733
+ "Q",
734
+ 11,
735
+ 12,
736
+ 12,
737
+ 11,
738
+ ],
739
+ [
740
+ "Q",
741
+ 13,
742
+ 10,
743
+ 11,
744
+ 10,
745
+ ],
746
+ [
747
+ "L",
748
+ 11,
749
+ 12,
750
+ ],
751
+ [
752
+ "Q",
753
+ 11,
754
+ 12,
755
+ 10,
756
+ 12,
757
+ ],
758
+ [
759
+ "C",
760
+ 10,
761
+ 12,
762
+ 9,
763
+ 12,
764
+ 7,
765
+ 11,
766
+ ],
767
+ [
768
+ "C",
769
+ 7,
770
+ 10,
771
+ 7,
772
+ 10,
773
+ 5,
774
+ 9,
775
+ ],
776
+ [
777
+ "Z",
778
+ ],
779
+ [
780
+ "M",
781
+ 2,
782
+ 7,
783
+ ],
784
+ [
785
+ "L",
786
+ 3,
787
+ 7,
788
+ ],
789
+ [
790
+ "L",
791
+ 3,
792
+ 8,
793
+ ],
794
+ [
795
+ "L",
796
+ 2,
797
+ 8,
798
+ ],
799
+ [
800
+ "Z",
801
+ ],
802
+ [
803
+ "M",
804
+ 1,
805
+ 1,
806
+ ],
807
+ [
808
+ "C",
809
+ 0.44771525016920655,
810
+ 1.5522847498307935,
811
+ 0.44771525016920655,
812
+ 2.4477152501692068,
813
+ 1,
814
+ 3,
815
+ ],
816
+ [
817
+ "C",
818
+ 1.5522847498307935,
819
+ 3.5522847498307932,
820
+ 2.4477152501692068,
821
+ 3.5522847498307932,
822
+ 3,
823
+ 3,
824
+ ],
825
+ [
826
+ "C",
827
+ 2.1715728752538106,
828
+ 3.8284271247461903,
829
+ 2.1715728752538106,
830
+ 5.17157287525381,
831
+ 3.0000000000000004,
832
+ 6,
833
+ ],
834
+ [
835
+ "C",
836
+ 3.8284271247461903,
837
+ 6.82842712474619,
838
+ 5.17157287525381,
839
+ 6.82842712474619,
840
+ 6,
841
+ 6,
842
+ ],
843
+ ]
844
+ `;
@@ -1,6 +1,112 @@
1
- import { getPathSegmentsInfo, parsePath, makePathSimpler } from '.';
1
+ import {
2
+ getPathSegmentsInfo,
3
+ parsePath,
4
+ makePathSimpler,
5
+ getRegularPolygonPath,
6
+ joinPath,
7
+ } from '.';
8
+ import type { TSimplePathData } from './typedefs';
2
9
 
3
10
  describe('Path Utils', () => {
11
+ describe('parsePath', () => {
12
+ const path =
13
+ 'M 2 5 l 2 -2 L 4 4 h 3 H 9 C 8 3 10 3 10 3 c 1 -1 2 0 1 1 S 8 5 9 7 v 1 s 2 -1 1 2 Q 9 10 10 11 T 12 11 t -1 -1 v 2 T 10 12 S 9 12 7 11 c 0 -1 0 -1 -2 -2 z m 0 2 l 1 0 l 0 1 l -1 0 z M 1 1 a 1 1 30 1 0 2 2 A 2 2 30 1 0 6 6';
14
+ test('can parse path string', () => {
15
+ const parsed = parsePath(path);
16
+ expect(parsed).toMatchSnapshot();
17
+ const simplified = makePathSimpler(parsed);
18
+ expect(simplified).toMatchSnapshot();
19
+ });
20
+ test('Path written with uncommon scenario', () => {
21
+ const path =
22
+ 'a10.56 10.56 0 00-1.484-.133a10.56 , 10.56 0, 0,0-1.484-.133a10.56 , 10.56 0, 0,0-1.484-.133a1.056e+1 , 105.6e-1,0,0,0-1.484-.133';
23
+ const parsed = parsePath(path);
24
+ expect(parsed[0]).toEqual(parsed[1]);
25
+ expect(parsed[1]).toEqual(parsed[2]);
26
+ expect(parsed[2]).toEqual(parsed[3]);
27
+ expect(parsed).toMatchSnapshot();
28
+ });
29
+ test('fabric.util.parsePath can parse arcs correctly when no spaces between flags', () => {
30
+ const pathWithWeirdArc = 'a10.56 10.56 0 00-1.484-.133';
31
+ const expected = ['a', 10.56, 10.56, 0, 0, 0, -1.484, -0.133];
32
+ const parsed = parsePath(pathWithWeirdArc);
33
+ const command = parsed[0];
34
+ expect(command).toEqual(expected);
35
+ });
36
+ test('getPathSegmentsInfo', () => {
37
+ const parsed = makePathSimpler(parsePath(path));
38
+ const infos = getPathSegmentsInfo(parsed);
39
+ // 'the command 0 a M has a length 0');
40
+ expect(infos[0].length).toBe(0);
41
+ // 'the command 1 a L has a length 2.828',
42
+ expect(infos[1].length.toFixed(5)).toBe('2.82843');
43
+ // 'the command 2 a L with one step on Y has a length 1',
44
+ expect(infos[2].length).toBe(1);
45
+ // 'the command 3 a L with 3 step on X has a length 3'
46
+ expect(infos[3].length).toBe(3);
47
+ // 'the command 4 a L with 2 step on X has a length 0',
48
+ expect(infos[4].length).toBe(2);
49
+ // 'the command 5 a C has a approximated length of 2.062',
50
+ expect(infos[5].length.toFixed(5)).toBe('2.06242');
51
+ // 'the command 6 a C has a approximated length of 2.828',
52
+ expect(infos[6].length.toFixed(5)).toBe('2.82832');
53
+ // 'the command 7 a C has a approximated length of 4.189',
54
+ expect(infos[7].length.toFixed(5)).toBe('4.18970');
55
+ // 'the command 8 a L with 1 step on the Y has an exact length of 1',
56
+ expect(infos[8].length).toBe(1);
57
+ // 'the command 9 a C has a approximated length of 3.227',
58
+ expect(infos[9].length.toFixed(5)).toBe('3.22727');
59
+ // 'the command 10 a Q has a approximated length of 1.540',
60
+ expect(infos[10].length.toFixed(5)).toBe('1.54026');
61
+ // 'the command 11 a Q has a approximated length of 2.295',
62
+ expect(infos[11].length.toFixed(5)).toBe('2.29556');
63
+ });
64
+ test('fabric.util.getPathSegmentsInfo test Z command', () => {
65
+ const parsed = makePathSimpler(parsePath('M 0 0 h 20, v 20 L 0, 20 Z'));
66
+ const infos = getPathSegmentsInfo(parsed);
67
+ // 'the command 0 a M has a length 0'
68
+ expect(infos[0].length).toBe(0);
69
+ // 'the command 1 a L has length 20'
70
+ expect(infos[1].length).toBe(20);
71
+ // 'the command 2 a L has length 20'
72
+ expect(infos[2].length).toBe(20);
73
+ // 'the command 3 a L has length 20'
74
+ expect(infos[3].length).toBe(20);
75
+ // 'the command 4 a Z has length 20'
76
+ expect(infos[4].length).toBe(20);
77
+ });
78
+ });
79
+ test('fabric.util.getRegularPolygonPath', () => {
80
+ const penta = getRegularPolygonPath(5, 50);
81
+ const hexa = getRegularPolygonPath(6, 50);
82
+ // 'regular pentagon should match',
83
+ expect(penta).toMatchSnapshot();
84
+ // 'regular hexagon should match',
85
+ expect(hexa).toMatchSnapshot();
86
+ });
87
+
88
+ test('fabric.util.joinPath', () => {
89
+ const pathData: TSimplePathData = [
90
+ ['M', 3.12345678, 2.12345678],
91
+ ['L', 1.00001111, 2.40001111],
92
+ ['Z'],
93
+ ] as const;
94
+ const digit = 2;
95
+ const expected = 'M 3.12 2.12 L 1 2.4 Z';
96
+ const result = joinPath(pathData, digit);
97
+ expect(result).toBe(expected);
98
+ });
99
+
100
+ test('fabric.util.joinPath without rounding', () => {
101
+ const pathData: TSimplePathData = [
102
+ ['M', 3.12345678, 2.12345678],
103
+ ['L', 1.00001111, 2.40001111],
104
+ ['Z'],
105
+ ] as const;
106
+ const expected = 'M 3.12345678 2.12345678 L 1.00001111 2.40001111 Z';
107
+ const result = joinPath(pathData);
108
+ expect(result).toBe(expected);
109
+ });
4
110
  describe('makePathSimpler', () => {
5
111
  test('can parse paths that return NaN segments', () => {
6
112
  expect(
@@ -19,16 +19,17 @@ import type {
19
19
  TPathSegmentInfoCommon,
20
20
  TEndPathInfo,
21
21
  TParsedArcCommand,
22
+ TComplexParsedCommandType,
22
23
  } from './typedefs';
23
24
  import type { XY } from '../../Point';
24
25
  import { Point } from '../../Point';
25
- import { rePathCommand } from './regex';
26
- import { cleanupSvgAttribute } from '../internals/cleanupSvgAttribute';
26
+ import { reArcCommandPoints, rePathCommand } from './regex';
27
+ import { reNum } from '../../parser/constants';
27
28
 
28
29
  /**
29
30
  * Commands that may be repeated
30
31
  */
31
- const repeatedCommands: Record<string, string | undefined> = {
32
+ const repeatedCommands: Record<string, 'l' | 'L'> = {
32
33
  m: 'l',
33
34
  M: 'L',
34
35
  };
@@ -829,8 +830,19 @@ export const getPointOnPath = (
829
830
  };
830
831
 
831
832
  const rePathCmdAll = new RegExp(rePathCommand, 'gi');
832
- const rePathCmd = new RegExp(rePathCommand, 'i');
833
-
833
+ const regExpArcCommandPoints = new RegExp(reArcCommandPoints, 'g');
834
+ const reMyNum = new RegExp(reNum, 'gi');
835
+ const commandLengths = {
836
+ m: 2,
837
+ l: 2,
838
+ h: 1,
839
+ v: 1,
840
+ c: 6,
841
+ s: 4,
842
+ q: 4,
843
+ t: 2,
844
+ a: 7,
845
+ } as const;
834
846
  /**
835
847
  *
836
848
  * @param {string} pathString
@@ -843,56 +855,49 @@ const rePathCmd = new RegExp(rePathCommand, 'i');
843
855
  * ];
844
856
  */
845
857
  export const parsePath = (pathString: string): TComplexPathData => {
846
- // clean the string
847
- // add spaces around the numbers
848
- pathString = cleanupSvgAttribute(pathString);
858
+ const chain: TComplexPathData = [];
859
+ const all = pathString.match(rePathCmdAll) ?? [];
860
+ for (const matchStr of all) {
861
+ // take match string and save the first letter as the command
862
+ const commandLetter = matchStr[0] as TComplexParsedCommandType;
863
+ // in case of Z we have very little to do
864
+ if (commandLetter === 'z' || commandLetter === 'Z') {
865
+ chain.push([commandLetter]);
866
+ continue;
867
+ }
868
+ const commandLength =
869
+ commandLengths[
870
+ commandLetter.toLowerCase() as keyof typeof commandLengths
871
+ ];
849
872
 
850
- const res: TComplexPathData = [];
851
- for (let [matchStr] of pathString.matchAll(rePathCmdAll)) {
852
- const chain: TComplexPathData = [];
853
- let paramArr: RegExpExecArray | null;
854
- do {
855
- paramArr = rePathCmd.exec(matchStr);
856
- if (!paramArr) {
857
- break;
873
+ let paramArr = [];
874
+ if (commandLetter === 'a' || commandLetter === 'A') {
875
+ // the arc command ha some peculariaties that requires a special regex other than numbers
876
+ // it is possible to avoid using a space between the sweep and large arc flags, making them either
877
+ // 00, 01, 10 or 11, making them identical to a plain number for the regex reMyNum
878
+ // reset the regexp
879
+ regExpArcCommandPoints.lastIndex = 0;
880
+ for (let out = null; (out = regExpArcCommandPoints.exec(matchStr)); ) {
881
+ paramArr.push(...out.slice(1));
858
882
  }
859
- // ignore undefined match groups
860
- const filteredGroups = paramArr.filter((g) => g);
861
- // remove the first element from the match array since it's just the whole command
862
- filteredGroups.shift();
863
- // if we can't parse the number, just interpret it as a string
864
- // (since it's probably the path command)
865
- const command = filteredGroups.map((g) => {
866
- const numParse = Number.parseFloat(g);
867
- if (Number.isNaN(numParse)) {
868
- return g;
869
- } else {
870
- return numParse;
871
- }
872
- });
873
- chain.push(command as any);
874
- // stop now if it's a z command
875
- if (filteredGroups.length <= 1) {
876
- break;
877
- }
878
- // remove the last part of the chained command
879
- filteredGroups.shift();
880
- // ` ?` is to support commands with optional spaces between flags
881
- matchStr = matchStr.replace(
882
- new RegExp(`${filteredGroups.join(' ?')} ?$`),
883
- '',
884
- );
885
- } while (paramArr);
886
- // add the chain, convert multiple m's to l's in the process
887
- chain.reverse().forEach((c, idx) => {
888
- const transformed = repeatedCommands[c[0]];
889
- if (idx > 0 && (transformed == 'l' || transformed == 'L')) {
890
- c[0] = transformed;
883
+ } else {
884
+ paramArr = matchStr.match(reMyNum) || [];
885
+ }
886
+
887
+ // inspect the length of paramArr, if is longer than commandLength
888
+ // we are dealing with repeated commands
889
+ for (let i = 0; i < paramArr.length; i += commandLength) {
890
+ const newCommand = new Array(commandLength) as TComplexParsedCommand;
891
+ const transformedCommand = repeatedCommands[commandLetter];
892
+ newCommand[0] =
893
+ i > 0 && transformedCommand ? transformedCommand : commandLetter;
894
+ for (let j = 0; j < commandLength; j++) {
895
+ newCommand[j + 1] = parseFloat(paramArr[i + j]);
891
896
  }
892
- res.push(c);
893
- });
897
+ chain.push(newCommand);
898
+ }
894
899
  }
895
- return res;
900
+ return chain;
896
901
  };
897
902
 
898
903
  /**