svg-path-commander 1.0.5 → 2.0.0-alpha2

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 (131) hide show
  1. package/README.md +26 -4
  2. package/dist/svg-path-commander.cjs +2 -0
  3. package/dist/svg-path-commander.cjs.map +1 -0
  4. package/dist/svg-path-commander.d.ts +454 -0
  5. package/dist/svg-path-commander.js +2 -3762
  6. package/dist/svg-path-commander.js.map +1 -0
  7. package/dist/svg-path-commander.mjs +1194 -0
  8. package/dist/svg-path-commander.mjs.map +1 -0
  9. package/package.json +39 -42
  10. package/src/convert/pathToAbsolute.ts +101 -0
  11. package/src/convert/{pathToCurve.js → pathToCurve.ts} +12 -14
  12. package/src/convert/pathToRelative.ts +92 -0
  13. package/src/convert/pathToString.ts +17 -0
  14. package/src/{svg-path-commander.js → index.ts} +143 -66
  15. package/src/interface.ts +129 -0
  16. package/src/math/distanceSquareRoot.ts +13 -0
  17. package/src/math/midPoint.ts +16 -0
  18. package/src/math/{polygonArea.js → polygonArea.ts} +6 -4
  19. package/src/math/{polygonLength.js → polygonLength.ts} +5 -3
  20. package/src/math/rotateVector.ts +16 -0
  21. package/src/options/options.ts +9 -0
  22. package/src/parser/error.ts +2 -0
  23. package/src/parser/finalizeSegment.ts +31 -0
  24. package/src/parser/{invalidPathValue.js → invalidPathValue.ts} +0 -0
  25. package/src/parser/{isArcCommand.js → isArcCommand.ts} +5 -4
  26. package/src/parser/isDigit.ts +12 -0
  27. package/src/parser/isDigitStart.ts +14 -0
  28. package/src/parser/isPathCommand.ts +28 -0
  29. package/src/parser/isSpace.ts +23 -0
  30. package/src/parser/paramsCount.ts +16 -0
  31. package/src/parser/paramsParser.ts +14 -0
  32. package/src/parser/{parsePathString.js → parsePathString.ts} +13 -7
  33. package/src/parser/pathParser.ts +29 -0
  34. package/src/parser/{scanFlag.js → scanFlag.ts} +8 -5
  35. package/src/parser/{scanParam.js → scanParam.ts} +12 -11
  36. package/src/parser/{scanSegment.js → scanSegment.ts} +9 -5
  37. package/src/parser/{skipSpaces.js → skipSpaces.ts} +5 -3
  38. package/src/process/{arcToCubic.js → arcToCubic.ts} +42 -28
  39. package/src/process/fixArc.ts +23 -0
  40. package/src/process/getSVGMatrix.ts +70 -0
  41. package/src/process/lineToCubic.ts +17 -0
  42. package/src/process/{normalizePath.js → normalizePath.ts} +10 -10
  43. package/src/process/normalizeSegment.ts +47 -0
  44. package/src/process/{optimizePath.js → optimizePath.ts} +18 -21
  45. package/src/process/{projection2d.js → projection2d.ts} +16 -15
  46. package/src/process/quadToCubic.ts +31 -0
  47. package/src/process/reverseCurve.ts +21 -0
  48. package/src/process/reversePath.ts +101 -0
  49. package/src/process/roundPath.ts +29 -0
  50. package/src/process/segmentToCubic.ts +46 -0
  51. package/src/process/shortenSegment.ts +79 -0
  52. package/src/process/splitCubic.ts +28 -0
  53. package/src/process/{splitPath.js → splitPath.ts} +9 -8
  54. package/src/process/{transformPath.js → transformPath.ts} +55 -48
  55. package/src/types.ts +193 -0
  56. package/src/util/getClosestPoint.ts +15 -0
  57. package/src/util/{getDrawDirection.js → getDrawDirection.ts} +7 -4
  58. package/src/util/getPathArea.ts +70 -0
  59. package/src/util/{getPathBBox.js → getPathBBox.ts} +16 -5
  60. package/src/util/getPointAtLength.ts +14 -0
  61. package/src/util/{getPropertiesAtLength.js → getPropertiesAtLength.ts} +28 -19
  62. package/src/util/{getPropertiesAtPoint.js → getPropertiesAtPoint.ts} +16 -12
  63. package/src/util/getSegmentAtLength.ts +15 -0
  64. package/src/util/getSegmentOfPoint.ts +18 -0
  65. package/src/util/{getTotalLength.js → getTotalLength.ts} +6 -4
  66. package/src/util/isAbsoluteArray.ts +18 -0
  67. package/src/util/{isCurveArray.js → isCurveArray.ts} +6 -4
  68. package/src/util/{isNormalizedArray.js → isNormalizedArray.ts} +4 -2
  69. package/src/util/isPathArray.ts +19 -0
  70. package/src/util/isPointInStroke.ts +15 -0
  71. package/src/util/isRelativeArray.ts +18 -0
  72. package/src/util/{isValidPath.js → isValidPath.ts} +5 -4
  73. package/src/util/{pathLengthFactory.js → pathLengthFactory.ts} +38 -31
  74. package/src/util/{segmentArcFactory.js → segmentArcFactory.ts} +71 -55
  75. package/src/util/segmentCubicFactory.ts +114 -0
  76. package/src/util/{segmentLineFactory.js → segmentLineFactory.ts} +10 -8
  77. package/src/util/{segmentQuadFactory.js → segmentQuadFactory.ts} +47 -32
  78. package/src/util/shapeToPath.ts +214 -0
  79. package/dist/svg-path-commander.es5.js +0 -3875
  80. package/dist/svg-path-commander.es5.min.js +0 -2
  81. package/dist/svg-path-commander.esm.js +0 -3754
  82. package/dist/svg-path-commander.esm.min.js +0 -2
  83. package/dist/svg-path-commander.min.js +0 -2
  84. package/src/convert/pathToAbsolute.js +0 -86
  85. package/src/convert/pathToRelative.js +0 -84
  86. package/src/convert/pathToString.js +0 -14
  87. package/src/index.js +0 -10
  88. package/src/math/distanceSquareRoot.js +0 -14
  89. package/src/math/epsilon.js +0 -8
  90. package/src/math/midPoint.js +0 -13
  91. package/src/math/rotateVector.js +0 -14
  92. package/src/options/options.js +0 -10
  93. package/src/parser/error.js +0 -2
  94. package/src/parser/finalizeSegment.js +0 -28
  95. package/src/parser/isDigit.js +0 -9
  96. package/src/parser/isDigitStart.js +0 -13
  97. package/src/parser/isPathCommand.js +0 -25
  98. package/src/parser/isSpace.js +0 -16
  99. package/src/parser/paramsCount.js +0 -9
  100. package/src/parser/paramsParser.js +0 -8
  101. package/src/parser/pathParser.js +0 -24
  102. package/src/process/clonePath.js +0 -9
  103. package/src/process/fixArc.js +0 -21
  104. package/src/process/fixPath.js +0 -31
  105. package/src/process/getSVGMatrix.js +0 -61
  106. package/src/process/lineToCubic.js +0 -30
  107. package/src/process/normalizeSegment.js +0 -45
  108. package/src/process/quadToCubic.js +0 -22
  109. package/src/process/reverseCurve.js +0 -18
  110. package/src/process/reversePath.js +0 -89
  111. package/src/process/roundPath.js +0 -26
  112. package/src/process/segmentToCubic.js +0 -46
  113. package/src/process/shortenSegment.js +0 -58
  114. package/src/process/splitCubic.js +0 -26
  115. package/src/util/getClosestPoint.js +0 -12
  116. package/src/util/getPathArea.js +0 -47
  117. package/src/util/getPointAtLength.js +0 -12
  118. package/src/util/getSegmentAtLength.js +0 -11
  119. package/src/util/getSegmentOfPoint.js +0 -12
  120. package/src/util/isAbsoluteArray.js +0 -14
  121. package/src/util/isPathArray.js +0 -14
  122. package/src/util/isPointInStroke.js +0 -13
  123. package/src/util/isRelativeArray.js +0 -14
  124. package/src/util/segmentCubicFactory.js +0 -97
  125. package/src/util/shapeToPath.js +0 -204
  126. package/src/util/util.js +0 -82
  127. package/src/version.js +0 -8
  128. package/types/index.d.ts +0 -120
  129. package/types/more/modules.ts +0 -82
  130. package/types/more/svg.d.ts +0 -211
  131. package/types/svg-path-commander.d.ts +0 -1089
@@ -0,0 +1,101 @@
1
+ import parsePathString from '../parser/parsePathString';
2
+ import isAbsoluteArray from '../util/isAbsoluteArray';
3
+ import type {
4
+ PathArray,
5
+ AbsoluteArray,
6
+ AbsoluteCommand,
7
+ AbsoluteSegment,
8
+ VSegment,
9
+ HSegment,
10
+ QSegment,
11
+ TSegment,
12
+ ASegment,
13
+ SSegment,
14
+ CSegment,
15
+ MSegment,
16
+ } from '../types';
17
+
18
+ /**
19
+ * Parses a path string value or object and returns an array
20
+ * of segments, all converted to absolute values.
21
+ *
22
+ * @param pathInput the path string | object
23
+ * @returns the resulted `pathArray` with absolute values
24
+ */
25
+ const pathToAbsolute = (pathInput: string | PathArray): AbsoluteArray => {
26
+ /* istanbul ignore else */
27
+ if (isAbsoluteArray(pathInput)) {
28
+ return [...pathInput];
29
+ }
30
+
31
+ const path = parsePathString(pathInput);
32
+ let x = 0;
33
+ let y = 0;
34
+ let mx = 0;
35
+ let my = 0;
36
+
37
+ // the `absoluteSegment[]` is for sure an `absolutePath`
38
+ return path.map(segment => {
39
+ const values = segment.slice(1).map(Number);
40
+ const [pathCommand] = segment;
41
+ const absCommand = pathCommand.toUpperCase() as AbsoluteCommand;
42
+
43
+ if (pathCommand === 'M') {
44
+ [x, y] = values;
45
+ mx = x;
46
+ my = y;
47
+ return ['M', x, y] as MSegment;
48
+ }
49
+
50
+ let absoluteSegment = [] as unknown as AbsoluteSegment;
51
+
52
+ if (pathCommand !== absCommand) {
53
+ if (absCommand === 'A') {
54
+ absoluteSegment = [
55
+ absCommand,
56
+ values[0],
57
+ values[1],
58
+ values[2],
59
+ values[3],
60
+ values[4],
61
+ values[5] + x,
62
+ values[6] + y,
63
+ ] as ASegment;
64
+ } else if (absCommand === 'V') {
65
+ absoluteSegment = [absCommand, values[0] + y] as VSegment;
66
+ } else if (absCommand === 'H') {
67
+ absoluteSegment = [absCommand, values[0] + x] as HSegment;
68
+ } else {
69
+ // use brakets for `eslint: no-case-declaration`
70
+ // https://stackoverflow.com/a/50753272/803358
71
+ const absValues = values.map((n, j) => n + (j % 2 ? y : x));
72
+ // for n, l, c, s, q, t
73
+ absoluteSegment = [absCommand, ...absValues] as QSegment | TSegment | SSegment | CSegment;
74
+ }
75
+ } else {
76
+ absoluteSegment = [absCommand, ...values] as typeof segment;
77
+ }
78
+
79
+ // const segLength = absoluteSegment.length;
80
+ if (absCommand === 'Z') {
81
+ x = mx;
82
+ y = my;
83
+ } else if (absCommand === 'H') {
84
+ [, x] = absoluteSegment as HSegment;
85
+ } else if (absCommand === 'V') {
86
+ [, y] = absoluteSegment as VSegment;
87
+ } else {
88
+ // x = absoluteSegment[segLength - 2];
89
+ // y = absoluteSegment[segLength - 1];
90
+ [x, y] = absoluteSegment.slice(-2) as [number, number];
91
+
92
+ if (absCommand === 'M') {
93
+ mx = x;
94
+ my = y;
95
+ }
96
+ }
97
+
98
+ return absoluteSegment;
99
+ }) as AbsoluteArray;
100
+ };
101
+ export default pathToAbsolute;
@@ -1,10 +1,9 @@
1
1
  import fixArc from '../process/fixArc';
2
- // import fixPath from '../process/fixPath';
3
2
  import isCurveArray from '../util/isCurveArray';
4
- import clonePath from '../process/clonePath';
5
3
  import normalizePath from '../process/normalizePath';
6
4
  import segmentToCubic from '../process/segmentToCubic';
7
5
  import paramsParser from '../parser/paramsParser';
6
+ import { CurveArray, PathArray, PathCommand } from '../types';
8
7
 
9
8
  /**
10
9
  * Parses a path string value or 'pathArray' and returns a new one
@@ -13,26 +12,24 @@ import paramsParser from '../parser/paramsParser';
13
12
  * In addition, un-necessary `Z` segment is removed if previous segment
14
13
  * extends to the `M` segment.
15
14
  *
16
- * @param {string | SVGPath.pathArray} pathInput the string to be parsed or 'pathArray'
17
- * @returns {SVGPath.curveArray} the resulted `pathArray` converted to cubic-bezier
15
+ * @param pathInput the string to be parsed or 'pathArray'
16
+ * @returns the resulted `pathArray` converted to cubic-bezier
18
17
  */
19
- export default function pathToCurve(pathInput) {
18
+ const pathToCurve = (pathInput: string | PathArray): CurveArray => {
20
19
  /* istanbul ignore else */
21
20
  if (isCurveArray(pathInput)) {
22
- // `isCurveArray` checks if it's `pathArray`
23
- return clonePath(pathInput);
21
+ return [...pathInput];
24
22
  }
25
23
 
26
- // const path = fixPath(normalizePath(pathInput));
27
24
  const path = normalizePath(pathInput);
28
25
  const params = { ...paramsParser };
29
- const allPathCommands = [];
26
+ const allPathCommands = [] as PathCommand[];
30
27
  let pathCommand = ''; // ts-lint
31
28
  let ii = path.length;
32
29
 
33
30
  for (let i = 0; i < ii; i += 1) {
34
31
  [pathCommand] = path[i];
35
- allPathCommands[i] = pathCommand;
32
+ allPathCommands[i] = pathCommand as PathCommand;
36
33
 
37
34
  path[i] = segmentToCubic(path[i], params);
38
35
 
@@ -43,9 +40,10 @@ export default function pathToCurve(pathInput) {
43
40
  const seglen = segment.length;
44
41
  params.x1 = +segment[seglen - 2];
45
42
  params.y1 = +segment[seglen - 1];
46
- params.x2 = +(segment[seglen - 4]) || params.x1;
47
- params.y2 = +(segment[seglen - 3]) || params.y1;
43
+ params.x2 = +segment[seglen - 4] || params.x1;
44
+ params.y2 = +segment[seglen - 3] || params.y1;
48
45
  }
49
46
 
50
- return path;
51
- }
47
+ return path as CurveArray;
48
+ };
49
+ export default pathToCurve;
@@ -0,0 +1,92 @@
1
+ import type {
2
+ aSegment,
3
+ hSegment,
4
+ PathArray,
5
+ RelativeArray,
6
+ RelativeCommand,
7
+ RelativeSegment,
8
+ vSegment,
9
+ } from '../types';
10
+ import parsePathString from '../parser/parsePathString';
11
+ import isRelativeArray from '../util/isRelativeArray';
12
+
13
+ /**
14
+ * Parses a path string value or object and returns an array
15
+ * of segments, all converted to relative values.
16
+ *
17
+ * @param pathInput the path string | object
18
+ * @returns the resulted `pathArray` with relative values
19
+ */
20
+ const pathToRelative = (pathInput: string | PathArray): RelativeArray => {
21
+ /* istanbul ignore else */
22
+ if (isRelativeArray(pathInput)) {
23
+ return [...pathInput];
24
+ }
25
+
26
+ const path = parsePathString(pathInput);
27
+ let x = 0;
28
+ let y = 0;
29
+ let mx = 0;
30
+ let my = 0;
31
+
32
+ return path.map(segment => {
33
+ const values = segment.slice(1).map(Number);
34
+ const [pathCommand] = segment;
35
+ const relativeCommand = pathCommand.toLowerCase() as RelativeCommand;
36
+
37
+ if (pathCommand === 'M') {
38
+ [x, y] = values;
39
+ mx = x;
40
+ my = y;
41
+ return ['M', x, y];
42
+ }
43
+
44
+ let relativeSegment = [];
45
+
46
+ if (pathCommand !== relativeCommand) {
47
+ if (relativeCommand === 'a') {
48
+ relativeSegment = [
49
+ relativeCommand,
50
+ values[0],
51
+ values[1],
52
+ values[2],
53
+ values[3],
54
+ values[4],
55
+ values[5] - x,
56
+ values[6] - y,
57
+ ] as aSegment;
58
+ } else if (relativeCommand === 'v') {
59
+ relativeSegment = [relativeCommand, values[0] - y] as vSegment;
60
+ } else if (relativeCommand === 'h') {
61
+ relativeSegment = [relativeCommand, values[0] - x] as hSegment;
62
+ } else {
63
+ // use brakets for `eslint: no-case-declaration`
64
+ // https://stackoverflow.com/a/50753272/803358
65
+ const relValues = values.map((n, j) => n - (j % 2 ? y : x));
66
+ relativeSegment = [relativeCommand, ...relValues] as RelativeSegment;
67
+ }
68
+ } else {
69
+ if (pathCommand === 'm') {
70
+ mx = values[0] + x;
71
+ my = values[1] + y;
72
+ }
73
+ relativeSegment = [relativeCommand, ...values] as RelativeSegment;
74
+ }
75
+
76
+ const segLength = relativeSegment.length;
77
+ if (relativeCommand === 'z') {
78
+ x = mx;
79
+ y = my;
80
+ } else if (relativeCommand === 'h') {
81
+ x += relativeSegment[1] as number;
82
+ } else if (relativeCommand === 'v') {
83
+ y += relativeSegment[1] as number;
84
+ } else {
85
+ x += relativeSegment[segLength - 2] as number;
86
+ y += relativeSegment[segLength - 1] as number;
87
+ }
88
+
89
+ return relativeSegment as typeof segment;
90
+ }) as RelativeArray;
91
+ };
92
+ export default pathToRelative;
@@ -0,0 +1,17 @@
1
+ import type { PathArray } from '../types';
2
+ import roundPath from '../process/roundPath';
3
+
4
+ /**
5
+ * Returns a valid `d` attribute string value created
6
+ * by rounding values and concatenating the `pathArray` segments.
7
+ *
8
+ * @param path the `pathArray` object
9
+ * @param round amount of decimals to round values to
10
+ * @returns the concatenated path string
11
+ */
12
+ const pathToString = (path: PathArray, round?: number | 'off'): string => {
13
+ return roundPath(path, round)
14
+ .map(x => x[0] + x.slice(1).join(' '))
15
+ .join('');
16
+ };
17
+ export default pathToString;
@@ -1,24 +1,49 @@
1
+ import { PathArray, TransformObjectValues } from './types';
2
+ import { Options, PathBBox, TransformEntries, TransformObject } from './interface';
1
3
  import defaultOptions from './options/options';
2
4
 
3
- import pathToAbsolute from './convert/pathToAbsolute';
4
- import pathToRelative from './convert/pathToRelative';
5
- import pathToCurve from './convert/pathToCurve';
6
- import pathToString from './convert/pathToString';
7
-
5
+ import error from './parser/error';
8
6
  import parsePathString from './parser/parsePathString';
9
- import reversePath from './process/reversePath';
10
7
 
11
- import clonePath from './process/clonePath';
8
+ import polygonArea from './math/polygonArea';
9
+ import polygonLength from './math/polygonLength';
10
+
11
+ import CSSMatrix from '@thednp/dommatrix';
12
+ import getPathBBox from './util/getPathBBox';
13
+ import getPathArea from './util/getPathArea';
14
+ import getTotalLength from './util/getTotalLength';
15
+ import getDrawDirection from './util/getDrawDirection';
16
+ import getPointAtLength from './util/getPointAtLength';
17
+ import pathLengthFactory from './util/pathLengthFactory';
18
+
19
+ import getPropertiesAtLength from './util/getPropertiesAtLength';
20
+ import getPropertiesAtPoint from './util/getPropertiesAtPoint';
21
+ import getClosestPoint from './util/getClosestPoint';
22
+ import getSegmentOfPoint from './util/getSegmentOfPoint';
23
+ import getSegmentAtLength from './util/getSegmentAtLength';
24
+ import isPointInStroke from './util/isPointInStroke';
25
+
26
+ import isValidPath from './util/isValidPath';
27
+ import isPathArray from './util/isPathArray';
28
+ import isAbsoluteArray from './util/isAbsoluteArray';
29
+ import isRelativeArray from './util/isRelativeArray';
30
+ import isCurveArray from './util/isCurveArray';
31
+ import isNormalizedArray from './util/isNormalizedArray';
32
+ import shapeToPath from './util/shapeToPath';
33
+
34
+ import roundPath from './process/roundPath';
12
35
  import splitPath from './process/splitPath';
13
36
  import optimizePath from './process/optimizePath';
37
+ import reverseCurve from './process/reverseCurve';
38
+ import reversePath from './process/reversePath';
14
39
  import normalizePath from './process/normalizePath';
15
40
  import transformPath from './process/transformPath';
41
+ import splitCubic from './process/splitCubic';
16
42
 
17
- import error from './parser/error';
18
-
19
- import getPathBBox from './util/getPathBBox';
20
- import getTotalLength from './util/getTotalLength';
21
- import getPointAtLength from './util/getPointAtLength';
43
+ import pathToAbsolute from './convert/pathToAbsolute';
44
+ import pathToRelative from './convert/pathToRelative';
45
+ import pathToCurve from './convert/pathToCurve';
46
+ import pathToString from './convert/pathToString';
22
47
 
23
48
  /**
24
49
  * Creates a new SVGPathCommander instance with the following properties:
@@ -31,14 +56,54 @@ import getPointAtLength from './util/getPointAtLength';
31
56
  * @returns {SVGPathCommander} a new SVGPathCommander instance
32
57
  */
33
58
  class SVGPathCommander {
59
+ // bring main utilities to front
60
+ public static CSSMatrix = CSSMatrix;
61
+ public static getPathBBox = getPathBBox;
62
+ public static getPathArea = getPathArea;
63
+ public static getTotalLength = getTotalLength;
64
+ public static getDrawDirection = getDrawDirection;
65
+ public static getPointAtLength = getPointAtLength;
66
+ public static pathLengthFactory = pathLengthFactory;
67
+ public static getPropertiesAtLength = getPropertiesAtLength;
68
+ public static getPropertiesAtPoint = getPropertiesAtPoint;
69
+ public static polygonLength = polygonLength;
70
+ public static polygonArea = polygonArea;
71
+ public static getClosestPoint = getClosestPoint;
72
+ public static getSegmentOfPoint = getSegmentOfPoint;
73
+ public static getSegmentAtLength = getSegmentAtLength;
74
+ public static isPointInStroke = isPointInStroke;
75
+ public static isValidPath = isValidPath;
76
+ public static isPathArray = isPathArray;
77
+ public static isAbsoluteArray = isAbsoluteArray;
78
+ public static isRelativeArray = isRelativeArray;
79
+ public static isCurveArray = isCurveArray;
80
+ public static isNormalizedArray = isNormalizedArray;
81
+ public static shapeToPath = shapeToPath;
82
+ public static parsePathString = parsePathString;
83
+ public static roundPath = roundPath;
84
+ public static splitPath = splitPath;
85
+ public static splitCubic = splitCubic;
86
+ public static optimizePath = optimizePath;
87
+ public static reverseCurve = reverseCurve;
88
+ public static reversePath = reversePath;
89
+ public static normalizePath = normalizePath;
90
+ public static transformPath = transformPath;
91
+ public static pathToAbsolute = pathToAbsolute;
92
+ public static pathToRelative = pathToRelative;
93
+ public static pathToCurve = pathToCurve;
94
+ public static pathToString = pathToString;
95
+ // declare class properties
96
+ declare segments: PathArray;
97
+ declare round: number | 'off';
98
+ declare origin: [number, number, number];
99
+
34
100
  /**
35
101
  * @constructor
36
102
  * @param {string} pathValue the path string
37
103
  * @param {any} config instance options
38
104
  */
39
- constructor(pathValue, config) {
105
+ constructor(pathValue: string, config?: Partial<Options>) {
40
106
  const instanceOptions = config || {};
41
-
42
107
  const undefPath = typeof pathValue === 'undefined';
43
108
 
44
109
  if (undefPath || !pathValue.length) {
@@ -46,35 +111,30 @@ class SVGPathCommander {
46
111
  }
47
112
 
48
113
  const segments = parsePathString(pathValue);
49
- if (typeof segments === 'string') {
50
- throw TypeError(segments);
51
- }
114
+ // if (typeof segments === 'string') {
115
+ // throw TypeError(segments);
116
+ // }
52
117
 
53
- /**
54
- * @type {SVGPath.pathArray}
55
- */
56
118
  this.segments = segments;
57
119
 
58
- const {
59
- width, height, cx, cy, cz,
60
- } = this.getBBox();
120
+ const { width, height, cx, cy, cz } = this.getBBox();
61
121
 
62
122
  // set instance options.round
63
123
  const { round: roundOption, origin: originOption } = instanceOptions;
64
- let round;
124
+ let round: number | 'off';
65
125
 
66
126
  if (roundOption === 'auto') {
67
- const pathScale = (`${Math.floor(Math.max(width, height))}`).length;
127
+ const pathScale = `${Math.floor(Math.max(width, height))}`.length;
68
128
  round = pathScale >= 4 ? 0 : 4 - pathScale;
69
129
  } else if (Number.isInteger(roundOption) || roundOption === 'off') {
70
- round = roundOption;
130
+ round = roundOption as number | 'off';
71
131
  } else {
72
- ({ round } = defaultOptions);
132
+ round = defaultOptions.round as number;
73
133
  }
74
134
 
75
135
  // set instance options.origin
76
136
  // the SVGPathCommander class will always override the default origin
77
- let origin;
137
+ let origin: [number, number, number];
78
138
  if (Array.isArray(originOption) && originOption.length >= 2) {
79
139
  const [originX, originY, originZ] = originOption.map(Number);
80
140
  origin = [
@@ -86,9 +146,7 @@ class SVGPathCommander {
86
146
  origin = [cx, cy, cz];
87
147
  }
88
148
 
89
- /** @type {number | 'off'} */
90
149
  this.round = round;
91
- /** @type {[number, number, number=]} */
92
150
  this.origin = origin;
93
151
 
94
152
  return this;
@@ -96,17 +154,19 @@ class SVGPathCommander {
96
154
 
97
155
  /**
98
156
  * Returns the path bounding box, equivalent to native `path.getBBox()`.
157
+ *
99
158
  * @public
100
- * @returns {SVGPath.pathBBox}
159
+ * @returns the pathBBox
101
160
  */
102
- getBBox() {
161
+ getBBox(): PathBBox {
103
162
  return getPathBBox(this.segments);
104
163
  }
105
164
 
106
165
  /**
107
166
  * Returns the total path length, equivalent to native `path.getTotalLength()`.
167
+ *
108
168
  * @public
109
- * @returns {number}
169
+ * @returns the path total length
110
170
  */
111
171
  getTotalLength() {
112
172
  return getTotalLength(this.segments);
@@ -117,15 +177,16 @@ class SVGPathCommander {
117
177
  * equivalent to the native `path.getPointAtLength()`.
118
178
  *
119
179
  * @public
120
- * @param {number} length the length
121
- * @returns {{x: number, y:number}} the requested point
180
+ * @param length the length
181
+ * @returns the requested point
122
182
  */
123
- getPointAtLength(length) {
183
+ getPointAtLength(length: number): { x: number; y: number } {
124
184
  return getPointAtLength(this.segments, length);
125
185
  }
126
186
 
127
187
  /**
128
188
  * Convert path to absolute values
189
+ *
129
190
  * @public
130
191
  */
131
192
  toAbsolute() {
@@ -136,6 +197,7 @@ class SVGPathCommander {
136
197
 
137
198
  /**
138
199
  * Convert path to relative values
200
+ *
139
201
  * @public
140
202
  */
141
203
  toRelative() {
@@ -158,22 +220,26 @@ class SVGPathCommander {
158
220
 
159
221
  /**
160
222
  * Reverse the order of the segments and their values.
161
- * @param {boolean} onlySubpath option to reverse all sub-paths except first
223
+ *
224
+ * @param onlySubpath option to reverse all sub-paths except first
162
225
  * @public
163
226
  */
164
- reverse(onlySubpath) {
227
+ reverse(onlySubpath?: boolean) {
165
228
  this.toAbsolute();
166
229
 
167
230
  const { segments } = this;
168
231
  const split = splitPath(segments);
169
- const subPath = split.length > 1 ? split : 0;
170
-
171
- const absoluteMultiPath = subPath && clonePath(subPath).map((x, i) => {
172
- if (onlySubpath) {
173
- return i ? reversePath(x) : parsePathString(x);
174
- }
175
- return reversePath(x);
176
- });
232
+ const subPath = split.length > 1 ? split : false;
233
+
234
+ const absoluteMultiPath = subPath
235
+ ? [...subPath].map((x, i) => {
236
+ if (onlySubpath) {
237
+ // return i ? reversePath(x) : parsePathString(x);
238
+ return i ? reversePath(x) : [...x];
239
+ }
240
+ return reversePath(x);
241
+ })
242
+ : [...segments];
177
243
 
178
244
  let path = [];
179
245
  if (subPath) {
@@ -182,7 +248,7 @@ class SVGPathCommander {
182
248
  path = onlySubpath ? segments : reversePath(segments);
183
249
  }
184
250
 
185
- this.segments = clonePath(path);
251
+ this.segments = [...path] as PathArray;
186
252
  return this;
187
253
  }
188
254
 
@@ -190,6 +256,7 @@ class SVGPathCommander {
190
256
  * Normalize path in 2 steps:
191
257
  * * convert `pathArray`(s) to absolute values
192
258
  * * convert shorthand notation to standard notation
259
+ *
193
260
  * @public
194
261
  */
195
262
  normalize() {
@@ -203,6 +270,7 @@ class SVGPathCommander {
203
270
  * * convert segments to absolute and/or relative values
204
271
  * * select segments with shortest resulted string
205
272
  * * round values to the specified `decimals` option value
273
+ *
206
274
  * @public
207
275
  */
208
276
  optimize() {
@@ -214,34 +282,40 @@ class SVGPathCommander {
214
282
 
215
283
  /**
216
284
  * Transform path using values from an `Object` defined as `transformObject`.
217
- * @see SVGPath.transformObject for a quick refference
218
285
  *
219
- * @param {SVGPath.transformObject} source a `transformObject`as described above
286
+ * @see TransformObject for a quick refference
287
+ *
288
+ * @param source a `transformObject`as described above
220
289
  * @public
221
290
  */
222
- transform(source) {
223
- if (!source || typeof source !== 'object' || (typeof source === 'object'
224
- && !['translate', 'rotate', 'skew', 'scale'].some((x) => x in source))) return this;
225
-
226
- /** @type {SVGPath.transformObject} */
227
- const transform = {};
228
- Object.keys(source).forEach((fn) => {
229
- transform[fn] = Array.isArray(source[fn]) ? [...source[fn]] : Number(source[fn]);
230
- });
231
- const { segments } = this;
291
+ transform(source?: Partial<TransformObject>) {
292
+ if (
293
+ !source ||
294
+ typeof source !== 'object' ||
295
+ (typeof source === 'object' && !['translate', 'rotate', 'skew', 'scale'].some(x => x in source))
296
+ )
297
+ return this;
298
+
299
+ const {
300
+ segments,
301
+ origin: [cx, cy, cz],
302
+ } = this;
303
+ const transform = {} as TransformObjectValues;
304
+ for (const [k, v] of Object.entries(source) as TransformEntries) {
305
+ if (k === 'skew' && Array.isArray(v)) {
306
+ transform[k] = v.map(Number) as [number, number];
307
+ } else if ((k === 'rotate' || k === 'translate' || k === 'origin' || k === 'scale') && Array.isArray(v)) {
308
+ transform[k] = v.map(Number) as [number, number, number];
309
+ } else if (k !== 'origin' && typeof Number(v) === 'number') transform[k] = Number(v);
310
+ }
232
311
 
233
312
  // if origin is not specified
234
313
  // it's important that we have one
235
- const [cx, cy, cz] = this.origin;
236
314
  const { origin } = transform;
237
315
 
238
316
  if (Array.isArray(origin) && origin.length >= 2) {
239
317
  const [originX, originY, originZ] = origin.map(Number);
240
- transform.origin = [
241
- !Number.isNaN(originX) ? originX : cx,
242
- !Number.isNaN(originY) ? originY : cy,
243
- originZ || cz,
244
- ];
318
+ transform.origin = [!Number.isNaN(originX) ? originX : cx, !Number.isNaN(originY) ? originY : cy, originZ || cz];
245
319
  } else {
246
320
  transform.origin = [cx, cy, cz];
247
321
  }
@@ -252,6 +326,7 @@ class SVGPathCommander {
252
326
 
253
327
  /**
254
328
  * Rotate path 180deg vertically
329
+ *
255
330
  * @public
256
331
  */
257
332
  flipX() {
@@ -261,6 +336,7 @@ class SVGPathCommander {
261
336
 
262
337
  /**
263
338
  * Rotate path 180deg horizontally
339
+ *
264
340
  * @public
265
341
  */
266
342
  flipY() {
@@ -271,8 +347,9 @@ class SVGPathCommander {
271
347
  /**
272
348
  * Export the current path to be used
273
349
  * for the `d` (description) attribute.
350
+ *
274
351
  * @public
275
- * @return {String} the path string
352
+ * @return the path string
276
353
  */
277
354
  toString() {
278
355
  return pathToString(this.segments, this.round);