svg-path-commander 0.1.10-alpha2 → 0.1.11-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 (123) hide show
  1. package/dist/svg-path-commander.esm.js +478 -454
  2. package/dist/svg-path-commander.esm.min.js +2 -2
  3. package/dist/svg-path-commander.js +490 -468
  4. package/dist/svg-path-commander.min.js +2 -2
  5. package/package.json +5 -5
  6. package/src/convert/pathToAbsolute.js +7 -5
  7. package/src/convert/pathToCurve.js +5 -5
  8. package/src/convert/pathToRelative.js +7 -6
  9. package/src/convert/pathToString.js +3 -3
  10. package/src/math/epsilon.js +1 -1
  11. package/src/math/rotateVector.js +3 -2
  12. package/src/parser/finalizeSegment.js +14 -17
  13. package/src/parser/isArcCommand.js +1 -1
  14. package/src/parser/isDigit.js +1 -1
  15. package/src/parser/isDigitStart.js +1 -1
  16. package/src/parser/isPathCommand.js +1 -1
  17. package/src/parser/isSpace.js +5 -6
  18. package/src/parser/parsePathString.js +5 -5
  19. package/src/parser/{svgPathArray.js → pathParser.js} +3 -3
  20. package/src/parser/scanFlag.js +1 -1
  21. package/src/parser/scanParam.js +1 -1
  22. package/src/parser/scanSegment.js +1 -1
  23. package/src/parser/skipSpaces.js +1 -1
  24. package/src/process/arcToCubic.js +59 -71
  25. package/src/process/clonePath.js +4 -5
  26. package/src/process/fixArc.js +3 -1
  27. package/src/process/getSVGMatrix.js +8 -6
  28. package/src/process/lineToCubic.js +7 -5
  29. package/src/process/normalizePath.js +4 -3
  30. package/src/process/normalizeSegment.js +6 -6
  31. package/src/process/optimizePath.js +7 -4
  32. package/src/process/projection2d.js +1 -1
  33. package/src/process/quadToCubic.js +7 -7
  34. package/src/process/reverseCurve.js +5 -4
  35. package/src/process/reversePath.js +2 -2
  36. package/src/process/roundPath.js +27 -12
  37. package/src/process/segmentToCubic.js +4 -4
  38. package/src/process/shorthandToCubic.js +6 -6
  39. package/src/process/shorthandToQuad.js +6 -6
  40. package/src/process/splitCubic.js +2 -2
  41. package/src/process/splitPath.js +1 -1
  42. package/src/process/transformPath.js +2 -2
  43. package/src/svg-path-commander.js +20 -20
  44. package/src/util/getCubicSize.js +5 -3
  45. package/src/util/getDrawDirection.js +1 -1
  46. package/src/util/getPathArea.js +6 -4
  47. package/src/util/getPathBBox.js +16 -12
  48. package/src/util/getPathLength.js +3 -2
  49. package/src/util/getPointAtLength.js +6 -4
  50. package/src/util/getPointAtSegLength.js +9 -9
  51. package/src/util/getSegArcLength.js +2 -2
  52. package/src/util/getSegCubicLength.js +19 -11
  53. package/src/util/getSegLineLength.js +5 -5
  54. package/src/util/getSegQuadLength.js +8 -8
  55. package/src/util/isAbsoluteArray.js +1 -1
  56. package/src/util/isCurveArray.js +1 -1
  57. package/src/util/isNormalizedArray.js +1 -1
  58. package/src/util/isPathArray.js +1 -1
  59. package/src/util/isRelativeArray.js +1 -1
  60. package/src/util/isValidPath.js +2 -2
  61. package/src/util/shapeToPath.js +23 -20
  62. package/types/convert/pathToAbsolute.d.ts +1 -0
  63. package/types/convert/pathToCurve.d.ts +1 -0
  64. package/types/convert/pathToRelative.d.ts +1 -0
  65. package/types/convert/pathToString.d.ts +1 -0
  66. package/types/index.d.ts +110 -834
  67. package/types/math/epsilon.d.ts +2 -0
  68. package/types/math/midPoint.d.ts +1 -0
  69. package/types/math/rotateVector.d.ts +4 -0
  70. package/types/options/options.d.ts +6 -0
  71. package/types/parser/finalizeSegment.d.ts +1 -0
  72. package/types/parser/invalidPathValue.d.ts +2 -0
  73. package/types/parser/isArcCommand.d.ts +1 -0
  74. package/types/parser/isDigit.d.ts +1 -0
  75. package/types/parser/isDigitStart.d.ts +1 -0
  76. package/types/parser/isPathCommand.d.ts +1 -0
  77. package/types/parser/isSpace.d.ts +1 -0
  78. package/types/parser/paramsCount.d.ts +4 -0
  79. package/types/parser/parsePathString.d.ts +1 -0
  80. package/types/parser/pathParser.d.ts +12 -0
  81. package/types/parser/scanFlag.d.ts +1 -0
  82. package/types/parser/scanParam.d.ts +1 -0
  83. package/types/parser/scanSegment.d.ts +1 -0
  84. package/types/parser/skipSpaces.d.ts +1 -0
  85. package/types/process/arcToCubic.d.ts +1 -0
  86. package/types/process/clonePath.d.ts +1 -0
  87. package/types/process/fixArc.d.ts +1 -0
  88. package/types/process/getSVGMatrix.d.ts +2 -0
  89. package/types/process/lineToCubic.d.ts +1 -0
  90. package/types/process/normalizePath.d.ts +1 -0
  91. package/types/process/normalizeSegment.d.ts +1 -0
  92. package/types/process/optimizePath.d.ts +1 -0
  93. package/types/process/projection2d.d.ts +1 -0
  94. package/types/process/quadToCubic.d.ts +1 -0
  95. package/types/process/reverseCurve.d.ts +1 -0
  96. package/types/process/reversePath.d.ts +1 -0
  97. package/types/process/roundPath.d.ts +1 -0
  98. package/types/process/segmentToCubic.d.ts +1 -0
  99. package/types/process/shorthandToCubic.d.ts +4 -0
  100. package/types/process/shorthandToQuad.d.ts +4 -0
  101. package/types/process/splitPath.d.ts +1 -0
  102. package/types/process/transformEllipse.d.ts +5 -0
  103. package/types/process/transformPath.d.ts +1 -0
  104. package/types/svg-path-commander.d.ts +18 -0
  105. package/types/util/getCubicSize.d.ts +1 -0
  106. package/types/util/getDrawDirection.d.ts +1 -0
  107. package/types/util/getPathArea.d.ts +1 -0
  108. package/types/util/getPathBBox.d.ts +1 -0
  109. package/types/util/getPathLength.d.ts +1 -0
  110. package/types/util/getPointAtLength.d.ts +1 -0
  111. package/types/util/getPointAtSegLength.d.ts +4 -0
  112. package/types/util/getSegCubicLength.d.ts +1 -0
  113. package/types/util/isAbsoluteArray.d.ts +1 -0
  114. package/types/util/isCurveArray.d.ts +1 -0
  115. package/types/util/isNormalizedArray.d.ts +1 -0
  116. package/types/util/isPathArray.d.ts +1 -0
  117. package/types/util/isRelativeArray.d.ts +1 -0
  118. package/types/util/isValidPath.d.ts +1 -0
  119. package/types/util/shapeToPath.d.ts +6 -0
  120. package/types/util/util.d.ts +61 -0
  121. package/types/util/version.d.ts +2 -0
  122. package/src/index.js +0 -3
  123. package/types/types.d.ts +0 -83
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * SVGPathCommander v0.1.10alpha2 (http://thednp.github.io/svg-path-commander)
2
+ * SVGPathCommander v0.1.11alpha2 (http://thednp.github.io/svg-path-commander)
3
3
  * Copyright 2021 © thednp
4
4
  * Licensed under MIT (https://github.com/thednp/svg-path-commander/blob/master/LICENSE)
5
5
  */
@@ -23,29 +23,26 @@ const paramsCount = {
23
23
  /**
24
24
  * Breaks the parsing of a pathString once a segment is finalized.
25
25
  *
26
- * @param {SVGPC.parserPathArray} path the `parserPathArray` instance
26
+ * @param {SVGPathCommander.PathParser} path the `PathParser` instance
27
27
  */
28
28
  function finalizeSegment(path) {
29
29
  let pathCommand = path.pathValue[path.segmentStart];
30
- let pathComLK = pathCommand.toLowerCase();
31
- let params = path.data;
30
+ let LK = pathCommand.toLowerCase();
31
+ let { data } = path;
32
32
 
33
33
  // Process duplicated commands (without comand name)
34
- if (pathComLK === 'm' && params.length > 2) {
35
- path.segments.push([pathCommand, params[0], params[1]]);
36
- params = params.slice(2);
37
- pathComLK = 'l';
38
- pathCommand = (pathCommand === 'm') ? 'l' : 'L';
34
+ if (LK === 'm' && data.length > 2) {
35
+ path.segments.push([pathCommand, data[0], data[1]]);
36
+ data = data.slice(2);
37
+ LK = 'l';
38
+ pathCommand = pathCommand === 'm' ? 'l' : 'L';
39
39
  }
40
40
 
41
- if (pathComLK === 'r') {
42
- path.segments.push([pathCommand].concat(params));
43
- } else {
44
- while (params.length >= paramsCount[pathComLK]) {
45
- path.segments.push([pathCommand].concat(params.splice(0, paramsCount[pathComLK])));
46
- if (!paramsCount[pathComLK]) {
47
- break;
48
- }
41
+ while (data.length >= paramsCount[LK]) {
42
+ // @ts-ignore
43
+ path.segments.push([pathCommand].concat(data.splice(0, paramsCount[LK])));
44
+ if (!paramsCount[LK]) {
45
+ break;
49
46
  }
50
47
  }
51
48
  }
@@ -56,7 +53,7 @@ const invalidPathValue = 'Invalid path value';
56
53
  * Validates an A (arc-to) specific path command value.
57
54
  * Usually a `large-arc-flag` or `sweep-flag`.
58
55
  *
59
- * @param {SVGPC.parserPathArray} path the `parserPathArray` instance
56
+ * @param {SVGPathCommander.PathParser} path the `PathParser` instance
60
57
  */
61
58
  function scanFlag(path) {
62
59
  const { index } = path;
@@ -80,7 +77,7 @@ function scanFlag(path) {
80
77
  /**
81
78
  * Checks if a character is a digit.
82
79
  *
83
- * @param {string} code the character to check
80
+ * @param {number} code the character to check
84
81
  * @returns {boolean} check result
85
82
  */
86
83
  function isDigit(code) {
@@ -91,7 +88,7 @@ function isDigit(code) {
91
88
  * Validates every character of the path string,
92
89
  * every path command, negative numbers or floating point numbers.
93
90
  *
94
- * @param {SVGPC.parserPathArray} path the `parserPathArray` instance
91
+ * @param {SVGPathCommander.PathParser} path the `PathParser` instance
95
92
  */
96
93
  function scanParam(path) {
97
94
  const { max, pathValue, index: start } = path;
@@ -185,18 +182,17 @@ function scanParam(path) {
185
182
  /**
186
183
  * Checks if the character is a space.
187
184
  *
188
- * @param {string} code the character to check
185
+ * @param {number} ch the character to check
189
186
  * @returns {boolean} check result
190
187
  */
191
- function isSpace(code) {
188
+ function isSpace(ch) {
192
189
  const specialSpaces = [
193
190
  0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
194
191
  0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF];
195
- // Line terminators
196
- return (code === 0x0A) || (code === 0x0D) || (code === 0x2028) || (code === 0x2029)
192
+ return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) // Line terminators
197
193
  // White spaces
198
- || (code === 0x20) || (code === 0x09) || (code === 0x0B) || (code === 0x0C) || (code === 0xA0)
199
- || (code >= 0x1680 && specialSpaces.indexOf(code) >= 0);
194
+ || (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0)
195
+ || (ch >= 0x1680 && specialSpaces.indexOf(ch) >= 0);
200
196
  }
201
197
 
202
198
  /**
@@ -204,7 +200,7 @@ function isSpace(code) {
204
200
  * path string every time it encounters any kind of
205
201
  * space character.
206
202
  *
207
- * @param {SVGPC.parserPathArray} path the `parserPathArray` instance
203
+ * @param {SVGPathCommander.PathParser} path the `PathParser` instance
208
204
  */
209
205
  function skipSpaces(path) {
210
206
  const { pathValue, max } = path;
@@ -232,7 +228,7 @@ function isPathCommand(code) {
232
228
  case 0x71/* q */:
233
229
  case 0x74/* t */:
234
230
  case 0x61/* a */:
235
- case 0x72/* r */:
231
+ // case 0x72/* r */: // R is not supported
236
232
  return true;
237
233
  default:
238
234
  return false;
@@ -243,7 +239,7 @@ function isPathCommand(code) {
243
239
  * Checks if the character is or belongs to a number.
244
240
  * [0-9]|+|-|.
245
241
  *
246
- * @param {string} code the character to check
242
+ * @param {number} code the character to check
247
243
  * @returns {boolean} check result
248
244
  */
249
245
  function isDigitStart(code) {
@@ -256,7 +252,7 @@ function isDigitStart(code) {
256
252
  /**
257
253
  * Checks if the character is an A (arc-to) path command.
258
254
  *
259
- * @param {string} code the character to check
255
+ * @param {number} code the character to check
260
256
  * @returns {boolean} check result
261
257
  */
262
258
  function isArcCommand(code) {
@@ -268,7 +264,7 @@ function isArcCommand(code) {
268
264
  * Scans every character in the path string to determine
269
265
  * where a segment starts and where it ends.
270
266
  *
271
- * @param {SVGPC.parserPathArray} path the `parserPathArray` instance
267
+ * @param {SVGPathCommander.PathParser} path the `PathParser` instance
272
268
  */
273
269
  function scanSegment(path) {
274
270
  const { max, pathValue, index } = path;
@@ -325,29 +321,28 @@ function scanSegment(path) {
325
321
  finalizeSegment(path);
326
322
  }
327
323
 
328
- // @ts-nocheck
329
324
  /**
330
325
  * Returns a clone of an existing `pathArray`.
331
326
  *
332
- * @param {SVGPC.pathArray | string[]} path the source `pathArray`
333
- * @returns {SVGPC.pathArray} the cloned `pathArray`
327
+ * @param {SVGPathCommander.pathArray | any[] | string} path the source `pathArray`
328
+ * @returns {any} the cloned `pathArray`
334
329
  */
335
330
  function clonePath(path) {
336
- return path.map((x) => {
331
+ return Array.isArray(path) ? path.map((x) => {
337
332
  if (Array.isArray(x)) {
338
333
  return clonePath(x);
339
334
  }
340
335
  return !Number.isNaN(+x) ? +x : x;
341
- });
336
+ }) : path;
342
337
  }
343
338
 
344
339
  /**
345
- * The `parserPathArray` used by the parser.
340
+ * The `PathParser` used by the parser.
346
341
  *
347
342
  * @param {string} pathString
348
343
  */
349
- function SVGPathArray(pathString) {
350
- /** @type {[string, ...number[]][]} */
344
+ function PathParser(pathString) {
345
+ /** @type {SVGPathCommander.pathArray} */
351
346
  this.segments = [];
352
347
  /** @type {string} */
353
348
  this.pathValue = pathString;
@@ -368,7 +363,7 @@ function SVGPathArray(pathString) {
368
363
  /**
369
364
  * Iterates an array to check if it's an actual `pathArray`.
370
365
  *
371
- * @param {string | SVGPC.pathArray} path the `pathArray` to be checked
366
+ * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
372
367
  * @returns {boolean} iteration result
373
368
  */
374
369
  function isPathArray(path) {
@@ -382,15 +377,15 @@ function isPathArray(path) {
382
377
  * Parses a path string value and returns an array
383
378
  * of segments we like to call `pathArray`.
384
379
  *
385
- * @param {string | SVGPC.pathArray} pathInput the string to be parsed
386
- * @returns {SVGPC.pathArray} the resulted `pathArray`
380
+ * @param {SVGPathCommander.pathArray | string} pathInput the string to be parsed
381
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray`
387
382
  */
388
383
  function parsePathString(pathInput) {
389
384
  if (isPathArray(pathInput)) {
390
385
  return clonePath(pathInput);
391
386
  }
392
387
 
393
- const path = new SVGPathArray(pathInput);
388
+ const path = new PathParser(`${pathInput}`); // TS expects string
394
389
 
395
390
  skipSpaces(path);
396
391
 
@@ -401,7 +396,7 @@ function parsePathString(pathInput) {
401
396
  if (path.err.length) {
402
397
  path.segments = [];
403
398
  } else if (path.segments.length) {
404
- if ('mM'.indexOf(path.segments[0][0]) < 0) {
399
+ if (!'mM'.includes(path.segments[0][0])) {
405
400
  path.err = `${invalidPathValue}: missing M/m`;
406
401
  path.segments = [];
407
402
  } else {
@@ -416,7 +411,7 @@ function parsePathString(pathInput) {
416
411
  * Iterates an array to check if it's a `pathArray`
417
412
  * with all absolute values.
418
413
  *
419
- * @param {string | SVGPC.pathArray} path the `pathArray` to be checked
414
+ * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
420
415
  * @returns {boolean} iteration result
421
416
  */
422
417
  function isAbsoluteArray(path) {
@@ -428,17 +423,17 @@ function isAbsoluteArray(path) {
428
423
  * Parses a path string value or object and returns an array
429
424
  * of segments, all converted to absolute values.
430
425
  *
431
- * @param {string | SVGPC.pathArray} pathInput the path string | object
432
- * @returns {SVGPC.pathArray} the resulted `pathArray` with absolute values
426
+ * @param {SVGPathCommander.pathArray | string} pathInput the path string | object
427
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with absolute values
433
428
  */
434
429
  function pathToAbsolute(pathInput) {
435
- if (Array.isArray(pathInput) && isAbsoluteArray(pathInput)) {
430
+ if (isAbsoluteArray(pathInput)) {
436
431
  return clonePath(pathInput);
437
432
  }
438
433
 
439
434
  const path = parsePathString(pathInput);
440
435
  const ii = path.length;
441
- /** @type {SVGPC.pathArray} */
436
+ /** @type {SVGPathCommander.pathArray} */
442
437
  const resultArray = [];
443
438
  let x = 0;
444
439
  let y = 0;
@@ -459,6 +454,8 @@ function pathToAbsolute(pathInput) {
459
454
  const segment = path[i];
460
455
  const [pathCommand] = segment;
461
456
  const absCommand = pathCommand.toUpperCase();
457
+ /** @type {SVGPathCommander.pathSegment} */
458
+ // @ts-ignore -- trust me
462
459
  const absoluteSegment = [];
463
460
  let newSeg = [];
464
461
 
@@ -493,7 +490,7 @@ function pathToAbsolute(pathInput) {
493
490
  absoluteSegment.push(segment[j]);
494
491
  }
495
492
  }
496
- // @ts-ignore
493
+
497
494
  resultArray.push(absoluteSegment);
498
495
 
499
496
  const segLength = absoluteSegment.length;
@@ -526,7 +523,7 @@ function pathToAbsolute(pathInput) {
526
523
  * Iterates an array to check if it's a `pathArray`
527
524
  * with relative values.
528
525
  *
529
- * @param {string | SVGPC.pathArray} path the `pathArray` to be checked
526
+ * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
530
527
  * @returns {boolean} iteration result
531
528
  */
532
529
  function isRelativeArray(path) {
@@ -538,17 +535,17 @@ function isRelativeArray(path) {
538
535
  * Parses a path string value or object and returns an array
539
536
  * of segments, all converted to relative values.
540
537
  *
541
- * @param {string | SVGPC.pathArray} pathInput the path string | object
542
- * @returns {SVGPC.pathArray} the resulted `pathArray` with relative values
538
+ * @param {string | SVGPathCommander.pathArray} pathInput the path string | object
539
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with relative values
543
540
  */
544
541
  function pathToRelative(pathInput) {
545
- if (Array.isArray(pathInput) && isRelativeArray(pathInput)) {
542
+ if (isRelativeArray(pathInput)) {
546
543
  return clonePath(pathInput);
547
544
  }
548
545
 
549
546
  const path = parsePathString(pathInput);
550
547
  const ii = path.length;
551
- /** @type {SVGPC.pathArray} */
548
+ /** @type {SVGPathCommander.pathArray} */
552
549
  const resultArray = [];
553
550
  let x = 0;
554
551
  let y = 0;
@@ -569,7 +566,9 @@ function pathToRelative(pathInput) {
569
566
  const segment = path[i];
570
567
  const [pathCommand] = segment;
571
568
  const relativeCommand = pathCommand.toLowerCase();
572
- const relativeSegment = []; // this a test to please TS
569
+ /** @type {SVGPathCommander.pathSegment} */
570
+ // @ts-ignore -- trust me DON'T CHANGE
571
+ const relativeSegment = [];
573
572
  let newSeg = [];
574
573
 
575
574
  if (pathCommand !== relativeCommand) {
@@ -605,7 +604,6 @@ function pathToRelative(pathInput) {
605
604
  relativeSegment.push(segment[j]);
606
605
  }
607
606
  }
608
- // @ts-ignore
609
607
  resultArray.push(relativeSegment);
610
608
 
611
609
  const segLength = relativeSegment.length;
@@ -633,51 +631,66 @@ function pathToRelative(pathInput) {
633
631
  * Rounds the values of a `pathArray` instance to
634
632
  * a specified amount of decimals and returns it.
635
633
  *
636
- * @param {SVGPC.pathArray} path the source `pathArray`
637
- * @param {null | number} round the amount of decimals to round numbers to
638
- * @returns {SVGPC.pathArray} the resulted `pathArray` with rounded values
634
+ * @param {SVGPathCommander.pathArray} path the source `pathArray`
635
+ * @param {number | boolean | null} round the amount of decimals to round numbers to
636
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray` with rounded values
639
637
  */
640
638
  function roundPath(path, round) {
641
639
  const { round: defaultRound, decimals: defaultDecimals } = SVGPCO;
642
640
  const decimalsOption = round && !Number.isNaN(+round) ? +round
643
641
  : defaultRound && defaultDecimals;
644
642
 
645
- if (!decimalsOption) return clonePath(path);
643
+ if (round === false || (!defaultRound && !decimalsOption)) return clonePath(path);
646
644
 
647
- // @ts-ignore
648
- return path.map((seg) => seg.map((c) => {
649
- const nr = +c;
650
- const dc = 10 ** decimalsOption;
651
- if (!Number.isNaN(nr)) {
652
- return nr % 1 === 0 ? nr : Math.round(nr * dc) / dc;
645
+ const dc = 10 ** decimalsOption;
646
+ /** @type {SVGPathCommander.pathArray} */
647
+ const result = [];
648
+ const pl = path.length;
649
+ /** @type {SVGPathCommander.pathSegment} */
650
+ let segment;
651
+ /** @type {number} */
652
+ let n = 0;
653
+ let pi = [];
654
+
655
+ // FOR works best with TS
656
+ for (let i = 0; i < pl; i += 1) {
657
+ pi = path[i];
658
+ segment = [''];
659
+ for (let j = 0; j < pi.length; j += 1) {
660
+ if (!j) segment[j] = pi[j];
661
+ else {
662
+ n = +pi[j];
663
+ segment.push(!j || n % 1 === 0 ? n : Math.round(n * dc) / dc);
664
+ }
653
665
  }
654
- return c;
655
- }));
666
+ result.push(segment);
667
+ }
668
+ return result;
656
669
  }
657
670
 
658
671
  /**
659
672
  * Returns a valid `d` attribute string value created
660
673
  * by rounding values and concatenating the `pathArray` segments.
661
674
  *
662
- * @param {SVGPC.pathArray} path the `pathArray` object
663
- * @param {number | null} round amount of decimals to round values to
675
+ * @param {SVGPathCommander.pathArray} path the `pathArray` object
676
+ * @param {any} round amount of decimals to round values to
664
677
  * @returns {string} the concatenated path string
665
678
  */
666
679
  function pathToString(path, round) {
667
680
  return roundPath(path, round)
668
- .map((x) => x[0].concat(x.slice(1).join(' '))).join('');
681
+ .map((x) => x[0] + (x.slice(1).join(' '))).join('');
669
682
  }
670
683
 
671
684
  /**
672
685
  * Returns the missing control point from an
673
686
  * T (shorthand quadratic bezier) segment.
674
687
  *
675
- * @param {Number} x1 curve start x
676
- * @param {Number} y1 curve start y
677
- * @param {Number} qx control point x
678
- * @param {Number} qy control point y
679
- * @param {String} prevCommand the previous path command
680
- * @returns {Object} the missing control point
688
+ * @param {number} x1 curve start x
689
+ * @param {number} y1 curve start y
690
+ * @param {number} qx control point x
691
+ * @param {number} qy control point y
692
+ * @param {string} prevCommand the previous path command
693
+ * @returns {{qx: number, qy: number}}} the missing control point
681
694
  */
682
695
  function shorthandToQuad(x1, y1, qx, qy, prevCommand) {
683
696
  return 'QT'.indexOf(prevCommand) > -1
@@ -689,12 +702,12 @@ function shorthandToQuad(x1, y1, qx, qy, prevCommand) {
689
702
  * Returns the missing control point from an
690
703
  * S (shorthand cubic bezier) segment.
691
704
  *
692
- * @param {Number} x1 curve start x
693
- * @param {Number} y1 curve start y
694
- * @param {Number} x2 curve end x
695
- * @param {Number} y2 curve end y
696
- * @param {String} prevCommand the previous path command
697
- * @returns {Object} the missing control point
705
+ * @param {number} x1 curve start x
706
+ * @param {number} y1 curve start y
707
+ * @param {number} x2 curve end x
708
+ * @param {number} y2 curve end y
709
+ * @param {string} prevCommand the previous path command
710
+ * @returns {{x1: number, y1: number}}} the missing control point
698
711
  */
699
712
  function shorthandToCubic(x1, y1, x2, y2, prevCommand) {
700
713
  return 'CS'.indexOf(prevCommand) > -1
@@ -705,17 +718,17 @@ function shorthandToCubic(x1, y1, x2, y2, prevCommand) {
705
718
  /**
706
719
  * Normalizes a single segment of a `pathArray` object.
707
720
  *
708
- * @param {SVGPC.pathSegment} segment the segment object
709
- * @param {Object} params the coordinates of the previous segment
710
- * @param {String} prevCommand the path command of the previous segment
711
- * @returns {SVGPC.pathSegment} the normalized segment
721
+ * @param {SVGPathCommander.pathSegment} segment the segment object
722
+ * @param {any} params the coordinates of the previous segment
723
+ * @param {string} prevCommand the path command of the previous segment
724
+ * @returns {any} the normalized segment
712
725
  */
713
726
  function normalizeSegment(segment, params, prevCommand) {
714
727
  const [pathCommand] = segment;
715
728
  const xy = segment.slice(1);
716
- let result = segment;
729
+ let result = segment.slice();
717
730
 
718
- if ('TQ'.indexOf(segment[0]) < 0) {
731
+ if (!'TQ'.includes(segment[0])) {
719
732
  // optional but good to be cautious
720
733
  params.qx = null;
721
734
  params.qy = null;
@@ -748,7 +761,7 @@ function normalizeSegment(segment, params, prevCommand) {
748
761
  * with all segments are in non-shorthand notation
749
762
  * with absolute values.
750
763
  *
751
- * @param {string | SVGPC.pathArray} path the `pathArray` to be checked
764
+ * @param {string | SVGPathCommander.pathArray} path the `pathArray` to be checked
752
765
  * @returns {boolean} iteration result
753
766
  */
754
767
  function isNormalizedArray(path) {
@@ -763,8 +776,8 @@ function isNormalizedArray(path) {
763
776
  * * convert segments to absolute values
764
777
  * * convert shorthand path commands to their non-shorthand notation
765
778
  *
766
- * @param {string | SVGPC.pathArray} pathInput the string to be parsed or 'pathArray'
767
- * @returns {SVGPC.pathArray} the normalized `pathArray`
779
+ * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or 'pathArray'
780
+ * @returns {SVGPathCommander.pathArray} the normalized `pathArray`
768
781
  */
769
782
  function normalizePath(pathInput) { // path|pathString
770
783
  if (Array.isArray(pathInput) && isNormalizedArray(pathInput)) {
@@ -777,13 +790,14 @@ function normalizePath(pathInput) { // path|pathString
777
790
  };
778
791
  const allPathCommands = [];
779
792
  const ii = path.length;
793
+ let pathCommand = '';
780
794
  let prevCommand = '';
781
795
  let segment;
782
796
  let seglen;
783
797
 
784
798
  for (let i = 0; i < ii; i += 1) {
785
799
  // save current path command
786
- const [pathCommand] = path[i];
800
+ [pathCommand] = path[i];
787
801
 
788
802
  // Save current path command
789
803
  allPathCommands[i] = pathCommand;
@@ -807,8 +821,8 @@ function normalizePath(pathInput) { // path|pathString
807
821
  * Reverses all segments and their values of a `pathArray`
808
822
  * and returns a new instance.
809
823
  *
810
- * @param {SVGPC.pathArray} pathInput the source `pathArray`
811
- * @returns {SVGPC.pathArray} the reversed `pathArray`
824
+ * @param {SVGPathCommander.pathArray} pathInput the source `pathArray`
825
+ * @returns {SVGPathCommander.pathArray} the reversed `pathArray`
812
826
  */
813
827
  function reversePath(pathInput) {
814
828
  const absolutePath = pathToAbsolute(pathInput);
@@ -897,7 +911,7 @@ function reversePath(pathInput) {
897
911
  * In the process, values are converted to absolute
898
912
  * for visual consistency.
899
913
  *
900
- * @param {SVGPC.pathArray | string} pathInput the cubic-bezier parameters
914
+ * @param {SVGPathCommander.pathArray | string} pathInput the cubic-bezier parameters
901
915
  * @return {string[]} an array with all sub-path strings
902
916
  */
903
917
  function splitPath(pathInput) {
@@ -914,16 +928,19 @@ function splitPath(pathInput) {
914
928
  * * create a new `pathArray` with elements with shortest segments
915
929
  * from absolute and relative `pathArray`s
916
930
  *
917
- * @param {string | SVGPC.pathArray} pathInput a string or `pathArray`
918
- * @param {number | null} round the amount of decimals to round values to
919
- * @returns {SVGPC.pathArray} the optimized `pathArray`
931
+ * @param {string | SVGPathCommander.pathArray} pathInput a string or `pathArray`
932
+ * @param {number | boolean | null} round the amount of decimals to round values to
933
+ * @returns {SVGPathCommander.pathArray} the optimized `pathArray`
920
934
  */
921
935
  function optimizePath(pathInput, round) {
922
936
  const absolutePath = roundPath(pathToAbsolute(pathInput), round);
923
937
  const relativePath = roundPath(pathToRelative(pathInput), round);
938
+
924
939
  return absolutePath.map((x, i) => {
925
940
  if (i) {
926
- return x.join('').length < relativePath[i].join('').length ? x : relativePath[i];
941
+ return x.join('').length < relativePath[i].join('').length
942
+ ? x
943
+ : relativePath[i];
927
944
  }
928
945
  return x;
929
946
  });
@@ -932,7 +949,7 @@ function optimizePath(pathInput, round) {
932
949
  /**
933
950
  * A global namespace for epsilon.
934
951
  *
935
- * @type {Number}
952
+ * @type {number}
936
953
  */
937
954
  const epsilon = 1e-9;
938
955
 
@@ -940,8 +957,9 @@ const epsilon = 1e-9;
940
957
  * Returns an {x,y} vector rotated by a given
941
958
  * angle in radian.
942
959
  *
943
- * @param {Number} x the initial vector x
944
- * @param {Number} y the initial vector y
960
+ * @param {number} x the initial vector x
961
+ * @param {number} y the initial vector y
962
+ * @param {number} rad the radian vector angle
945
963
  * @returns {{x: number, y: number}} the rotated vector
946
964
  */
947
965
  function rotateVector(x, y, rad) {
@@ -956,29 +974,27 @@ function rotateVector(x, y, rad) {
956
974
  * For more information of where this math came from visit:
957
975
  * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
958
976
  *
959
- * @param {number} x1 the starting x position
960
- * @param {number} y1 the starting y position
961
- * @param {number} rx x-radius of the arc
962
- * @param {number} ry y-radius of the arc
977
+ * @param {number} X1 the starting x position
978
+ * @param {number} Y1 the starting y position
979
+ * @param {number} RX x-radius of the arc
980
+ * @param {number} RY y-radius of the arc
963
981
  * @param {number} angle x-axis-rotation of the arc
964
982
  * @param {number} LAF large-arc-flag of the arc
965
983
  * @param {number} SF sweep-flag of the arc
966
- * @param {number} x2 the ending x position
967
- * @param {number} y2 the ending y position
984
+ * @param {number} X2 the ending x position
985
+ * @param {number} Y2 the ending y position
968
986
  * @param {number[] | null} recursive the parameters needed to split arc into 2 segments
969
- * @return {number[]} the resulting cubic-bezier segment(s)
987
+ * @return {any} the resulting cubic-bezier segment(s)
970
988
  */
971
- function arcToCubic(x1, y1, rx, ry, angle, LAF, SF, x2, y2, recursive) {
989
+ // export default function arcToCubic(x1, y1, rx, ry, angle, LAF, SF, x2, y2, recursive) {
990
+ function arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, recursive) {
991
+ let x1 = X1; let y1 = Y1; let rx = RX; let ry = RY; let x2 = X2; let y2 = Y2;
992
+ // for more information of where this Math came from visit:
993
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
972
994
  const d120 = (Math.PI * 120) / 180;
973
- const rad = (Math.PI / 180) * (angle || 0);
974
- /** @type {number[]} */
995
+
996
+ const rad = (Math.PI / 180) * (+angle || 0);
975
997
  let res = [];
976
- let X1 = x1;
977
- let X2 = x2;
978
- let Y1 = y1;
979
- let Y2 = y2;
980
- let RX = rx;
981
- let RY = ry;
982
998
  let xy;
983
999
  let f1;
984
1000
  let f2;
@@ -986,41 +1002,39 @@ function arcToCubic(x1, y1, rx, ry, angle, LAF, SF, x2, y2, recursive) {
986
1002
  let cy;
987
1003
 
988
1004
  if (!recursive) {
989
- xy = rotateVector(X1, Y1, -rad);
990
- X1 = xy.x;
991
- Y1 = xy.y;
992
- xy = rotateVector(X2, Y2, -rad);
993
- X2 = xy.x;
994
- Y2 = xy.y;
995
-
996
- const x = (X1 - X2) / 2;
997
- const y = (Y1 - Y2) / 2;
998
- let h = (x ** 2) / (RX ** 2) + (y ** 2) / (RY ** 2);
1005
+ xy = rotateVector(x1, y1, -rad);
1006
+ x1 = xy.x;
1007
+ y1 = xy.y;
1008
+ xy = rotateVector(x2, y2, -rad);
1009
+ x2 = xy.x;
1010
+ y2 = xy.y;
1011
+
1012
+ const x = (x1 - x2) / 2;
1013
+ const y = (y1 - y2) / 2;
1014
+ let h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
999
1015
  if (h > 1) {
1000
1016
  h = Math.sqrt(h);
1001
- RX *= h;
1002
- RY *= h;
1017
+ rx *= h;
1018
+ ry *= h;
1003
1019
  }
1004
- const rx2 = RX ** 2;
1005
- const ry2 = RY ** 2;
1006
- const k = (LAF === SF ? -1 : 1)
1007
- * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x)
1008
- / (rx2 * y * y + ry2 * x * x)));
1020
+ const rx2 = rx * rx;
1021
+ const ry2 = ry * ry;
1009
1022
 
1010
- cx = ((k * RX * y) / RY) + ((X1 + X2) / 2);
1011
- cy = ((k * -RY * x) / RX) + ((Y1 + Y2) / 2);
1023
+ const k = (LAF === SF ? -1 : 1)
1024
+ * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x)
1025
+ / (rx2 * y * y + ry2 * x * x)));
1012
1026
 
1027
+ cx = ((k * rx * y) / ry) + ((x1 + x2) / 2);
1028
+ cy = ((k * -ry * x) / rx) + ((y1 + y2) / 2);
1013
1029
  // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise
1014
- f1 = Math.asin((((Y1 - cy) / RY) * 10 ** 9 >> 0) / (10 ** 9));
1030
+ f1 = (Math.asin((((y1 - cy) / ry))) * (10 ** 9) >> 0) / (10 ** 9);
1015
1031
  // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise
1016
- f2 = Math.asin((((Y2 - cy) / RY) * 10 ** 9 >> 0) / (10 ** 9));
1017
-
1018
- f1 = X1 < cx ? Math.PI - f1 : f1;
1019
- f2 = X2 < cx ? Math.PI - f2 : f2;
1020
-
1021
- if (f1 < 0) { f1 = Math.PI * 2 + f1; }
1022
- if (f2 < 0) { f2 = Math.PI * 2 + f2; }
1032
+ f2 = (Math.asin((((y2 - cy) / ry))) * (10 ** 9) >> 0) / (10 ** 9);
1023
1033
 
1034
+ f1 = x1 < cx ? Math.PI - f1 : f1;
1035
+ f2 = x2 < cx ? Math.PI - f2 : f2;
1036
+ if (f1 < 0) (f1 = Math.PI * 2 + f1);
1037
+ if (f2 < 0) (f2 = Math.PI * 2 + f2);
1024
1038
  if (SF && f1 > f2) {
1025
1039
  f1 -= Math.PI * 2;
1026
1040
  }
@@ -1028,63 +1042,55 @@ function arcToCubic(x1, y1, rx, ry, angle, LAF, SF, x2, y2, recursive) {
1028
1042
  f2 -= Math.PI * 2;
1029
1043
  }
1030
1044
  } else {
1031
- const [r1, r2, r3, r4] = recursive;
1032
- f1 = r1;
1033
- f2 = r2;
1034
- cx = r3;
1035
- cy = r4;
1045
+ [f1, f2, cx, cy] = recursive;
1036
1046
  }
1037
-
1038
1047
  let df = f2 - f1;
1039
-
1040
1048
  if (Math.abs(df) > d120) {
1041
1049
  const f2old = f2;
1042
- const x2old = X2;
1043
- const y2old = Y2;
1044
-
1050
+ const x2old = x2;
1051
+ const y2old = y2;
1045
1052
  f2 = f1 + d120 * (SF && f2 > f1 ? 1 : -1);
1046
- X2 = cx + RX * Math.cos(f2);
1047
- Y2 = cy + RY * Math.sin(f2);
1048
- res = arcToCubic(X2, Y2, RX, RY, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]);
1053
+ x2 = cx + rx * Math.cos(f2);
1054
+ y2 = cy + ry * Math.sin(f2);
1055
+ res = arcToCubic(x2, y2, rx, ry, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]);
1049
1056
  }
1050
-
1051
1057
  df = f2 - f1;
1052
1058
  const c1 = Math.cos(f1);
1053
1059
  const s1 = Math.sin(f1);
1054
1060
  const c2 = Math.cos(f2);
1055
1061
  const s2 = Math.sin(f2);
1056
1062
  const t = Math.tan(df / 4);
1057
- const hx = (4 / 3) * RX * t;
1058
- const hy = (4 / 3) * RY * t;
1059
- const m1 = [X1, Y1];
1060
- const m2 = [X1 + hx * s1, Y1 - hy * c1];
1061
- const m3 = [X2 + hx * s2, Y2 - hy * c2];
1062
- const m4 = [X2, Y2];
1063
+ const hx = (4 / 3) * rx * t;
1064
+ const hy = (4 / 3) * ry * t;
1065
+ const m1 = [x1, y1];
1066
+ const m2 = [x1 + hx * s1, y1 - hy * c1];
1067
+ const m3 = [x2 + hx * s2, y2 - hy * c2];
1068
+ const m4 = [x2, y2];
1063
1069
  m2[0] = 2 * m1[0] - m2[0];
1064
1070
  m2[1] = 2 * m1[1] - m2[1];
1065
-
1066
1071
  if (recursive) {
1067
- return [m2, m3, m4].concat(res).map((n) => +n);
1072
+ return [m2, m3, m4].concat(res);
1068
1073
  }
1069
- res = [m2, m3, m4].concat(res).join().split(',').map((n) => +n);
1070
- return res.map((rz, i) => {
1071
- if (i % 2) {
1072
- return rotateVector(res[i - 1], rz, rad).y;
1073
- }
1074
- return rotateVector(rz, res[i + 1], rad).x;
1075
- });
1074
+ res = [m2, m3, m4].concat(res).join().split(',');
1075
+ const newres = [];
1076
+ for (let i = 0, ii = res.length; i < ii; i += 1) {
1077
+ newres[i] = i % 2
1078
+ // @ts-ignore
1079
+ ? rotateVector(res[i - 1], res[i], rad).y : rotateVector(res[i], res[i + 1], rad).x;
1080
+ }
1081
+ return newres;
1076
1082
  }
1077
1083
 
1078
1084
  /**
1079
1085
  * Converts a Q (quadratic-bezier) segment to C (cubic-bezier).
1080
1086
  *
1081
- * @param {Number} x1 curve start x
1082
- * @param {Number} y1 curve start y
1083
- * @param {Number} qx control point x
1084
- * @param {Number} qy control point y
1085
- * @param {Number} x2 curve end x
1086
- * @param {Number} y2 curve end y
1087
- * @returns {Number[]} the cubic-bezier segment
1087
+ * @param {number} x1 curve start x
1088
+ * @param {number} y1 curve start y
1089
+ * @param {number} qx control point x
1090
+ * @param {number} qy control point y
1091
+ * @param {number} x2 curve end x
1092
+ * @param {number} y2 curve end y
1093
+ * @returns {number[]} the cubic-bezier segment
1088
1094
  */
1089
1095
  function quadToCubic(x1, y1, qx, qy, x2, y2) {
1090
1096
  const r13 = 1 / 3;
@@ -1102,15 +1108,15 @@ function quadToCubic(x1, y1, qx, qy, x2, y2) {
1102
1108
  * Returns the {x,y} coordinates of a point at a
1103
1109
  * given length of a cubic-bezier segment.
1104
1110
  *
1105
- * @param {Number} p1x the starting point X
1106
- * @param {Number} p1y the starting point Y
1107
- * @param {Number} c1x the first control point X
1108
- * @param {Number} c1y the first control point Y
1109
- * @param {Number} c2x the second control point X
1110
- * @param {Number} c2y the second control point Y
1111
- * @param {Number} px2 the ending point X
1112
- * @param {Number} py2 the ending point Y
1113
- * @param {Number} t a [0-1] ratio
1111
+ * @param {number} p1x the starting point X
1112
+ * @param {number} p1y the starting point Y
1113
+ * @param {number} c1x the first control point X
1114
+ * @param {number} c1y the first control point Y
1115
+ * @param {number} c2x the second control point X
1116
+ * @param {number} c2y the second control point Y
1117
+ * @param {number} p2x the ending point X
1118
+ * @param {number} p2y the ending point Y
1119
+ * @param {number} t a [0-1] ratio
1114
1120
  * @returns {{x: number, y: number}} the requested {x,y} coordinates
1115
1121
  */
1116
1122
  function getPointAtSegLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
@@ -1144,11 +1150,11 @@ function midPoint(a, b, t) {
1144
1150
  /**
1145
1151
  * Converts an L (line-to) segment to C (cubic-bezier).
1146
1152
  *
1147
- * @param {Number} x1 line start x
1148
- * @param {Number} y1 line start y
1149
- * @param {Number} x2 line end x
1150
- * @param {Number} y2 line end y
1151
- * @returns {Number[]} the cubic-bezier segment
1153
+ * @param {number} x1 line start x
1154
+ * @param {number} y1 line start y
1155
+ * @param {number} x2 line end x
1156
+ * @param {number} y2 line end y
1157
+ * @returns {number[]} the cubic-bezier segment
1152
1158
  */
1153
1159
  function lineToCubic(x1, y1, x2, y2) {
1154
1160
  const t = 0.5;
@@ -1159,7 +1165,9 @@ function lineToCubic(x1, y1, x2, y2) {
1159
1165
  const p4 = midPoint(p2, p3, t);
1160
1166
  const p5 = midPoint(p3, p4, t);
1161
1167
  const p6 = midPoint(p4, p5, t);
1168
+ // @ts-ignore -- rest operator won't fix
1162
1169
  const cp1 = getPointAtSegLength.apply(0, p0.concat(p2, p4, p6, t));
1170
+ // @ts-ignore
1163
1171
  const cp2 = getPointAtSegLength.apply(0, p6.concat(p5, p3, p1, 0));
1164
1172
 
1165
1173
  return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
@@ -1168,12 +1176,12 @@ function lineToCubic(x1, y1, x2, y2) {
1168
1176
  /**
1169
1177
  * Converts any segment to C (cubic-bezier).
1170
1178
  *
1171
- * @param {SVGPC.pathSegment} segment the source segment
1172
- * @param {SVGPC.parserParams} params the source segment parameters
1173
- * @returns {SVGPC.pathSegment} the cubic-bezier segment
1179
+ * @param {SVGPathCommander.pathSegment} segment the source segment
1180
+ * @param {SVGPathCommander.parserParams} params the source segment parameters
1181
+ * @returns {SVGPathCommander.pathSegment} the cubic-bezier segment
1174
1182
  */
1175
1183
  function segmentToCubic(segment, params) {
1176
- if ('TQ'.indexOf(segment[0]) < 0) {
1184
+ if (!'TQ'.includes(segment[0])) {
1177
1185
  params.qx = null;
1178
1186
  params.qy = null;
1179
1187
  }
@@ -1206,7 +1214,7 @@ function segmentToCubic(segment, params) {
1206
1214
  /**
1207
1215
  * Splits an extended A (arc-to) segment into two cubic-bezier segments.
1208
1216
  *
1209
- * @param {SVGPC.pathArray} path the `pathArray` this segment belongs to
1217
+ * @param {SVGPathCommander.pathArray} path the `pathArray` this segment belongs to
1210
1218
  * @param {string[]} allPathCommands all previous path commands
1211
1219
  * @param {Number} i the index of the segment
1212
1220
  */
@@ -1219,31 +1227,22 @@ function fixArc(path, allPathCommands, i) {
1219
1227
  while (segment.length) {
1220
1228
  // if created multiple C:s, their original seg is saved
1221
1229
  allPathCommands[i] = 'A';
1230
+ // path.splice(i++, 0, ['C'].concat(segment.splice(0, 6)));
1231
+ // @ts-ignore -- cannot fix
1222
1232
  path.splice(ni += 1, 0, ['C'].concat(segment.splice(0, 6)));
1223
1233
  }
1224
1234
  path.splice(i, 1);
1225
1235
  }
1226
1236
  }
1227
1237
 
1228
- var version$1 = "0.0.16alpha4";
1229
-
1230
- // @ts-ignore
1231
-
1232
- /**
1233
- * A global namespace for library version.
1234
- * @type {string}
1235
- */
1236
- const DMVersion = version$1;
1237
-
1238
1238
  // DOMMatrix Static methods
1239
- // * `fromFloat64Array` and `fromFloat32Array` methods are not supported;
1240
- // * `fromArray` a more simple implementation, should also accept float[32/64]Array;
1241
- // * `fromMatrix` load values from another CSSMatrix/DOMMatrix instance;
1242
- // * `fromString` parses and loads values from any valid CSS transform string.
1239
+ // * `fromFloat64Array` and `fromFloat32Array are not implemented;
1240
+ // * `fromArray` is a more simple implementation, should also accept Float[32/64]Array;
1241
+ // * `fromMatrix` load values from another CSSMatrix/DOMMatrix instance or JSON object;
1242
+ // * `fromString` parses and loads values from any valid CSS transform string (TransformList).
1243
1243
 
1244
1244
  /**
1245
- * Creates a new mutable `CSSMatrix` object given an array of floating point values.
1246
- *
1245
+ * Creates a new mutable `CSSMatrix` instance given an array of 16/6 floating point values.
1247
1246
  * This static method invalidates arrays that contain non-number elements.
1248
1247
  *
1249
1248
  * If the array has six values, the result is a 2D matrix; if the array has 16 values,
@@ -1253,12 +1252,12 @@ const DMVersion = version$1;
1253
1252
  * @return {CSSMatrix} the resulted matrix.
1254
1253
  */
1255
1254
  function fromArray(array) {
1256
- if (!array.every((n) => !Number.isNaN(n))) {
1257
- throw TypeError(`CSSMatrix: "${array}" must only have numbers.`);
1258
- }
1259
1255
  const m = new CSSMatrix();
1260
1256
  const a = Array.from(array);
1261
1257
 
1258
+ if (!a.every((n) => !Number.isNaN(n))) {
1259
+ throw TypeError(`CSSMatrix: "${array}" must only have numbers.`);
1260
+ }
1262
1261
  if (a.length === 16) {
1263
1262
  const [m11, m12, m13, m14,
1264
1263
  m21, m22, m23, m24,
@@ -1296,25 +1295,25 @@ function fromArray(array) {
1296
1295
  m.m34 = m34;
1297
1296
  m.m44 = m44;
1298
1297
  } else if (a.length === 6) {
1299
- const [m11, m12, m21, m22, m41, m42] = a;
1298
+ const [M11, M12, M21, M22, M41, M42] = a;
1300
1299
 
1301
- m.m11 = m11;
1302
- m.a = m11;
1300
+ m.m11 = M11;
1301
+ m.a = M11;
1303
1302
 
1304
- m.m12 = m12;
1305
- m.b = m12;
1303
+ m.m12 = M12;
1304
+ m.b = M12;
1306
1305
 
1307
- m.m21 = m21;
1308
- m.c = m21;
1306
+ m.m21 = M21;
1307
+ m.c = M21;
1309
1308
 
1310
- m.m22 = m22;
1311
- m.d = m22;
1309
+ m.m22 = M22;
1310
+ m.d = M22;
1312
1311
 
1313
- m.m41 = m41;
1314
- m.e = m41;
1312
+ m.m41 = M41;
1313
+ m.e = M41;
1315
1314
 
1316
- m.m42 = m42;
1317
- m.f = m42;
1315
+ m.m42 = M42;
1316
+ m.f = M42;
1318
1317
  } else {
1319
1318
  throw new TypeError('CSSMatrix: expecting an Array of 6/16 values.');
1320
1319
  }
@@ -1325,17 +1324,12 @@ function fromArray(array) {
1325
1324
  * Creates a new mutable `CSSMatrix` instance given an existing matrix or a
1326
1325
  * `DOMMatrix` instance which provides the values for its properties.
1327
1326
  *
1328
- * @param {CSSMatrix | DOMMatrix | DMNS.jsonMatrix} m the source matrix to feed values from.
1327
+ * @param {CSSMatrix | DOMMatrix | CSSMatrix.JSONMatrix} m the source matrix to feed values from.
1329
1328
  * @return {CSSMatrix} the resulted matrix.
1330
1329
  */
1331
1330
  function fromMatrix(m) {
1332
- const keys = [
1333
- 'm11', 'm12', 'm13', 'm14',
1334
- 'm21', 'm22', 'm23', 'm24',
1335
- 'm31', 'm32', 'm33', 'm34',
1336
- 'm41', 'm42', 'm43', 'm44'];
1337
- if ([CSSMatrix, DOMMatrix].some((x) => m instanceof x)
1338
- || (typeof m === 'object' && keys.every((k) => k in m))) {
1331
+ const keys = Object.keys(new CSSMatrix());
1332
+ if (typeof m === 'object' && keys.every((k) => k in m)) {
1339
1333
  return fromArray(
1340
1334
  [m.m11, m.m12, m.m13, m.m14,
1341
1335
  m.m21, m.m22, m.m23, m.m24,
@@ -1343,11 +1337,12 @@ function fromMatrix(m) {
1343
1337
  m.m41, m.m42, m.m43, m.m44],
1344
1338
  );
1345
1339
  }
1346
- throw TypeError(`CSSMatrix: "${m}" is not a DOMMatrix / CSSMatrix compatible object.`);
1340
+ throw TypeError(`CSSMatrix: "${m}" is not a DOMMatrix / CSSMatrix / JSON compatible object.`);
1347
1341
  }
1348
1342
 
1349
1343
  /**
1350
- * Creates a new mutable `CSSMatrix` instance given any valid CSS transform string.
1344
+ * Creates a new mutable `CSSMatrix` given any valid CSS transform string,
1345
+ * or what we call `TransformList`:
1351
1346
  *
1352
1347
  * * `matrix(a, b, c, d, e, f)` - valid matrix() transform function
1353
1348
  * * `matrix3d(m11, m12, m13, ...m44)` - valid matrix3d() transform function
@@ -1364,55 +1359,62 @@ function fromString(source) {
1364
1359
  }
1365
1360
  const str = String(source).replace(/\s/g, '');
1366
1361
  let m = new CSSMatrix();
1367
- let is2D = true;
1368
- const tramsformObject = str.split(')').filter((f) => f).map((fn) => {
1369
- const [prop, value] = fn.split('(');
1362
+ const invalidStringError = `CSSMatrix: invalid transform string "${source}"`;
1363
+
1364
+ // const px = ['perspective'];
1365
+ // const length = ['translate', 'translate3d', 'translateX', 'translateY', 'translateZ'];
1366
+ // const deg = ['rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'skew', 'skewX', 'skewY'];
1367
+ // const abs = ['scale', 'scale3d', 'matrix', 'matrix3d'];
1368
+ // const transformFunctions = px.concat(length, deg, abs);
1369
+
1370
+ str.split(')').filter((f) => f).forEach((tf) => {
1371
+ const [prop, value] = tf.split('(');
1372
+
1373
+ // invalidate empty string
1374
+ if (!value) throw TypeError(invalidStringError);
1375
+
1370
1376
  const components = value.split(',')
1371
1377
  .map((n) => (n.includes('rad') ? parseFloat(n) * (180 / Math.PI) : parseFloat(n)));
1372
- const [x, y, z, a] = components;
1373
-
1374
- // don't add perspective if is2D
1375
- if (is2D && (prop === 'matrix3d' // only modify is2D once
1376
- || (prop === 'rotate3d' && [x, y].every((n) => !Number.isNaN(+n) && n !== 0) && a)
1377
- || (['rotateX', 'rotateY'].includes(prop) && x)
1378
- || (prop === 'translate3d' && [x, y, z].every((n) => !Number.isNaN(+n)) && z)
1379
- || (prop === 'scale3d' && [x, y, z].every((n) => !Number.isNaN(+n) && n !== x))
1380
- )) {
1381
- is2D = false;
1382
- }
1383
- return { prop, components };
1384
- });
1385
1378
 
1386
- tramsformObject.forEach((tf) => {
1387
- const { prop, components } = tf;
1388
1379
  const [x, y, z, a] = components;
1389
1380
  const xyz = [x, y, z];
1390
1381
  const xyza = [x, y, z, a];
1391
1382
 
1392
- if (prop === 'perspective' && !is2D) {
1383
+ // single number value expected
1384
+ if (prop === 'perspective' && x && [y, z].every((n) => n === undefined)) {
1393
1385
  m.m34 = -1 / x;
1394
- } else if (prop.includes('matrix')) {
1386
+ // 6/16 number values expected
1387
+ } else if (prop.includes('matrix') && [6, 16].includes(components.length)
1388
+ && components.every((n) => !Number.isNaN(+n))) {
1395
1389
  const values = components.map((n) => (Math.abs(n) < 1e-6 ? 0 : n));
1396
- if ([6, 16].includes(values.length)) {
1397
- m = m.multiply(fromArray(values));
1398
- }
1399
- } else if (['translate', 'translate3d'].some((p) => prop === p) && x) {
1400
- m = m.translate(x, y || 0, z || 0);
1390
+ m = m.multiply(fromArray(values));
1391
+ // 3 values expected
1392
+ } else if (prop === 'translate3d' && xyz.every((n) => !Number.isNaN(+n))) {
1393
+ m = m.translate(x, y, z);
1394
+ // single/double number value(s) expected
1395
+ } else if (prop === 'translate' && x && z === undefined) {
1396
+ m = m.translate(x, y || 0, 0);
1397
+ // all 4 values expected
1401
1398
  } else if (prop === 'rotate3d' && xyza.every((n) => !Number.isNaN(+n)) && a) {
1402
1399
  m = m.rotateAxisAngle(x, y, z, a);
1400
+ // single value expected
1401
+ } else if (prop === 'rotate' && x && [y, z].every((n) => n === undefined)) {
1402
+ m = m.rotate(0, 0, x);
1403
+ // 4 values expected
1403
1404
  } else if (prop === 'scale3d' && xyz.every((n) => !Number.isNaN(+n)) && xyz.some((n) => n !== 1)) {
1404
1405
  m = m.scale(x, y, z);
1405
- } else if (prop === 'rotate' && x) {
1406
- m = m.rotate(0, 0, x);
1407
- } else if (prop === 'scale' && !Number.isNaN(x) && x !== 1) {
1406
+ // single value expected
1407
+ } else if (prop === 'scale' && !Number.isNaN(x) && x !== 1 && z === undefined) {
1408
1408
  const nosy = Number.isNaN(+y);
1409
1409
  const sy = nosy ? x : y;
1410
1410
  m = m.scale(x, sy, 1);
1411
- } else if (prop === 'skew' && (x || y)) {
1412
- m = x ? m.skewX(x) : m;
1411
+ // single/double value expected
1412
+ } else if (prop === 'skew' && x && z === undefined) {
1413
+ m = m.skewX(x);
1413
1414
  m = y ? m.skewY(y) : m;
1414
- } else if (/[XYZ]/.test(prop) && x) {
1415
- if (prop.includes('skew')) {
1415
+ } else if (/[XYZ]/.test(prop) && x && [y, z].every((n) => n === undefined) // a single value expected
1416
+ && ['translate', 'rotate', 'scale', 'skew'].some((p) => prop.includes(p))) {
1417
+ if (['skewX', 'skewY'].includes(prop)) {
1416
1418
  // @ts-ignore unfortunately
1417
1419
  m = m[prop](x);
1418
1420
  } else {
@@ -1426,6 +1428,8 @@ function fromString(source) {
1426
1428
  // @ts-ignore unfortunately
1427
1429
  m = m[fn](...axeValues);
1428
1430
  }
1431
+ } else {
1432
+ throw TypeError(invalidStringError);
1429
1433
  }
1430
1434
  });
1431
1435
 
@@ -1575,7 +1579,8 @@ function RotateAxisAngle(x, y, z, alpha) {
1575
1579
 
1576
1580
  /**
1577
1581
  * Creates a new `CSSMatrix` for the scale matrix and returns it.
1578
- * This method is equivalent to the CSS `scale3d()` function.
1582
+ * This method is equivalent to the CSS `scale3d()` function, except it doesn't
1583
+ * accept {x, y, z} transform origin parameters.
1579
1584
  *
1580
1585
  * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale3d
1581
1586
  *
@@ -1670,18 +1675,18 @@ function Multiply(m1, m2) {
1670
1675
  }
1671
1676
 
1672
1677
  /**
1673
- * Creates and returns a new `DOMMatrix` compatible *Object*
1674
- * with equivalent instance methods.
1678
+ * Creates and returns a new `DOMMatrix` compatible instance
1679
+ * with equivalent instance.
1675
1680
  *
1676
1681
  * https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix
1677
1682
  * https://github.com/thednp/DOMMatrix/
1683
+ * @class
1678
1684
  */
1679
1685
 
1680
1686
  class CSSMatrix {
1681
1687
  /**
1682
1688
  * @constructor
1683
1689
  * @param {any} args accepts all parameter configurations:
1684
- *
1685
1690
  * * valid CSS transform string,
1686
1691
  * * CSSMatrix/DOMMatrix instance,
1687
1692
  * * a 6/16 elements *Array*.
@@ -1699,15 +1704,8 @@ class CSSMatrix {
1699
1704
  m.m41 = 0; m.m42 = 0; m.m43 = 0; m.m44 = 1;
1700
1705
 
1701
1706
  if (args && args.length) {
1702
- let ARGS = args;
1707
+ const ARGS = [16, 6].some((l) => l === args.length) ? args : args[0];
1703
1708
 
1704
- if (args instanceof Array) {
1705
- if ((args[0] instanceof Array && [16, 6].includes(args[0].length))
1706
- || typeof args[0] === 'string'
1707
- || [CSSMatrix, DOMMatrix].some((x) => args[0] instanceof x)) {
1708
- [ARGS] = args;
1709
- }
1710
- }
1711
1709
  return m.setMatrixValue(ARGS);
1712
1710
  }
1713
1711
  return m;
@@ -1716,7 +1714,7 @@ class CSSMatrix {
1716
1714
  /**
1717
1715
  * Sets a new `Boolean` flag value for `this.isIdentity` matrix property.
1718
1716
  *
1719
- * @param {Boolean} value sets a new flag for this property
1717
+ * @param {boolean} value sets a new flag for this property
1720
1718
  */
1721
1719
  set isIdentity(value) {
1722
1720
  this.isIdentity = value;
@@ -1727,7 +1725,7 @@ class CSSMatrix {
1727
1725
  * matrix is one in which every value is 0 except those on the main diagonal from top-left
1728
1726
  * to bottom-right corner (in other words, where the offsets in each direction are equal).
1729
1727
  *
1730
- * @return {Boolean} the current property value
1728
+ * @return {boolean} the current property value
1731
1729
  */
1732
1730
  get isIdentity() {
1733
1731
  const m = this;
@@ -1741,7 +1739,7 @@ class CSSMatrix {
1741
1739
  * A `Boolean` flag whose value is `true` if the matrix was initialized as a 2D matrix
1742
1740
  * and `false` if the matrix is 3D.
1743
1741
  *
1744
- * @return {Boolean} the current property value
1742
+ * @return {boolean} the current property value
1745
1743
  */
1746
1744
  get is2D() {
1747
1745
  const m = this;
@@ -1751,7 +1749,7 @@ class CSSMatrix {
1751
1749
  /**
1752
1750
  * Sets a new `Boolean` flag value for `this.is2D` matrix property.
1753
1751
  *
1754
- * @param {Boolean} value sets a new flag for this property
1752
+ * @param {boolean} value sets a new flag for this property
1755
1753
  */
1756
1754
  set is2D(value) {
1757
1755
  this.is2D = value;
@@ -1774,47 +1772,31 @@ class CSSMatrix {
1774
1772
  setMatrixValue(source) {
1775
1773
  const m = this;
1776
1774
 
1777
- // new CSSMatrix(CSSMatrix | DOMMatrix)
1778
- if ([DOMMatrix, CSSMatrix].some((x) => source instanceof x)) {
1779
- // @ts-ignore
1780
- return fromMatrix(source);
1781
- // CSS transform string source
1782
- } if (typeof source === 'string' && source.length && source !== 'none') {
1783
- return fromString(source);
1784
1775
  // [Arguments list | Array] come here
1785
- } if (Array.isArray(source)) {
1776
+ if ([Array, Float64Array, Float32Array].some((a) => source instanceof a)) {
1786
1777
  return fromArray(source);
1787
1778
  }
1779
+ // CSS transform string source - TransformList
1780
+ if (typeof source === 'string' && source.length && source !== 'none') {
1781
+ return fromString(source);
1782
+ }
1783
+ // new CSSMatrix(CSSMatrix | DOMMatrix | JSON)
1784
+ if (typeof source === 'object') {
1785
+ return fromMatrix(source);
1786
+ }
1788
1787
  return m;
1789
1788
  }
1790
1789
 
1791
1790
  /**
1792
- * Creates and returns a string representation of the matrix in `CSS` matrix syntax,
1793
- * using the appropriate `CSS` matrix notation.
1794
- *
1795
- * matrix3d *matrix3d(m11, m12, m13, m14, m21, ...)*
1796
- * matrix *matrix(a, b, c, d, e, f)*
1797
- *
1798
- * @return {string} a string representation of the matrix
1799
- */
1800
- toString() {
1801
- const m = this;
1802
- const values = m.toArray().join(',');
1803
- const type = m.is2D ? 'matrix' : 'matrix3d';
1804
- return `${type}(${values})`;
1805
- }
1806
-
1807
- /**
1808
- * Returns an *Array* containing all 16 elements which comprise the matrix.
1809
- * The method can return either the elements.
1810
- *
1811
- * Other methods make use of this method to feed their output values from this matrix.
1791
+ * Returns an *Array* containing elements which comprise the matrix.
1792
+ * The method can return either the 16 elements or the 6 elements
1793
+ * depending on the value of the `is2D` property.
1812
1794
  *
1813
1795
  * @return {number[]} an *Array* representation of the matrix
1814
1796
  */
1815
1797
  toArray() {
1816
1798
  const m = this;
1817
- const pow6 = (10 ** 6);
1799
+ const pow = (10 ** 6);
1818
1800
  let result;
1819
1801
 
1820
1802
  if (m.is2D) {
@@ -1827,21 +1809,39 @@ class CSSMatrix {
1827
1809
  }
1828
1810
  // clean up the numbers
1829
1811
  // eslint-disable-next-line -- no-bitwise
1830
- return result.map((n) => (Math.abs(n) < 1e-6 ? 0 : ((n * pow6) >> 0) / pow6));
1812
+ return result.map((n) => (Math.abs(n) < 1e-6 ? 0 : ((n * pow) >> 0) / pow));
1813
+ }
1814
+
1815
+ /**
1816
+ * Creates and returns a string representation of the matrix in `CSS` matrix syntax,
1817
+ * using the appropriate `CSS` matrix notation.
1818
+ *
1819
+ * matrix3d *matrix3d(m11, m12, m13, m14, m21, ...)*
1820
+ * matrix *matrix(a, b, c, d, e, f)*
1821
+ *
1822
+ * @return {string} a string representation of the matrix
1823
+ */
1824
+ toString() {
1825
+ const m = this;
1826
+ const values = m.toArray();
1827
+ const type = m.is2D ? 'matrix' : 'matrix3d';
1828
+ return `${type}(${values})`;
1831
1829
  }
1832
1830
 
1833
1831
  /**
1834
1832
  * Returns a JSON representation of the `CSSMatrix` instance, a standard *Object*
1835
- * that includes `{a,b,c,d,e,f}` and `{m11,m12,m13,..m44}` properties and
1836
- * excludes `is2D` & `isIdentity` properties.
1833
+ * that includes `{a,b,c,d,e,f}` and `{m11,m12,m13,..m44}` properties as well
1834
+ * as the `is2D` & `isIdentity` properties.
1837
1835
  *
1838
1836
  * The result can also be used as a second parameter for the `fromMatrix` static method
1839
- * to load values into a matrix instance.
1837
+ * to load values into another matrix instance.
1840
1838
  *
1841
- * @return {DMNS.jsonMatrix} an *Object* with all matrix values.
1839
+ * @return {CSSMatrix.JSONMatrix} an *Object* with all matrix values.
1842
1840
  */
1843
1841
  toJSON() {
1844
- return JSON.parse(JSON.stringify(this));
1842
+ const m = this;
1843
+ const { is2D, isIdentity } = m;
1844
+ return { ...m, is2D, isIdentity };
1845
1845
  }
1846
1846
 
1847
1847
  /**
@@ -1849,11 +1849,10 @@ class CSSMatrix {
1849
1849
  * matrix multiplied by the passed matrix, with the passed matrix to the right.
1850
1850
  * This matrix is not modified.
1851
1851
  *
1852
- * @param {CSSMatrix | DOMMatrix | DMNS.jsonMatrix} m2 CSSMatrix
1852
+ * @param {CSSMatrix | DOMMatrix | CSSMatrix.JSONMatrix} m2 CSSMatrix
1853
1853
  * @return {CSSMatrix} The resulted matrix.
1854
1854
  */
1855
1855
  multiply(m2) {
1856
- // @ts-ignore - we only access [m11, m12, ... m44] values
1857
1856
  return Multiply(this, m2);
1858
1857
  }
1859
1858
 
@@ -1864,16 +1863,16 @@ class CSSMatrix {
1864
1863
  * modified.
1865
1864
  *
1866
1865
  * @param {number} x X component of the translation value.
1867
- * @param {number | null} y Y component of the translation value.
1868
- * @param {number | null} z Z component of the translation value.
1866
+ * @param {number=} y Y component of the translation value.
1867
+ * @param {number=} z Z component of the translation value.
1869
1868
  * @return {CSSMatrix} The resulted matrix
1870
1869
  */
1871
1870
  translate(x, y, z) {
1872
1871
  const X = x;
1873
1872
  let Y = y;
1874
1873
  let Z = z;
1875
- if (Z == null) Z = 0;
1876
- if (Y == null) Y = 0;
1874
+ if (Z === undefined) Z = 0;
1875
+ if (Y === undefined) Y = 0;
1877
1876
  return Multiply(this, Translate(X, Y, Z));
1878
1877
  }
1879
1878
 
@@ -1884,16 +1883,16 @@ class CSSMatrix {
1884
1883
  * component value is used in its place. This matrix is not modified.
1885
1884
  *
1886
1885
  * @param {number} x The X component of the scale value.
1887
- * @param {number | null} y The Y component of the scale value.
1888
- * @param {number | null} z The Z component of the scale value.
1886
+ * @param {number=} y The Y component of the scale value.
1887
+ * @param {number=} z The Z component of the scale value.
1889
1888
  * @return {CSSMatrix} The resulted matrix
1890
1889
  */
1891
1890
  scale(x, y, z) {
1892
1891
  const X = x;
1893
1892
  let Y = y;
1894
1893
  let Z = z;
1895
- if (Y == null) Y = x;
1896
- if (Z == null) Z = x;
1894
+ if (Y === undefined) Y = x;
1895
+ if (Z === undefined) Z = 1; // Z must be 1 if undefined
1897
1896
 
1898
1897
  return Multiply(this, Scale(X, Y, Z));
1899
1898
  }
@@ -1906,16 +1905,16 @@ class CSSMatrix {
1906
1905
  * rotation values are in degrees. This matrix is not modified.
1907
1906
  *
1908
1907
  * @param {number} rx The X component of the rotation, or Z if Y and Z are null.
1909
- * @param {number | null} ry The (optional) Y component of the rotation value.
1910
- * @param {number | null} rz The (optional) Z component of the rotation value.
1908
+ * @param {number=} ry The (optional) Y component of the rotation value.
1909
+ * @param {number=} rz The (optional) Z component of the rotation value.
1911
1910
  * @return {CSSMatrix} The resulted matrix
1912
1911
  */
1913
1912
  rotate(rx, ry, rz) {
1914
1913
  let RX = rx;
1915
1914
  let RY = ry;
1916
1915
  let RZ = rz;
1917
- if (RY == null) RY = 0;
1918
- if (RZ == null) { RZ = RX; RX = 0; }
1916
+ if (RY === undefined) RY = 0;
1917
+ if (RZ === undefined) { RZ = RX; RX = 0; }
1919
1918
  return Multiply(this, Rotate(RX, RY, RZ));
1920
1919
  }
1921
1920
 
@@ -1970,8 +1969,8 @@ class CSSMatrix {
1970
1969
  *
1971
1970
  * @copyright thednp © 2021
1972
1971
  *
1973
- * @param {DMNS.PointTuple | DOMPoint} v Tuple or DOMPoint
1974
- * @return {DMNS.PointTuple} the resulting Tuple
1972
+ * @param {CSSMatrix.PointTuple | DOMPoint} v Tuple or DOMPoint
1973
+ * @return {CSSMatrix.PointTuple} the resulting Tuple
1975
1974
  */
1976
1975
  transformPoint(v) {
1977
1976
  const M = this;
@@ -1993,8 +1992,8 @@ class CSSMatrix {
1993
1992
  * {x,y,z,w} Tuple *Object* comprising the transformed vector.
1994
1993
  * Neither the matrix nor the original vector are altered.
1995
1994
  *
1996
- * @param {DMNS.PointTuple} t Tuple with `{x,y,z,w}` components
1997
- * @return {DMNS.PointTuple} the resulting Tuple
1995
+ * @param {CSSMatrix.PointTuple} t Tuple with `{x,y,z,w}` components
1996
+ * @return {CSSMatrix.PointTuple} the resulting Tuple
1998
1997
  */
1999
1998
  transform(t) {
2000
1999
  const m = this;
@@ -2013,29 +2012,31 @@ class CSSMatrix {
2013
2012
  }
2014
2013
 
2015
2014
  // Add Transform Functions to CSSMatrix object
2016
- CSSMatrix.Translate = Translate;
2017
- CSSMatrix.Rotate = Rotate;
2018
- CSSMatrix.RotateAxisAngle = RotateAxisAngle;
2019
- CSSMatrix.Scale = Scale;
2020
- CSSMatrix.SkewX = SkewX;
2021
- CSSMatrix.SkewY = SkewY;
2022
- CSSMatrix.Multiply = Multiply;
2023
- CSSMatrix.fromArray = fromArray;
2024
- CSSMatrix.fromMatrix = fromMatrix;
2025
- CSSMatrix.fromString = fromString;
2026
- CSSMatrix.Version = DMVersion;
2015
+ // without creating a TypeScript namespace.
2016
+ Object.assign(CSSMatrix, {
2017
+ Translate,
2018
+ Rotate,
2019
+ RotateAxisAngle,
2020
+ Scale,
2021
+ SkewX,
2022
+ SkewY,
2023
+ Multiply,
2024
+ fromArray,
2025
+ fromMatrix,
2026
+ fromString,
2027
+ });
2027
2028
 
2028
2029
  /**
2029
2030
  * Returns a transformation matrix to apply to `<path>` elements.
2030
2031
  *
2031
- * @param {SVGPC.transformObject} transform the `transformObject`
2032
+ * @param {SVGPathCommander.transformObject} transform the `transformObject`
2032
2033
  * @returns {CSSMatrix} a new transformation matrix
2033
2034
  */
2034
2035
  function getSVGMatrix(transform) {
2035
2036
  let matrix = new CSSMatrix();
2036
2037
  const { origin } = transform;
2037
- const originX = +origin[0];
2038
- const originY = +origin[1];
2038
+ const originX = origin[0];
2039
+ const originY = origin[1];
2039
2040
  const { translate } = transform;
2040
2041
  const { rotate } = transform;
2041
2042
  const { skew } = transform;
@@ -2045,19 +2046,20 @@ function getSVGMatrix(transform) {
2045
2046
  if ((Array.isArray(translate) && translate.some((x) => +x !== 0)) || !Number.isNaN(translate)) {
2046
2047
  matrix = Array.isArray(translate)
2047
2048
  ? matrix.translate(+translate[0] || 0, +translate[1] || 0, +translate[2] || 0)
2048
- : matrix.translate(+translate || 0);
2049
+ : matrix.translate(+translate || 0, 0, 0);
2049
2050
  }
2050
2051
 
2051
2052
  if (rotate || skew || scale) {
2052
2053
  // set SVG transform-origin, always defined
2053
2054
  // matrix = matrix.translate(+originX,+originY,+originZ)
2055
+ // @ts-ignore -- SVG transform origin is always 2D
2054
2056
  matrix = matrix.translate(+originX, +originY);
2055
2057
 
2056
2058
  // set rotation
2057
2059
  if (rotate) {
2058
2060
  matrix = Array.isArray(rotate) && rotate.some((x) => +x !== 0)
2059
2061
  ? matrix.rotate(+rotate[0] || 0, +rotate[1] || 0, +rotate[2] || 0)
2060
- : matrix.rotate(+rotate || 0);
2062
+ : matrix.rotate(0, 0, +rotate || 0);
2061
2063
  }
2062
2064
  // set skew(s)
2063
2065
  if (Array.isArray(skew) && skew.some((x) => +x !== 0)) {
@@ -2072,10 +2074,11 @@ function getSVGMatrix(transform) {
2072
2074
  if (!Number.isNaN(scale) || (Array.isArray(scale) && scale.some((x) => +x !== 1))) {
2073
2075
  matrix = Array.isArray(scale)
2074
2076
  ? (matrix.scale(+scale[0] || 1, +scale[1] || 1, +scale[2] || 1))
2075
- : matrix.scale(+scale || 1);
2077
+ : matrix.scale(+scale || 1, +scale || 1, +scale || 1);
2076
2078
  }
2077
2079
  // set SVG transform-origin
2078
2080
  // matrix = matrix.translate(-originX,-originY,-originZ)
2081
+ // @ts-ignore -- SVG transform origin is always 2D
2079
2082
  matrix = matrix.translate(-originX, -originY);
2080
2083
  }
2081
2084
  return matrix;
@@ -2162,7 +2165,7 @@ function transformEllipse(m, rx, ry, ax) {
2162
2165
  * Details =>
2163
2166
  * https://stackoverflow.com/questions/23792505/predicted-rendering-of-css-3d-transformed-pixel
2164
2167
  *
2165
- * @param {SVGPC.CSSMatrix} m the transformation matrix
2168
+ * @param {SVGPathCommander.CSSMatrix} m the transformation matrix
2166
2169
  * @param {Number[]} point2D the initial [x,y] coordinates
2167
2170
  * @param {number[]} origin the initial [x,y] coordinates
2168
2171
  * @returns {Number[]} the projected [x,y] coordinates
@@ -2190,9 +2193,9 @@ function projection2d(m, point2D, origin) {
2190
2193
  * Since *SVGElement* doesn't support 3D transformation, this function
2191
2194
  * creates a 2D projection of the <path> element.
2192
2195
  *
2193
- * @param {SVGPC.pathArray} path the `pathArray` to apply transformation
2196
+ * @param {SVGPathCommander.pathArray} path the `pathArray` to apply transformation
2194
2197
  * @param {any} transform the transform functions `Object`
2195
- * @returns {SVGPC.pathArray} the resulted `pathArray`
2198
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray`
2196
2199
  */
2197
2200
  function transformPath(path, transform) {
2198
2201
  let x = 0; let y = 0; let i; let j; let ii; let jj; let lx; let ly; let te;
@@ -2324,7 +2327,7 @@ function transformPath(path, transform) {
2324
2327
  * @param {number} c2y the second control point Y
2325
2328
  * @param {number} p2x the ending point X
2326
2329
  * @param {number} p2y the ending point Y
2327
- * @returns {SVGPC.segmentLimits} the length of the cubic-bezier segment
2330
+ * @returns {SVGPathCommander.segmentLimits} the length of the cubic-bezier segment
2328
2331
  */
2329
2332
  function getCubicSize(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
2330
2333
  let a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x);
@@ -2335,8 +2338,9 @@ function getCubicSize(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
2335
2338
  const y = [p1y, p2y];
2336
2339
  const x = [p1x, p2x];
2337
2340
  let dot;
2338
-
2341
+ // @ts-ignore
2339
2342
  if (Math.abs(t1) > '1e12') t1 = 0.5;
2343
+ // @ts-ignore
2340
2344
  if (Math.abs(t2) > '1e12') t2 = 0.5;
2341
2345
 
2342
2346
  if (t1 > 0 && t1 < 1) {
@@ -2354,8 +2358,9 @@ function getCubicSize(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
2354
2358
  c = p1y - c1y;
2355
2359
  t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2356
2360
  t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2357
-
2361
+ // @ts-ignore
2358
2362
  if (Math.abs(t1) > '1e12') t1 = 0.5;
2363
+ // @ts-ignore
2359
2364
  if (Math.abs(t2) > '1e12') t2 = 0.5;
2360
2365
 
2361
2366
  if (t1 > 0 && t1 < 1) {
@@ -2378,7 +2383,7 @@ function getCubicSize(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
2378
2383
  * Iterates an array to check if it's a `pathArray`
2379
2384
  * with all C (cubic bezier) segments.
2380
2385
  *
2381
- * @param {string | SVGPC.pathArray} path the `Array` to be checked
2386
+ * @param {string | SVGPathCommander.pathArray} path the `Array` to be checked
2382
2387
  * @returns {boolean} iteration result
2383
2388
  */
2384
2389
  function isCurveArray(path) {
@@ -2390,11 +2395,11 @@ function isCurveArray(path) {
2390
2395
  * Parses a path string value or 'pathArray' and returns a new one
2391
2396
  * in which all segments are converted to cubic-bezier.
2392
2397
  *
2393
- * @param {string | SVGPC.pathArray} pathInput the string to be parsed or object
2394
- * @returns {SVGPC.pathArray} the resulted `pathArray` converted to cubic-bezier
2398
+ * @param {string | SVGPathCommander.pathArray} pathInput the string to be parsed or object
2399
+ * @returns {SVGPathCommander.pathArray} the resulted `pathArray` converted to cubic-bezier
2395
2400
  */
2396
2401
  function pathToCurve(pathInput) {
2397
- if (Array.isArray(pathInput) && isCurveArray(pathInput)) {
2402
+ if (isCurveArray(pathInput)) {
2398
2403
  return clonePath(pathInput);
2399
2404
  }
2400
2405
 
@@ -2402,15 +2407,15 @@ function pathToCurve(pathInput) {
2402
2407
  const params = {
2403
2408
  x1: 0, y1: 0, x2: 0, y2: 0, x: 0, y: 0, qx: null, qy: null,
2404
2409
  };
2410
+ /** @type {string[]} */
2405
2411
  const allPathCommands = [];
2406
- let pathCommand = '';
2412
+ let pathCommand = ''; // ts-lint
2407
2413
  let ii = path.length;
2408
2414
 
2409
2415
  for (let i = 0; i < ii; i += 1) {
2410
2416
  const segment = path[i];
2411
2417
  const seglen = segment.length;
2412
2418
  if (segment) [pathCommand] = segment;
2413
-
2414
2419
  allPathCommands[i] = pathCommand;
2415
2420
  path[i] = segmentToCubic(segment, params);
2416
2421
 
@@ -2429,41 +2434,45 @@ function pathToCurve(pathInput) {
2429
2434
  /**
2430
2435
  * Returns the bounding box of a shape.
2431
2436
  *
2432
- * @param {SVGPC.pathArray} path the shape `pathArray`
2433
- * @returns {SVGPC.pathBBox} the length of the cubic-bezier segment
2437
+ * @param {SVGPathCommander.pathArray} path the shape `pathArray`
2438
+ * @returns {SVGPathCommander.pathBBox} the length of the cubic-bezier segment
2434
2439
  */
2435
2440
  function getPathBBox(path) {
2436
2441
  if (!path) {
2437
2442
  return {
2438
- x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0,
2443
+ x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0, cx: 0, cy: 0,
2439
2444
  };
2440
2445
  }
2441
2446
  const pathCurve = pathToCurve(path);
2442
-
2443
- let x = 0;
2444
- let y = 0;
2445
- let X = [];
2446
- let Y = [];
2447
+ // @ts-ignore
2448
+ let x = 0; let y = 0; let X = []; let Y = [];
2447
2449
 
2448
2450
  pathCurve.forEach((segment) => {
2449
2451
  const [s1, s2] = segment.slice(-2);
2450
2452
  if (segment[0] === 'M') {
2451
- x = s1;
2452
- y = s2;
2453
+ x = +s1;
2454
+ y = +s2;
2453
2455
  X.push(s1);
2454
2456
  Y.push(s2);
2455
2457
  } else {
2458
+ // @ts-ignore
2456
2459
  const dim = getCubicSize.apply(0, [x, y].concat(segment.slice(1)));
2460
+ // @ts-ignore
2457
2461
  X = X.concat(dim.min.x, dim.max.x);
2462
+ // @ts-ignore
2458
2463
  Y = Y.concat(dim.min.y, dim.max.y);
2459
- x = s1;
2460
- y = s2;
2464
+ x = +s1;
2465
+ y = +s2;
2461
2466
  }
2462
2467
  });
2463
2468
 
2469
+ // @ts-ignore
2464
2470
  const xTop = Math.min.apply(0, X);
2471
+ // @ts-ignore
2465
2472
  const yTop = Math.min.apply(0, Y);
2473
+ // @ts-ignore
2466
2474
  const xBot = Math.max.apply(0, X);
2475
+ // @ts-ignore
2467
2476
  const yBot = Math.max.apply(0, Y);
2468
2477
  const width = xBot - xTop;
2469
2478
  const height = yBot - yTop;
@@ -2507,8 +2516,8 @@ function getCubicSegArea(x0, y0, x1, y1, x2, y2, x3, y3) {
2507
2516
  *
2508
2517
  * => https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
2509
2518
  *
2510
- * @param {SVGPC.pathArray} path the shape `pathArray`
2511
- * @returns {SVGPC.pathBBox} the length of the cubic-bezier segment
2519
+ * @param {SVGPathCommander.pathArray} path the shape `pathArray`
2520
+ * @returns {number} the length of the cubic-bezier segment
2512
2521
  */
2513
2522
  function getPathArea(path) {
2514
2523
  let x = 0; let y = 0;
@@ -2518,19 +2527,29 @@ function getPathArea(path) {
2518
2527
  switch (seg[0]) {
2519
2528
  case 'M':
2520
2529
  case 'Z':
2521
- mx = seg[0] === 'M' ? seg[1] : mx;
2522
- my = seg[0] === 'M' ? seg[2] : my;
2530
+ // @ts-ignore
2531
+ mx = seg[0] === 'M' ? seg[1] : mx; my = seg[0] === 'M' ? seg[2] : my;
2523
2532
  x = mx;
2524
2533
  y = my;
2525
2534
  return 0;
2526
2535
  default:
2536
+ // @ts-ignore
2527
2537
  len = getCubicSegArea.apply(0, [x, y].concat(seg.slice(1)));
2538
+ // @ts-ignore
2528
2539
  [x, y] = seg.slice(-2);
2529
2540
  return len;
2530
2541
  }
2531
2542
  }).reduce((a, b) => a + b, 0);
2532
2543
  }
2533
2544
 
2545
+ /**
2546
+ * @param {number} p1
2547
+ * @param {number} p2
2548
+ * @param {number} p3
2549
+ * @param {number} p4
2550
+ * @param {number} t a [0-1] ratio
2551
+ * @returns {number}
2552
+ */
2534
2553
  function base3(p1, p2, p3, p4, t) {
2535
2554
  const t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4;
2536
2555
  const t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3;
@@ -2540,19 +2559,19 @@ function base3(p1, p2, p3, p4, t) {
2540
2559
  /**
2541
2560
  * Returns the C (cubic-bezier) segment length.
2542
2561
  *
2543
- * @param {Number} x1 the starting point X
2544
- * @param {Number} y1 the starting point Y
2545
- * @param {Number} x2 the first control point X
2546
- * @param {Number} y2 the first control point Y
2547
- * @param {Number} x3 the second control point X
2548
- * @param {Number} y3 the second control point Y
2549
- * @param {Number} x4 the ending point X
2550
- * @param {Number} y4 the ending point Y
2551
- * @param {Number} z a [0-1] ratio
2552
- * @returns {Number} the cubic-bezier segment length
2562
+ * @param {number} x1 the starting point X
2563
+ * @param {number} y1 the starting point Y
2564
+ * @param {number} x2 the first control point X
2565
+ * @param {number} y2 the first control point Y
2566
+ * @param {number} x3 the second control point X
2567
+ * @param {number} y3 the second control point Y
2568
+ * @param {number} x4 the ending point X
2569
+ * @param {number} y4 the ending point Y
2570
+ * @param {number} z a [0-1] ratio
2571
+ * @returns {number} the cubic-bezier segment length
2553
2572
  */
2554
2573
  function getSegCubicLength(x1, y1, x2, y2, x3, y3, x4, y4, z) {
2555
- let Z;
2574
+ let Z = z;
2556
2575
  if (z === null || Number.isNaN(+z)) Z = 1;
2557
2576
 
2558
2577
  // Z = Z > 1 ? 1 : Z < 0 ? 0 : Z;
@@ -2581,13 +2600,14 @@ function getSegCubicLength(x1, y1, x2, y2, x3, y3, x4, y4, z) {
2581
2600
  * or the equivalent to `shape.getTotalLength()`
2582
2601
  * pathToCurve version
2583
2602
  *
2584
- * @param {SVGPC.pathArray} path the ending point Y
2585
- * @returns {Number} the shape total length
2603
+ * @param {SVGPathCommander.pathArray} path the ending point Y
2604
+ * @returns {number} the shape total length
2586
2605
  */
2587
2606
  function getPathLength(path) {
2588
2607
  let totalLength = 0;
2589
2608
  pathToCurve(path).forEach((s, i, curveArray) => {
2590
2609
  totalLength += s[0] === 'M' ? 0
2610
+ // @ts-ignore
2591
2611
  : getSegCubicLength.apply(0, curveArray[i - 1].slice(-2).concat(s.slice(1)));
2592
2612
  });
2593
2613
  return totalLength;
@@ -2597,7 +2617,7 @@ function getPathLength(path) {
2597
2617
  * Check if a path is drawn clockwise and returns true if so,
2598
2618
  * false otherwise.
2599
2619
  *
2600
- * @param {string | SVGPC.pathArray} path the path string or `pathArray`
2620
+ * @param {string | SVGPathCommander.pathArray} path the path string or `pathArray`
2601
2621
  * @returns {boolean} true when clockwise or false if not
2602
2622
  */
2603
2623
  function getDrawDirection(path) {
@@ -2607,24 +2627,26 @@ function getDrawDirection(path) {
2607
2627
  /**
2608
2628
  * Returns [x,y] coordinates of a point at a given length of a shape.
2609
2629
  *
2610
- * @param {string | SVGPC.pathArray} path the `pathArray` to look into
2611
- * @param {Number} length the length of the shape to look at
2612
- * @returns {Number[]} the requested [x,y] coordinates
2630
+ * @param {string | SVGPathCommander.pathArray} path the `pathArray` to look into
2631
+ * @param {number} length the length of the shape to look at
2632
+ * @returns {number[]} the requested [x,y] coordinates
2613
2633
  */
2614
2634
  function getPointAtLength(path, length) {
2615
2635
  let totalLength = 0;
2616
2636
  let segLen;
2617
2637
  let data;
2618
2638
  let result;
2619
-
2639
+ // @ts-ignore
2620
2640
  return pathToCurve(path).map((seg, i, curveArray) => {
2621
2641
  data = i ? curveArray[i - 1].slice(-2).concat(seg.slice(1)) : seg.slice(1);
2642
+ // @ts-ignore
2622
2643
  segLen = i ? getSegCubicLength.apply(0, data) : 0;
2623
2644
  totalLength += segLen;
2624
2645
 
2625
2646
  if (i === 0) {
2626
2647
  result = { x: data[0], y: data[1] };
2627
2648
  } else if (totalLength > length && length > totalLength - segLen) {
2649
+ // @ts-ignore
2628
2650
  result = getPointAtSegLength.apply(0, data.concat(1 - (totalLength - length) / segLen));
2629
2651
  } else {
2630
2652
  result = null;
@@ -2646,7 +2668,7 @@ function isValidPath(pathString) {
2646
2668
  return false;
2647
2669
  }
2648
2670
 
2649
- const path = new SVGPathArray(pathString);
2671
+ const path = new PathParser(pathString);
2650
2672
 
2651
2673
  skipSpaces(path);
2652
2674
 
@@ -2659,6 +2681,7 @@ function isValidPath(pathString) {
2659
2681
 
2660
2682
  /**
2661
2683
  * Supported shapes and their specific parameters.
2684
+ * @type {Object.<string, string[]>}
2662
2685
  */
2663
2686
  const shapeParams = {
2664
2687
  circle: ['cx', 'cy', 'r'],
@@ -2672,8 +2695,8 @@ const shapeParams = {
2672
2695
  /**
2673
2696
  * Returns a new `pathArray` from line attributes.
2674
2697
  *
2675
- * @param {SVGPC.lineAttr} attr shape configuration
2676
- * @return {SVGPC.pathArray} a new line `pathArray`
2698
+ * @param {SVGPathCommander.lineAttr} attr shape configuration
2699
+ * @returns {SVGPathCommander.pathArray} a new line `pathArray`
2677
2700
  */
2678
2701
  function getLinePath(attr) {
2679
2702
  const {
@@ -2685,11 +2708,11 @@ function getLinePath(attr) {
2685
2708
  /**
2686
2709
  * Returns a new `pathArray` like from polyline/polygon attributes.
2687
2710
  *
2688
- * @param {SVGPC.polyAttr} attr shape configuration
2689
- * @return {SVGPC.pathArray} a new polygon/polyline `pathArray`
2711
+ * @param {SVGPathCommander.polyAttr} attr shape configuration
2712
+ * @return {SVGPathCommander.pathArray} a new polygon/polyline `pathArray`
2690
2713
  */
2691
2714
  function getPolyPath(attr) {
2692
- /** @type {SVGPC.pathArray} */
2715
+ /** @type {SVGPathCommander.pathArray} */
2693
2716
  const pathArray = [];
2694
2717
  const points = attr.points.split(/[\s|,]/).map(Number);
2695
2718
 
@@ -2705,8 +2728,8 @@ function getPolyPath(attr) {
2705
2728
  /**
2706
2729
  * Returns a new `pathArray` from circle attributes.
2707
2730
  *
2708
- * @param {SVGPC.circleAttr} attr shape configuration
2709
- * @return {SVGPC.pathArray} a circle `pathArray`
2731
+ * @param {SVGPathCommander.circleAttr} attr shape configuration
2732
+ * @return {SVGPathCommander.pathArray} a circle `pathArray`
2710
2733
  */
2711
2734
  function getCirclePath(attr) {
2712
2735
  const {
@@ -2723,8 +2746,8 @@ function getCirclePath(attr) {
2723
2746
  /**
2724
2747
  * Returns a new `pathArray` from ellipse attributes.
2725
2748
  *
2726
- * @param {SVGPC.ellipseAttr} attr shape configuration
2727
- * @return {SVGPC.pathArray} an ellipse `pathArray`
2749
+ * @param {SVGPathCommander.ellipseAttr} attr shape configuration
2750
+ * @return {SVGPathCommander.pathArray} an ellipse `pathArray`
2728
2751
  */
2729
2752
  function getEllipsePath(attr) {
2730
2753
  const {
@@ -2741,8 +2764,8 @@ function getEllipsePath(attr) {
2741
2764
  /**
2742
2765
  * Returns a new `pathArray` like from rect attributes.
2743
2766
  *
2744
- * @param {SVGPC.rectAttr} attr object with properties above
2745
- * @return {SVGPC.pathArray} a new `pathArray` from `<rect>` attributes
2767
+ * @param {SVGPathCommander.rectAttr} attr object with properties above
2768
+ * @return {SVGPathCommander.pathArray} a new `pathArray` from `<rect>` attributes
2746
2769
  */
2747
2770
  function getRectanglePath(attr) {
2748
2771
  const x = +attr.x || 0;
@@ -2790,7 +2813,7 @@ function getRectanglePath(attr) {
2790
2813
  * The newly created `<path>` element keeps all non-specific
2791
2814
  * attributes like `class`, `fill`, etc.
2792
2815
  *
2793
- * @param {SVGPC.shapeTypes} element target shape
2816
+ * @param {SVGPathCommander.shapeTypes} element target shape
2794
2817
  * @param {boolean} replace option to replace target
2795
2818
  * @return {?SVGPathElement} the newly created `<path>` element
2796
2819
  */
@@ -2803,12 +2826,10 @@ function shapeToPath(element, replace) {
2803
2826
 
2804
2827
  const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
2805
2828
  const type = element.tagName;
2806
- /** @type {string[]} */
2807
2829
  const shapeAttrs = shapeParams[type];
2808
-
2809
- // set config
2810
2830
  const config = {};
2811
2831
  config.type = type;
2832
+
2812
2833
  shapeAttrs.forEach((p) => { config[p] = element.getAttribute(p); });
2813
2834
 
2814
2835
  // set no-specific shape attributes: fill, stroke, etc
@@ -2818,11 +2839,14 @@ function shapeToPath(element, replace) {
2818
2839
 
2819
2840
  // set d
2820
2841
  let description;
2821
- if (type === 'circle') description = pathToString(getCirclePath(config));
2822
- else if (type === 'ellipse') description = pathToString(getEllipsePath(config));
2823
- else if (['polyline', 'polygon'].includes(type)) description = pathToString(getPolyPath(config));
2824
- else if (type === 'rect') description = pathToString(getRectanglePath(config));
2825
- else if (type === 'line') description = pathToString(getLinePath(config));
2842
+ const { round, decimals } = SVGPCO;
2843
+ const rounding = round && decimals ? decimals : null;
2844
+
2845
+ if (type === 'circle') description = pathToString(getCirclePath(config), rounding);
2846
+ else if (type === 'ellipse') description = pathToString(getEllipsePath(config), rounding);
2847
+ else if (['polyline', 'polygon'].includes(type)) description = pathToString(getPolyPath(config), rounding);
2848
+ else if (type === 'rect') description = pathToString(getRectanglePath(config), rounding);
2849
+ else if (type === 'line') description = pathToString(getLinePath(config), rounding);
2826
2850
  else if (type === 'glyph') description = element.getAttribute('d');
2827
2851
 
2828
2852
  // replace target element
@@ -2841,8 +2865,8 @@ function shapeToPath(element, replace) {
2841
2865
  * Reverses all segments and their values from a `pathArray`
2842
2866
  * which consists of only C (cubic-bezier) path commands.
2843
2867
  *
2844
- * @param {SVGPC.pathArray} path the source `pathArray`
2845
- * @returns {SVGPC.pathArray} the reversed `pathArray`
2868
+ * @param {SVGPathCommander.pathArray} path the source `pathArray`
2869
+ * @returns {SVGPathCommander.pathArray} the reversed `pathArray`
2846
2870
  */
2847
2871
  function reverseCurve(path) {
2848
2872
  const rotatedCurve = path.slice(1)
@@ -2852,12 +2876,13 @@ function reverseCurve(path) {
2852
2876
  .map((x) => x.map((_, i) => x[x.length - i - 2 * (1 - (i % 2))]))
2853
2877
  .reverse();
2854
2878
 
2855
- return [['M'].concat(rotatedCurve[0]
2856
- .slice(0, 2))]
2879
+ // @ts-ignore
2880
+ return [['M'].concat(rotatedCurve[0].slice(0, 2))]
2881
+ // @ts-ignore
2857
2882
  .concat(rotatedCurve.map((x) => ['C'].concat(x.slice(2))));
2858
2883
  }
2859
2884
 
2860
- var version = "0.1.10alpha2";
2885
+ var version = "0.1.11alpha2";
2861
2886
 
2862
2887
  // @ts-ignore
2863
2888
 
@@ -2899,8 +2924,6 @@ const Util = {
2899
2924
  Version,
2900
2925
  };
2901
2926
 
2902
- // import isPathArray from './util/isPathArray';
2903
-
2904
2927
  /**
2905
2928
  * Creates a new SVGPathCommander instance.
2906
2929
  *
@@ -2911,7 +2934,7 @@ class SVGPathCommander {
2911
2934
  /**
2912
2935
  * @constructor
2913
2936
  * @param {string} pathValue the path string
2914
- * @param {any} config instance options
2937
+ * @param {SVGPathCommander.options} config instance options
2915
2938
  */
2916
2939
  constructor(pathValue, config) {
2917
2940
  const options = config || {};
@@ -2922,13 +2945,13 @@ class SVGPathCommander {
2922
2945
  round = 0;
2923
2946
  }
2924
2947
 
2925
- const { decimals } = round && (options || SVGPCO);
2948
+ const { decimals } = round ? (options || SVGPCO) : { decimals: false };
2926
2949
 
2927
2950
  // set instance options
2928
- this.round = round === 0 ? 0 : decimals;
2951
+ this.round = decimals;
2929
2952
  // ZERO | FALSE will disable rounding numbers
2930
2953
 
2931
- /** @type {SVGPC.pathArray} */
2954
+ /** @type {SVGPathCommander.pathArray} */
2932
2955
  this.segments = parsePathString(pathValue);
2933
2956
 
2934
2957
  /** * @type {string} */
@@ -2968,20 +2991,21 @@ class SVGPathCommander {
2968
2991
  const { segments } = this;
2969
2992
  const split = splitPath(this.toString());
2970
2993
  const subPath = split.length > 1 ? split : 0;
2994
+ /**
2995
+ * @param {import("../types").pathArray} x
2996
+ * @param {number} i
2997
+ */
2998
+ const reverser = (x, i) => {
2999
+ if (onlySubpath) {
3000
+ return i ? reversePath(x) : parsePathString(x);
3001
+ }
3002
+ return reversePath(x);
3003
+ };
2971
3004
 
2972
- const absoluteMultiPath = subPath && clonePath(subPath)
2973
- .map((x, i) => {
2974
- if (onlySubpath) {
2975
- // @ts-ignore
2976
- return i ? reversePath(x) : parsePathString(x);
2977
- }
2978
- // @ts-ignore
2979
- return reversePath(x);
2980
- });
3005
+ const absoluteMultiPath = subPath && clonePath(subPath).map(reverser);
2981
3006
 
2982
3007
  let path = [];
2983
3008
  if (subPath) {
2984
- // @ts-ignore
2985
3009
  path = absoluteMultiPath.flat(1);
2986
3010
  } else {
2987
3011
  path = onlySubpath ? segments : reversePath(segments);
@@ -3019,7 +3043,7 @@ class SVGPathCommander {
3019
3043
 
3020
3044
  /**
3021
3045
  * Transform path using values from an `Object` defined as `transformObject`.
3022
- * @see SVGPC.transformObject for a quick refference
3046
+ * @see SVGPathCommander.transformObject for a quick refference
3023
3047
  *
3024
3048
  * @param {Object.<string, (number | number[])>} source a `transformObject`as described above
3025
3049
  * @public
@@ -3035,7 +3059,7 @@ class SVGPathCommander {
3035
3059
  // it's important that we have one
3036
3060
  if (!transform.origin) {
3037
3061
  const BBox = getPathBBox(segments);
3038
- transform.origin = [BBox.cx, BBox.cy, BBox.cx];
3062
+ transform.origin = [+BBox.cx, +BBox.cy];
3039
3063
  }
3040
3064
 
3041
3065
  this.segments = transformPath(segments, transform);
@@ -3071,7 +3095,7 @@ class SVGPathCommander {
3071
3095
  }
3072
3096
  }
3073
3097
 
3074
- // @ts-ignore
3075
- Object.keys(Util).forEach((x) => { SVGPathCommander[x] = Util[x]; });
3098
+ // Export Util to global
3099
+ Object.assign(SVGPathCommander, Util);
3076
3100
 
3077
3101
  export { SVGPathCommander as default };