svg-path-commander 0.1.23 → 0.2.0-alpha1

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 (72) hide show
  1. package/README.md +6 -4
  2. package/dist/svg-path-commander.es5.js +3948 -0
  3. package/dist/svg-path-commander.es5.min.js +2 -0
  4. package/dist/svg-path-commander.esm.js +438 -411
  5. package/dist/svg-path-commander.esm.min.js +2 -2
  6. package/dist/svg-path-commander.js +1455 -1530
  7. package/dist/svg-path-commander.min.js +2 -2
  8. package/package.json +15 -2
  9. package/src/convert/pathToAbsolute.js +4 -4
  10. package/src/convert/pathToCurve.js +2 -2
  11. package/src/convert/pathToRelative.js +4 -4
  12. package/src/convert/pathToString.js +2 -2
  13. package/src/math/polygonLength.js +1 -2
  14. package/src/options/options.js +1 -1
  15. package/src/parser/error.js +2 -0
  16. package/src/parser/finalizeSegment.js +1 -1
  17. package/src/parser/isSpace.js +1 -1
  18. package/src/parser/paramsParser.js +1 -1
  19. package/src/parser/parsePathString.js +6 -11
  20. package/src/parser/pathParser.js +1 -1
  21. package/src/parser/scanFlag.js +3 -3
  22. package/src/parser/scanParam.js +7 -6
  23. package/src/parser/scanSegment.js +3 -2
  24. package/src/parser/skipSpaces.js +1 -1
  25. package/src/process/clonePath.js +1 -1
  26. package/src/process/fixArc.js +1 -1
  27. package/src/process/fixPath.js +2 -2
  28. package/src/process/getSVGMatrix.js +3 -2
  29. package/src/process/normalizePath.js +3 -3
  30. package/src/process/normalizeSegment.js +2 -2
  31. package/src/process/optimizePath.js +2 -2
  32. package/src/process/projection2d.js +2 -2
  33. package/src/process/reverseCurve.js +3 -3
  34. package/src/process/reversePath.js +4 -5
  35. package/src/process/roundPath.js +7 -6
  36. package/src/process/segmentToCubic.js +3 -3
  37. package/src/process/shortenSegment.js +3 -3
  38. package/src/process/splitCubic.js +1 -1
  39. package/src/process/splitPath.js +1 -1
  40. package/src/process/transformPath.js +8 -7
  41. package/src/svg-path-commander.js +60 -20
  42. package/src/util/getClosestPoint.js +1 -1
  43. package/src/util/getCubicSize.js +1 -1
  44. package/src/util/getDrawDirection.js +1 -1
  45. package/src/util/getPathArea.js +1 -1
  46. package/src/util/getPathBBox.js +2 -2
  47. package/src/util/getPathLength.js +1 -1
  48. package/src/util/getPointAtLength.js +1 -1
  49. package/src/util/getPropertiesAtLength.js +5 -4
  50. package/src/util/getPropertiesAtPoint.js +5 -4
  51. package/src/util/getSegmentAtLength.js +2 -2
  52. package/src/util/getSegmentOfPoint.js +2 -2
  53. package/src/util/getTotalLength.js +1 -1
  54. package/src/util/isAbsoluteArray.js +1 -1
  55. package/src/util/isCurveArray.js +1 -1
  56. package/src/util/isNormalizedArray.js +1 -1
  57. package/src/util/isPathArray.js +1 -1
  58. package/src/util/isPointInStroke.js +2 -2
  59. package/src/util/isRelativeArray.js +1 -1
  60. package/src/util/pathLengthFactory.js +12 -10
  61. package/src/util/segmentArcFactory.js +6 -5
  62. package/src/util/segmentCubicFactory.js +6 -5
  63. package/src/util/segmentLineFactory.js +2 -2
  64. package/src/util/segmentQuadFactory.js +6 -5
  65. package/src/util/shapeToPath.js +14 -14
  66. package/src/util/util.js +0 -2
  67. package/types/index.d.ts +1 -3
  68. package/types/more/modules.ts +0 -3
  69. package/types/more/svg.d.ts +11 -10
  70. package/types/svg-path-commander.d.ts +218 -228
  71. package/src/util/createPath.js +0 -17
  72. package/src/util/getPointAtPathLength.js +0 -15
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * SVGPathCommander v0.1.23 (http://thednp.github.io/svg-path-commander)
3
- * Copyright 2021 © thednp
2
+ * SVGPathCommander v0.2.0alpha1 (http://thednp.github.io/svg-path-commander)
3
+ * Copyright 2022 © thednp
4
4
  * Licensed under MIT (https://github.com/thednp/svg-path-commander/blob/master/LICENSE)
5
5
  */
6
6
  /**
7
7
  * SVGPathCommander default options
8
- * @type {SVGPathCommander.options}
8
+ * @type {SVGPath.options}
9
9
  */
10
10
  const defaultOptions = {
11
11
  origin: [0, 0, 0],
@@ -23,7 +23,7 @@ const paramsCount = {
23
23
  /**
24
24
  * Breaks the parsing of a pathString once a segment is finalized.
25
25
  *
26
- * @param {SVGPathCommander.PathParser} path the `PathParser` instance
26
+ * @param {SVGPath.PathParser} path the `PathParser` instance
27
27
  */
28
28
  function finalizeSegment(path) {
29
29
  let pathCommand = path.pathValue[path.segmentStart];
@@ -51,13 +51,13 @@ function finalizeSegment(path) {
51
51
  }
52
52
  }
53
53
 
54
- const invalidPathValue = 'Invalid path value';
54
+ const error = 'SVGPathCommander error';
55
55
 
56
56
  /**
57
57
  * Validates an A (arc-to) specific path command value.
58
58
  * Usually a `large-arc-flag` or `sweep-flag`.
59
59
  *
60
- * @param {SVGPathCommander.PathParser} path the `PathParser` instance
60
+ * @param {SVGPath.PathParser} path the `PathParser` instance
61
61
  */
62
62
  function scanFlag(path) {
63
63
  const { index } = path;
@@ -75,7 +75,7 @@ function scanFlag(path) {
75
75
  return;
76
76
  }
77
77
 
78
- path.err = `${invalidPathValue}: invalid Arc flag "${ch}", expecting 0 or 1 at index ${index}`;
78
+ path.err = `${error}: invalid Arc flag "${ch}", expecting 0 or 1 at index ${index}`;
79
79
  }
80
80
 
81
81
  /**
@@ -88,11 +88,13 @@ function isDigit(code) {
88
88
  return (code >= 48 && code <= 57); // 0..9
89
89
  }
90
90
 
91
+ const invalidPathValue = 'Invalid path value';
92
+
91
93
  /**
92
94
  * Validates every character of the path string,
93
95
  * every path command, negative numbers or floating point numbers.
94
96
  *
95
- * @param {SVGPathCommander.PathParser} path the `PathParser` instance
97
+ * @param {SVGPath.PathParser} path the `PathParser` instance
96
98
  */
97
99
  function scanParam(path) {
98
100
  const { max, pathValue, index: start } = path;
@@ -105,7 +107,7 @@ function scanParam(path) {
105
107
 
106
108
  if (index >= max) {
107
109
  // path.err = 'SvgPath: missed param (at pos ' + index + ')';
108
- path.err = `${invalidPathValue} at ${index}: missing param ${pathValue[index]}`;
110
+ path.err = `${error}: ${invalidPathValue} at index ${index}, "pathValue" is missing param`;
109
111
  return;
110
112
  }
111
113
  ch = pathValue.charCodeAt(index);
@@ -119,7 +121,7 @@ function scanParam(path) {
119
121
  // https://github.com/ariya/esprimas
120
122
  if (!isDigit(ch) && ch !== 0x2E/* . */) {
121
123
  // path.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
122
- path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} is not a number`;
124
+ path.err = `${error}: ${invalidPathValue} at index ${index}, "${pathValue[index]}" is not a number`;
123
125
  return;
124
126
  }
125
127
 
@@ -134,7 +136,7 @@ function scanParam(path) {
134
136
  if (ch && isDigit(ch)) {
135
137
  // path.err = 'SvgPath: numbers started with `0` such as `09`
136
138
  // are illegal (at pos ' + start + ')';
137
- path.err = `${invalidPathValue} at index ${start}: ${pathValue[start]} illegal number`;
139
+ path.err = `${error}: ${invalidPathValue} at index ${start}, "${pathValue[start]}" illegal number`;
138
140
  return;
139
141
  }
140
142
  }
@@ -158,7 +160,7 @@ function scanParam(path) {
158
160
 
159
161
  if (ch === 0x65/* e */ || ch === 0x45/* E */) {
160
162
  if (hasDot && !hasCeiling && !hasDecimal) {
161
- path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} invalid float exponent`;
163
+ path.err = `${error}: ${invalidPathValue} at index ${index}, "${pathValue[index]}" invalid float exponent`;
162
164
  return;
163
165
  }
164
166
 
@@ -174,7 +176,7 @@ function scanParam(path) {
174
176
  }
175
177
  } else {
176
178
  // path.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
177
- path.err = `${invalidPathValue} at index ${index}: ${pathValue[index]} invalid float exponent`;
179
+ path.err = `${error}: ${invalidPathValue} at index ${index}: "${pathValue[index]}" invalid float exponent`;
178
180
  return;
179
181
  }
180
182
  }
@@ -196,7 +198,7 @@ function isSpace(ch) {
196
198
  return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) // Line terminators
197
199
  // White spaces
198
200
  || (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0)
199
- || (ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0);
201
+ || (ch >= 0x1680 && specialSpaces.includes(ch));
200
202
  }
201
203
 
202
204
  /**
@@ -204,7 +206,7 @@ function isSpace(ch) {
204
206
  * path string every time it encounters any kind of
205
207
  * space character.
206
208
  *
207
- * @param {SVGPathCommander.PathParser} path the `PathParser` instance
209
+ * @param {SVGPath.PathParser} path the `PathParser` instance
208
210
  */
209
211
  function skipSpaces(path) {
210
212
  const { pathValue, max } = path;
@@ -268,7 +270,7 @@ function isArcCommand(code) {
268
270
  * Scans every character in the path string to determine
269
271
  * where a segment starts and where it ends.
270
272
  *
271
- * @param {SVGPathCommander.PathParser} path the `PathParser` instance
273
+ * @param {SVGPath.PathParser} path the `PathParser` instance
272
274
  */
273
275
  function scanSegment(path) {
274
276
  const { max, pathValue, index } = path;
@@ -278,7 +280,7 @@ function scanSegment(path) {
278
280
  path.segmentStart = index;
279
281
 
280
282
  if (!isPathCommand(cmdCode)) {
281
- path.err = `${invalidPathValue}: ${pathValue[index]} not a path command`;
283
+ path.err = `${error}: ${invalidPathValue} "${pathValue[index]}" is not a path command`;
282
284
  return;
283
285
  }
284
286
 
@@ -328,7 +330,7 @@ function scanSegment(path) {
328
330
  /**
329
331
  * Returns a clone of an existing `pathArray`.
330
332
  *
331
- * @param {SVGPathCommander.pathArray | SVGPathCommander.pathSegment} path the source `pathArray`
333
+ * @param {SVGPath.pathArray | SVGPath.pathSegment} path the source `pathArray`
332
334
  * @returns {any} the cloned `pathArray`
333
335
  */
334
336
  function clonePath(path) {
@@ -342,7 +344,7 @@ function clonePath(path) {
342
344
  * @param {string} pathString
343
345
  */
344
346
  function PathParser(pathString) {
345
- /** @type {SVGPathCommander.pathArray} */
347
+ /** @type {SVGPath.pathArray} */
346
348
  // @ts-ignore
347
349
  this.segments = [];
348
350
  /** @type {string} */
@@ -364,7 +366,7 @@ function PathParser(pathString) {
364
366
  /**
365
367
  * Iterates an array to check if it's an actual `pathArray`.
366
368
  *
367
- * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
369
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
368
370
  * @returns {boolean} iteration result
369
371
  */
370
372
  function isPathArray(path) {
@@ -378,8 +380,8 @@ function isPathArray(path) {
378
380
  * Parses a path string value and returns an array
379
381
  * of segments we like to call `pathArray`.
380
382
  *
381
- * @param {SVGPathCommander.pathArray | string} pathInput the string to be parsed
382
- * @returns {SVGPathCommander.pathArray} the resulted `pathArray`
383
+ * @param {SVGPath.pathArray | string} pathInput the string to be parsed
384
+ * @returns {SVGPath.pathArray | string} the resulted `pathArray`
383
385
  */
384
386
  function parsePathString(pathInput) {
385
387
  if (isPathArray(pathInput)) {
@@ -396,27 +398,22 @@ function parsePathString(pathInput) {
396
398
  scanSegment(path);
397
399
  }
398
400
 
399
- if (path.err.length) {
400
- // @ts-ignore
401
- path.segments = [];
402
- } else if (path.segments.length) {
401
+ if (!path.err.length) {
403
402
  if (!'mM'.includes(path.segments[0][0])) {
404
- path.err = `${invalidPathValue}: missing M/m`;
405
- // @ts-ignore
406
- path.segments = [];
403
+ path.err = `${error}: missing M/m`;
407
404
  } else {
408
405
  path.segments[0][0] = 'M';
409
406
  }
410
407
  }
411
408
 
412
- return path.segments;
409
+ return path.err ? path.err : path.segments;
413
410
  }
414
411
 
415
412
  /**
416
413
  * Iterates an array to check if it's a `pathArray`
417
414
  * with all absolute values.
418
415
  *
419
- * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
416
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
420
417
  * @returns {boolean} iteration result
421
418
  */
422
419
  function isAbsoluteArray(path) {
@@ -429,8 +426,8 @@ function isAbsoluteArray(path) {
429
426
  * Parses a path string value or object and returns an array
430
427
  * of segments, all converted to absolute values.
431
428
  *
432
- * @param {string | SVGPathCommander.pathArray} pathInput the path string | object
433
- * @returns {SVGPathCommander.absoluteArray} the resulted `pathArray` with absolute values
429
+ * @param {string | SVGPath.pathArray} pathInput the path string | object
430
+ * @returns {SVGPath.absoluteArray} the resulted `pathArray` with absolute values
434
431
  */
435
432
  function pathToAbsolute(pathInput) {
436
433
  if (isAbsoluteArray(pathInput)) {
@@ -446,7 +443,7 @@ function pathToAbsolute(pathInput) {
446
443
  return path.map((segment) => {
447
444
  const values = segment.slice(1).map(Number);
448
445
  const [pathCommand] = segment;
449
- /** @type {SVGPathCommander.absoluteCommand} */
446
+ /** @type {SVGPath.absoluteCommand} */
450
447
  // @ts-ignore
451
448
  const absCommand = pathCommand.toUpperCase();
452
449
 
@@ -456,7 +453,7 @@ function pathToAbsolute(pathInput) {
456
453
  my = y;
457
454
  return ['M', x, y];
458
455
  }
459
- /** @type {SVGPathCommander.absoluteSegment} */
456
+ /** @type {SVGPath.absoluteSegment} */
460
457
  // @ts-ignore
461
458
  let absoluteSegment = [];
462
459
 
@@ -519,7 +516,7 @@ function pathToAbsolute(pathInput) {
519
516
  * Iterates an array to check if it's a `pathArray`
520
517
  * with relative values.
521
518
  *
522
- * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
519
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
523
520
  * @returns {boolean} iteration result
524
521
  */
525
522
  function isRelativeArray(path) {
@@ -532,8 +529,8 @@ function isRelativeArray(path) {
532
529
  * Parses a path string value or object and returns an array
533
530
  * of segments, all converted to relative values.
534
531
  *
535
- * @param {string | SVGPathCommander.pathArray} pathInput the path string | object
536
- * @returns {SVGPathCommander.relativeArray} the resulted `pathArray` with relative values
532
+ * @param {string | SVGPath.pathArray} pathInput the path string | object
533
+ * @returns {SVGPath.relativeArray} the resulted `pathArray` with relative values
537
534
  */
538
535
  function pathToRelative(pathInput) {
539
536
  if (isRelativeArray(pathInput)) {
@@ -549,7 +546,7 @@ function pathToRelative(pathInput) {
549
546
  return path.map((segment) => {
550
547
  const values = segment.slice(1).map(Number);
551
548
  const [pathCommand] = segment;
552
- /** @type {SVGPathCommander.relativeCommand} */
549
+ /** @type {SVGPath.relativeCommand} */
553
550
  // @ts-ignore
554
551
  const relativeCommand = pathCommand.toLowerCase();
555
552
 
@@ -560,7 +557,7 @@ function pathToRelative(pathInput) {
560
557
  return ['M', x, y];
561
558
  }
562
559
 
563
- /** @type {SVGPathCommander.relativeSegment} */
560
+ /** @type {SVGPath.relativeSegment} */
564
561
  // @ts-ignore -- trust me DON'T CHANGE
565
562
  let relativeSegment = [];
566
563
 
@@ -627,7 +624,7 @@ function pathToRelative(pathInput) {
627
624
  /**
628
625
  * Splits an extended A (arc-to) segment into two cubic-bezier segments.
629
626
  *
630
- * @param {SVGPathCommander.pathArray} path the `pathArray` this segment belongs to
627
+ * @param {SVGPath.pathArray} path the `pathArray` this segment belongs to
631
628
  * @param {string[]} allPathCommands all previous path commands
632
629
  * @param {number} i the segment index
633
630
  */
@@ -684,10 +681,10 @@ function shorthandToCubic(x1, y1, x2, y2, prevCommand) {
684
681
  /**
685
682
  * Normalizes a single segment of a `pathArray` object.
686
683
  *
687
- * @param {SVGPathCommander.pathSegment} segment the segment object
684
+ * @param {SVGPath.pathSegment} segment the segment object
688
685
  * @param {any} params the coordinates of the previous segment
689
686
  * @param {string} prevCommand the path command of the previous segment
690
- * @returns {SVGPathCommander.normalSegment} the normalized segment
687
+ * @returns {SVGPath.normalSegment} the normalized segment
691
688
  */
692
689
  function normalizeSegment(segment, params, prevCommand) {
693
690
  const [pathCommand] = segment;
@@ -734,7 +731,7 @@ function normalizeSegment(segment, params, prevCommand) {
734
731
  * with all segments are in non-shorthand notation
735
732
  * with absolute values.
736
733
  *
737
- * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
734
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
738
735
  * @returns {boolean} iteration result
739
736
  */
740
737
  function isNormalizedArray(path) {
@@ -743,7 +740,7 @@ function isNormalizedArray(path) {
743
740
  }
744
741
 
745
742
  /**
746
- * @type {SVGPathCommander.parserParams}
743
+ * @type {SVGPath.parserParams}
747
744
  */
748
745
  const paramsParser = {
749
746
  x1: 0, y1: 0, x2: 0, y2: 0, x: 0, y: 0, qx: null, qy: null,
@@ -754,8 +751,8 @@ const paramsParser = {
754
751
  * * convert segments to absolute values
755
752
  * * convert shorthand path commands to their non-shorthand notation
756
753
  *
757
- * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
758
- * @returns {SVGPathCommander.normalArray} the normalized `pathArray`
754
+ * @param {string | SVGPath.pathArray} pathInput the string to be parsed or 'pathArray'
755
+ * @returns {SVGPath.normalArray} the normalized `pathArray`
759
756
  */
760
757
  function normalizePath(pathInput) {
761
758
  if (isNormalizedArray(pathInput)) {
@@ -763,7 +760,7 @@ function normalizePath(pathInput) {
763
760
  return clonePath(pathInput);
764
761
  }
765
762
 
766
- /** @type {SVGPathCommander.normalArray} */
763
+ /** @type {SVGPath.normalArray} */
767
764
  // @ts-ignore -- `absoluteArray` will become a `normalArray`
768
765
  const path = pathToAbsolute(pathInput);
769
766
  const params = { ...paramsParser };
@@ -804,8 +801,8 @@ function normalizePath(pathInput) {
804
801
  * use `splitPath` first and apply this utility on each
805
802
  * sub-path separately.
806
803
  *
807
- * @param {SVGPathCommander.pathArray | string} pathInput the `pathArray` source
808
- * @return {SVGPathCommander.pathArray} a fixed `pathArray`
804
+ * @param {SVGPath.pathArray | string} pathInput the `pathArray` source
805
+ * @return {SVGPath.pathArray} a fixed `pathArray`
809
806
  */
810
807
  function fixPath(pathInput) {
811
808
  const pathArray = parsePathString(pathInput);
@@ -828,7 +825,7 @@ function fixPath(pathInput) {
828
825
  * Iterates an array to check if it's a `pathArray`
829
826
  * with all C (cubic bezier) segments.
830
827
  *
831
- * @param {string | SVGPathCommander.pathArray} path the `Array` to be checked
828
+ * @param {string | SVGPath.pathArray} path the `Array` to be checked
832
829
  * @returns {boolean} iteration result
833
830
  */
834
831
  function isCurveArray(path) {
@@ -1017,7 +1014,7 @@ function distanceSquareRoot(a, b) {
1017
1014
  }
1018
1015
 
1019
1016
  /**
1020
- * Returns the length of a line (L,V,H,Z) segment,
1017
+ * Returns the length of a line (L,V,H,Z) segment
1021
1018
  * or a point at a given length.
1022
1019
  *
1023
1020
  * @param {number} x1 the starting point X
@@ -1035,7 +1032,7 @@ function segmentLineFactory(x1, y1, x2, y2, distance) {
1035
1032
  if (distance < margin) {
1036
1033
  return { x: x1, y: y1 };
1037
1034
  }
1038
- if (distance > length + margin) {
1035
+ if (distance > length) {
1039
1036
  return { x: x2, y: y2 };
1040
1037
  }
1041
1038
  const [x, y] = midPoint([x1, y1], [x2, y2], distance / length);
@@ -1078,9 +1075,9 @@ function lineToCubic(x1, y1, x2, y2) {
1078
1075
  /**
1079
1076
  * Converts any segment to C (cubic-bezier).
1080
1077
  *
1081
- * @param {SVGPathCommander.pathSegment} segment the source segment
1082
- * @param {SVGPathCommander.parserParams} params the source segment parameters
1083
- * @returns {SVGPathCommander.cubicSegment | SVGPathCommander.MSegment} the cubic-bezier segment
1078
+ * @param {SVGPath.pathSegment} segment the source segment
1079
+ * @param {SVGPath.parserParams} params the source segment parameters
1080
+ * @returns {SVGPath.cubicSegment | SVGPath.MSegment} the cubic-bezier segment
1084
1081
  */
1085
1082
  function segmentToCubic(segment, params) {
1086
1083
  const [pathCommand] = segment;
@@ -1129,8 +1126,8 @@ function segmentToCubic(segment, params) {
1129
1126
  * In addition, un-necessary `Z` segment is removed if previous segment
1130
1127
  * extends to the `M` segment.
1131
1128
  *
1132
- * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
1133
- * @returns {SVGPathCommander.curveArray} the resulted `pathArray` converted to cubic-bezier
1129
+ * @param {string | SVGPath.pathArray} pathInput the string to be parsed or 'pathArray'
1130
+ * @returns {SVGPath.curveArray} the resulted `pathArray` converted to cubic-bezier
1134
1131
  */
1135
1132
  function pathToCurve(pathInput) {
1136
1133
  if (isCurveArray(pathInput)) {
@@ -1169,23 +1166,24 @@ function pathToCurve(pathInput) {
1169
1166
  * Rounds the values of a `pathArray` instance to
1170
1167
  * a specified amount of decimals and returns it.
1171
1168
  *
1172
- * @param {SVGPathCommander.pathArray} path the source `pathArray`
1173
- * @param {number | boolean} roundOption the amount of decimals to round numbers to
1174
- * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with rounded values
1169
+ * @param {SVGPath.pathArray} path the source `pathArray`
1170
+ * @param {number | false} roundOption the amount of decimals to round numbers to
1171
+ * @returns {SVGPath.pathArray} the resulted `pathArray` with rounded values
1175
1172
  */
1176
1173
  function roundPath(path, roundOption) {
1177
1174
  let { round } = defaultOptions;
1178
1175
  if (roundOption === false || round === false) return clonePath(path);
1179
- round = roundOption >= 1 ? roundOption : round;
1176
+ // round = roundOption >= 1 ? roundOption : round;
1177
+ // allow for ZERO decimals
1178
+ round = roundOption >= 0 ? roundOption : round;
1180
1179
  // to round values to the power
1181
1180
  // the `round` value must be integer
1182
- // @ts-ignore
1183
1181
  const pow = round >= 1 ? (10 ** round) : 1;
1184
1182
 
1185
1183
  // @ts-ignore -- `pathSegment[]` is `pathArray`
1186
1184
  return path.map((pi) => {
1187
1185
  const values = pi.slice(1).map(Number)
1188
- .map((n) => (n % 1 === 0 ? n : Math.round(n * pow) / pow));
1186
+ .map((n) => (round ? (Math.round(n * pow) / pow) : Math.round(n)));
1189
1187
  return [pi[0], ...values];
1190
1188
  });
1191
1189
  }
@@ -1194,8 +1192,8 @@ function roundPath(path, roundOption) {
1194
1192
  * Returns a valid `d` attribute string value created
1195
1193
  * by rounding values and concatenating the `pathArray` segments.
1196
1194
  *
1197
- * @param {SVGPathCommander.pathArray} path the `pathArray` object
1198
- * @param {any} round amount of decimals to round values to
1195
+ * @param {SVGPath.pathArray} path the `pathArray` object
1196
+ * @param {number | false} round amount of decimals to round values to
1199
1197
  * @returns {string} the concatenated path string
1200
1198
  */
1201
1199
  function pathToString(path, round) {
@@ -1204,11 +1202,10 @@ function pathToString(path, round) {
1204
1202
  }
1205
1203
 
1206
1204
  /**
1207
- * Reverses all segments and their values of a `pathArray`
1208
- * and returns a new instance.
1205
+ * Reverses all segments of a `pathArray` and returns a new `pathArray` instance.
1209
1206
  *
1210
- * @param {SVGPathCommander.pathArray} pathInput the source `pathArray`
1211
- * @returns {SVGPathCommander.pathArray} the reversed `pathArray`
1207
+ * @param {SVGPath.pathArray} pathInput the source `pathArray`
1208
+ * @returns {SVGPath.pathArray} the reversed `pathArray`
1212
1209
  */
1213
1210
  function reversePath(pathInput) {
1214
1211
  const absolutePath = pathToAbsolute(pathInput);
@@ -1233,7 +1230,7 @@ function reversePath(pathInput) {
1233
1230
  /** @type {number} */
1234
1231
  const x = i ? path[i - 1].x : path[pLen - 1].x;
1235
1232
  const y = i ? path[i - 1].y : path[pLen - 1].y;
1236
- /** @type {SVGPathCommander.pathSegment} */
1233
+ /** @type {SVGPath.pathSegment} */
1237
1234
  // @ts-ignore
1238
1235
  let result = [];
1239
1236
 
@@ -1307,7 +1304,7 @@ function reversePath(pathInput) {
1307
1304
  * In the process, values are converted to absolute
1308
1305
  * for visual consistency.
1309
1306
  *
1310
- * @param {SVGPathCommander.pathArray | string} pathInput the source `pathArray`
1307
+ * @param {SVGPath.pathArray | string} pathInput the source `pathArray`
1311
1308
  * @return {string[]} an array with all sub-path strings
1312
1309
  */
1313
1310
  function splitPath(pathInput) {
@@ -1321,11 +1318,11 @@ function splitPath(pathInput) {
1321
1318
  /**
1322
1319
  * Shorten a single segment of a `pathArray` object.
1323
1320
  *
1324
- * @param {SVGPathCommander.absoluteSegment} segment the `absoluteSegment` object
1325
- * @param {SVGPathCommander.normalSegment} normalSegment the `normalSegment` object
1321
+ * @param {SVGPath.absoluteSegment} segment the `absoluteSegment` object
1322
+ * @param {SVGPath.normalSegment} normalSegment the `normalSegment` object
1326
1323
  * @param {any} params the coordinates of the previous segment
1327
1324
  * @param {string} prevCommand the path command of the previous segment
1328
- * @returns {SVGPathCommander.shortSegment | SVGPathCommander.pathSegment} the shortened segment
1325
+ * @returns {SVGPath.shortSegment | SVGPath.pathSegment} the shortened segment
1329
1326
  */
1330
1327
  function shortenSegment(segment, normalSegment, params, prevCommand) {
1331
1328
  const [pathCommand] = segment;
@@ -1389,9 +1386,9 @@ function shortenSegment(segment, normalSegment, params, prevCommand) {
1389
1386
  * * implement `auto` for rounding values based on pathBBox
1390
1387
  * * also revers path check if it's smaller string, maybe?
1391
1388
  *
1392
- * @param {SVGPathCommander.pathArray} pathInput a string or `pathArray`
1389
+ * @param {SVGPath.pathArray} pathInput a string or `pathArray`
1393
1390
  * @param {number | boolean} round the amount of decimals to round values to
1394
- * @returns {SVGPathCommander.pathArray} the optimized `pathArray`
1391
+ * @returns {SVGPath.pathArray} the optimized `pathArray`
1395
1392
  */
1396
1393
  function optimizePath(pathInput, round) {
1397
1394
  const path = pathToAbsolute(pathInput);
@@ -2277,14 +2274,15 @@ Object.assign(CSSMatrix, { Version: Version$1 });
2277
2274
  /**
2278
2275
  * Returns a transformation matrix to apply to `<path>` elements.
2279
2276
  *
2280
- * @see SVGPathCommander.transformObject
2277
+ * @see SVGPath.transformObject
2281
2278
  *
2282
- * @param {SVGPathCommander.transformObject} transform the `transformObject`
2279
+ * @param {SVGPath.transformObject} transform the `transformObject`
2283
2280
  * @returns {CSSMatrix} a new transformation matrix
2284
2281
  */
2285
2282
  function getSVGMatrix(transform) {
2286
2283
  let matrix = new CSSMatrix();
2287
2284
  const { origin } = transform;
2285
+ // @ts-ignore -- at this point the origin is surely defined
2288
2286
  const [originX, originY] = origin;
2289
2287
  const { translate } = transform;
2290
2288
  const { rotate } = transform;
@@ -2415,9 +2413,9 @@ function transformEllipse(m, rx, ry, ax) {
2415
2413
  * Details =>
2416
2414
  * https://stackoverflow.com/questions/23792505/predicted-rendering-of-css-3d-transformed-pixel
2417
2415
  *
2418
- * @param {SVGPathCommander.CSSMatrix} m the transformation matrix
2416
+ * @param {SVGPath.CSSMatrix} m the transformation matrix
2419
2417
  * @param {[number, number]} point2D the initial [x,y] coordinates
2420
- * @param {number[]} origin the initial [x,y] coordinates
2418
+ * @param {number[]} origin the [x,y,z] transform origin
2421
2419
  * @returns {[number, number]} the projected [x,y] coordinates
2422
2420
  */
2423
2421
  function projection2d(m, point2D, origin) {
@@ -2443,9 +2441,9 @@ function projection2d(m, point2D, origin) {
2443
2441
  * Since *SVGElement* doesn't support 3D transformation, this function
2444
2442
  * creates a 2D projection of the <path> element.
2445
2443
  *
2446
- * @param {SVGPathCommander.pathArray} path the `pathArray` to apply transformation
2447
- * @param {SVGPathCommander.transformObject} transform the transform functions `Object`
2448
- * @returns {SVGPathCommander.pathArray} the resulted `pathArray`
2444
+ * @param {SVGPath.pathArray} path the `pathArray` to apply transformation
2445
+ * @param {SVGPath.transformObject} transform the transform functions `Object`
2446
+ * @returns {SVGPath.pathArray} the resulted `pathArray`
2449
2447
  */
2450
2448
  function transformPath(path, transform) {
2451
2449
  let x = 0; let y = 0; let i; let j; let ii; let jj; let lx; let ly; let te;
@@ -2460,12 +2458,12 @@ function transformPath(path, transform) {
2460
2458
  const matrix2d = [a, b, c, d, e, f];
2461
2459
  const params = { ...paramsParser };
2462
2460
  /** @ts-ignore */
2463
- /** @type {SVGPathCommander.pathSegment} */
2461
+ /** @type {SVGPath.pathSegment} */
2464
2462
  // @ts-ignore
2465
2463
  let segment = [];
2466
2464
  let seglen = 0;
2467
2465
  let pathCommand = '';
2468
- /** @type {SVGPathCommander.pathTransformList[]} */
2466
+ /** @type {SVGPath.pathTransformList[]} */
2469
2467
  let transformedPath = [];
2470
2468
  const allPathCommands = []; // needed for arc to curve transformation
2471
2469
 
@@ -2504,7 +2502,7 @@ function transformPath(path, transform) {
2504
2502
  params.x2 = +(segment[seglen - 4]) || params.x1;
2505
2503
  params.y2 = +(segment[seglen - 3]) || params.y1;
2506
2504
 
2507
- /** @type {SVGPathCommander.pathTransformList} */
2505
+ /** @type {SVGPath.pathTransformList} */
2508
2506
  const result = {
2509
2507
  s: absolutePath[i], c: absolutePath[i][0], x: params.x1, y: params.y1,
2510
2508
  };
@@ -2541,6 +2539,7 @@ function transformPath(path, transform) {
2541
2539
  case 'L':
2542
2540
  case 'H':
2543
2541
  case 'V':
2542
+ // @ts-ignore
2544
2543
  [lx, ly] = projection2d(matrixInstance, [seg.x, seg.y], origin);
2545
2544
 
2546
2545
  if (x !== lx && y !== ly) {
@@ -2557,7 +2556,7 @@ function transformPath(path, transform) {
2557
2556
  default:
2558
2557
 
2559
2558
  for (j = 1, jj = segment.length; j < jj; j += 2) {
2560
- // compute line coordinates without altering previous coordinates
2559
+ // @ts-ignore compute line coordinates without altering previous coordinates
2561
2560
  [x, y] = projection2d(matrixInstance, [+segment[j], +segment[j + 1]], origin);
2562
2561
  segment[j] = x;
2563
2562
  segment[j + 1] = y;
@@ -2599,7 +2598,7 @@ function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
2599
2598
  }
2600
2599
 
2601
2600
  /**
2602
- * Returns the length of a C (cubic-bezier) segment,
2601
+ * Returns the length of a C (cubic-bezier) segment
2603
2602
  * or an {x,y} point at a given length.
2604
2603
  *
2605
2604
  * @param {number} x1 the starting point X
@@ -2614,15 +2613,16 @@ function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
2614
2613
  * @returns {{x: number, y: number} | number} the segment length or point
2615
2614
  */
2616
2615
  function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
2617
- let x = x1; let y = y1;
2616
+ const distanceIsNumber = typeof distance === 'number';
2618
2617
  const lengthMargin = 0.001;
2618
+ let x = x1; let y = y1;
2619
2619
  let totalLength = 0;
2620
2620
  let prev = [x1, y1, totalLength];
2621
2621
  /** @type {[number, number]} */
2622
2622
  let cur = [x1, y1];
2623
2623
  let t = 0;
2624
2624
 
2625
- if (typeof distance === 'number' && distance < lengthMargin) {
2625
+ if (distanceIsNumber && distance < lengthMargin) {
2626
2626
  return { x, y };
2627
2627
  }
2628
2628
 
@@ -2634,7 +2634,7 @@ function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
2634
2634
  totalLength += distanceSquareRoot(cur, [x, y]);
2635
2635
  cur = [x, y];
2636
2636
 
2637
- if (typeof distance === 'number' && totalLength >= distance) {
2637
+ if (distanceIsNumber && totalLength >= distance) {
2638
2638
  const dv = (totalLength - distance) / (totalLength - prev[2]);
2639
2639
 
2640
2640
  return {
@@ -2645,7 +2645,7 @@ function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
2645
2645
  prev = [x, y, totalLength];
2646
2646
  }
2647
2647
 
2648
- if (typeof distance === 'number' && distance >= totalLength) {
2648
+ if (distanceIsNumber && distance >= totalLength) {
2649
2649
  return { x: x2, y: y2 };
2650
2650
  }
2651
2651
  return totalLength;
@@ -2662,7 +2662,7 @@ function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
2662
2662
  * @param {number} c2y the second control point Y
2663
2663
  * @param {number} x2 the ending point X
2664
2664
  * @param {number} y2 the ending point Y
2665
- * @returns {SVGPathCommander.segmentLimits} the bounding box of the cubic-bezier segment
2665
+ * @returns {SVGPath.segmentLimits} the bounding box of the cubic-bezier segment
2666
2666
  */
2667
2667
  function getCubicSize(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
2668
2668
  let a = (c2x - 2 * c1x + x1) - (x2 - 2 * c2x + c1x);
@@ -2719,8 +2719,8 @@ function getCubicSize(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
2719
2719
  /**
2720
2720
  * Returns the bounding box of a shape.
2721
2721
  *
2722
- * @param {SVGPathCommander.pathArray} path the shape `pathArray`
2723
- * @returns {SVGPathCommander.pathBBox} the length of the cubic-bezier segment
2722
+ * @param {SVGPath.pathArray} path the shape `pathArray`
2723
+ * @returns {SVGPath.pathBBox} the length of the cubic-bezier segment
2724
2724
  */
2725
2725
  function getPathBBox(path) {
2726
2726
  if (!path) {
@@ -2777,6 +2777,254 @@ function getPathBBox(path) {
2777
2777
  };
2778
2778
  }
2779
2779
 
2780
+ /**
2781
+ * Returns the length of an A (arc-to) segment
2782
+ * or an {x,y} point at a given length.
2783
+ *
2784
+ * @param {number} X1 the starting x position
2785
+ * @param {number} Y1 the starting y position
2786
+ * @param {number} RX x-radius of the arc
2787
+ * @param {number} RY y-radius of the arc
2788
+ * @param {number} angle x-axis-rotation of the arc
2789
+ * @param {number} LAF large-arc-flag of the arc
2790
+ * @param {number} SF sweep-flag of the arc
2791
+ * @param {number} X2 the ending x position
2792
+ * @param {number} Y2 the ending y position
2793
+ * @param {number} distance the point distance
2794
+ * @returns {{x: number, y: number} | number} the segment length or point
2795
+ */
2796
+ function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) {
2797
+ const cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2);
2798
+ const distanceIsNumber = typeof distance === 'number';
2799
+ let [x, y] = [X1, Y1];
2800
+ const lengthMargin = 0.001;
2801
+ let totalLength = 0;
2802
+ let cubicSubseg = [];
2803
+ let argsc = [];
2804
+ let segLen = 0;
2805
+
2806
+ if (distanceIsNumber && distance < lengthMargin) {
2807
+ return { x, y };
2808
+ }
2809
+
2810
+ for (let i = 0, ii = cubicSeg.length; i < ii; i += 6) {
2811
+ cubicSubseg = cubicSeg.slice(i, i + 6);
2812
+ argsc = [x, y, ...cubicSubseg];
2813
+ // @ts-ignore
2814
+ segLen = segmentCubicFactory(...argsc);
2815
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2816
+ // @ts-ignore -- this is a `cubicSegment`
2817
+ return segmentCubicFactory(...argsc, distance - totalLength);
2818
+ }
2819
+ totalLength += segLen;
2820
+ [x, y] = cubicSubseg.slice(-2);
2821
+ }
2822
+
2823
+ if (distanceIsNumber && distance >= totalLength) {
2824
+ return { x: X2, y: Y2 };
2825
+ }
2826
+
2827
+ return totalLength;
2828
+ }
2829
+
2830
+ /**
2831
+ * Returns the {x,y} coordinates of a point at a
2832
+ * given length of a quad-bezier segment.
2833
+ *
2834
+ * @see https://github.com/substack/point-at-length
2835
+ *
2836
+ * @param {number} x1 the starting point X
2837
+ * @param {number} y1 the starting point Y
2838
+ * @param {number} cx the control point X
2839
+ * @param {number} cy the control point Y
2840
+ * @param {number} x2 the ending point X
2841
+ * @param {number} y2 the ending point Y
2842
+ * @param {number} t a [0-1] ratio
2843
+ * @returns {{x: number, y: number}} the requested {x,y} coordinates
2844
+ */
2845
+ function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) {
2846
+ const t1 = 1 - t;
2847
+ return {
2848
+ x: (t1 ** 2) * x1
2849
+ + 2 * t1 * t * cx
2850
+ + (t ** 2) * x2,
2851
+ y: (t1 ** 2) * y1
2852
+ + 2 * t1 * t * cy
2853
+ + (t ** 2) * y2,
2854
+ };
2855
+ }
2856
+
2857
+ /**
2858
+ * Returns the Q (quadratic-bezier) segment length
2859
+ * or an {x,y} point at a given length.
2860
+ *
2861
+ * @param {number} x1 the starting point X
2862
+ * @param {number} y1 the starting point Y
2863
+ * @param {number} qx the control point X
2864
+ * @param {number} qy the control point Y
2865
+ * @param {number} x2 the ending point X
2866
+ * @param {number} y2 the ending point Y
2867
+ * @param {number=} distance the distance to point
2868
+ * @returns {{x: number, y: number} | number} the segment length or point
2869
+ */
2870
+ function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) {
2871
+ const distanceIsNumber = typeof distance === 'number';
2872
+ const lengthMargin = 0.001;
2873
+ let x = x1; let y = y1;
2874
+ let totalLength = 0;
2875
+ let prev = [x1, y1, totalLength];
2876
+ /** @type {[number, number]} */
2877
+ let cur = [x1, y1];
2878
+ let t = 0;
2879
+
2880
+ if (distanceIsNumber && distance < lengthMargin) {
2881
+ return { x, y };
2882
+ }
2883
+
2884
+ const n = 100;
2885
+ for (let j = 0; j <= n; j += 1) {
2886
+ t = j / n;
2887
+
2888
+ ({ x, y } = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t));
2889
+ totalLength += distanceSquareRoot(cur, [x, y]);
2890
+ cur = [x, y];
2891
+
2892
+ if (distanceIsNumber && totalLength >= distance) {
2893
+ const dv = (totalLength - distance) / (totalLength - prev[2]);
2894
+
2895
+ return {
2896
+ x: cur[0] * (1 - dv) + prev[0] * dv,
2897
+ y: cur[1] * (1 - dv) + prev[1] * dv,
2898
+ };
2899
+ }
2900
+ prev = [x, y, totalLength];
2901
+ }
2902
+ if (distanceIsNumber && distance >= totalLength) {
2903
+ return { x: x2, y: y2 };
2904
+ }
2905
+ return totalLength;
2906
+ }
2907
+
2908
+ /**
2909
+ * Returns a {x,y} point at a given length
2910
+ * of a shape or the shape total length.
2911
+ *
2912
+ * @param {string | SVGPath.pathArray} pathInput the `pathArray` to look into
2913
+ * @param {number=} distance the length of the shape to look at
2914
+ * @returns {{x: number, y: number} | number} the total length or point
2915
+ */
2916
+ function pathLengthFactory(pathInput, distance) {
2917
+ const path = fixPath(normalizePath(pathInput));
2918
+ const distanceIsNumber = typeof distance === 'number';
2919
+ let totalLength = 0;
2920
+ let isM = true;
2921
+ /** @type {number[]} */
2922
+ let data = [];
2923
+ let pathCommand = 'M';
2924
+ let segLen = 0;
2925
+ let x = 0;
2926
+ let y = 0;
2927
+ let mx = 0;
2928
+ let my = 0;
2929
+ let seg;
2930
+
2931
+ for (let i = 0, ll = path.length; i < ll; i += 1) {
2932
+ seg = path[i];
2933
+ [pathCommand] = seg;
2934
+ isM = pathCommand === 'M';
2935
+ // @ts-ignore
2936
+ data = !isM ? [x, y, ...seg.slice(1)] : data;
2937
+
2938
+ // this segment is always ZERO
2939
+ if (isM) {
2940
+ // remember mx, my for Z
2941
+ // @ts-ignore
2942
+ [, mx, my] = seg;
2943
+ if (distanceIsNumber && distance < 0.001) {
2944
+ return { x: mx, y: my };
2945
+ }
2946
+ } else if (pathCommand === 'L') {
2947
+ // @ts-ignore
2948
+ segLen = segmentLineFactory(...data);
2949
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2950
+ // @ts-ignore
2951
+ return segmentLineFactory(...data, distance - totalLength);
2952
+ }
2953
+ totalLength += segLen;
2954
+ } else if (pathCommand === 'A') {
2955
+ // @ts-ignore
2956
+ segLen = segmentArcFactory(...data);
2957
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2958
+ // @ts-ignore
2959
+ return segmentArcFactory(...data, distance - totalLength);
2960
+ }
2961
+ totalLength += segLen;
2962
+ } else if (pathCommand === 'C') {
2963
+ // @ts-ignore
2964
+ segLen = segmentCubicFactory(...data);
2965
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2966
+ // @ts-ignore
2967
+ return segmentCubicFactory(...data, distance - totalLength);
2968
+ }
2969
+ totalLength += segLen;
2970
+ } else if (pathCommand === 'Q') {
2971
+ // @ts-ignore
2972
+ segLen = segmentQuadFactory(...data);
2973
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2974
+ // @ts-ignore
2975
+ return segmentQuadFactory(...data, distance - totalLength);
2976
+ }
2977
+ totalLength += segLen;
2978
+ } else if (pathCommand === 'Z') {
2979
+ data = [x, y, mx, my];
2980
+ // @ts-ignore
2981
+ segLen = segmentLineFactory(...data);
2982
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2983
+ // @ts-ignore
2984
+ return segmentLineFactory(...data, distance - totalLength);
2985
+ }
2986
+ totalLength += segLen;
2987
+ }
2988
+
2989
+ // @ts-ignore -- needed for the below
2990
+ [x, y] = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my];
2991
+ }
2992
+
2993
+ // native `getPointAtLength` behavior when the given distance
2994
+ // is higher than total length
2995
+ if (distanceIsNumber && distance >= totalLength) {
2996
+ return { x, y };
2997
+ }
2998
+
2999
+ return totalLength;
3000
+ }
3001
+
3002
+ /**
3003
+ * Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
3004
+ *
3005
+ * The `normalizePath` version is lighter, faster, more efficient and more accurate
3006
+ * with paths that are not `curveArray`.
3007
+ *
3008
+ * @param {string | SVGPath.pathArray} pathInput the target `pathArray`
3009
+ * @returns {number} the shape total length
3010
+ */
3011
+ function getTotalLength(pathInput) {
3012
+ // @ts-ignore - it's fine
3013
+ return pathLengthFactory(pathInput);
3014
+ }
3015
+
3016
+ /**
3017
+ * Returns [x,y] coordinates of a point at a given length of a shape.
3018
+ *
3019
+ * @param {string | SVGPath.pathArray} pathInput the `pathArray` to look into
3020
+ * @param {number} distance the length of the shape to look at
3021
+ * @returns {{x: number, y: number}} the requested {x, y} point coordinates
3022
+ */
3023
+ function getPointAtLength(pathInput, distance) {
3024
+ // @ts-ignore
3025
+ return pathLengthFactory(pathInput, distance);
3026
+ }
3027
+
2780
3028
  /**
2781
3029
  * Creates a new SVGPathCommander instance with the following properties:
2782
3030
  * * segments: `pathArray`
@@ -2796,18 +3044,25 @@ class SVGPathCommander {
2796
3044
  constructor(pathValue, config) {
2797
3045
  const instanceOptions = config || {};
2798
3046
 
3047
+ const undefPath = typeof pathValue === 'undefined';
3048
+
3049
+ if (undefPath || !pathValue.length) {
3050
+ throw TypeError(`${error}: "pathValue" is ${undefPath ? 'undefined' : 'empty'}`);
3051
+ }
3052
+
3053
+ const segments = parsePathString(pathValue);
3054
+ if (typeof segments === 'string') {
3055
+ throw TypeError(segments);
3056
+ }
3057
+
2799
3058
  /**
2800
- * @type {SVGPathCommander.pathArray}
3059
+ * @type {SVGPath.pathArray}
2801
3060
  */
2802
- this.segments = parsePathString(pathValue);
2803
- const BBox = getPathBBox(this.segments);
3061
+ this.segments = segments;
3062
+
2804
3063
  const {
2805
- width,
2806
- height,
2807
- cx,
2808
- cy,
2809
- cz,
2810
- } = BBox;
3064
+ width, height, cx, cy, cz,
3065
+ } = this.getBBox();
2811
3066
 
2812
3067
  // set instance options.round
2813
3068
  let { round, origin } = defaultOptions;
@@ -2816,7 +3071,7 @@ class SVGPathCommander {
2816
3071
  if (roundOption === 'auto') {
2817
3072
  const pathScale = (`${Math.floor(Math.max(width, height))}`).length;
2818
3073
  round = pathScale >= 4 ? 0 : 4 - pathScale;
2819
- } else if ((Number.isInteger(roundOption) && roundOption >= 1) || roundOption === false) {
3074
+ } else if (Number.isInteger(roundOption) || roundOption === false) {
2820
3075
  round = roundOption;
2821
3076
  }
2822
3077
 
@@ -2826,15 +3081,14 @@ class SVGPathCommander {
2826
3081
  origin = [
2827
3082
  !Number.isNaN(originX) ? originX : cx,
2828
3083
  !Number.isNaN(originY) ? originY : cy,
2829
- originZ || cz,
3084
+ !Number.isNaN(originZ) ? originZ : cz,
2830
3085
  ];
2831
3086
  } else {
2832
3087
  origin = [cx, cy, cz];
2833
3088
  }
2834
3089
 
2835
3090
  /**
2836
- * @type {number | boolean}
2837
- * @default 4
3091
+ * @type {number | false}
2838
3092
  */
2839
3093
  this.round = round;
2840
3094
  this.origin = origin;
@@ -2842,6 +3096,36 @@ class SVGPathCommander {
2842
3096
  return this;
2843
3097
  }
2844
3098
 
3099
+ /**
3100
+ * Returns the path bounding box, equivalent to native `path.getBBox()`.
3101
+ * @public
3102
+ * @returns {SVGPath.pathBBox}
3103
+ */
3104
+ getBBox() {
3105
+ return getPathBBox(this.segments);
3106
+ }
3107
+
3108
+ /**
3109
+ * Returns the total path length, equivalent to native `path.getTotalLength()`.
3110
+ * @public
3111
+ * @returns {number}
3112
+ */
3113
+ getTotalLength() {
3114
+ return getTotalLength(this.segments);
3115
+ }
3116
+
3117
+ /**
3118
+ * Returns an `{x,y}` point in the path stroke at a given length,
3119
+ * equivalent to the native `path.getPointAtLength()`.
3120
+ *
3121
+ * @public
3122
+ * @param {number} length the length
3123
+ * @returns {{x: number, y:number}} the requested point
3124
+ */
3125
+ getPointAtLength(length) {
3126
+ return getPointAtLength(this.segments, length);
3127
+ }
3128
+
2845
3129
  /**
2846
3130
  * Convert path to absolute values
2847
3131
  * @public
@@ -2933,16 +3217,16 @@ class SVGPathCommander {
2933
3217
 
2934
3218
  /**
2935
3219
  * Transform path using values from an `Object` defined as `transformObject`.
2936
- * @see SVGPathCommander.transformObject for a quick refference
3220
+ * @see SVGPath.transformObject for a quick refference
2937
3221
  *
2938
- * @param {SVGPathCommander.transformObject} source a `transformObject`as described above
3222
+ * @param {SVGPath.transformObject} source a `transformObject`as described above
2939
3223
  * @public
2940
3224
  */
2941
3225
  transform(source) {
2942
3226
  if (!source || typeof source !== 'object' || (typeof source === 'object'
2943
3227
  && !['translate', 'rotate', 'skew', 'scale'].some((x) => x in source))) return this;
2944
3228
 
2945
- /** @type {SVGPathCommander.transformObject} */
3229
+ /** @type {SVGPath.transformObject} */
2946
3230
  const transform = {};
2947
3231
  Object.keys(source).forEach((fn) => {
2948
3232
  // @ts-ignore
@@ -2952,18 +3236,18 @@ class SVGPathCommander {
2952
3236
 
2953
3237
  // if origin is not specified
2954
3238
  // it's important that we have one
3239
+ const [cx, cy, cz] = this.origin;
2955
3240
  const { origin } = transform;
2956
- if (origin && origin.length >= 2) {
3241
+
3242
+ if (Array.isArray(origin) && origin.length >= 2) {
2957
3243
  const [originX, originY, originZ] = origin.map(Number);
2958
- const [cx, cy, cz] = this.origin;
2959
3244
  transform.origin = [
2960
3245
  !Number.isNaN(originX) ? originX : cx,
2961
3246
  !Number.isNaN(originY) ? originY : cy,
2962
3247
  originZ || cz,
2963
3248
  ];
2964
3249
  } else {
2965
- // @ts-ignore
2966
- transform.origin = { ...this.origin };
3250
+ transform.origin = [cx, cy, cz];
2967
3251
  }
2968
3252
 
2969
3253
  this.segments = transformPath(segments, transform);
@@ -3026,7 +3310,7 @@ function getCubicSegArea(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
3026
3310
  *
3027
3311
  * @see https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
3028
3312
  *
3029
- * @param {SVGPathCommander.pathArray} path the shape `pathArray`
3313
+ * @param {SVGPath.pathArray} path the shape `pathArray`
3030
3314
  * @returns {number} the length of the cubic-bezier segment
3031
3315
  */
3032
3316
  function getPathArea(path) {
@@ -3053,7 +3337,7 @@ function getPathArea(path) {
3053
3337
  * This is the `pathToCurve` version which is faster and more efficient for
3054
3338
  * paths that are `curveArray`.
3055
3339
  *
3056
- * @param {string | SVGPathCommander.curveArray} path the target `pathArray`
3340
+ * @param {string | SVGPath.curveArray} path the target `pathArray`
3057
3341
  * @returns {number} the `curveArray` total length
3058
3342
  */
3059
3343
  function getPathLength(path) {
@@ -3066,243 +3350,11 @@ function getPathLength(path) {
3066
3350
  return totalLength;
3067
3351
  }
3068
3352
 
3069
- /**
3070
- * Returns the length of a A (arc-to) segment,
3071
- * or an {x,y} point at a given length.
3072
- *
3073
- * @param {number} X1 the starting x position
3074
- * @param {number} Y1 the starting y position
3075
- * @param {number} RX x-radius of the arc
3076
- * @param {number} RY y-radius of the arc
3077
- * @param {number} angle x-axis-rotation of the arc
3078
- * @param {number} LAF large-arc-flag of the arc
3079
- * @param {number} SF sweep-flag of the arc
3080
- * @param {number} X2 the ending x position
3081
- * @param {number} Y2 the ending y position
3082
- * @param {number} distance the point distance
3083
- * @returns {{x: number, y: number} | number} the segment length or point
3084
- */
3085
- function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) {
3086
- let [x, y] = [X1, Y1];
3087
- const cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2);
3088
- const lengthMargin = 0.001;
3089
- let totalLength = 0;
3090
- let cubicSubseg = [];
3091
- let argsc = [];
3092
- let segLen = 0;
3093
-
3094
- if (typeof distance === 'number' && distance < lengthMargin) {
3095
- return { x, y };
3096
- }
3097
-
3098
- for (let i = 0, ii = cubicSeg.length; i < ii; i += 6) {
3099
- cubicSubseg = cubicSeg.slice(i, i + 6);
3100
- argsc = [x, y, ...cubicSubseg];
3101
- // @ts-ignore
3102
- segLen = segmentCubicFactory(...argsc);
3103
- if (typeof distance === 'number' && totalLength + segLen >= distance) {
3104
- // @ts-ignore -- this is a `cubicSegment`
3105
- return segmentCubicFactory(...argsc, distance - totalLength);
3106
- }
3107
- totalLength += segLen;
3108
- [x, y] = cubicSubseg.slice(-2);
3109
- }
3110
-
3111
- if (typeof distance === 'number' && distance >= totalLength) {
3112
- return { x: X2, y: Y2 };
3113
- }
3114
-
3115
- return totalLength;
3116
- }
3117
-
3118
- /**
3119
- * Returns the {x,y} coordinates of a point at a
3120
- * given length of a quad-bezier segment.
3121
- *
3122
- * @see https://github.com/substack/point-at-length
3123
- *
3124
- * @param {number} x1 the starting point X
3125
- * @param {number} y1 the starting point Y
3126
- * @param {number} cx the control point X
3127
- * @param {number} cy the control point Y
3128
- * @param {number} x2 the ending point X
3129
- * @param {number} y2 the ending point Y
3130
- * @param {number} t a [0-1] ratio
3131
- * @returns {{x: number, y: number}} the requested {x,y} coordinates
3132
- */
3133
- function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) {
3134
- const t1 = 1 - t;
3135
- return {
3136
- x: (t1 ** 2) * x1
3137
- + 2 * t1 * t * cx
3138
- + (t ** 2) * x2,
3139
- y: (t1 ** 2) * y1
3140
- + 2 * t1 * t * cy
3141
- + (t ** 2) * y2,
3142
- };
3143
- }
3144
-
3145
- /**
3146
- * Returns the Q (quadratic-bezier) segment length,
3147
- * or an {x,y} point at a given length.
3148
- *
3149
- * @param {number} x1 the starting point X
3150
- * @param {number} y1 the starting point Y
3151
- * @param {number} qx the control point X
3152
- * @param {number} qy the control point Y
3153
- * @param {number} x2 the ending point X
3154
- * @param {number} y2 the ending point Y
3155
- * @param {number=} distance the distance to point
3156
- * @returns {{x: number, y: number} | number} the segment length or point
3157
- */
3158
- function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) {
3159
- let x = x1; let y = y1;
3160
- const lengthMargin = 0.001;
3161
- let totalLength = 0;
3162
- let prev = [x1, y1, totalLength];
3163
- /** @type {[number, number]} */
3164
- let cur = [x1, y1];
3165
- let t = 0;
3166
-
3167
- if (typeof distance === 'number' && distance < lengthMargin) {
3168
- return { x, y };
3169
- }
3170
-
3171
- const n = 100;
3172
- for (let j = 0; j <= n; j += 1) {
3173
- t = j / n;
3174
-
3175
- ({ x, y } = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t));
3176
- totalLength += distanceSquareRoot(cur, [x, y]);
3177
- cur = [x, y];
3178
-
3179
- if (typeof distance === 'number' && totalLength >= distance) {
3180
- const dv = (totalLength - distance) / (totalLength - prev[2]);
3181
-
3182
- return {
3183
- x: cur[0] * (1 - dv) + prev[0] * dv,
3184
- y: cur[1] * (1 - dv) + prev[1] * dv,
3185
- };
3186
- }
3187
- prev = [x, y, totalLength];
3188
- }
3189
- if (typeof distance === 'number' && distance >= totalLength) {
3190
- return { x: x2, y: y2 };
3191
- }
3192
- return totalLength;
3193
- }
3194
-
3195
- /**
3196
- * Returns a {x,y} point at a given length of a shape or the shape total length.
3197
- *
3198
- * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
3199
- * @param {number=} distance the length of the shape to look at
3200
- * @returns {{x: number, y: number} | number} the total length or point
3201
- */
3202
- function pathLengthFactory(pathInput, distance) {
3203
- let totalLength = 0;
3204
- let isM = true;
3205
- /** @type {number[]} */
3206
- let data = [];
3207
- let pathCommand = 'M';
3208
- let segLen = 0;
3209
- let x = 0;
3210
- let y = 0;
3211
- let mx = 0;
3212
- let my = 0;
3213
- let seg;
3214
- const path = fixPath(normalizePath(pathInput));
3215
-
3216
- for (let i = 0, ll = path.length; i < ll; i += 1) {
3217
- seg = path[i];
3218
- [pathCommand] = seg;
3219
- isM = pathCommand === 'M';
3220
- // @ts-ignore
3221
- data = !isM ? [x, y, ...seg.slice(1)] : data;
3222
-
3223
- // this segment is always ZERO
3224
- if (isM) {
3225
- // remember mx, my for Z
3226
- // @ts-ignore
3227
- [, mx, my] = seg;
3228
- if (typeof distance === 'number' && distance < 0.001) {
3229
- return { x: mx, y: my };
3230
- }
3231
- } else if (pathCommand === 'L') {
3232
- // @ts-ignore
3233
- segLen = segmentLineFactory(...data);
3234
- if (distance && totalLength + segLen >= distance) {
3235
- // @ts-ignore
3236
- return segmentLineFactory(...data, distance - totalLength);
3237
- }
3238
- totalLength += segLen;
3239
- } else if (pathCommand === 'A') {
3240
- // @ts-ignore
3241
- segLen = segmentArcFactory(...data);
3242
- if (distance && totalLength + segLen >= distance) {
3243
- // @ts-ignore
3244
- return segmentArcFactory(...data, distance - totalLength);
3245
- }
3246
- totalLength += segLen;
3247
- } else if (pathCommand === 'C') {
3248
- // @ts-ignore
3249
- segLen = segmentCubicFactory(...data);
3250
- if (distance && totalLength + segLen >= distance) {
3251
- // @ts-ignore
3252
- return segmentCubicFactory(...data, distance - totalLength);
3253
- }
3254
- totalLength += segLen;
3255
- } else if (pathCommand === 'Q') {
3256
- // @ts-ignore
3257
- segLen = segmentQuadFactory(...data);
3258
- if (distance && totalLength + segLen >= distance) {
3259
- // @ts-ignore
3260
- return segmentQuadFactory(...data, distance - totalLength);
3261
- }
3262
- totalLength += segLen;
3263
- } else if (pathCommand === 'Z') {
3264
- data = [x, y, mx, my];
3265
- // @ts-ignore
3266
- segLen = segmentLineFactory(...data);
3267
- if (distance && totalLength + segLen >= distance) {
3268
- // @ts-ignore
3269
- return segmentLineFactory(...data, distance - totalLength);
3270
- }
3271
- totalLength += segLen;
3272
- }
3273
-
3274
- // @ts-ignore -- needed for the below
3275
- [x, y] = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my];
3276
- }
3277
-
3278
- // native `getPointAtLength` behavior when the given distance
3279
- // is higher than total length
3280
- if (distance && distance >= totalLength) {
3281
- return { x, y };
3282
- }
3283
-
3284
- return totalLength;
3285
- }
3286
-
3287
- /**
3288
- * Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
3289
- *
3290
- * The `normalizePath` version is lighter, faster, more efficient and more accurate
3291
- * with paths that are not `curveArray`.
3292
- *
3293
- * @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray`
3294
- * @returns {number} the shape total length
3295
- */
3296
- function getTotalLength(pathInput) {
3297
- // @ts-ignore - it's fine
3298
- return pathLengthFactory(pathInput);
3299
- }
3300
-
3301
3353
  /**
3302
3354
  * Check if a path is drawn clockwise and returns true if so,
3303
3355
  * false otherwise.
3304
3356
  *
3305
- * @param {SVGPathCommander.pathArray} path the path string or `pathArray`
3357
+ * @param {SVGPath.pathArray} path the path string or `pathArray`
3306
3358
  * @returns {boolean} true when clockwise or false if not
3307
3359
  */
3308
3360
  function getDrawDirection(path) {
@@ -3310,37 +3362,12 @@ function getDrawDirection(path) {
3310
3362
  }
3311
3363
 
3312
3364
  /**
3313
- * Returns [x,y] coordinates of a point at a given length of a shape.
3314
- *
3315
- * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
3316
- * @param {number} distance the length of the shape to look at
3317
- * @returns {{x: number, y: number}} the requested {x, y} point coordinates
3318
- */
3319
- function getPointAtLength(pathInput, distance) {
3320
- // @ts-ignore
3321
- return pathLengthFactory(pathInput, distance);
3322
- }
3323
-
3324
- /**
3325
- * Returns [x,y] coordinates of a point at a given length of a shape.
3326
- * `pathToCurve` version.
3365
+ * Returns the segment, its index and length as well as
3366
+ * the length to that segment at a given length in a path.
3327
3367
  *
3328
- * @deprecated
3329
- *
3330
- * @param {string | SVGPathCommander.pathArray} pathInput the `pathArray` to look into
3331
- * @param {number} distance the length of the shape to look at
3332
- * @returns {{x: number, y: number}} the requested {x, y} point coordinates
3333
- */
3334
- function getPointAtPathLength(pathInput, distance) {
3335
- return getPointAtLength(pathInput, distance);
3336
- }
3337
-
3338
- /**
3339
- * Returns the properties at a given length in path.
3340
- *
3341
- * @param {string | SVGPathCommander.pathArray} pathInput target `pathArray`
3368
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3342
3369
  * @param {number=} distance the given length
3343
- * @returns {SVGPathCommander.segmentProperties=} the requested properties
3370
+ * @returns {SVGPath.segmentProperties=} the requested properties
3344
3371
  */
3345
3372
  function getPropertiesAtLength(pathInput, distance) {
3346
3373
  const pathArray = parsePathString(pathInput);
@@ -3352,7 +3379,7 @@ function getPropertiesAtLength(pathInput, distance) {
3352
3379
  let index = pathTemp.length - 1;
3353
3380
  let lengthAtSegment = 0;
3354
3381
  let length = 0;
3355
- /** @type {SVGPathCommander.pathSegment} */
3382
+ /** @type {SVGPath.pathSegment} */
3356
3383
  let segment = pathArray[0];
3357
3384
  const [x, y] = segment.slice(-2);
3358
3385
  const point = { x, y };
@@ -3396,12 +3423,13 @@ function getPropertiesAtLength(pathInput, distance) {
3396
3423
  }
3397
3424
 
3398
3425
  /**
3399
- * Returns the point in path closest to a given point.
3426
+ * Returns the point and segment in path closest to a given point as well as
3427
+ * the distance to the path stroke.
3400
3428
  * @see https://bl.ocks.org/mbostock/8027637
3401
3429
  *
3402
- * @param {string | SVGPathCommander.pathArray} pathInput target `pathArray`
3430
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3403
3431
  * @param {{x: number, y: number}} point the given point
3404
- * @returns {SVGPathCommander.pointProperties} the requested properties
3432
+ * @returns {SVGPath.pointProperties} the requested properties
3405
3433
  */
3406
3434
  function getPropertiesAtPoint(pathInput, point) {
3407
3435
  const path = fixPath(parsePathString(pathInput));
@@ -3460,7 +3488,7 @@ function getPropertiesAtPoint(pathInput, point) {
3460
3488
  }
3461
3489
  }
3462
3490
 
3463
- const segment = getPropertiesAtLength(path, bestDistance);
3491
+ const segment = getPropertiesAtLength(path, bestLength);
3464
3492
  const distance = Math.sqrt(bestDistance);
3465
3493
 
3466
3494
  return { closest, distance, segment };
@@ -3469,7 +3497,7 @@ function getPropertiesAtPoint(pathInput, point) {
3469
3497
  /**
3470
3498
  * Returns the point in path closest to a given point.
3471
3499
  *
3472
- * @param {string | SVGPathCommander.pathArray} pathInput target `pathArray`
3500
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3473
3501
  * @param {{x: number, y: number}} point the given point
3474
3502
  * @returns {{x: number, y: number}} the best match
3475
3503
  */
@@ -3480,9 +3508,9 @@ function getClosestPoint(pathInput, point) {
3480
3508
  /**
3481
3509
  * Returns the path segment which contains a given point.
3482
3510
  *
3483
- * @param {string | SVGPathCommander.pathArray} path the `pathArray` to look into
3511
+ * @param {string | SVGPath.pathArray} path the `pathArray` to look into
3484
3512
  * @param {{x: number, y: number}} point the point of the shape to look for
3485
- * @returns {SVGPathCommander.pathSegment?} the requested segment
3513
+ * @returns {SVGPath.pathSegment?} the requested segment
3486
3514
  */
3487
3515
  function getSegmentOfPoint(path, point) {
3488
3516
  const props = getPropertiesAtPoint(path, point);
@@ -3492,9 +3520,9 @@ function getSegmentOfPoint(path, point) {
3492
3520
 
3493
3521
  /**
3494
3522
  * Returns the segment at a given length.
3495
- * @param {string | SVGPathCommander.pathArray} pathInput the target `pathArray`
3523
+ * @param {string | SVGPath.pathArray} pathInput the target `pathArray`
3496
3524
  * @param {number} distance the distance in path to look at
3497
- * @returns {SVGPathCommander.pathSegment?} the requested segment
3525
+ * @returns {SVGPath.pathSegment?} the requested segment
3498
3526
  */
3499
3527
  function getSegmentAtLength(pathInput, distance) {
3500
3528
  const props = getPropertiesAtLength(pathInput, distance);
@@ -3505,8 +3533,8 @@ function getSegmentAtLength(pathInput, distance) {
3505
3533
  /**
3506
3534
  * Checks if a given point is in the stroke of a path.
3507
3535
  *
3508
- * @param {string | SVGPathCommander.pathArray} pathInput target path
3509
- * @param {{x: number, y: number}} point
3536
+ * @param {string | SVGPath.pathArray} pathInput target path
3537
+ * @param {{x: number, y: number}} point the given `{x,y}` point
3510
3538
  * @returns {boolean} the query result
3511
3539
  */
3512
3540
  function isPointInStroke(pathInput, point) {
@@ -3553,8 +3581,8 @@ const shapeParams = {
3553
3581
  /**
3554
3582
  * Returns a new `pathArray` from line attributes.
3555
3583
  *
3556
- * @param {SVGPathCommander.lineAttr} attr shape configuration
3557
- * @returns {SVGPathCommander.pathArray} a new line `pathArray`
3584
+ * @param {SVGPath.lineAttr} attr shape configuration
3585
+ * @returns {SVGPath.pathArray} a new line `pathArray`
3558
3586
  */
3559
3587
  function getLinePath(attr) {
3560
3588
  const {
@@ -3566,14 +3594,14 @@ function getLinePath(attr) {
3566
3594
  /**
3567
3595
  * Returns a new `pathArray` like from polyline/polygon attributes.
3568
3596
  *
3569
- * @param {SVGPathCommander.polyAttr} attr shape configuration
3570
- * @return {SVGPathCommander.pathArray} a new polygon/polyline `pathArray`
3597
+ * @param {SVGPath.polyAttr} attr shape configuration
3598
+ * @return {SVGPath.pathArray} a new polygon/polyline `pathArray`
3571
3599
  */
3572
3600
  function getPolyPath(attr) {
3573
- /** @type {SVGPathCommander.pathArray} */
3601
+ /** @type {SVGPath.pathArray} */
3574
3602
  // @ts-ignore -- it's an empty `pathArray`
3575
3603
  const pathArray = [];
3576
- const points = attr.points.split(/[\s|,]/).map(Number);
3604
+ const points = attr.points.trim().split(/[\s|,]/).map(Number);
3577
3605
 
3578
3606
  let index = 0;
3579
3607
  while (index < points.length) {
@@ -3587,8 +3615,8 @@ function getPolyPath(attr) {
3587
3615
  /**
3588
3616
  * Returns a new `pathArray` from circle attributes.
3589
3617
  *
3590
- * @param {SVGPathCommander.circleAttr} attr shape configuration
3591
- * @return {SVGPathCommander.pathArray} a circle `pathArray`
3618
+ * @param {SVGPath.circleAttr} attr shape configuration
3619
+ * @return {SVGPath.pathArray} a circle `pathArray`
3592
3620
  */
3593
3621
  function getCirclePath(attr) {
3594
3622
  const {
@@ -3605,8 +3633,8 @@ function getCirclePath(attr) {
3605
3633
  /**
3606
3634
  * Returns a new `pathArray` from ellipse attributes.
3607
3635
  *
3608
- * @param {SVGPathCommander.ellipseAttr} attr shape configuration
3609
- * @return {SVGPathCommander.pathArray} an ellipse `pathArray`
3636
+ * @param {SVGPath.ellipseAttr} attr shape configuration
3637
+ * @return {SVGPath.pathArray} an ellipse `pathArray`
3610
3638
  */
3611
3639
  function getEllipsePath(attr) {
3612
3640
  const {
@@ -3623,8 +3651,8 @@ function getEllipsePath(attr) {
3623
3651
  /**
3624
3652
  * Returns a new `pathArray` like from rect attributes.
3625
3653
  *
3626
- * @param {SVGPathCommander.rectAttr} attr object with properties above
3627
- * @return {SVGPathCommander.pathArray} a new `pathArray` from `<rect>` attributes
3654
+ * @param {SVGPath.rectAttr} attr object with properties above
3655
+ * @return {SVGPath.pathArray} a new `pathArray` from `<rect>` attributes
3628
3656
  */
3629
3657
  function getRectanglePath(attr) {
3630
3658
  const x = +attr.x || 0;
@@ -3670,12 +3698,12 @@ function getRectanglePath(attr) {
3670
3698
  * is `true`, it will replace the target.
3671
3699
  *
3672
3700
  * It can also work with an options object,
3673
- * @see SVGPathCommander.shapeOps
3701
+ * @see SVGPath.shapeOps
3674
3702
  *
3675
3703
  * The newly created `<path>` element keeps all non-specific
3676
3704
  * attributes like `class`, `fill`, etc.
3677
3705
  *
3678
- * @param {SVGPathCommander.shapeTypes | SVGPathCommander.shapeOps} element target shape
3706
+ * @param {SVGPath.shapeTypes | SVGPath.shapeOps} element target shape
3679
3707
  * @param {boolean=} replace option to replace target
3680
3708
  * @return {SVGPathElement | boolean} the newly created `<path>` element
3681
3709
  */
@@ -3729,11 +3757,11 @@ function shapeToPath(element, replace) {
3729
3757
  }
3730
3758
 
3731
3759
  /**
3732
- * Reverses all segments and their values from a `pathArray`
3760
+ * Reverses all segments of a `pathArray`
3733
3761
  * which consists of only C (cubic-bezier) path commands.
3734
3762
  *
3735
- * @param {SVGPathCommander.curveArray} path the source `pathArray`
3736
- * @returns {SVGPathCommander.curveArray} the reversed `pathArray`
3763
+ * @param {SVGPath.curveArray} path the source `pathArray`
3764
+ * @returns {SVGPath.curveArray} the reversed `pathArray`
3737
3765
  */
3738
3766
  function reverseCurve(path) {
3739
3767
  const rotatedCurve = path.slice(1)
@@ -3770,7 +3798,6 @@ const Util = {
3770
3798
  getTotalLength,
3771
3799
  getPathLength,
3772
3800
  getPointAtLength,
3773
- getPointAtPathLength,
3774
3801
  getClosestPoint,
3775
3802
  getSegmentOfPoint,
3776
3803
  getPropertiesAtPoint,
@@ -3790,7 +3817,7 @@ const Util = {
3790
3817
  options: defaultOptions,
3791
3818
  };
3792
3819
 
3793
- var version = "0.1.23";
3820
+ var version = "0.2.0alpha1";
3794
3821
 
3795
3822
  // @ts-ignore
3796
3823