svg-path-commander 0.1.24 → 0.2.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 (72) hide show
  1. package/README.md +5 -3
  2. package/dist/svg-path-commander.es5.js +3948 -0
  3. package/dist/svg-path-commander.es5.min.js +2 -0
  4. package/dist/svg-path-commander.esm.js +428 -407
  5. package/dist/svg-path-commander.esm.min.js +2 -2
  6. package/dist/svg-path-commander.js +1434 -1515
  7. package/dist/svg-path-commander.min.js +2 -2
  8. package/package.json +15 -2
  9. package/src/convert/pathToAbsolute.js +4 -4
  10. package/src/convert/pathToCurve.js +2 -2
  11. package/src/convert/pathToRelative.js +4 -4
  12. package/src/convert/pathToString.js +2 -2
  13. package/src/math/polygonLength.js +1 -2
  14. package/src/options/options.js +1 -1
  15. package/src/parser/error.js +2 -0
  16. package/src/parser/finalizeSegment.js +1 -1
  17. package/src/parser/isSpace.js +1 -1
  18. package/src/parser/paramsParser.js +1 -1
  19. package/src/parser/parsePathString.js +6 -11
  20. package/src/parser/pathParser.js +1 -1
  21. package/src/parser/scanFlag.js +3 -3
  22. package/src/parser/scanParam.js +7 -6
  23. package/src/parser/scanSegment.js +3 -2
  24. package/src/parser/skipSpaces.js +1 -1
  25. package/src/process/clonePath.js +1 -1
  26. package/src/process/fixArc.js +1 -1
  27. package/src/process/fixPath.js +2 -2
  28. package/src/process/getSVGMatrix.js +3 -2
  29. package/src/process/normalizePath.js +3 -3
  30. package/src/process/normalizeSegment.js +2 -2
  31. package/src/process/optimizePath.js +2 -2
  32. package/src/process/projection2d.js +2 -2
  33. package/src/process/reverseCurve.js +3 -3
  34. package/src/process/reversePath.js +4 -5
  35. package/src/process/roundPath.js +7 -6
  36. package/src/process/segmentToCubic.js +3 -3
  37. package/src/process/shortenSegment.js +3 -3
  38. package/src/process/splitCubic.js +1 -1
  39. package/src/process/splitPath.js +1 -1
  40. package/src/process/transformPath.js +8 -7
  41. package/src/svg-path-commander.js +60 -20
  42. package/src/util/getClosestPoint.js +1 -1
  43. package/src/util/getCubicSize.js +1 -1
  44. package/src/util/getDrawDirection.js +1 -1
  45. package/src/util/getPathArea.js +1 -1
  46. package/src/util/getPathBBox.js +2 -2
  47. package/src/util/getPathLength.js +1 -1
  48. package/src/util/getPointAtLength.js +1 -1
  49. package/src/util/getPropertiesAtLength.js +3 -3
  50. package/src/util/getPropertiesAtPoint.js +2 -2
  51. package/src/util/getSegmentAtLength.js +2 -2
  52. package/src/util/getSegmentOfPoint.js +2 -2
  53. package/src/util/getTotalLength.js +1 -1
  54. package/src/util/isAbsoluteArray.js +1 -1
  55. package/src/util/isCurveArray.js +1 -1
  56. package/src/util/isNormalizedArray.js +1 -1
  57. package/src/util/isPathArray.js +1 -1
  58. package/src/util/isPointInStroke.js +2 -2
  59. package/src/util/isRelativeArray.js +1 -1
  60. package/src/util/pathLengthFactory.js +3 -2
  61. package/src/util/segmentArcFactory.js +1 -1
  62. package/src/util/segmentCubicFactory.js +1 -1
  63. package/src/util/segmentLineFactory.js +1 -1
  64. package/src/util/segmentQuadFactory.js +1 -1
  65. package/src/util/shapeToPath.js +14 -14
  66. package/src/util/util.js +0 -2
  67. package/types/index.d.ts +1 -3
  68. package/types/more/modules.ts +0 -3
  69. package/types/more/svg.d.ts +11 -10
  70. package/types/svg-path-commander.d.ts +214 -226
  71. package/src/util/createPath.js +0 -17
  72. package/src/util/getPointAtPathLength.js +0 -15
@@ -0,0 +1,3948 @@
1
+ /*!
2
+ * SVGPathCommander v0.2.0alpha2 (http://thednp.github.io/svg-path-commander)
3
+ * Copyright 2022 © thednp
4
+ * Licensed under MIT (https://github.com/thednp/svg-path-commander/blob/master/LICENSE)
5
+ */
6
+ (function (global, factory) {
7
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
+ typeof define === 'function' && define.amd ? define(factory) :
9
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SVGPathCommander = factory());
10
+ })(this, (function () { 'use strict';
11
+
12
+ /**
13
+ * SVGPathCommander default options
14
+ * @type {SVGPath.options}
15
+ */
16
+ var defaultOptions = {
17
+ origin: [0, 0, 0],
18
+ round: 4,
19
+ };
20
+
21
+ /**
22
+ * Segment params length
23
+ * @type {Record<string, number>}
24
+ */
25
+ var paramsCount = {
26
+ a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0,
27
+ };
28
+
29
+ /**
30
+ * Breaks the parsing of a pathString once a segment is finalized.
31
+ *
32
+ * @param {SVGPath.PathParser} path the `PathParser` instance
33
+ */
34
+ function finalizeSegment(path) {
35
+ var pathCommand = path.pathValue[path.segmentStart];
36
+ var LK = pathCommand.toLowerCase();
37
+ var data = path.data;
38
+
39
+ // Process duplicated commands (without comand name)
40
+ if (LK === 'm' && data.length > 2) {
41
+ // @ts-ignore
42
+ path.segments.push([pathCommand, data[0], data[1]]);
43
+ data = data.slice(2);
44
+ LK = 'l';
45
+ pathCommand = pathCommand === 'm' ? 'l' : 'L';
46
+ }
47
+
48
+ // @ts-ignore
49
+ while (data.length >= paramsCount[LK]) {
50
+ // path.segments.push([pathCommand].concat(data.splice(0, paramsCount[LK])));
51
+ // @ts-ignore
52
+ path.segments.push([pathCommand ].concat( data.splice(0, paramsCount[LK])));
53
+ // @ts-ignore
54
+ if (!paramsCount[LK]) {
55
+ break;
56
+ }
57
+ }
58
+ }
59
+
60
+ var error = 'SVGPathCommander error';
61
+
62
+ /**
63
+ * Validates an A (arc-to) specific path command value.
64
+ * Usually a `large-arc-flag` or `sweep-flag`.
65
+ *
66
+ * @param {SVGPath.PathParser} path the `PathParser` instance
67
+ */
68
+ function scanFlag(path) {
69
+ var index = path.index;
70
+ var ch = path.pathValue.charCodeAt(index);
71
+
72
+ if (ch === 0x30/* 0 */) {
73
+ path.param = 0;
74
+ path.index += 1;
75
+ return;
76
+ }
77
+
78
+ if (ch === 0x31/* 1 */) {
79
+ path.param = 1;
80
+ path.index += 1;
81
+ return;
82
+ }
83
+
84
+ path.err = error + ": invalid Arc flag \"" + ch + "\", expecting 0 or 1 at index " + index;
85
+ }
86
+
87
+ /**
88
+ * Checks if a character is a digit.
89
+ *
90
+ * @param {number} code the character to check
91
+ * @returns {boolean} check result
92
+ */
93
+ function isDigit(code) {
94
+ return (code >= 48 && code <= 57); // 0..9
95
+ }
96
+
97
+ var invalidPathValue = 'Invalid path value';
98
+
99
+ /**
100
+ * Validates every character of the path string,
101
+ * every path command, negative numbers or floating point numbers.
102
+ *
103
+ * @param {SVGPath.PathParser} path the `PathParser` instance
104
+ */
105
+ function scanParam(path) {
106
+ var max = path.max;
107
+ var pathValue = path.pathValue;
108
+ var start = path.index;
109
+ var index = start;
110
+ var zeroFirst = false;
111
+ var hasCeiling = false;
112
+ var hasDecimal = false;
113
+ var hasDot = false;
114
+ var ch;
115
+
116
+ if (index >= max) {
117
+ // path.err = 'SvgPath: missed param (at pos ' + index + ')';
118
+ path.err = error + ": " + invalidPathValue + " at index " + index + ", \"pathValue\" is missing param";
119
+ return;
120
+ }
121
+ ch = pathValue.charCodeAt(index);
122
+
123
+ if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
124
+ index += 1;
125
+ ch = (index < max) ? pathValue.charCodeAt(index) : 0;
126
+ }
127
+
128
+ // This logic is shamelessly borrowed from Esprima
129
+ // https://github.com/ariya/esprimas
130
+ if (!isDigit(ch) && ch !== 0x2E/* . */) {
131
+ // path.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')';
132
+ path.err = error + ": " + invalidPathValue + " at index " + index + ", \"" + (pathValue[index]) + "\" is not a number";
133
+ return;
134
+ }
135
+
136
+ if (ch !== 0x2E/* . */) {
137
+ zeroFirst = (ch === 0x30/* 0 */);
138
+ index += 1;
139
+
140
+ ch = (index < max) ? pathValue.charCodeAt(index) : 0;
141
+
142
+ if (zeroFirst && index < max) {
143
+ // decimal number starts with '0' such as '09' is illegal.
144
+ if (ch && isDigit(ch)) {
145
+ // path.err = 'SvgPath: numbers started with `0` such as `09`
146
+ // are illegal (at pos ' + start + ')';
147
+ path.err = error + ": " + invalidPathValue + " at index " + start + ", \"" + (pathValue[start]) + "\" illegal number";
148
+ return;
149
+ }
150
+ }
151
+
152
+ while (index < max && isDigit(pathValue.charCodeAt(index))) {
153
+ index += 1;
154
+ hasCeiling = true;
155
+ }
156
+ ch = (index < max) ? pathValue.charCodeAt(index) : 0;
157
+ }
158
+
159
+ if (ch === 0x2E/* . */) {
160
+ hasDot = true;
161
+ index += 1;
162
+ while (isDigit(pathValue.charCodeAt(index))) {
163
+ index += 1;
164
+ hasDecimal = true;
165
+ }
166
+ ch = (index < max) ? pathValue.charCodeAt(index) : 0;
167
+ }
168
+
169
+ if (ch === 0x65/* e */ || ch === 0x45/* E */) {
170
+ if (hasDot && !hasCeiling && !hasDecimal) {
171
+ path.err = error + ": " + invalidPathValue + " at index " + index + ", \"" + (pathValue[index]) + "\" invalid float exponent";
172
+ return;
173
+ }
174
+
175
+ index += 1;
176
+
177
+ ch = (index < max) ? pathValue.charCodeAt(index) : 0;
178
+ if (ch === 0x2B/* + */ || ch === 0x2D/* - */) {
179
+ index += 1;
180
+ }
181
+ if (index < max && isDigit(pathValue.charCodeAt(index))) {
182
+ while (index < max && isDigit(pathValue.charCodeAt(index))) {
183
+ index += 1;
184
+ }
185
+ } else {
186
+ // path.err = 'SvgPath: invalid float exponent (at pos ' + index + ')';
187
+ path.err = error + ": " + invalidPathValue + " at index " + index + ": \"" + (pathValue[index]) + "\" invalid float exponent";
188
+ return;
189
+ }
190
+ }
191
+
192
+ path.index = index;
193
+ path.param = +path.pathValue.slice(start, index);
194
+ }
195
+
196
+ /**
197
+ * Checks if the character is a space.
198
+ *
199
+ * @param {number} ch the character to check
200
+ * @returns {boolean} check result
201
+ */
202
+ function isSpace(ch) {
203
+ var specialSpaces = [
204
+ 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006,
205
+ 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF];
206
+ return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) // Line terminators
207
+ // White spaces
208
+ || (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0)
209
+ || (ch >= 0x1680 && specialSpaces.includes(ch));
210
+ }
211
+
212
+ /**
213
+ * Points the parser to the next character in the
214
+ * path string every time it encounters any kind of
215
+ * space character.
216
+ *
217
+ * @param {SVGPath.PathParser} path the `PathParser` instance
218
+ */
219
+ function skipSpaces(path) {
220
+ var pathValue = path.pathValue;
221
+ var max = path.max;
222
+ while (path.index < max && isSpace(pathValue.charCodeAt(path.index))) {
223
+ path.index += 1;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Checks if the character is a path command.
229
+ *
230
+ * @param {any} code the character to check
231
+ * @returns {boolean} check result
232
+ */
233
+ function isPathCommand(code) {
234
+ // eslint-disable-next-line no-bitwise -- Impossible to satisfy
235
+ switch (code | 0x20) {
236
+ case 0x6D/* m */:
237
+ case 0x7A/* z */:
238
+ case 0x6C/* l */:
239
+ case 0x68/* h */:
240
+ case 0x76/* v */:
241
+ case 0x63/* c */:
242
+ case 0x73/* s */:
243
+ case 0x71/* q */:
244
+ case 0x74/* t */:
245
+ case 0x61/* a */:
246
+ // case 0x72/* r */:
247
+ return true;
248
+ default:
249
+ return false;
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Checks if the character is or belongs to a number.
255
+ * [0-9]|+|-|.
256
+ *
257
+ * @param {number} code the character to check
258
+ * @returns {boolean} check result
259
+ */
260
+ function isDigitStart(code) {
261
+ return (code >= 48 && code <= 57) /* 0..9 */
262
+ || code === 0x2B /* + */
263
+ || code === 0x2D /* - */
264
+ || code === 0x2E; /* . */
265
+ }
266
+
267
+ /**
268
+ * Checks if the character is an A (arc-to) path command.
269
+ *
270
+ * @param {number} code the character to check
271
+ * @returns {boolean} check result
272
+ */
273
+ function isArcCommand(code) {
274
+ // eslint-disable-next-line no-bitwise -- Impossible to satisfy
275
+ return (code | 0x20) === 0x61;
276
+ }
277
+
278
+ /**
279
+ * Scans every character in the path string to determine
280
+ * where a segment starts and where it ends.
281
+ *
282
+ * @param {SVGPath.PathParser} path the `PathParser` instance
283
+ */
284
+ function scanSegment(path) {
285
+ var max = path.max;
286
+ var pathValue = path.pathValue;
287
+ var index = path.index;
288
+ var cmdCode = pathValue.charCodeAt(index);
289
+ var reqParams = paramsCount[pathValue[index].toLowerCase()];
290
+
291
+ path.segmentStart = index;
292
+
293
+ if (!isPathCommand(cmdCode)) {
294
+ path.err = error + ": " + invalidPathValue + " \"" + (pathValue[index]) + "\" is not a path command";
295
+ return;
296
+ }
297
+
298
+ path.index += 1;
299
+ skipSpaces(path);
300
+
301
+ path.data = [];
302
+
303
+ if (!reqParams) {
304
+ // Z
305
+ finalizeSegment(path);
306
+ return;
307
+ }
308
+
309
+ for (;;) {
310
+ for (var i = reqParams; i > 0; i -= 1) {
311
+ if (isArcCommand(cmdCode) && (i === 3 || i === 4)) { scanFlag(path); }
312
+ else { scanParam(path); }
313
+
314
+ if (path.err.length) {
315
+ return;
316
+ }
317
+ path.data.push(path.param);
318
+
319
+ skipSpaces(path);
320
+
321
+ // after ',' param is mandatory
322
+ if (path.index < max && pathValue.charCodeAt(path.index) === 0x2C/* , */) {
323
+ path.index += 1;
324
+ skipSpaces(path);
325
+ }
326
+ }
327
+
328
+ if (path.index >= path.max) {
329
+ break;
330
+ }
331
+
332
+ // Stop on next segment
333
+ if (!isDigitStart(pathValue.charCodeAt(path.index))) {
334
+ break;
335
+ }
336
+ }
337
+
338
+ finalizeSegment(path);
339
+ }
340
+
341
+ /**
342
+ * Returns a clone of an existing `pathArray`.
343
+ *
344
+ * @param {SVGPath.pathArray | SVGPath.pathSegment} path the source `pathArray`
345
+ * @returns {any} the cloned `pathArray`
346
+ */
347
+ function clonePath(path) {
348
+ return path.map(function (x) { return (Array.isArray(x) ? [].concat( x ) : x); });
349
+ }
350
+
351
+ /**
352
+ * The `PathParser` is used by the `parsePathString` static method
353
+ * to generate a `pathArray`.
354
+ *
355
+ * @param {string} pathString
356
+ */
357
+ function PathParser(pathString) {
358
+ /** @type {SVGPath.pathArray} */
359
+ // @ts-ignore
360
+ this.segments = [];
361
+ /** @type {string} */
362
+ this.pathValue = pathString;
363
+ /** @type {number} */
364
+ this.max = pathString.length;
365
+ /** @type {number} */
366
+ this.index = 0;
367
+ /** @type {number} */
368
+ this.param = 0.0;
369
+ /** @type {number} */
370
+ this.segmentStart = 0;
371
+ /** @type {any} */
372
+ this.data = [];
373
+ /** @type {string} */
374
+ this.err = '';
375
+ }
376
+
377
+ /**
378
+ * Iterates an array to check if it's an actual `pathArray`.
379
+ *
380
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
381
+ * @returns {boolean} iteration result
382
+ */
383
+ function isPathArray(path) {
384
+ return Array.isArray(path) && path.every(function (seg) {
385
+ var lk = seg[0].toLowerCase();
386
+ return paramsCount[lk] === seg.length - 1 && 'achlmqstvz'.includes(lk);
387
+ });
388
+ }
389
+
390
+ /**
391
+ * Parses a path string value and returns an array
392
+ * of segments we like to call `pathArray`.
393
+ *
394
+ * @param {SVGPath.pathArray | string} pathInput the string to be parsed
395
+ * @returns {SVGPath.pathArray | string} the resulted `pathArray`
396
+ */
397
+ function parsePathString(pathInput) {
398
+ if (isPathArray(pathInput)) {
399
+ // @ts-ignore -- isPathArray also checks if it's an `Array`
400
+ return clonePath(pathInput);
401
+ }
402
+
403
+ // @ts-ignore -- pathInput is now string
404
+ var path = new PathParser(pathInput);
405
+
406
+ skipSpaces(path);
407
+
408
+ while (path.index < path.max && !path.err.length) {
409
+ scanSegment(path);
410
+ }
411
+
412
+ if (!path.err.length) {
413
+ if (!'mM'.includes(path.segments[0][0])) {
414
+ path.err = error + ": missing M/m";
415
+ } else {
416
+ path.segments[0][0] = 'M';
417
+ }
418
+ }
419
+
420
+ return path.err ? path.err : path.segments;
421
+ }
422
+
423
+ /**
424
+ * Iterates an array to check if it's a `pathArray`
425
+ * with all absolute values.
426
+ *
427
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
428
+ * @returns {boolean} iteration result
429
+ */
430
+ function isAbsoluteArray(path) {
431
+ return isPathArray(path)
432
+ // @ts-ignore -- `isPathArray` also checks if it's `Array`
433
+ && path.every(function (x) { return x[0] === x[0].toUpperCase(); });
434
+ }
435
+
436
+ /**
437
+ * Parses a path string value or object and returns an array
438
+ * of segments, all converted to absolute values.
439
+ *
440
+ * @param {string | SVGPath.pathArray} pathInput the path string | object
441
+ * @returns {SVGPath.absoluteArray} the resulted `pathArray` with absolute values
442
+ */
443
+ function pathToAbsolute(pathInput) {
444
+ if (isAbsoluteArray(pathInput)) {
445
+ // @ts-ignore -- `isAbsoluteArray` checks if it's `pathArray`
446
+ return clonePath(pathInput);
447
+ }
448
+
449
+ var path = parsePathString(pathInput);
450
+ var x = 0; var y = 0;
451
+ var mx = 0; var my = 0;
452
+
453
+ // @ts-ignore -- the `absoluteSegment[]` is for sure an `absolutePath`
454
+ return path.map(function (segment) {
455
+ var assign, assign$1, assign$2;
456
+
457
+ var values = segment.slice(1).map(Number);
458
+ var pathCommand = segment[0];
459
+ /** @type {SVGPath.absoluteCommand} */
460
+ // @ts-ignore
461
+ var absCommand = pathCommand.toUpperCase();
462
+
463
+ if (pathCommand === 'M') {
464
+ (assign = values, x = assign[0], y = assign[1]);
465
+ mx = x;
466
+ my = y;
467
+ return ['M', x, y];
468
+ }
469
+ /** @type {SVGPath.absoluteSegment} */
470
+ // @ts-ignore
471
+ var absoluteSegment = [];
472
+
473
+ if (pathCommand !== absCommand) {
474
+ switch (absCommand) {
475
+ case 'A':
476
+ absoluteSegment = [
477
+ absCommand, values[0], values[1], values[2],
478
+ values[3], values[4], values[5] + x, values[6] + y];
479
+ break;
480
+ case 'V':
481
+ absoluteSegment = [absCommand, values[0] + y];
482
+ break;
483
+ case 'H':
484
+ absoluteSegment = [absCommand, values[0] + x];
485
+ break;
486
+ default: {
487
+ // use brakets for `eslint: no-case-declaration`
488
+ // https://stackoverflow.com/a/50753272/803358
489
+ var absValues = values.map(function (n, j) { return n + (j % 2 ? y : x); });
490
+ // @ts-ignore for n, l, c, s, q, t
491
+ absoluteSegment = [absCommand ].concat( absValues);
492
+ }
493
+ }
494
+ } else {
495
+ // @ts-ignore
496
+ absoluteSegment = [absCommand ].concat( values);
497
+ }
498
+
499
+ var segLength = absoluteSegment.length;
500
+ switch (absCommand) {
501
+ case 'Z':
502
+ x = mx;
503
+ y = my;
504
+ break;
505
+ case 'H':
506
+ // @ts-ignore
507
+ (assign$1 = absoluteSegment, x = assign$1[1]);
508
+ break;
509
+ case 'V':
510
+ // @ts-ignore
511
+ (assign$2 = absoluteSegment, y = assign$2[1]);
512
+ break;
513
+ default:
514
+ // @ts-ignore
515
+ x = absoluteSegment[segLength - 2];
516
+ // @ts-ignore
517
+ y = absoluteSegment[segLength - 1];
518
+
519
+ if (absCommand === 'M') {
520
+ mx = x;
521
+ my = y;
522
+ }
523
+ }
524
+ return absoluteSegment;
525
+ });
526
+ }
527
+
528
+ /**
529
+ * Iterates an array to check if it's a `pathArray`
530
+ * with relative values.
531
+ *
532
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
533
+ * @returns {boolean} iteration result
534
+ */
535
+ function isRelativeArray(path) {
536
+ return isPathArray(path)
537
+ // @ts-ignore -- `isPathArray` checks if it's `Array`
538
+ && path.slice(1).every(function (seg) { return seg[0] === seg[0].toLowerCase(); });
539
+ }
540
+
541
+ /**
542
+ * Parses a path string value or object and returns an array
543
+ * of segments, all converted to relative values.
544
+ *
545
+ * @param {string | SVGPath.pathArray} pathInput the path string | object
546
+ * @returns {SVGPath.relativeArray} the resulted `pathArray` with relative values
547
+ */
548
+ function pathToRelative(pathInput) {
549
+ if (isRelativeArray(pathInput)) {
550
+ // @ts-ignore -- `isRelativeArray` checks if it's `pathArray`
551
+ return clonePath(pathInput);
552
+ }
553
+
554
+ var path = parsePathString(pathInput);
555
+ var x = 0; var y = 0;
556
+ var mx = 0; var my = 0;
557
+
558
+ // @ts-ignore -- this is actually a `relativeArray`
559
+ return path.map(function (segment) {
560
+ var assign, assign$1;
561
+
562
+ var values = segment.slice(1).map(Number);
563
+ var pathCommand = segment[0];
564
+ /** @type {SVGPath.relativeCommand} */
565
+ // @ts-ignore
566
+ var relativeCommand = pathCommand.toLowerCase();
567
+
568
+ if (pathCommand === 'M') {
569
+ (assign = values, x = assign[0], y = assign[1]);
570
+ mx = x;
571
+ my = y;
572
+ return ['M', x, y];
573
+ }
574
+
575
+ /** @type {SVGPath.relativeSegment} */
576
+ // @ts-ignore -- trust me DON'T CHANGE
577
+ var relativeSegment = [];
578
+
579
+ if (pathCommand !== relativeCommand) {
580
+ switch (relativeCommand) {
581
+ case 'a':
582
+ relativeSegment = [
583
+ relativeCommand, values[0], values[1], values[2],
584
+ values[3], values[4], values[5] - x, values[6] - y];
585
+ break;
586
+ case 'v':
587
+ relativeSegment = [relativeCommand, values[0] - y];
588
+ break;
589
+ case 'h':
590
+ relativeSegment = [relativeCommand, values[0] - x];
591
+ break;
592
+ default: {
593
+ // use brakets for `eslint: no-case-declaration`
594
+ // https://stackoverflow.com/a/50753272/803358
595
+ var relValues = values.map(function (n, j) { return n - (j % 2 ? y : x); });
596
+ // @ts-ignore for M, L, C, S, Q, T
597
+ relativeSegment = [relativeCommand ].concat( relValues);
598
+
599
+ if (relativeCommand === 'm') {
600
+ (assign$1 = values, x = assign$1[0], y = assign$1[1]);
601
+ mx = x;
602
+ my = y;
603
+ }
604
+ }
605
+ }
606
+ } else {
607
+ if (pathCommand === 'm') {
608
+ mx = values[0] + x;
609
+ my = values[1] + y;
610
+ }
611
+ // @ts-ignore
612
+ relativeSegment = [relativeCommand ].concat( values);
613
+ }
614
+
615
+ var segLength = relativeSegment.length;
616
+ switch (relativeCommand) {
617
+ case 'z':
618
+ x = mx;
619
+ y = my;
620
+ break;
621
+ case 'h':
622
+ // @ts-ignore
623
+ x += relativeSegment[1];
624
+ break;
625
+ case 'v':
626
+ // @ts-ignore
627
+ y += relativeSegment[1];
628
+ break;
629
+ default:
630
+ // @ts-ignore
631
+ x += relativeSegment[segLength - 2];
632
+ // @ts-ignore
633
+ y += relativeSegment[segLength - 1];
634
+ }
635
+ return relativeSegment;
636
+ });
637
+ }
638
+
639
+ /**
640
+ * Splits an extended A (arc-to) segment into two cubic-bezier segments.
641
+ *
642
+ * @param {SVGPath.pathArray} path the `pathArray` this segment belongs to
643
+ * @param {string[]} allPathCommands all previous path commands
644
+ * @param {number} i the segment index
645
+ */
646
+
647
+ function fixArc(path, allPathCommands, i) {
648
+ if (path[i].length > 7) {
649
+ path[i].shift();
650
+ var segment = path[i];
651
+ var ni = i; // ESLint
652
+ while (segment.length) {
653
+ // if created multiple C:s, their original seg is saved
654
+ allPathCommands[i] = 'A';
655
+ // @ts-ignore
656
+ path.splice(ni += 1, 0, ['C' ].concat( segment.splice(0, 6)));
657
+ }
658
+ path.splice(i, 1);
659
+ }
660
+ }
661
+
662
+ /**
663
+ * Returns the missing control point from an
664
+ * T (shorthand quadratic bezier) segment.
665
+ *
666
+ * @param {number} x1 curve start x
667
+ * @param {number} y1 curve start y
668
+ * @param {number} qx control point x
669
+ * @param {number} qy control point y
670
+ * @param {string} prevCommand the previous path command
671
+ * @returns {{qx: number, qy: number}}} the missing control point
672
+ */
673
+ function shorthandToQuad(x1, y1, qx, qy, prevCommand) {
674
+ return 'QT'.includes(prevCommand)
675
+ ? { qx: x1 * 2 - qx, qy: y1 * 2 - qy }
676
+ : { qx: x1, qy: y1 };
677
+ }
678
+
679
+ /**
680
+ * Returns the missing control point from an
681
+ * S (shorthand cubic bezier) segment.
682
+ *
683
+ * @param {number} x1 curve start x
684
+ * @param {number} y1 curve start y
685
+ * @param {number} x2 curve end x
686
+ * @param {number} y2 curve end y
687
+ * @param {string} prevCommand the previous path command
688
+ * @returns {{x1: number, y1: number}}} the missing control point
689
+ */
690
+ function shorthandToCubic(x1, y1, x2, y2, prevCommand) {
691
+ return 'CS'.includes(prevCommand)
692
+ ? { x1: x1 * 2 - x2, y1: y1 * 2 - y2 }
693
+ : { x1: x1, y1: y1 };
694
+ }
695
+
696
+ /**
697
+ * Normalizes a single segment of a `pathArray` object.
698
+ *
699
+ * @param {SVGPath.pathSegment} segment the segment object
700
+ * @param {any} params the coordinates of the previous segment
701
+ * @param {string} prevCommand the path command of the previous segment
702
+ * @returns {SVGPath.normalSegment} the normalized segment
703
+ */
704
+ function normalizeSegment(segment, params, prevCommand) {
705
+ var pathCommand = segment[0];
706
+ var px1 = params.x1;
707
+ var py1 = params.y1;
708
+ var px2 = params.x2;
709
+ var py2 = params.y2;
710
+ var values = segment.slice(1).map(Number);
711
+ var result = segment;
712
+
713
+ if (!'TQ'.includes(pathCommand)) {
714
+ // optional but good to be cautious
715
+ params.qx = null;
716
+ params.qy = null;
717
+ }
718
+
719
+ if (pathCommand === 'H') {
720
+ result = ['L', segment[1], py1];
721
+ } else if (pathCommand === 'V') {
722
+ result = ['L', px1, segment[1]];
723
+ } else if (pathCommand === 'S') {
724
+ var ref = shorthandToCubic(px1, py1, px2, py2, prevCommand);
725
+ var x1 = ref.x1;
726
+ var y1 = ref.y1;
727
+ params.x1 = x1;
728
+ params.y1 = y1;
729
+ // @ts-ignore
730
+ result = ['C', x1, y1 ].concat( values);
731
+ } else if (pathCommand === 'T') {
732
+ var ref$1 = shorthandToQuad(px1, py1, params.qx, params.qy, prevCommand);
733
+ var qx = ref$1.qx;
734
+ var qy = ref$1.qy;
735
+ params.qx = qx;
736
+ params.qy = qy;
737
+ // @ts-ignore
738
+ result = ['Q', qx, qy ].concat( values);
739
+ } else if (pathCommand === 'Q') {
740
+ var nqx = values[0];
741
+ var nqy = values[1];
742
+ params.qx = nqx;
743
+ params.qy = nqy;
744
+ }
745
+
746
+ // @ts-ignore -- we-re switching `pathSegment` type
747
+ return result;
748
+ }
749
+
750
+ /**
751
+ * Iterates an array to check if it's a `pathArray`
752
+ * with all segments are in non-shorthand notation
753
+ * with absolute values.
754
+ *
755
+ * @param {string | SVGPath.pathArray} path the `pathArray` to be checked
756
+ * @returns {boolean} iteration result
757
+ */
758
+ function isNormalizedArray(path) {
759
+ // @ts-ignore -- `isAbsoluteArray` also checks if it's `Array`
760
+ return isAbsoluteArray(path) && path.every(function (seg) { return 'ACLMQZ'.includes(seg[0]); });
761
+ }
762
+
763
+ /**
764
+ * @type {SVGPath.parserParams}
765
+ */
766
+ var paramsParser = {
767
+ x1: 0, y1: 0, x2: 0, y2: 0, x: 0, y: 0, qx: null, qy: null,
768
+ };
769
+
770
+ /**
771
+ * Normalizes a `path` object for further processing:
772
+ * * convert segments to absolute values
773
+ * * convert shorthand path commands to their non-shorthand notation
774
+ *
775
+ * @param {string | SVGPath.pathArray} pathInput the string to be parsed or 'pathArray'
776
+ * @returns {SVGPath.normalArray} the normalized `pathArray`
777
+ */
778
+ function normalizePath(pathInput) {
779
+ var assign;
780
+
781
+ if (isNormalizedArray(pathInput)) {
782
+ // @ts-ignore -- `isNormalizedArray` checks if it's `pathArray`
783
+ return clonePath(pathInput);
784
+ }
785
+
786
+ /** @type {SVGPath.normalArray} */
787
+ // @ts-ignore -- `absoluteArray` will become a `normalArray`
788
+ var path = pathToAbsolute(pathInput);
789
+ var params = Object.assign({}, paramsParser);
790
+ var allPathCommands = [];
791
+ var ii = path.length;
792
+ var pathCommand = '';
793
+ var prevCommand = '';
794
+
795
+ for (var i = 0; i < ii; i += 1) {
796
+ (assign = path[i], pathCommand = assign[0]);
797
+
798
+ // Save current path command
799
+ allPathCommands[i] = pathCommand;
800
+ // Get previous path command
801
+ if (i) { prevCommand = allPathCommands[i - 1]; }
802
+ // Previous path command is used to normalizeSegment
803
+ // @ts-ignore -- expected on normalization
804
+ path[i] = normalizeSegment(path[i], params, prevCommand);
805
+
806
+ var segment = path[i];
807
+ var seglen = segment.length;
808
+
809
+ params.x1 = +segment[seglen - 2];
810
+ params.y1 = +segment[seglen - 1];
811
+ params.x2 = +(segment[seglen - 4]) || params.x1;
812
+ params.y2 = +(segment[seglen - 3]) || params.y1;
813
+ }
814
+
815
+ return path;
816
+ }
817
+
818
+ /**
819
+ * Checks a `pathArray` for an unnecessary `Z` segment
820
+ * and returns a new `pathArray` without it.
821
+ *
822
+ * The `pathInput` must be a single path, without
823
+ * sub-paths. For multi-path `<path>` elements,
824
+ * use `splitPath` first and apply this utility on each
825
+ * sub-path separately.
826
+ *
827
+ * @param {SVGPath.pathArray | string} pathInput the `pathArray` source
828
+ * @return {SVGPath.pathArray} a fixed `pathArray`
829
+ */
830
+ function fixPath(pathInput) {
831
+ var pathArray = parsePathString(pathInput);
832
+ var normalArray = normalizePath(pathArray);
833
+ var length = pathArray.length;
834
+ var isClosed = normalArray.slice(-1)[0][0] === 'Z';
835
+ var segBeforeZ = isClosed ? length - 2 : length - 1;
836
+
837
+ var ref = normalArray[0].slice(1);
838
+ var mx = ref[0];
839
+ var my = ref[1];
840
+ var ref$1 = normalArray[segBeforeZ].slice(-2);
841
+ var x = ref$1[0];
842
+ var y = ref$1[1];
843
+
844
+ if (isClosed && mx === x && my === y) {
845
+ // @ts-ignore -- `pathSegment[]` is quite a `pathArray`
846
+ return pathArray.slice(0, -1);
847
+ }
848
+ return pathArray;
849
+ }
850
+
851
+ /**
852
+ * Iterates an array to check if it's a `pathArray`
853
+ * with all C (cubic bezier) segments.
854
+ *
855
+ * @param {string | SVGPath.pathArray} path the `Array` to be checked
856
+ * @returns {boolean} iteration result
857
+ */
858
+ function isCurveArray(path) {
859
+ // @ts-ignore -- `isPathArray` also checks if it's `Array`
860
+ return isPathArray(path) && path.every(function (seg) { return 'MC'.includes(seg[0]); });
861
+ }
862
+
863
+ /**
864
+ * Returns an {x,y} vector rotated by a given
865
+ * angle in radian.
866
+ *
867
+ * @param {number} x the initial vector x
868
+ * @param {number} y the initial vector y
869
+ * @param {number} rad the radian vector angle
870
+ * @returns {{x: number, y: number}} the rotated vector
871
+ */
872
+ function rotateVector(x, y, rad) {
873
+ var X = x * Math.cos(rad) - y * Math.sin(rad);
874
+ var Y = x * Math.sin(rad) + y * Math.cos(rad);
875
+ return { x: X, y: Y };
876
+ }
877
+
878
+ /**
879
+ * Converts A (arc-to) segments to C (cubic-bezier-to).
880
+ *
881
+ * For more information of where this math came from visit:
882
+ * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
883
+ *
884
+ * @param {number} X1 the starting x position
885
+ * @param {number} Y1 the starting y position
886
+ * @param {number} RX x-radius of the arc
887
+ * @param {number} RY y-radius of the arc
888
+ * @param {number} angle x-axis-rotation of the arc
889
+ * @param {number} LAF large-arc-flag of the arc
890
+ * @param {number} SF sweep-flag of the arc
891
+ * @param {number} X2 the ending x position
892
+ * @param {number} Y2 the ending y position
893
+ * @param {number[]=} recursive the parameters needed to split arc into 2 segments
894
+ * @return {number[]} the resulting cubic-bezier segment(s)
895
+ */
896
+ function arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, recursive) {
897
+ var assign;
898
+
899
+ var x1 = X1; var y1 = Y1; var rx = RX; var ry = RY; var x2 = X2; var y2 = Y2;
900
+ // for more information of where this Math came from visit:
901
+ // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
902
+ var d120 = (Math.PI * 120) / 180;
903
+
904
+ var rad = (Math.PI / 180) * (+angle || 0);
905
+ /** @type {number[]} */
906
+ var res = [];
907
+ var xy;
908
+ var f1;
909
+ var f2;
910
+ var cx;
911
+ var cy;
912
+
913
+ if (!recursive) {
914
+ xy = rotateVector(x1, y1, -rad);
915
+ x1 = xy.x;
916
+ y1 = xy.y;
917
+ xy = rotateVector(x2, y2, -rad);
918
+ x2 = xy.x;
919
+ y2 = xy.y;
920
+
921
+ var x = (x1 - x2) / 2;
922
+ var y = (y1 - y2) / 2;
923
+ var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
924
+ if (h > 1) {
925
+ h = Math.sqrt(h);
926
+ rx *= h;
927
+ ry *= h;
928
+ }
929
+ var rx2 = rx * rx;
930
+ var ry2 = ry * ry;
931
+
932
+ var k = (LAF === SF ? -1 : 1)
933
+ * Math.sqrt(Math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x)
934
+ / (rx2 * y * y + ry2 * x * x)));
935
+
936
+ cx = ((k * rx * y) / ry) + ((x1 + x2) / 2);
937
+ cy = ((k * -ry * x) / rx) + ((y1 + y2) / 2);
938
+ // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise
939
+ f1 = (Math.asin((((y1 - cy) / ry))) * (Math.pow( 10, 9 )) >> 0) / (Math.pow( 10, 9 ));
940
+ // eslint-disable-next-line no-bitwise -- Impossible to satisfy no-bitwise
941
+ f2 = (Math.asin((((y2 - cy) / ry))) * (Math.pow( 10, 9 )) >> 0) / (Math.pow( 10, 9 ));
942
+
943
+ f1 = x1 < cx ? Math.PI - f1 : f1;
944
+ f2 = x2 < cx ? Math.PI - f2 : f2;
945
+ if (f1 < 0) { (f1 = Math.PI * 2 + f1); }
946
+ if (f2 < 0) { (f2 = Math.PI * 2 + f2); }
947
+ if (SF && f1 > f2) {
948
+ f1 -= Math.PI * 2;
949
+ }
950
+ if (!SF && f2 > f1) {
951
+ f2 -= Math.PI * 2;
952
+ }
953
+ } else {
954
+ (assign = recursive, f1 = assign[0], f2 = assign[1], cx = assign[2], cy = assign[3]);
955
+ }
956
+ var df = f2 - f1;
957
+ if (Math.abs(df) > d120) {
958
+ var f2old = f2;
959
+ var x2old = x2;
960
+ var y2old = y2;
961
+ f2 = f1 + d120 * (SF && f2 > f1 ? 1 : -1);
962
+ x2 = cx + rx * Math.cos(f2);
963
+ y2 = cy + ry * Math.sin(f2);
964
+ res = arcToCubic(x2, y2, rx, ry, angle, 0, SF, x2old, y2old, [f2, f2old, cx, cy]);
965
+ }
966
+ df = f2 - f1;
967
+ var c1 = Math.cos(f1);
968
+ var s1 = Math.sin(f1);
969
+ var c2 = Math.cos(f2);
970
+ var s2 = Math.sin(f2);
971
+ var t = Math.tan(df / 4);
972
+ var hx = (4 / 3) * rx * t;
973
+ var hy = (4 / 3) * ry * t;
974
+ var m1 = [x1, y1];
975
+ var m2 = [x1 + hx * s1, y1 - hy * c1];
976
+ var m3 = [x2 + hx * s2, y2 - hy * c2];
977
+ var m4 = [x2, y2];
978
+ m2[0] = 2 * m1[0] - m2[0];
979
+ m2[1] = 2 * m1[1] - m2[1];
980
+ if (recursive) {
981
+ return m2.concat( m3, m4, res);
982
+ }
983
+ res = m2.concat( m3, m4, res);
984
+ var newres = [];
985
+ for (var i = 0, ii = res.length; i < ii; i += 1) {
986
+ newres[i] = i % 2
987
+ ? rotateVector(res[i - 1], res[i], rad).y
988
+ : rotateVector(res[i], res[i + 1], rad).x;
989
+ }
990
+ return newres;
991
+ }
992
+
993
+ /**
994
+ * Converts a Q (quadratic-bezier) segment to C (cubic-bezier).
995
+ *
996
+ * @param {number} x1 curve start x
997
+ * @param {number} y1 curve start y
998
+ * @param {number} qx control point x
999
+ * @param {number} qy control point y
1000
+ * @param {number} x2 curve end x
1001
+ * @param {number} y2 curve end y
1002
+ * @returns {number[]} the cubic-bezier segment
1003
+ */
1004
+ function quadToCubic(x1, y1, qx, qy, x2, y2) {
1005
+ var r13 = 1 / 3;
1006
+ var r23 = 2 / 3;
1007
+ return [
1008
+ r13 * x1 + r23 * qx, // cpx1
1009
+ r13 * y1 + r23 * qy, // cpy1
1010
+ r13 * x2 + r23 * qx, // cpx2
1011
+ r13 * y2 + r23 * qy, // cpy2
1012
+ x2, y2 ];
1013
+ }
1014
+
1015
+ /**
1016
+ * Returns the coordinates of a specified distance
1017
+ * ratio between two points.
1018
+ *
1019
+ * @param {[number, number]} a the first point coordinates
1020
+ * @param {[number, number]} b the second point coordinates
1021
+ * @param {number} t the ratio
1022
+ * @returns {[number, number]} the midpoint coordinates
1023
+ */
1024
+ function midPoint(a, b, t) {
1025
+ var ax = a[0];
1026
+ var ay = a[1]; var bx = b[0];
1027
+ var by = b[1];
1028
+ return [ax + (bx - ax) * t, ay + (by - ay) * t];
1029
+ }
1030
+
1031
+ /**
1032
+ * Returns the square root of the distance
1033
+ * between two given points.
1034
+ *
1035
+ * @param {[number, number]} a the first point coordinates
1036
+ * @param {[number, number]} b the second point coordinates
1037
+ * @returns {number} the distance value
1038
+ */
1039
+ function distanceSquareRoot(a, b) {
1040
+ return Math.sqrt(
1041
+ (a[0] - b[0]) * (a[0] - b[0])
1042
+ + (a[1] - b[1]) * (a[1] - b[1])
1043
+ );
1044
+ }
1045
+
1046
+ /**
1047
+ * Returns the length of a line (L,V,H,Z) segment
1048
+ * or a point at a given length.
1049
+ *
1050
+ * @param {number} x1 the starting point X
1051
+ * @param {number} y1 the starting point Y
1052
+ * @param {number} x2 the ending point X
1053
+ * @param {number} y2 the ending point Y
1054
+ * @param {number=} distance the distance to point
1055
+ * @returns {{x: number, y: number} | number} the segment length or point
1056
+ */
1057
+ function segmentLineFactory(x1, y1, x2, y2, distance) {
1058
+ var length = distanceSquareRoot([x1, y1], [x2, y2]);
1059
+ var margin = 0.001;
1060
+
1061
+ if (typeof distance === 'number') {
1062
+ if (distance < margin) {
1063
+ return { x: x1, y: y1 };
1064
+ }
1065
+ if (distance > length) {
1066
+ return { x: x2, y: y2 };
1067
+ }
1068
+ var ref = midPoint([x1, y1], [x2, y2], distance / length);
1069
+ var x = ref[0];
1070
+ var y = ref[1];
1071
+ return { x: x, y: y };
1072
+ }
1073
+ return length;
1074
+ }
1075
+
1076
+ /**
1077
+ * Converts an L (line-to) segment to C (cubic-bezier).
1078
+ *
1079
+ * @param {number} x1 line start x
1080
+ * @param {number} y1 line start y
1081
+ * @param {number} x2 line end x
1082
+ * @param {number} y2 line end y
1083
+ * @returns {number[]} the cubic-bezier segment
1084
+ */
1085
+ function lineToCubic(x1, y1, x2, y2) {
1086
+ var t = 0.5;
1087
+ /** @type {[number, number]} */
1088
+ var p0 = [x1, y1];
1089
+ /** @type {[number, number]} */
1090
+ var p1 = [x2, y2];
1091
+ var p2 = midPoint(p0, p1, t);
1092
+ var p3 = midPoint(p1, p2, t);
1093
+ var p4 = midPoint(p2, p3, t);
1094
+ var p5 = midPoint(p3, p4, t);
1095
+ var p6 = midPoint(p4, p5, t);
1096
+ var seg1 = p0.concat( p2, p4, p6, [t]);
1097
+ // @ts-ignore
1098
+ var cp1 = segmentLineFactory.apply(void 0, seg1);
1099
+ var seg2 = p6.concat( p5, p3, p1, [0]);
1100
+ // @ts-ignore
1101
+ var cp2 = segmentLineFactory.apply(void 0, seg2);
1102
+
1103
+ // @ts-ignore
1104
+ return [cp1.x, cp1.y, cp2.x, cp2.y, x2, y2];
1105
+ }
1106
+
1107
+ /**
1108
+ * Converts any segment to C (cubic-bezier).
1109
+ *
1110
+ * @param {SVGPath.pathSegment} segment the source segment
1111
+ * @param {SVGPath.parserParams} params the source segment parameters
1112
+ * @returns {SVGPath.cubicSegment | SVGPath.MSegment} the cubic-bezier segment
1113
+ */
1114
+ function segmentToCubic(segment, params) {
1115
+ var pathCommand = segment[0];
1116
+ var values = segment.slice(1).map(function (n) { return +n; });
1117
+ var x = values[0];
1118
+ var y = values[1];
1119
+ var args;
1120
+ var px1 = params.x1;
1121
+ var py1 = params.y1;
1122
+ var px = params.x;
1123
+ var py = params.y;
1124
+
1125
+ if (!'TQ'.includes(pathCommand)) {
1126
+ params.qx = null;
1127
+ params.qy = null;
1128
+ }
1129
+
1130
+ switch (pathCommand) {
1131
+ case 'M':
1132
+ params.x = x;
1133
+ params.y = y;
1134
+ return segment;
1135
+ case 'A':
1136
+ args = [px1, py1 ].concat( values);
1137
+ // @ts-ignore -- relax, the utility will return 6 numbers
1138
+ return ['C' ].concat( arcToCubic.apply(void 0, args));
1139
+ case 'Q':
1140
+ params.qx = x;
1141
+ params.qy = y;
1142
+ args = [px1, py1 ].concat( values);
1143
+ // @ts-ignore -- also returning 6 numbers
1144
+ return ['C' ].concat( quadToCubic.apply(void 0, args));
1145
+ case 'L':
1146
+ // @ts-ignore -- also returning 6 numbers
1147
+ return ['C' ].concat( lineToCubic(px1, py1, x, y));
1148
+ case 'Z':
1149
+ // @ts-ignore -- also returning 6 numbers
1150
+ return ['C' ].concat( lineToCubic(px1, py1, px, py));
1151
+ }
1152
+ // @ts-ignore -- we're switching `pathSegment` type
1153
+ return segment;
1154
+ }
1155
+
1156
+ /**
1157
+ * Parses a path string value or 'pathArray' and returns a new one
1158
+ * in which all segments are converted to cubic-bezier.
1159
+ *
1160
+ * In addition, un-necessary `Z` segment is removed if previous segment
1161
+ * extends to the `M` segment.
1162
+ *
1163
+ * @param {string | SVGPath.pathArray} pathInput the string to be parsed or 'pathArray'
1164
+ * @returns {SVGPath.curveArray} the resulted `pathArray` converted to cubic-bezier
1165
+ */
1166
+ function pathToCurve(pathInput) {
1167
+ var assign;
1168
+
1169
+ if (isCurveArray(pathInput)) {
1170
+ // @ts-ignore -- `isCurveArray` checks if it's `pathArray`
1171
+ return clonePath(pathInput);
1172
+ }
1173
+
1174
+ var path = fixPath(normalizePath(pathInput));
1175
+ var params = Object.assign({}, paramsParser);
1176
+ var allPathCommands = [];
1177
+ var pathCommand = ''; // ts-lint
1178
+ var ii = path.length;
1179
+
1180
+ for (var i = 0; i < ii; i += 1) {
1181
+ (assign = path[i], pathCommand = assign[0]);
1182
+ allPathCommands[i] = pathCommand;
1183
+
1184
+ path[i] = segmentToCubic(path[i], params);
1185
+
1186
+ fixArc(path, allPathCommands, i);
1187
+ ii = path.length;
1188
+
1189
+ var segment = path[i];
1190
+ var seglen = segment.length;
1191
+ params.x1 = +segment[seglen - 2];
1192
+ params.y1 = +segment[seglen - 1];
1193
+ params.x2 = +(segment[seglen - 4]) || params.x1;
1194
+ params.y2 = +(segment[seglen - 3]) || params.y1;
1195
+ }
1196
+
1197
+ // @ts-ignore
1198
+ return path;
1199
+ }
1200
+
1201
+ /**
1202
+ * Rounds the values of a `pathArray` instance to
1203
+ * a specified amount of decimals and returns it.
1204
+ *
1205
+ * @param {SVGPath.pathArray} path the source `pathArray`
1206
+ * @param {number | false} roundOption the amount of decimals to round numbers to
1207
+ * @returns {SVGPath.pathArray} the resulted `pathArray` with rounded values
1208
+ */
1209
+ function roundPath(path, roundOption) {
1210
+ var round = defaultOptions.round;
1211
+ if (roundOption === false || round === false) { return clonePath(path); }
1212
+ // round = roundOption >= 1 ? roundOption : round;
1213
+ // allow for ZERO decimals
1214
+ round = roundOption >= 0 ? roundOption : round;
1215
+ // to round values to the power
1216
+ // the `round` value must be integer
1217
+ var pow = round >= 1 ? (Math.pow( 10, round )) : 1;
1218
+
1219
+ // @ts-ignore -- `pathSegment[]` is `pathArray`
1220
+ return path.map(function (pi) {
1221
+ var values = pi.slice(1).map(Number)
1222
+ .map(function (n) { return (round ? (Math.round(n * pow) / pow) : Math.round(n)); });
1223
+ return [pi[0] ].concat( values);
1224
+ });
1225
+ }
1226
+
1227
+ /**
1228
+ * Returns a valid `d` attribute string value created
1229
+ * by rounding values and concatenating the `pathArray` segments.
1230
+ *
1231
+ * @param {SVGPath.pathArray} path the `pathArray` object
1232
+ * @param {number | false} round amount of decimals to round values to
1233
+ * @returns {string} the concatenated path string
1234
+ */
1235
+ function pathToString(path, round) {
1236
+ return roundPath(path, round)
1237
+ .map(function (x) { return x[0] + x.slice(1).join(' '); }).join('');
1238
+ }
1239
+
1240
+ /**
1241
+ * Reverses all segments of a `pathArray` and returns a new `pathArray` instance.
1242
+ *
1243
+ * @param {SVGPath.pathArray} pathInput the source `pathArray`
1244
+ * @returns {SVGPath.pathArray} the reversed `pathArray`
1245
+ */
1246
+ function reversePath(pathInput) {
1247
+ var absolutePath = pathToAbsolute(pathInput);
1248
+ var isClosed = absolutePath.slice(-1)[0][0] === 'Z';
1249
+
1250
+ var reversedPath = normalizePath(absolutePath).map(function (segment, i) {
1251
+ var ref = segment.slice(-2).map(Number);
1252
+ var x = ref[0];
1253
+ var y = ref[1];
1254
+ return {
1255
+ seg: absolutePath[i], // absolute
1256
+ n: segment, // normalized
1257
+ c: absolutePath[i][0], // pathCommand
1258
+ x: x, // x
1259
+ y: y, // y
1260
+ };
1261
+ }).map(function (seg, i, path) {
1262
+ var segment = seg.seg;
1263
+ var data = seg.n;
1264
+ var prevSeg = i && path[i - 1];
1265
+ var nextSeg = path[i + 1] && path[i + 1];
1266
+ var pathCommand = seg.c;
1267
+ var pLen = path.length;
1268
+ /** @type {number} */
1269
+ var x = i ? path[i - 1].x : path[pLen - 1].x;
1270
+ var y = i ? path[i - 1].y : path[pLen - 1].y;
1271
+ /** @type {SVGPath.pathSegment} */
1272
+ // @ts-ignore
1273
+ var result = [];
1274
+
1275
+ switch (pathCommand) {
1276
+ case 'M':
1277
+ result = isClosed ? ['Z'] : [pathCommand, x, y];
1278
+ break;
1279
+ case 'A':
1280
+ // @ts-ignore -- expected on reverse
1281
+ result = [pathCommand ].concat( segment.slice(1, -3), [(segment[5] === 1 ? 0 : 1)], [x], [y]);
1282
+ break;
1283
+ case 'C':
1284
+ if (nextSeg && nextSeg.c === 'S') {
1285
+ // @ts-ignore -- expected on reverse
1286
+ result = ['S', segment[1], segment[2], x, y];
1287
+ } else {
1288
+ // @ts-ignore -- expected on reverse
1289
+ result = [pathCommand, segment[3], segment[4], segment[1], segment[2], x, y];
1290
+ }
1291
+ break;
1292
+ case 'S':
1293
+ if ((prevSeg && 'CS'.includes(prevSeg.c)) && (!nextSeg || (nextSeg && nextSeg.c !== 'S'))) {
1294
+ // @ts-ignore -- expected on reverse
1295
+ result = ['C', data[3], data[4], data[1], data[2], x, y];
1296
+ } else {
1297
+ // @ts-ignore -- expected on reverse
1298
+ result = [pathCommand, data[1], data[2], x, y];
1299
+ }
1300
+ break;
1301
+ case 'Q':
1302
+ if (nextSeg && nextSeg.c === 'T') {
1303
+ result = ['T', x, y];
1304
+ } else {
1305
+ // @ts-ignore -- expected on reverse
1306
+ result = [pathCommand ].concat( segment.slice(1, -2), [x], [y]);
1307
+ }
1308
+ break;
1309
+ case 'T':
1310
+ if ((prevSeg && 'QT'.includes(prevSeg.c)) && (!nextSeg || (nextSeg && nextSeg.c !== 'T'))) {
1311
+ // @ts-ignore -- expected on reverse
1312
+ result = ['Q', data[1], data[2], x, y];
1313
+ } else {
1314
+ result = [pathCommand, x, y];
1315
+ }
1316
+ break;
1317
+ case 'Z':
1318
+ result = ['M', x, y];
1319
+ break;
1320
+ case 'H':
1321
+ result = [pathCommand, x];
1322
+ break;
1323
+ case 'V':
1324
+ result = [pathCommand, y];
1325
+ break;
1326
+ default:
1327
+ // @ts-ignore -- expected on reverse
1328
+ result = [pathCommand ].concat( segment.slice(1, -2), [x], [y]);
1329
+ }
1330
+
1331
+ return result;
1332
+ });
1333
+
1334
+ // @ts-ignore -- `pathSegment[]` is definitely `pathArray`
1335
+ return isClosed ? reversedPath.reverse()
1336
+ : [reversedPath[0] ].concat( reversedPath.slice(1).reverse());
1337
+ }
1338
+
1339
+ /**
1340
+ * Split a path into an `Array` of sub-path strings.
1341
+ *
1342
+ * In the process, values are converted to absolute
1343
+ * for visual consistency.
1344
+ *
1345
+ * @param {SVGPath.pathArray | string} pathInput the source `pathArray`
1346
+ * @return {string[]} an array with all sub-path strings
1347
+ */
1348
+ function splitPath(pathInput) {
1349
+ return pathToString(pathToAbsolute(pathInput), 0)
1350
+ .replace(/(m|M)/g, '|$1')
1351
+ .split('|')
1352
+ .map(function (s) { return s.trim(); })
1353
+ .filter(function (s) { return s; });
1354
+ }
1355
+
1356
+ /**
1357
+ * Shorten a single segment of a `pathArray` object.
1358
+ *
1359
+ * @param {SVGPath.absoluteSegment} segment the `absoluteSegment` object
1360
+ * @param {SVGPath.normalSegment} normalSegment the `normalSegment` object
1361
+ * @param {any} params the coordinates of the previous segment
1362
+ * @param {string} prevCommand the path command of the previous segment
1363
+ * @returns {SVGPath.shortSegment | SVGPath.pathSegment} the shortened segment
1364
+ */
1365
+ function shortenSegment(segment, normalSegment, params, prevCommand) {
1366
+ var pathCommand = segment[0];
1367
+ var round4 = function (/** @type {number} */n) { return Math.round(n * (Math.pow( 10, 4 ))) / Math.pow( 10, 4 ); };
1368
+ var segmentValues = segment.slice(1).map(function (n) { return +n; });
1369
+ var normalValues = normalSegment.slice(1).map(function (n) { return +n; });
1370
+ var px1 = params.x1;
1371
+ var py1 = params.y1;
1372
+ var px2 = params.x2;
1373
+ var py2 = params.y2;
1374
+ var px = params.x;
1375
+ var py = params.y;
1376
+ var result = segment;
1377
+ var ref = normalValues.slice(-2);
1378
+ var x = ref[0];
1379
+ var y = ref[1];
1380
+
1381
+ if (!'TQ'.includes(pathCommand)) {
1382
+ // optional but good to be cautious
1383
+ params.qx = null;
1384
+ params.qy = null;
1385
+ }
1386
+
1387
+ if (['V', 'H', 'S', 'T', 'Z'].includes(pathCommand)) {
1388
+ // @ts-ignore -- expected when so many types are included
1389
+ result = [pathCommand ].concat( segmentValues);
1390
+ } else if (pathCommand === 'L') {
1391
+ if (round4(px) === round4(x)) {
1392
+ result = ['V', y];
1393
+ } else if (round4(py) === round4(y)) {
1394
+ result = ['H', x];
1395
+ }
1396
+ } else if (pathCommand === 'C') {
1397
+ var x1 = normalValues[0];
1398
+ var y1 = normalValues[1];
1399
+
1400
+ if ('CS'.includes(prevCommand)
1401
+ && round4(x1) === round4(px1 * 2 - px2)
1402
+ && round4(y1) === round4(py1 * 2 - py2)) {
1403
+ // @ts-ignore -- the amount of numbers should suffice
1404
+ result = ['S' ].concat( normalValues.slice(-4));
1405
+ }
1406
+ params.x1 = x1;
1407
+ params.y1 = y1;
1408
+ } else if (pathCommand === 'Q') {
1409
+ var qx = normalValues[0];
1410
+ var qy = normalValues[1];
1411
+ params.qx = qx;
1412
+ params.qy = qy;
1413
+
1414
+ if ('QT'.includes(prevCommand)
1415
+ && round4(qx) === round4(px1 * 2 - px2)
1416
+ && round4(qy) === round4(py1 * 2 - py2)) {
1417
+ // @ts-ignore -- the amount of numbers should suffice
1418
+ result = ['T' ].concat( normalValues.slice(-2));
1419
+ }
1420
+ }
1421
+
1422
+ return result;
1423
+ }
1424
+
1425
+ /**
1426
+ * Optimizes a `pathArray` object:
1427
+ * * convert segments to shorthand if possible
1428
+ * * select shortest segments from absolute and relative `pathArray`s
1429
+ *
1430
+ * TO DO
1431
+ * * implement `auto` for rounding values based on pathBBox
1432
+ * * also revers path check if it's smaller string, maybe?
1433
+ *
1434
+ * @param {SVGPath.pathArray} pathInput a string or `pathArray`
1435
+ * @param {number | boolean} round the amount of decimals to round values to
1436
+ * @returns {SVGPath.pathArray} the optimized `pathArray`
1437
+ */
1438
+ function optimizePath(pathInput, round) {
1439
+ var assign, assign$1, assign$2, assign$3;
1440
+
1441
+ var path = pathToAbsolute(pathInput);
1442
+ var normalPath = normalizePath(path);
1443
+ var params = Object.assign({}, paramsParser);
1444
+ var allPathCommands = [];
1445
+ var ii = path.length;
1446
+ var pathCommand = '';
1447
+ var prevCommand = '';
1448
+ var x = 0;
1449
+ var y = 0;
1450
+ var mx = 0;
1451
+ var my = 0;
1452
+
1453
+ for (var i = 0; i < ii; i += 1) {
1454
+ (assign = path[i], pathCommand = assign[0]);
1455
+
1456
+ // Save current path command
1457
+ allPathCommands[i] = pathCommand;
1458
+ // Get previous path command for `shortenSegment`
1459
+ if (i) { prevCommand = allPathCommands[i - 1]; }
1460
+ // @ts-ignore -- expected when switching `pathSegment` type
1461
+ path[i] = shortenSegment(path[i], normalPath[i], params, prevCommand);
1462
+
1463
+ var segment = path[i];
1464
+ var seglen = segment.length;
1465
+
1466
+ // update C, S, Q, T specific params
1467
+ params.x1 = +segment[seglen - 2];
1468
+ params.y1 = +segment[seglen - 1];
1469
+ params.x2 = +(segment[seglen - 4]) || params.x1;
1470
+ params.y2 = +(segment[seglen - 3]) || params.y1;
1471
+
1472
+ // update x, y params
1473
+ switch (pathCommand) {
1474
+ case 'Z':
1475
+ x = mx;
1476
+ y = my;
1477
+ break;
1478
+ case 'H':
1479
+ // @ts-ignore
1480
+ (assign$1 = segment, x = assign$1[1]);
1481
+ break;
1482
+ case 'V':
1483
+ // @ts-ignore
1484
+ (assign$2 = segment, y = assign$2[1]);
1485
+ break;
1486
+ default:
1487
+ (assign$3 = segment.slice(-2).map(Number), x = assign$3[0], y = assign$3[1]);
1488
+
1489
+ if (pathCommand === 'M') {
1490
+ mx = x;
1491
+ my = y;
1492
+ }
1493
+ }
1494
+ params.x = x;
1495
+ params.y = y;
1496
+ }
1497
+
1498
+ var absolutePath = roundPath(path, round);
1499
+ var relativePath = roundPath(pathToRelative(path), round);
1500
+
1501
+ // @ts-ignore - it's expected an optimized `pathArray` to contain all kinds of segments
1502
+ return absolutePath.map(function (a, i) {
1503
+ if (i) {
1504
+ return a.join('').length < relativePath[i].join('').length
1505
+ ? a : relativePath[i];
1506
+ }
1507
+ return a;
1508
+ });
1509
+ }
1510
+
1511
+ /**
1512
+ * A global namespace for epsilon.
1513
+ *
1514
+ * @type {number}
1515
+ */
1516
+ var epsilon = 1e-9;
1517
+
1518
+ // DOMMatrix Static methods
1519
+ // * `fromFloat64Array` and `fromFloat32Array are not implemented;
1520
+ // * `fromArray` is a more simple implementation, should also accept Float[32/64]Array;
1521
+ // * `fromMatrix` load values from another CSSMatrix/DOMMatrix instance or JSON object;
1522
+ // * `fromString` parses and loads values from any valid CSS transform string (TransformList).
1523
+
1524
+ /**
1525
+ * Creates a new mutable `CSSMatrix` instance given an array of 16/6 floating point values.
1526
+ * This static method invalidates arrays that contain non-number elements.
1527
+ *
1528
+ * If the array has six values, the result is a 2D matrix; if the array has 16 values,
1529
+ * the result is a 3D matrix. Otherwise, a TypeError exception is thrown.
1530
+ *
1531
+ * @param {number[]} array an `Array` to feed values from.
1532
+ * @return {CSSMatrix} the resulted matrix.
1533
+ */
1534
+ function fromArray(array) {
1535
+ var m = new CSSMatrix();
1536
+ var a = Array.from(array);
1537
+
1538
+ if (!a.every(function (n) { return !Number.isNaN(n); })) {
1539
+ throw TypeError(("CSSMatrix: \"" + array + "\" must only have numbers."));
1540
+ }
1541
+ if (a.length === 16) {
1542
+ var m11 = a[0];
1543
+ var m12 = a[1];
1544
+ var m13 = a[2];
1545
+ var m14 = a[3];
1546
+ var m21 = a[4];
1547
+ var m22 = a[5];
1548
+ var m23 = a[6];
1549
+ var m24 = a[7];
1550
+ var m31 = a[8];
1551
+ var m32 = a[9];
1552
+ var m33 = a[10];
1553
+ var m34 = a[11];
1554
+ var m41 = a[12];
1555
+ var m42 = a[13];
1556
+ var m43 = a[14];
1557
+ var m44 = a[15];
1558
+
1559
+ m.m11 = m11;
1560
+ m.a = m11;
1561
+
1562
+ m.m21 = m21;
1563
+ m.c = m21;
1564
+
1565
+ m.m31 = m31;
1566
+
1567
+ m.m41 = m41;
1568
+ m.e = m41;
1569
+
1570
+ m.m12 = m12;
1571
+ m.b = m12;
1572
+
1573
+ m.m22 = m22;
1574
+ m.d = m22;
1575
+
1576
+ m.m32 = m32;
1577
+
1578
+ m.m42 = m42;
1579
+ m.f = m42;
1580
+
1581
+ m.m13 = m13;
1582
+ m.m23 = m23;
1583
+ m.m33 = m33;
1584
+ m.m43 = m43;
1585
+ m.m14 = m14;
1586
+ m.m24 = m24;
1587
+ m.m34 = m34;
1588
+ m.m44 = m44;
1589
+ } else if (a.length === 6) {
1590
+ var M11 = a[0];
1591
+ var M12 = a[1];
1592
+ var M21 = a[2];
1593
+ var M22 = a[3];
1594
+ var M41 = a[4];
1595
+ var M42 = a[5];
1596
+
1597
+ m.m11 = M11;
1598
+ m.a = M11;
1599
+
1600
+ m.m12 = M12;
1601
+ m.b = M12;
1602
+
1603
+ m.m21 = M21;
1604
+ m.c = M21;
1605
+
1606
+ m.m22 = M22;
1607
+ m.d = M22;
1608
+
1609
+ m.m41 = M41;
1610
+ m.e = M41;
1611
+
1612
+ m.m42 = M42;
1613
+ m.f = M42;
1614
+ } else {
1615
+ throw new TypeError('CSSMatrix: expecting an Array of 6/16 values.');
1616
+ }
1617
+ return m;
1618
+ }
1619
+
1620
+ /**
1621
+ * Creates a new mutable `CSSMatrix` instance given an existing matrix or a
1622
+ * `DOMMatrix` instance which provides the values for its properties.
1623
+ *
1624
+ * @param {CSSMatrix | DOMMatrix | CSSMatrix.JSONMatrix} m the source matrix to feed values from.
1625
+ * @return {CSSMatrix} the resulted matrix.
1626
+ */
1627
+ function fromMatrix(m) {
1628
+ var keys = Object.keys(new CSSMatrix());
1629
+ if (typeof m === 'object' && keys.every(function (k) { return k in m; })) {
1630
+ return fromArray(
1631
+ [m.m11, m.m12, m.m13, m.m14,
1632
+ m.m21, m.m22, m.m23, m.m24,
1633
+ m.m31, m.m32, m.m33, m.m34,
1634
+ m.m41, m.m42, m.m43, m.m44]
1635
+ );
1636
+ }
1637
+ throw TypeError(("CSSMatrix: \"" + m + "\" is not a DOMMatrix / CSSMatrix / JSON compatible object."));
1638
+ }
1639
+
1640
+ /**
1641
+ * Creates a new mutable `CSSMatrix` given any valid CSS transform string,
1642
+ * or what we call `TransformList`:
1643
+ *
1644
+ * * `matrix(a, b, c, d, e, f)` - valid matrix() transform function
1645
+ * * `matrix3d(m11, m12, m13, ...m44)` - valid matrix3d() transform function
1646
+ * * `translate(tx, ty) rotateX(alpha)` - any valid transform function(s)
1647
+ *
1648
+ * @copyright thednp © 2021
1649
+ *
1650
+ * @param {string} source valid CSS transform string syntax.
1651
+ * @return {CSSMatrix} the resulted matrix.
1652
+ */
1653
+ function fromString(source) {
1654
+ if (typeof source !== 'string') {
1655
+ throw TypeError(("CSSMatrix: \"" + source + "\" is not a string."));
1656
+ }
1657
+ var str = String(source).replace(/\s/g, '');
1658
+ var m = new CSSMatrix();
1659
+ var invalidStringError = "CSSMatrix: invalid transform string \"" + source + "\"";
1660
+
1661
+ // const px = ['perspective'];
1662
+ // const length = ['translate', 'translate3d', 'translateX', 'translateY', 'translateZ'];
1663
+ // const deg = ['rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'skew', 'skewX', 'skewY'];
1664
+ // const abs = ['scale', 'scale3d', 'matrix', 'matrix3d'];
1665
+ // const transformFunctions = px.concat(length, deg, abs);
1666
+
1667
+ str.split(')').filter(function (f) { return f; }).forEach(function (tf) {
1668
+ var ref = tf.split('(');
1669
+ var prop = ref[0];
1670
+ var value = ref[1];
1671
+
1672
+ // invalidate empty string
1673
+ if (!value) { throw TypeError(invalidStringError); }
1674
+
1675
+ var components = value.split(',')
1676
+ .map(function (n) { return (n.includes('rad') ? parseFloat(n) * (180 / Math.PI) : parseFloat(n)); });
1677
+
1678
+ var x = components[0];
1679
+ var y = components[1];
1680
+ var z = components[2];
1681
+ var a = components[3];
1682
+ var xyz = [x, y, z];
1683
+ var xyza = [x, y, z, a];
1684
+
1685
+ // single number value expected
1686
+ if (prop === 'perspective' && x && [y, z].every(function (n) { return n === undefined; })) {
1687
+ m.m34 = -1 / x;
1688
+ // 6/16 number values expected
1689
+ } else if (prop.includes('matrix') && [6, 16].includes(components.length)
1690
+ && components.every(function (n) { return !Number.isNaN(+n); })) {
1691
+ var values = components.map(function (n) { return (Math.abs(n) < 1e-6 ? 0 : n); });
1692
+ m = m.multiply(fromArray(values));
1693
+ // 3 values expected
1694
+ } else if (prop === 'translate3d' && xyz.every(function (n) { return !Number.isNaN(+n); })) {
1695
+ m = m.translate(x, y, z);
1696
+ // single/double number value(s) expected
1697
+ } else if (prop === 'translate' && x && z === undefined) {
1698
+ m = m.translate(x, y || 0, 0);
1699
+ // all 4 values expected
1700
+ } else if (prop === 'rotate3d' && xyza.every(function (n) { return !Number.isNaN(+n); }) && a) {
1701
+ m = m.rotateAxisAngle(x, y, z, a);
1702
+ // single value expected
1703
+ } else if (prop === 'rotate' && x && [y, z].every(function (n) { return n === undefined; })) {
1704
+ m = m.rotate(0, 0, x);
1705
+ // 4 values expected
1706
+ } else if (prop === 'scale3d' && xyz.every(function (n) { return !Number.isNaN(+n); }) && xyz.some(function (n) { return n !== 1; })) {
1707
+ m = m.scale(x, y, z);
1708
+ // single value expected
1709
+ } else if (prop === 'scale' && !Number.isNaN(x) && x !== 1 && z === undefined) {
1710
+ var nosy = Number.isNaN(+y);
1711
+ var sy = nosy ? x : y;
1712
+ m = m.scale(x, sy, 1);
1713
+ // single/double value expected
1714
+ } else if (prop === 'skew' && x && z === undefined) {
1715
+ m = m.skewX(x);
1716
+ m = y ? m.skewY(y) : m;
1717
+ } else if (/[XYZ]/.test(prop) && x && [y, z].every(function (n) { return n === undefined; }) // a single value expected
1718
+ && ['translate', 'rotate', 'scale', 'skew'].some(function (p) { return prop.includes(p); })) {
1719
+ if (['skewX', 'skewY'].includes(prop)) {
1720
+ // @ts-ignore unfortunately
1721
+ m = m[prop](x);
1722
+ } else {
1723
+ var fn = prop.replace(/[XYZ]/, '');
1724
+ var axis = prop.replace(fn, '');
1725
+ var idx = ['X', 'Y', 'Z'].indexOf(axis);
1726
+ var axeValues = [
1727
+ idx === 0 ? x : 0,
1728
+ idx === 1 ? x : 0,
1729
+ idx === 2 ? x : 0];
1730
+ // @ts-ignore unfortunately
1731
+ m = m[fn].apply(m, axeValues);
1732
+ }
1733
+ } else {
1734
+ throw TypeError(invalidStringError);
1735
+ }
1736
+ });
1737
+
1738
+ return m;
1739
+ }
1740
+
1741
+ // Transform Functions
1742
+ // https://www.w3.org/TR/css-transforms-1/#transform-functions
1743
+
1744
+ /**
1745
+ * Creates a new `CSSMatrix` for the translation matrix and returns it.
1746
+ * This method is equivalent to the CSS `translate3d()` function.
1747
+ *
1748
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate3d
1749
+ *
1750
+ * @param {number} x the `x-axis` position.
1751
+ * @param {number} y the `y-axis` position.
1752
+ * @param {number} z the `z-axis` position.
1753
+ * @return {CSSMatrix} the resulted matrix.
1754
+ */
1755
+ function Translate(x, y, z) {
1756
+ var m = new CSSMatrix();
1757
+ m.m41 = x;
1758
+ m.e = x;
1759
+ m.m42 = y;
1760
+ m.f = y;
1761
+ m.m43 = z;
1762
+ return m;
1763
+ }
1764
+
1765
+ /**
1766
+ * Creates a new `CSSMatrix` for the rotation matrix and returns it.
1767
+ *
1768
+ * http://en.wikipedia.org/wiki/Rotation_matrix
1769
+ *
1770
+ * @param {number} rx the `x-axis` rotation.
1771
+ * @param {number} ry the `y-axis` rotation.
1772
+ * @param {number} rz the `z-axis` rotation.
1773
+ * @return {CSSMatrix} the resulted matrix.
1774
+ */
1775
+ function Rotate(rx, ry, rz) {
1776
+ var m = new CSSMatrix();
1777
+ var degToRad = Math.PI / 180;
1778
+ var radX = rx * degToRad;
1779
+ var radY = ry * degToRad;
1780
+ var radZ = rz * degToRad;
1781
+
1782
+ // minus sin() because of right-handed system
1783
+ var cosx = Math.cos(radX);
1784
+ var sinx = -Math.sin(radX);
1785
+ var cosy = Math.cos(radY);
1786
+ var siny = -Math.sin(radY);
1787
+ var cosz = Math.cos(radZ);
1788
+ var sinz = -Math.sin(radZ);
1789
+
1790
+ var m11 = cosy * cosz;
1791
+ var m12 = -cosy * sinz;
1792
+
1793
+ m.m11 = m11;
1794
+ m.a = m11;
1795
+
1796
+ m.m12 = m12;
1797
+ m.b = m12;
1798
+
1799
+ m.m13 = siny;
1800
+
1801
+ var m21 = sinx * siny * cosz + cosx * sinz;
1802
+ m.m21 = m21;
1803
+ m.c = m21;
1804
+
1805
+ var m22 = cosx * cosz - sinx * siny * sinz;
1806
+ m.m22 = m22;
1807
+ m.d = m22;
1808
+
1809
+ m.m23 = -sinx * cosy;
1810
+
1811
+ m.m31 = sinx * sinz - cosx * siny * cosz;
1812
+ m.m32 = sinx * cosz + cosx * siny * sinz;
1813
+ m.m33 = cosx * cosy;
1814
+
1815
+ return m;
1816
+ }
1817
+
1818
+ /**
1819
+ * Creates a new `CSSMatrix` for the rotation matrix and returns it.
1820
+ * This method is equivalent to the CSS `rotate3d()` function.
1821
+ *
1822
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/rotate3d
1823
+ *
1824
+ * @param {number} x the `x-axis` vector length.
1825
+ * @param {number} y the `y-axis` vector length.
1826
+ * @param {number} z the `z-axis` vector length.
1827
+ * @param {number} alpha the value in degrees of the rotation.
1828
+ * @return {CSSMatrix} the resulted matrix.
1829
+ */
1830
+ function RotateAxisAngle(x, y, z, alpha) {
1831
+ var m = new CSSMatrix();
1832
+ var angle = alpha * (Math.PI / 360);
1833
+ var sinA = Math.sin(angle);
1834
+ var cosA = Math.cos(angle);
1835
+ var sinA2 = sinA * sinA;
1836
+ var length = Math.sqrt(x * x + y * y + z * z);
1837
+ var X = x;
1838
+ var Y = y;
1839
+ var Z = z;
1840
+
1841
+ if (length === 0) {
1842
+ // bad vector length, use something reasonable
1843
+ X = 0;
1844
+ Y = 0;
1845
+ Z = 1;
1846
+ } else {
1847
+ X /= length;
1848
+ Y /= length;
1849
+ Z /= length;
1850
+ }
1851
+
1852
+ var x2 = X * X;
1853
+ var y2 = Y * Y;
1854
+ var z2 = Z * Z;
1855
+
1856
+ var m11 = 1 - 2 * (y2 + z2) * sinA2;
1857
+ m.m11 = m11;
1858
+ m.a = m11;
1859
+
1860
+ var m12 = 2 * (X * Y * sinA2 + Z * sinA * cosA);
1861
+ m.m12 = m12;
1862
+ m.b = m12;
1863
+
1864
+ m.m13 = 2 * (X * Z * sinA2 - Y * sinA * cosA);
1865
+
1866
+ var m21 = 2 * (Y * X * sinA2 - Z * sinA * cosA);
1867
+ m.m21 = m21;
1868
+ m.c = m21;
1869
+
1870
+ var m22 = 1 - 2 * (z2 + x2) * sinA2;
1871
+ m.m22 = m22;
1872
+ m.d = m22;
1873
+
1874
+ m.m23 = 2 * (Y * Z * sinA2 + X * sinA * cosA);
1875
+ m.m31 = 2 * (Z * X * sinA2 + Y * sinA * cosA);
1876
+ m.m32 = 2 * (Z * Y * sinA2 - X * sinA * cosA);
1877
+ m.m33 = 1 - 2 * (x2 + y2) * sinA2;
1878
+
1879
+ return m;
1880
+ }
1881
+
1882
+ /**
1883
+ * Creates a new `CSSMatrix` for the scale matrix and returns it.
1884
+ * This method is equivalent to the CSS `scale3d()` function, except it doesn't
1885
+ * accept {x, y, z} transform origin parameters.
1886
+ *
1887
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/scale3d
1888
+ *
1889
+ * @param {number} x the `x-axis` scale.
1890
+ * @param {number} y the `y-axis` scale.
1891
+ * @param {number} z the `z-axis` scale.
1892
+ * @return {CSSMatrix} the resulted matrix.
1893
+ */
1894
+ function Scale(x, y, z) {
1895
+ var m = new CSSMatrix();
1896
+ m.m11 = x;
1897
+ m.a = x;
1898
+
1899
+ m.m22 = y;
1900
+ m.d = y;
1901
+
1902
+ m.m33 = z;
1903
+ return m;
1904
+ }
1905
+
1906
+ /**
1907
+ * Creates a new `CSSMatrix` for the shear of the `x-axis` rotation matrix and
1908
+ * returns it. This method is equivalent to the CSS `skewX()` function.
1909
+ *
1910
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewX
1911
+ *
1912
+ * @param {number} angle the angle in degrees.
1913
+ * @return {CSSMatrix} the resulted matrix.
1914
+ */
1915
+ function SkewX(angle) {
1916
+ var m = new CSSMatrix();
1917
+ var radA = (angle * Math.PI) / 180;
1918
+ var t = Math.tan(radA);
1919
+ m.m21 = t;
1920
+ m.c = t;
1921
+ return m;
1922
+ }
1923
+
1924
+ /**
1925
+ * Creates a new `CSSMatrix` for the shear of the `y-axis` rotation matrix and
1926
+ * returns it. This method is equivalent to the CSS `skewY()` function.
1927
+ *
1928
+ * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/skewY
1929
+ *
1930
+ * @param {number} angle the angle in degrees.
1931
+ * @return {CSSMatrix} the resulted matrix.
1932
+ */
1933
+ function SkewY(angle) {
1934
+ var m = new CSSMatrix();
1935
+ var radA = (angle * Math.PI) / 180;
1936
+ var t = Math.tan(radA);
1937
+ m.m12 = t;
1938
+ m.b = t;
1939
+ return m;
1940
+ }
1941
+
1942
+ /**
1943
+ * Creates a new `CSSMatrix` resulted from the multiplication of two matrixes
1944
+ * and returns it. Both matrixes are not changed.
1945
+ *
1946
+ * @param {CSSMatrix} m1 the first matrix.
1947
+ * @param {CSSMatrix} m2 the second matrix.
1948
+ * @return {CSSMatrix} the resulted matrix.
1949
+ */
1950
+ function Multiply(m1, m2) {
1951
+ var m11 = m2.m11 * m1.m11 + m2.m12 * m1.m21 + m2.m13 * m1.m31 + m2.m14 * m1.m41;
1952
+ var m12 = m2.m11 * m1.m12 + m2.m12 * m1.m22 + m2.m13 * m1.m32 + m2.m14 * m1.m42;
1953
+ var m13 = m2.m11 * m1.m13 + m2.m12 * m1.m23 + m2.m13 * m1.m33 + m2.m14 * m1.m43;
1954
+ var m14 = m2.m11 * m1.m14 + m2.m12 * m1.m24 + m2.m13 * m1.m34 + m2.m14 * m1.m44;
1955
+
1956
+ var m21 = m2.m21 * m1.m11 + m2.m22 * m1.m21 + m2.m23 * m1.m31 + m2.m24 * m1.m41;
1957
+ var m22 = m2.m21 * m1.m12 + m2.m22 * m1.m22 + m2.m23 * m1.m32 + m2.m24 * m1.m42;
1958
+ var m23 = m2.m21 * m1.m13 + m2.m22 * m1.m23 + m2.m23 * m1.m33 + m2.m24 * m1.m43;
1959
+ var m24 = m2.m21 * m1.m14 + m2.m22 * m1.m24 + m2.m23 * m1.m34 + m2.m24 * m1.m44;
1960
+
1961
+ var m31 = m2.m31 * m1.m11 + m2.m32 * m1.m21 + m2.m33 * m1.m31 + m2.m34 * m1.m41;
1962
+ var m32 = m2.m31 * m1.m12 + m2.m32 * m1.m22 + m2.m33 * m1.m32 + m2.m34 * m1.m42;
1963
+ var m33 = m2.m31 * m1.m13 + m2.m32 * m1.m23 + m2.m33 * m1.m33 + m2.m34 * m1.m43;
1964
+ var m34 = m2.m31 * m1.m14 + m2.m32 * m1.m24 + m2.m33 * m1.m34 + m2.m34 * m1.m44;
1965
+
1966
+ var m41 = m2.m41 * m1.m11 + m2.m42 * m1.m21 + m2.m43 * m1.m31 + m2.m44 * m1.m41;
1967
+ var m42 = m2.m41 * m1.m12 + m2.m42 * m1.m22 + m2.m43 * m1.m32 + m2.m44 * m1.m42;
1968
+ var m43 = m2.m41 * m1.m13 + m2.m42 * m1.m23 + m2.m43 * m1.m33 + m2.m44 * m1.m43;
1969
+ var m44 = m2.m41 * m1.m14 + m2.m42 * m1.m24 + m2.m43 * m1.m34 + m2.m44 * m1.m44;
1970
+
1971
+ return fromArray(
1972
+ [m11, m12, m13, m14,
1973
+ m21, m22, m23, m24,
1974
+ m31, m32, m33, m34,
1975
+ m41, m42, m43, m44]
1976
+ );
1977
+ }
1978
+
1979
+ /**
1980
+ * Creates and returns a new `DOMMatrix` compatible instance
1981
+ * with equivalent instance.
1982
+ * @class CSSMatrix
1983
+ *
1984
+ * @author thednp <https://github.com/thednp/DOMMatrix/>
1985
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix
1986
+ */
1987
+
1988
+ var CSSMatrix = function CSSMatrix() {
1989
+ var args = [], len = arguments.length;
1990
+ while ( len-- ) args[ len ] = arguments[ len ];
1991
+
1992
+ var m = this;
1993
+ // array 6
1994
+ m.a = 1; m.b = 0;
1995
+ m.c = 0; m.d = 1;
1996
+ m.e = 0; m.f = 0;
1997
+ // array 16
1998
+ m.m11 = 1; m.m12 = 0; m.m13 = 0; m.m14 = 0;
1999
+ m.m21 = 0; m.m22 = 1; m.m23 = 0; m.m24 = 0;
2000
+ m.m31 = 0; m.m32 = 0; m.m33 = 1; m.m34 = 0;
2001
+ m.m41 = 0; m.m42 = 0; m.m43 = 0; m.m44 = 1;
2002
+
2003
+ if (args && args.length) {
2004
+ var ARGS = [16, 6].some(function (l) { return l === args.length; }) ? args : args[0];
2005
+
2006
+ return m.setMatrixValue(ARGS);
2007
+ }
2008
+ return m;
2009
+ };
2010
+
2011
+ var prototypeAccessors = { isIdentity: { configurable: true },is2D: { configurable: true } };
2012
+
2013
+ /**
2014
+ * Sets a new `Boolean` flag value for `this.isIdentity` matrix property.
2015
+ *
2016
+ * @param {boolean} value sets a new flag for this property
2017
+ */
2018
+ prototypeAccessors.isIdentity.set = function (value) {
2019
+ this.isIdentity = value;
2020
+ };
2021
+
2022
+ /**
2023
+ * A `Boolean` whose value is `true` if the matrix is the identity matrix. The identity
2024
+ * matrix is one in which every value is 0 except those on the main diagonal from top-left
2025
+ * to bottom-right corner (in other words, where the offsets in each direction are equal).
2026
+ *
2027
+ * @return {boolean} the current property value
2028
+ */
2029
+ prototypeAccessors.isIdentity.get = function () {
2030
+ var m = this;
2031
+ return (m.m11 === 1 && m.m12 === 0 && m.m13 === 0 && m.m14 === 0
2032
+ && m.m21 === 0 && m.m22 === 1 && m.m23 === 0 && m.m24 === 0
2033
+ && m.m31 === 0 && m.m32 === 0 && m.m33 === 1 && m.m34 === 0
2034
+ && m.m41 === 0 && m.m42 === 0 && m.m43 === 0 && m.m44 === 1);
2035
+ };
2036
+
2037
+ /**
2038
+ * A `Boolean` flag whose value is `true` if the matrix was initialized as a 2D matrix
2039
+ * and `false` if the matrix is 3D.
2040
+ *
2041
+ * @return {boolean} the current property value
2042
+ */
2043
+ prototypeAccessors.is2D.get = function () {
2044
+ var m = this;
2045
+ return (m.m31 === 0 && m.m32 === 0 && m.m33 === 1 && m.m34 === 0 && m.m43 === 0 && m.m44 === 1);
2046
+ };
2047
+
2048
+ /**
2049
+ * Sets a new `Boolean` flag value for `this.is2D` matrix property.
2050
+ *
2051
+ * @param {boolean} value sets a new flag for this property
2052
+ */
2053
+ prototypeAccessors.is2D.set = function (value) {
2054
+ this.is2D = value;
2055
+ };
2056
+
2057
+ /**
2058
+ * The `setMatrixValue` method replaces the existing matrix with one computed
2059
+ * in the browser. EG: `matrix(1,0.25,-0.25,1,0,0)`
2060
+ *
2061
+ * The method accepts any *Array* values, the result of
2062
+ * `DOMMatrix` instance method `toFloat64Array()` / `toFloat32Array()` calls
2063
+ *or `CSSMatrix` instance method `toArray()`.
2064
+ *
2065
+ * This method expects valid *matrix()* / *matrix3d()* string values, as well
2066
+ * as other transform functions like *translateX(10px)*.
2067
+ *
2068
+ * @param {string | number[] | CSSMatrix | DOMMatrix} source
2069
+ * @return {CSSMatrix} the matrix instance
2070
+ */
2071
+ CSSMatrix.prototype.setMatrixValue = function setMatrixValue (source) {
2072
+ var m = this;
2073
+
2074
+ // [Arguments list | Array] come here
2075
+ if ([Array, Float64Array, Float32Array].some(function (a) { return source instanceof a; })) {
2076
+ return fromArray(source);
2077
+ }
2078
+ // CSS transform string source - TransformList
2079
+ if (typeof source === 'string' && source.length && source !== 'none') {
2080
+ return fromString(source);
2081
+ }
2082
+ // new CSSMatrix(CSSMatrix | DOMMatrix | JSON)
2083
+ if (typeof source === 'object') {
2084
+ return fromMatrix(source);
2085
+ }
2086
+ return m;
2087
+ };
2088
+
2089
+ /**
2090
+ * Returns an *Array* containing elements which comprise the matrix.
2091
+ * The method can return either the 16 elements or the 6 elements
2092
+ * depending on the value of the `is2D` property.
2093
+ *
2094
+ * @return {number[]} an *Array* representation of the matrix
2095
+ */
2096
+ CSSMatrix.prototype.toArray = function toArray () {
2097
+ var m = this;
2098
+ var pow = (Math.pow( 10, 6 ));
2099
+ var result;
2100
+
2101
+ if (m.is2D) {
2102
+ result = [m.a, m.b, m.c, m.d, m.e, m.f];
2103
+ } else {
2104
+ result = [m.m11, m.m12, m.m13, m.m14,
2105
+ m.m21, m.m22, m.m23, m.m24,
2106
+ m.m31, m.m32, m.m33, m.m34,
2107
+ m.m41, m.m42, m.m43, m.m44];
2108
+ }
2109
+ // clean up the numbers
2110
+ // eslint-disable-next-line -- no-bitwise
2111
+ return result.map(function (n) { return (Math.abs(n) < 1e-6 ? 0 : ((n * pow) >> 0) / pow); });
2112
+ };
2113
+
2114
+ /**
2115
+ * Creates and returns a string representation of the matrix in `CSS` matrix syntax,
2116
+ * using the appropriate `CSS` matrix notation.
2117
+ *
2118
+ * matrix3d *matrix3d(m11, m12, m13, m14, m21, ...)*
2119
+ * matrix *matrix(a, b, c, d, e, f)*
2120
+ *
2121
+ * @return {string} a string representation of the matrix
2122
+ */
2123
+ CSSMatrix.prototype.toString = function toString () {
2124
+ var m = this;
2125
+ var values = m.toArray();
2126
+ var type = m.is2D ? 'matrix' : 'matrix3d';
2127
+ return (type + "(" + values + ")");
2128
+ };
2129
+
2130
+ /**
2131
+ * Returns a JSON representation of the `CSSMatrix` instance, a standard *Object*
2132
+ * that includes `{a,b,c,d,e,f}` and `{m11,m12,m13,..m44}` properties as well
2133
+ * as the `is2D` & `isIdentity` properties.
2134
+ *
2135
+ * The result can also be used as a second parameter for the `fromMatrix` static method
2136
+ * to load values into another matrix instance.
2137
+ *
2138
+ * @return {CSSMatrix.JSONMatrix} an *Object* with all matrix values.
2139
+ */
2140
+ CSSMatrix.prototype.toJSON = function toJSON () {
2141
+ var m = this;
2142
+ var is2D = m.is2D;
2143
+ var isIdentity = m.isIdentity;
2144
+ return Object.assign({}, m, {is2D: is2D, isIdentity: isIdentity});
2145
+ };
2146
+
2147
+ /**
2148
+ * The Multiply method returns a new CSSMatrix which is the result of this
2149
+ * matrix multiplied by the passed matrix, with the passed matrix to the right.
2150
+ * This matrix is not modified.
2151
+ *
2152
+ * @param {CSSMatrix | DOMMatrix | CSSMatrix.JSONMatrix} m2 CSSMatrix
2153
+ * @return {CSSMatrix} The resulted matrix.
2154
+ */
2155
+ CSSMatrix.prototype.multiply = function multiply (m2) {
2156
+ return Multiply(this, m2);
2157
+ };
2158
+
2159
+ /**
2160
+ * The translate method returns a new matrix which is this matrix post
2161
+ * multiplied by a translation matrix containing the passed values. If the z
2162
+ * component is undefined, a 0 value is used in its place. This matrix is not
2163
+ * modified.
2164
+ *
2165
+ * @param {number} x X component of the translation value.
2166
+ * @param {number=} y Y component of the translation value.
2167
+ * @param {number=} z Z component of the translation value.
2168
+ * @return {CSSMatrix} The resulted matrix
2169
+ */
2170
+ CSSMatrix.prototype.translate = function translate (x, y, z) {
2171
+ var X = x;
2172
+ var Y = y;
2173
+ var Z = z;
2174
+ if (Z === undefined) { Z = 0; }
2175
+ if (Y === undefined) { Y = 0; }
2176
+ return Multiply(this, Translate(X, Y, Z));
2177
+ };
2178
+
2179
+ /**
2180
+ * The scale method returns a new matrix which is this matrix post multiplied by
2181
+ * a scale matrix containing the passed values. If the z component is undefined,
2182
+ * a 1 value is used in its place. If the y component is undefined, the x
2183
+ * component value is used in its place. This matrix is not modified.
2184
+ *
2185
+ * @param {number} x The X component of the scale value.
2186
+ * @param {number=} y The Y component of the scale value.
2187
+ * @param {number=} z The Z component of the scale value.
2188
+ * @return {CSSMatrix} The resulted matrix
2189
+ */
2190
+ CSSMatrix.prototype.scale = function scale (x, y, z) {
2191
+ var X = x;
2192
+ var Y = y;
2193
+ var Z = z;
2194
+ if (Y === undefined) { Y = x; }
2195
+ if (Z === undefined) { Z = 1; } // Z must be 1 if undefined
2196
+
2197
+ return Multiply(this, Scale(X, Y, Z));
2198
+ };
2199
+
2200
+ /**
2201
+ * The rotate method returns a new matrix which is this matrix post multiplied
2202
+ * by each of 3 rotation matrices about the major axes, first X, then Y, then Z.
2203
+ * If the y and z components are undefined, the x value is used to rotate the
2204
+ * object about the z axis, as though the vector (0,0,x) were passed. All
2205
+ * rotation values are in degrees. This matrix is not modified.
2206
+ *
2207
+ * @param {number} rx The X component of the rotation, or Z if Y and Z are null.
2208
+ * @param {number=} ry The (optional) Y component of the rotation value.
2209
+ * @param {number=} rz The (optional) Z component of the rotation value.
2210
+ * @return {CSSMatrix} The resulted matrix
2211
+ */
2212
+ CSSMatrix.prototype.rotate = function rotate (rx, ry, rz) {
2213
+ var RX = rx;
2214
+ var RY = ry;
2215
+ var RZ = rz;
2216
+ if (RY === undefined) { RY = 0; }
2217
+ if (RZ === undefined) { RZ = RX; RX = 0; }
2218
+ return Multiply(this, Rotate(RX, RY, RZ));
2219
+ };
2220
+
2221
+ /**
2222
+ * The rotateAxisAngle method returns a new matrix which is this matrix post
2223
+ * multiplied by a rotation matrix with the given axis and `angle`. The right-hand
2224
+ * rule is used to determine the direction of rotation. All rotation values are
2225
+ * in degrees. This matrix is not modified.
2226
+ *
2227
+ * @param {number} x The X component of the axis vector.
2228
+ * @param {number} y The Y component of the axis vector.
2229
+ * @param {number} z The Z component of the axis vector.
2230
+ * @param {number} angle The angle of rotation about the axis vector, in degrees.
2231
+ * @return {CSSMatrix} The resulted matrix
2232
+ */
2233
+ CSSMatrix.prototype.rotateAxisAngle = function rotateAxisAngle (x, y, z, angle) {
2234
+ if ([x, y, z, angle].some(function (n) { return Number.isNaN(n); })) {
2235
+ throw new TypeError('CSSMatrix: expecting 4 values');
2236
+ }
2237
+ return Multiply(this, RotateAxisAngle(x, y, z, angle));
2238
+ };
2239
+
2240
+ /**
2241
+ * Specifies a skew transformation along the `x-axis` by the given angle.
2242
+ * This matrix is not modified.
2243
+ *
2244
+ * @param {number} angle The angle amount in degrees to skew.
2245
+ * @return {CSSMatrix} The resulted matrix
2246
+ */
2247
+ CSSMatrix.prototype.skewX = function skewX (angle) {
2248
+ return Multiply(this, SkewX(angle));
2249
+ };
2250
+
2251
+ /**
2252
+ * Specifies a skew transformation along the `y-axis` by the given angle.
2253
+ * This matrix is not modified.
2254
+ *
2255
+ * @param {number} angle The angle amount in degrees to skew.
2256
+ * @return {CSSMatrix} The resulted matrix
2257
+ */
2258
+ CSSMatrix.prototype.skewY = function skewY (angle) {
2259
+ return Multiply(this, SkewY(angle));
2260
+ };
2261
+
2262
+ /**
2263
+ * Transforms a specified point using the matrix, returning a new
2264
+ * Tuple *Object* comprising of the transformed point.
2265
+ * Neither the matrix nor the original point are altered.
2266
+ *
2267
+ * The method is equivalent with `transformPoint()` method
2268
+ * of the `DOMMatrix` constructor.
2269
+ *
2270
+ * @copyright thednp © 2021
2271
+ *
2272
+ * @param {CSSMatrix.PointTuple | DOMPoint} v Tuple or DOMPoint
2273
+ * @return {CSSMatrix.PointTuple} the resulting Tuple
2274
+ */
2275
+ CSSMatrix.prototype.transformPoint = function transformPoint (v) {
2276
+ var M = this;
2277
+ var m = Translate(v.x, v.y, v.z);
2278
+
2279
+ m.m44 = v.w || 1;
2280
+ m = M.multiply(m);
2281
+
2282
+ return {
2283
+ x: m.m41,
2284
+ y: m.m42,
2285
+ z: m.m43,
2286
+ w: m.m44,
2287
+ };
2288
+ };
2289
+
2290
+ /**
2291
+ * Transforms a specified vector using the matrix, returning a new
2292
+ * {x,y,z,w} Tuple *Object* comprising the transformed vector.
2293
+ * Neither the matrix nor the original vector are altered.
2294
+ *
2295
+ * @param {CSSMatrix.PointTuple} t Tuple with `{x,y,z,w}` components
2296
+ * @return {CSSMatrix.PointTuple} the resulting Tuple
2297
+ */
2298
+ CSSMatrix.prototype.transform = function transform (t) {
2299
+ var m = this;
2300
+ var x = m.m11 * t.x + m.m12 * t.y + m.m13 * t.z + m.m14 * t.w;
2301
+ var y = m.m21 * t.x + m.m22 * t.y + m.m23 * t.z + m.m24 * t.w;
2302
+ var z = m.m31 * t.x + m.m32 * t.y + m.m33 * t.z + m.m34 * t.w;
2303
+ var w = m.m41 * t.x + m.m42 * t.y + m.m43 * t.z + m.m44 * t.w;
2304
+
2305
+ return {
2306
+ x: x / w,
2307
+ y: y / w,
2308
+ z: z / w,
2309
+ w: w,
2310
+ };
2311
+ };
2312
+
2313
+ Object.defineProperties( CSSMatrix.prototype, prototypeAccessors );
2314
+
2315
+ // Add Transform Functions to CSSMatrix object
2316
+ // without creating a TypeScript namespace.
2317
+ Object.assign(CSSMatrix, {
2318
+ Translate: Translate,
2319
+ Rotate: Rotate,
2320
+ RotateAxisAngle: RotateAxisAngle,
2321
+ Scale: Scale,
2322
+ SkewX: SkewX,
2323
+ SkewY: SkewY,
2324
+ Multiply: Multiply,
2325
+ fromArray: fromArray,
2326
+ fromMatrix: fromMatrix,
2327
+ fromString: fromString,
2328
+ });
2329
+
2330
+ var version$1 = "0.0.24";
2331
+
2332
+ // @ts-ignore
2333
+
2334
+ /**
2335
+ * A global namespace for library version.
2336
+ * @type {string}
2337
+ */
2338
+ var Version$1 = version$1;
2339
+
2340
+ Object.assign(CSSMatrix, { Version: Version$1 });
2341
+
2342
+ /**
2343
+ * Returns a transformation matrix to apply to `<path>` elements.
2344
+ *
2345
+ * @see SVGPath.transformObject
2346
+ *
2347
+ * @param {SVGPath.transformObject} transform the `transformObject`
2348
+ * @returns {CSSMatrix} a new transformation matrix
2349
+ */
2350
+ function getSVGMatrix(transform) {
2351
+ var matrix = new CSSMatrix();
2352
+ var origin = transform.origin;
2353
+ // @ts-ignore -- at this point the origin is surely defined
2354
+ var originX = origin[0];
2355
+ var originY = origin[1];
2356
+ var translate = transform.translate;
2357
+ var rotate = transform.rotate;
2358
+ var skew = transform.skew;
2359
+ var scale = transform.scale;
2360
+
2361
+ // set translate
2362
+ if (Array.isArray(translate) && translate.every(function (x) { return !Number.isNaN(+x); })
2363
+ && translate.some(function (x) { return x !== 0; })) {
2364
+ matrix = matrix.translate(translate[0] || 0, translate[1] || 0, translate[2] || 0);
2365
+ } else if (typeof translate === 'number' && !Number.isNaN(+translate)) {
2366
+ matrix = matrix.translate(translate || 0, 0, 0);
2367
+ }
2368
+
2369
+ if (rotate || skew || scale) {
2370
+ // set SVG transform-origin, always defined
2371
+ matrix = matrix.translate(originX, originY);
2372
+
2373
+ // set rotation
2374
+ if (Array.isArray(rotate) && rotate.every(function (x) { return !Number.isNaN(+x); })
2375
+ && rotate.some(function (x) { return x !== 0; })) {
2376
+ matrix = matrix.rotate(rotate[0], rotate[1], rotate[2]);
2377
+ } else if (typeof rotate === 'number' && !Number.isNaN(+rotate)) {
2378
+ matrix = matrix.rotate(0, 0, rotate);
2379
+ }
2380
+
2381
+ // set skew(s)
2382
+ if (Array.isArray(skew) && skew.every(function (x) { return !Number.isNaN(+x); })
2383
+ && skew.some(function (x) { return x !== 0; })) {
2384
+ matrix = skew[0] ? matrix.skewX(skew[0]) : matrix;
2385
+ matrix = skew[1] ? matrix.skewY(skew[1]) : matrix;
2386
+ } else if (typeof skew === 'number' && !Number.isNaN(+skew)) {
2387
+ matrix = matrix.skewX(skew || 0);
2388
+ }
2389
+
2390
+ // set scale
2391
+ if (Array.isArray(scale) && scale.every(function (x) { return !Number.isNaN(+x); })
2392
+ && scale.some(function (x) { return x !== 1; })) {
2393
+ matrix = matrix.scale(scale[0], scale[1], scale[2]);
2394
+ } else if (typeof scale === 'number' && !Number.isNaN(+scale)) {
2395
+ matrix = matrix.scale(scale || 1, scale || 1, scale || 1);
2396
+ }
2397
+ // set SVG transform-origin
2398
+ matrix = matrix.translate(-originX, -originY);
2399
+ }
2400
+
2401
+ return matrix;
2402
+ }
2403
+
2404
+ /**
2405
+ * Apply a 2D transformation matrix to an ellipse.
2406
+ *
2407
+ * @param {number[]} m the 2D transformation matrix
2408
+ * @param {number} rx ellipse radius X
2409
+ * @param {number} ry ellipse radius Y
2410
+ * @param {number} ax ellipse rotation angle
2411
+ */
2412
+ function transformEllipse(m, rx, ry, ax) {
2413
+ // We consider the current ellipse as image of the unit circle
2414
+ // by first scale(rx,ry) and then rotate(ax) ...
2415
+ // So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle.
2416
+ var c = Math.cos((ax * Math.PI) / 180);
2417
+ var s = Math.sin((ax * Math.PI) / 180);
2418
+ var ma = [
2419
+ rx * (m[0] * c + m[2] * s),
2420
+ rx * (m[1] * c + m[3] * s),
2421
+ ry * (-m[0] * s + m[2] * c),
2422
+ ry * (-m[1] * s + m[3] * c) ];
2423
+
2424
+ // ma * transpose(ma) = [ J L ]
2425
+ // [ L K ]
2426
+ // L is calculated later (if the image is not a circle)
2427
+ var J = ma[0] * ma[0] + ma[2] * ma[2];
2428
+ var K = ma[1] * ma[1] + ma[3] * ma[3];
2429
+
2430
+ // the discriminant of the characteristic polynomial of ma * transpose(ma)
2431
+ var D = ((ma[0] - ma[3]) * (ma[0] - ma[3]) + (ma[2] + ma[1]) * (ma[2] + ma[1]))
2432
+ * ((ma[0] + ma[3]) * (ma[0] + ma[3]) + (ma[2] - ma[1]) * (ma[2] - ma[1]));
2433
+
2434
+ // the "mean eigenvalue"
2435
+ var JK = (J + K) / 2;
2436
+
2437
+ // check if the image is (almost) a circle
2438
+ if (D < epsilon * JK) {
2439
+ // if it is
2440
+ var rxy = Math.sqrt(JK);
2441
+
2442
+ return { rx: rxy, ry: rxy, ax: 0 };
2443
+ }
2444
+
2445
+ // if it is not a circle
2446
+ var L = ma[0] * ma[1] + ma[2] * ma[3];
2447
+
2448
+ D = Math.sqrt(D);
2449
+
2450
+ // {l1,l2} = the two eigen values of ma * transpose(ma)
2451
+ var l1 = JK + D / 2;
2452
+ var l2 = JK - D / 2;
2453
+ // the x - axis - rotation angle is the argument of the l1 - eigenvector
2454
+ var AX = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ? 90
2455
+ : Math.atan(Math.abs(L) > Math.abs(l1 - K) ? (l1 - J) / L
2456
+ : ((L / (l1 - K))) * 180) / Math.PI;
2457
+ var RX;
2458
+ var RY;
2459
+
2460
+ // if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90
2461
+ if (AX >= 0) {
2462
+ // if ax in [0,90]
2463
+ RX = Math.sqrt(l1);
2464
+ RY = Math.sqrt(l2);
2465
+ } else {
2466
+ // if ax in ]-90,0[ => exchange axes
2467
+ AX += 90;
2468
+ RX = Math.sqrt(l2);
2469
+ RY = Math.sqrt(l1);
2470
+ }
2471
+
2472
+ return { rx: RX, ry: RY, ax: AX };
2473
+ }
2474
+
2475
+ /**
2476
+ * Returns the [x,y] projected coordinates for a given an [x,y] point
2477
+ * and an [x,y,z] perspective origin point.
2478
+ *
2479
+ * Equation found here =>
2480
+ * http://en.wikipedia.org/wiki/3D_projection#Diagram
2481
+ * Details =>
2482
+ * https://stackoverflow.com/questions/23792505/predicted-rendering-of-css-3d-transformed-pixel
2483
+ *
2484
+ * @param {SVGPath.CSSMatrix} m the transformation matrix
2485
+ * @param {[number, number]} point2D the initial [x,y] coordinates
2486
+ * @param {number[]} origin the [x,y,z] transform origin
2487
+ * @returns {[number, number]} the projected [x,y] coordinates
2488
+ */
2489
+ function projection2d(m, point2D, origin) {
2490
+ var px = point2D[0];
2491
+ var py = point2D[1];
2492
+ var originX = origin[0];
2493
+ var originY = origin[1];
2494
+ var originZ = origin[2];
2495
+ var point3D = m.transformPoint({
2496
+ x: px, y: py, z: 0, w: 1,
2497
+ });
2498
+
2499
+ var relativePositionX = point3D.x - originX;
2500
+ var relativePositionY = point3D.y - originY;
2501
+ var relativePositionZ = point3D.z - originZ;
2502
+
2503
+ return [
2504
+ relativePositionX * (Math.abs(originZ) / Math.abs(relativePositionZ)) + originX,
2505
+ relativePositionY * (Math.abs(originZ) / Math.abs(relativePositionZ)) + originY ];
2506
+ }
2507
+
2508
+ /**
2509
+ * Apply a 2D / 3D transformation to a `pathArray` instance.
2510
+ *
2511
+ * Since *SVGElement* doesn't support 3D transformation, this function
2512
+ * creates a 2D projection of the <path> element.
2513
+ *
2514
+ * @param {SVGPath.pathArray} path the `pathArray` to apply transformation
2515
+ * @param {SVGPath.transformObject} transform the transform functions `Object`
2516
+ * @returns {SVGPath.pathArray} the resulted `pathArray`
2517
+ */
2518
+ function transformPath(path, transform) {
2519
+ var assign;
2520
+
2521
+ var x = 0; var y = 0; var i; var j; var ii; var jj; var lx; var ly; var te;
2522
+ var absolutePath = pathToAbsolute(path);
2523
+ var normalizedPath = normalizePath(absolutePath);
2524
+ var matrixInstance = getSVGMatrix(transform);
2525
+ var transformProps = Object.keys(transform);
2526
+ var origin = transform.origin;
2527
+ var a = matrixInstance.a;
2528
+ var b = matrixInstance.b;
2529
+ var c = matrixInstance.c;
2530
+ var d = matrixInstance.d;
2531
+ var e = matrixInstance.e;
2532
+ var f = matrixInstance.f;
2533
+ var matrix2d = [a, b, c, d, e, f];
2534
+ var params = Object.assign({}, paramsParser);
2535
+ /** @ts-ignore */
2536
+ /** @type {SVGPath.pathSegment} */
2537
+ // @ts-ignore
2538
+ var segment = [];
2539
+ var seglen = 0;
2540
+ var pathCommand = '';
2541
+ /** @type {SVGPath.pathTransformList[]} */
2542
+ var transformedPath = [];
2543
+ var allPathCommands = []; // needed for arc to curve transformation
2544
+
2545
+ if (!matrixInstance.isIdentity) {
2546
+ for (i = 0, ii = absolutePath.length; i < ii; i += 1) {
2547
+ segment = absolutePath[i];
2548
+
2549
+ if (absolutePath[i]) { (assign = segment, pathCommand = assign[0]); }
2550
+
2551
+ // REPLACE Arc path commands with Cubic Beziers
2552
+ // we don't have any scripting know-how on 3d ellipse transformation
2553
+ /// ////////////////////////////////////////
2554
+ allPathCommands[i] = pathCommand;
2555
+
2556
+ // Arcs don't work very well with 3D transformations or skews
2557
+ if (pathCommand === 'A' && (!matrixInstance.is2D
2558
+ || !['skewX', 'skewY'].find(function (p) { return transformProps.includes(p); }))) {
2559
+ segment = segmentToCubic(normalizedPath[i], params);
2560
+
2561
+ // @ts-ignore -- expected when switching `pathSegment` type
2562
+ absolutePath[i] = segmentToCubic(normalizedPath[i], params);
2563
+ fixArc(absolutePath, allPathCommands, i);
2564
+
2565
+ // @ts-ignore -- expected when switching `pathSegment` type
2566
+ normalizedPath[i] = segmentToCubic(normalizedPath[i], params);
2567
+ fixArc(normalizedPath, allPathCommands, i);
2568
+ ii = Math.max(absolutePath.length, normalizedPath.length);
2569
+ }
2570
+ /// ////////////////////////////////////////
2571
+
2572
+ segment = normalizedPath[i];
2573
+ seglen = segment.length;
2574
+
2575
+ params.x1 = +segment[seglen - 2];
2576
+ params.y1 = +segment[seglen - 1];
2577
+ params.x2 = +(segment[seglen - 4]) || params.x1;
2578
+ params.y2 = +(segment[seglen - 3]) || params.y1;
2579
+
2580
+ /** @type {SVGPath.pathTransformList} */
2581
+ var result = {
2582
+ s: absolutePath[i], c: absolutePath[i][0], x: params.x1, y: params.y1,
2583
+ };
2584
+
2585
+ transformedPath = transformedPath.concat( [result]);
2586
+ }
2587
+
2588
+ // @ts-ignore
2589
+ return transformedPath.map(function (seg) {
2590
+ var assign, assign$1, assign$2;
2591
+
2592
+ pathCommand = seg.c;
2593
+ segment = seg.s;
2594
+ switch (pathCommand) {
2595
+ case 'A': // only apply to 2D transformations
2596
+ // @ts-ignore
2597
+ te = transformEllipse(matrix2d, segment[1], segment[2], segment[3]);
2598
+
2599
+ if (matrix2d[0] * matrix2d[3] - matrix2d[1] * matrix2d[2] < 0) {
2600
+ segment[5] = segment[5] ? 0 : 1;
2601
+ }
2602
+
2603
+ // @ts-ignore
2604
+ (assign = projection2d(matrixInstance, [+segment[6], +segment[7]], origin), lx = assign[0], ly = assign[1]);
2605
+
2606
+ if ((x === lx && y === ly) || (te.rx < epsilon * te.ry) || (te.ry < epsilon * te.rx)) {
2607
+ segment = ['L', lx, ly];
2608
+ } else {
2609
+ // @ts-ignore
2610
+ segment = [pathCommand, te.rx, te.ry, te.ax, segment[4], segment[5], lx, ly];
2611
+ }
2612
+
2613
+ x = lx; y = ly;
2614
+ return segment;
2615
+
2616
+ case 'L':
2617
+ case 'H':
2618
+ case 'V':
2619
+ // @ts-ignore
2620
+ (assign$1 = projection2d(matrixInstance, [seg.x, seg.y], origin), lx = assign$1[0], ly = assign$1[1]);
2621
+
2622
+ if (x !== lx && y !== ly) {
2623
+ segment = ['L', lx, ly];
2624
+ } else if (y === ly) {
2625
+ segment = ['H', lx];
2626
+ } else if (x === lx) {
2627
+ segment = ['V', ly];
2628
+ }
2629
+
2630
+ x = lx; y = ly; // now update x and y
2631
+
2632
+ return segment;
2633
+ default:
2634
+
2635
+ for (j = 1, jj = segment.length; j < jj; j += 2) {
2636
+ // @ts-ignore compute line coordinates without altering previous coordinates
2637
+ (assign$2 = projection2d(matrixInstance, [+segment[j], +segment[j + 1]], origin), x = assign$2[0], y = assign$2[1]);
2638
+ segment[j] = x;
2639
+ segment[j + 1] = y;
2640
+ }
2641
+
2642
+ return segment;
2643
+ }
2644
+ });
2645
+ }
2646
+ return clonePath(absolutePath);
2647
+ }
2648
+
2649
+ /**
2650
+ * Returns a point at a given length of a C (cubic-bezier) segment.
2651
+ *
2652
+ * @param {number} x1 the starting point X
2653
+ * @param {number} y1 the starting point Y
2654
+ * @param {number} c1x the first control point X
2655
+ * @param {number} c1y the first control point Y
2656
+ * @param {number} c2x the second control point X
2657
+ * @param {number} c2y the second control point Y
2658
+ * @param {number} x2 the ending point X
2659
+ * @param {number} y2 the ending point Y
2660
+ * @param {number} t a [0-1] ratio
2661
+ * @returns {{x: number, y: number}} the cubic-bezier segment length
2662
+ */
2663
+ function getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t) {
2664
+ var t1 = 1 - t;
2665
+ return {
2666
+ x: (Math.pow( t1, 3 )) * x1
2667
+ + 3 * (Math.pow( t1, 2 )) * t * c1x
2668
+ + 3 * t1 * (Math.pow( t, 2 )) * c2x
2669
+ + (Math.pow( t, 3 )) * x2,
2670
+ y: (Math.pow( t1, 3 )) * y1
2671
+ + 3 * (Math.pow( t1, 2 )) * t * c1y
2672
+ + 3 * t1 * (Math.pow( t, 2 )) * c2y
2673
+ + (Math.pow( t, 3 )) * y2,
2674
+ };
2675
+ }
2676
+
2677
+ /**
2678
+ * Returns the length of a C (cubic-bezier) segment
2679
+ * or an {x,y} point at a given length.
2680
+ *
2681
+ * @param {number} x1 the starting point X
2682
+ * @param {number} y1 the starting point Y
2683
+ * @param {number} c1x the first control point X
2684
+ * @param {number} c1y the first control point Y
2685
+ * @param {number} c2x the second control point X
2686
+ * @param {number} c2y the second control point Y
2687
+ * @param {number} x2 the ending point X
2688
+ * @param {number} y2 the ending point Y
2689
+ * @param {number=} distance the point distance
2690
+ * @returns {{x: number, y: number} | number} the segment length or point
2691
+ */
2692
+ function segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, distance) {
2693
+ var assign;
2694
+
2695
+ var distanceIsNumber = typeof distance === 'number';
2696
+ var lengthMargin = 0.001;
2697
+ var x = x1; var y = y1;
2698
+ var totalLength = 0;
2699
+ var prev = [x1, y1, totalLength];
2700
+ /** @type {[number, number]} */
2701
+ var cur = [x1, y1];
2702
+ var t = 0;
2703
+
2704
+ if (distanceIsNumber && distance < lengthMargin) {
2705
+ return { x: x, y: y };
2706
+ }
2707
+
2708
+ var n = 100;
2709
+ for (var j = 0; j <= n; j += 1) {
2710
+ t = j / n;
2711
+
2712
+ ((assign = getPointAtCubicSegmentLength(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t), x = assign.x, y = assign.y));
2713
+ totalLength += distanceSquareRoot(cur, [x, y]);
2714
+ cur = [x, y];
2715
+
2716
+ if (distanceIsNumber && totalLength >= distance) {
2717
+ var dv = (totalLength - distance) / (totalLength - prev[2]);
2718
+
2719
+ return {
2720
+ x: cur[0] * (1 - dv) + prev[0] * dv,
2721
+ y: cur[1] * (1 - dv) + prev[1] * dv,
2722
+ };
2723
+ }
2724
+ prev = [x, y, totalLength];
2725
+ }
2726
+
2727
+ if (distanceIsNumber && distance >= totalLength) {
2728
+ return { x: x2, y: y2 };
2729
+ }
2730
+ return totalLength;
2731
+ }
2732
+
2733
+ /**
2734
+ * Returns the cubic-bezier segment bounding box.
2735
+ *
2736
+ * @param {number} x1 the starting point X
2737
+ * @param {number} y1 the starting point Y
2738
+ * @param {number} c1x the first control point X
2739
+ * @param {number} c1y the first control point Y
2740
+ * @param {number} c2x the second control point X
2741
+ * @param {number} c2y the second control point Y
2742
+ * @param {number} x2 the ending point X
2743
+ * @param {number} y2 the ending point Y
2744
+ * @returns {SVGPath.segmentLimits} the bounding box of the cubic-bezier segment
2745
+ */
2746
+ function getCubicSize(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
2747
+ var assign, assign$1, assign$2, assign$3;
2748
+
2749
+ var a = (c2x - 2 * c1x + x1) - (x2 - 2 * c2x + c1x);
2750
+ var b = 2 * (c1x - x1) - 2 * (c2x - c1x);
2751
+ var c = x1 - c1x;
2752
+ var t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2753
+ var t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2754
+ var X = [x1, x2];
2755
+ var Y = [y1, y2];
2756
+ var x = 0;
2757
+ var y = 0;
2758
+
2759
+ if (Math.abs(t1) > 1e12) { t1 = 0.5; }
2760
+ if (Math.abs(t2) > 1e12) { t2 = 0.5; }
2761
+
2762
+ if (t1 > 0 && t1 < 1) {
2763
+ // @ts-ignore
2764
+ ((assign = segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t1), x = assign.x, y = assign.y));
2765
+ X.push(x);
2766
+ Y.push(y);
2767
+ }
2768
+ if (t2 > 0 && t2 < 1) {
2769
+ // @ts-ignore
2770
+ ((assign$1 = segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t2), x = assign$1.x, y = assign$1.y));
2771
+ X.push(x);
2772
+ Y.push(y);
2773
+ }
2774
+ a = (c2y - 2 * c1y + y1) - (y2 - 2 * c2y + c1y);
2775
+ b = 2 * (c1y - y1) - 2 * (c2y - c1y);
2776
+ c = y1 - c1y;
2777
+ t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2778
+ t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / 2 / a;
2779
+ if (Math.abs(t1) > 1e12) { t1 = 0.5; }
2780
+ if (Math.abs(t2) > 1e12) { t2 = 0.5; }
2781
+
2782
+ if (t1 > 0 && t1 < 1) {
2783
+ // @ts-ignore
2784
+ ((assign$2 = segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t1), x = assign$2.x, y = assign$2.y));
2785
+ X.push(x);
2786
+ Y.push(y);
2787
+ }
2788
+ if (t2 > 0 && t2 < 1) {
2789
+ // @ts-ignore
2790
+ ((assign$3 = segmentCubicFactory(x1, y1, c1x, c1y, c2x, c2y, x2, y2, t2), x = assign$3.x, y = assign$3.y));
2791
+ X.push(x);
2792
+ Y.push(y);
2793
+ }
2794
+ return {
2795
+ min: { x: Math.min.apply(Math, X), y: Math.min.apply(Math, Y) },
2796
+ max: { x: Math.max.apply(Math, X), y: Math.max.apply(Math, Y) },
2797
+ };
2798
+ }
2799
+
2800
+ /**
2801
+ * Returns the bounding box of a shape.
2802
+ *
2803
+ * @param {SVGPath.pathArray} path the shape `pathArray`
2804
+ * @returns {SVGPath.pathBBox} the length of the cubic-bezier segment
2805
+ */
2806
+ function getPathBBox(path) {
2807
+ if (!path) {
2808
+ return {
2809
+ x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0, cx: 0, cy: 0, cz: 0,
2810
+ };
2811
+ }
2812
+ var pathCurve = pathToCurve(path);
2813
+
2814
+ var x = 0; var y = 0;
2815
+ /** @type {number[]} */
2816
+ var X = [];
2817
+ /** @type {number[]} */
2818
+ var Y = [];
2819
+
2820
+ pathCurve.forEach(function (segment) {
2821
+ var ref = segment.slice(-2).map(Number);
2822
+ var s1 = ref[0];
2823
+ var s2 = ref[1];
2824
+ if (segment[0] === 'M') {
2825
+ x = s1;
2826
+ y = s2;
2827
+ X.push(s1);
2828
+ Y.push(s2);
2829
+ } else {
2830
+ var sizeArgs = [x, y ].concat( segment.slice(1));
2831
+ // @ts-ignore -- this should be fine
2832
+ var dim = getCubicSize.apply(void 0, sizeArgs);
2833
+
2834
+ X = X.concat( [dim.min.x], [dim.max.x]);
2835
+ Y = Y.concat( [dim.min.y], [dim.max.y]);
2836
+ x = s1;
2837
+ y = s2;
2838
+ }
2839
+ });
2840
+
2841
+ var xTop = Math.min.apply(Math, X);
2842
+ var yTop = Math.min.apply(Math, Y);
2843
+ var xBot = Math.max.apply(Math, X);
2844
+ var yBot = Math.max.apply(Math, Y);
2845
+ var width = xBot - xTop;
2846
+ var height = yBot - yTop;
2847
+
2848
+ // an estimted guess
2849
+ var cz = Math.max(width, height) + Math.min(width, height) / 2;
2850
+ return {
2851
+ width: width,
2852
+ height: height,
2853
+ x: xTop,
2854
+ y: yTop,
2855
+ x2: xBot,
2856
+ y2: yBot,
2857
+ cx: xTop + width / 2,
2858
+ cy: yTop + height / 2,
2859
+ cz: cz,
2860
+ };
2861
+ }
2862
+
2863
+ /**
2864
+ * Returns the length of an A (arc-to) segment
2865
+ * or an {x,y} point at a given length.
2866
+ *
2867
+ * @param {number} X1 the starting x position
2868
+ * @param {number} Y1 the starting y position
2869
+ * @param {number} RX x-radius of the arc
2870
+ * @param {number} RY y-radius of the arc
2871
+ * @param {number} angle x-axis-rotation of the arc
2872
+ * @param {number} LAF large-arc-flag of the arc
2873
+ * @param {number} SF sweep-flag of the arc
2874
+ * @param {number} X2 the ending x position
2875
+ * @param {number} Y2 the ending y position
2876
+ * @param {number} distance the point distance
2877
+ * @returns {{x: number, y: number} | number} the segment length or point
2878
+ */
2879
+ function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance) {
2880
+ var assign;
2881
+
2882
+ var cubicSeg = arcToCubic(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2);
2883
+ var distanceIsNumber = typeof distance === 'number';
2884
+ var ref = [X1, Y1];
2885
+ var x = ref[0];
2886
+ var y = ref[1];
2887
+ var lengthMargin = 0.001;
2888
+ var totalLength = 0;
2889
+ var cubicSubseg = [];
2890
+ var argsc = [];
2891
+ var segLen = 0;
2892
+
2893
+ if (distanceIsNumber && distance < lengthMargin) {
2894
+ return { x: x, y: y };
2895
+ }
2896
+
2897
+ for (var i = 0, ii = cubicSeg.length; i < ii; i += 6) {
2898
+ cubicSubseg = cubicSeg.slice(i, i + 6);
2899
+ argsc = [x, y ].concat( cubicSubseg);
2900
+ // @ts-ignore
2901
+ segLen = segmentCubicFactory.apply(void 0, argsc);
2902
+ if (distanceIsNumber && totalLength + segLen >= distance) {
2903
+ // @ts-ignore -- this is a `cubicSegment`
2904
+ return segmentCubicFactory.apply(void 0, argsc.concat( [distance - totalLength] ));
2905
+ }
2906
+ totalLength += segLen;
2907
+ (assign = cubicSubseg.slice(-2), x = assign[0], y = assign[1]);
2908
+ }
2909
+
2910
+ if (distanceIsNumber && distance >= totalLength) {
2911
+ return { x: X2, y: Y2 };
2912
+ }
2913
+
2914
+ return totalLength;
2915
+ }
2916
+
2917
+ /**
2918
+ * Returns the {x,y} coordinates of a point at a
2919
+ * given length of a quad-bezier segment.
2920
+ *
2921
+ * @see https://github.com/substack/point-at-length
2922
+ *
2923
+ * @param {number} x1 the starting point X
2924
+ * @param {number} y1 the starting point Y
2925
+ * @param {number} cx the control point X
2926
+ * @param {number} cy the control point Y
2927
+ * @param {number} x2 the ending point X
2928
+ * @param {number} y2 the ending point Y
2929
+ * @param {number} t a [0-1] ratio
2930
+ * @returns {{x: number, y: number}} the requested {x,y} coordinates
2931
+ */
2932
+ function getPointAtQuadSegmentLength(x1, y1, cx, cy, x2, y2, t) {
2933
+ var t1 = 1 - t;
2934
+ return {
2935
+ x: (Math.pow( t1, 2 )) * x1
2936
+ + 2 * t1 * t * cx
2937
+ + (Math.pow( t, 2 )) * x2,
2938
+ y: (Math.pow( t1, 2 )) * y1
2939
+ + 2 * t1 * t * cy
2940
+ + (Math.pow( t, 2 )) * y2,
2941
+ };
2942
+ }
2943
+
2944
+ /**
2945
+ * Returns the Q (quadratic-bezier) segment length
2946
+ * or an {x,y} point at a given length.
2947
+ *
2948
+ * @param {number} x1 the starting point X
2949
+ * @param {number} y1 the starting point Y
2950
+ * @param {number} qx the control point X
2951
+ * @param {number} qy the control point Y
2952
+ * @param {number} x2 the ending point X
2953
+ * @param {number} y2 the ending point Y
2954
+ * @param {number=} distance the distance to point
2955
+ * @returns {{x: number, y: number} | number} the segment length or point
2956
+ */
2957
+ function segmentQuadFactory(x1, y1, qx, qy, x2, y2, distance) {
2958
+ var assign;
2959
+
2960
+ var distanceIsNumber = typeof distance === 'number';
2961
+ var lengthMargin = 0.001;
2962
+ var x = x1; var y = y1;
2963
+ var totalLength = 0;
2964
+ var prev = [x1, y1, totalLength];
2965
+ /** @type {[number, number]} */
2966
+ var cur = [x1, y1];
2967
+ var t = 0;
2968
+
2969
+ if (distanceIsNumber && distance < lengthMargin) {
2970
+ return { x: x, y: y };
2971
+ }
2972
+
2973
+ var n = 100;
2974
+ for (var j = 0; j <= n; j += 1) {
2975
+ t = j / n;
2976
+
2977
+ ((assign = getPointAtQuadSegmentLength(x1, y1, qx, qy, x2, y2, t), x = assign.x, y = assign.y));
2978
+ totalLength += distanceSquareRoot(cur, [x, y]);
2979
+ cur = [x, y];
2980
+
2981
+ if (distanceIsNumber && totalLength >= distance) {
2982
+ var dv = (totalLength - distance) / (totalLength - prev[2]);
2983
+
2984
+ return {
2985
+ x: cur[0] * (1 - dv) + prev[0] * dv,
2986
+ y: cur[1] * (1 - dv) + prev[1] * dv,
2987
+ };
2988
+ }
2989
+ prev = [x, y, totalLength];
2990
+ }
2991
+ if (distanceIsNumber && distance >= totalLength) {
2992
+ return { x: x2, y: y2 };
2993
+ }
2994
+ return totalLength;
2995
+ }
2996
+
2997
+ /**
2998
+ * Returns a {x,y} point at a given length
2999
+ * of a shape or the shape total length.
3000
+ *
3001
+ * @param {string | SVGPath.pathArray} pathInput the `pathArray` to look into
3002
+ * @param {number=} distance the length of the shape to look at
3003
+ * @returns {{x: number, y: number} | number} the total length or point
3004
+ */
3005
+ function pathLengthFactory(pathInput, distance) {
3006
+ var assign, assign$1, assign$2;
3007
+
3008
+ var path = fixPath(normalizePath(pathInput));
3009
+ var distanceIsNumber = typeof distance === 'number';
3010
+ var totalLength = 0;
3011
+ var isM = true;
3012
+ /** @type {number[]} */
3013
+ var data = [];
3014
+ var pathCommand = 'M';
3015
+ var segLen = 0;
3016
+ var x = 0;
3017
+ var y = 0;
3018
+ var mx = 0;
3019
+ var my = 0;
3020
+ var seg;
3021
+
3022
+ for (var i = 0, ll = path.length; i < ll; i += 1) {
3023
+ seg = path[i];
3024
+ (assign = seg, pathCommand = assign[0]);
3025
+ isM = pathCommand === 'M';
3026
+ // @ts-ignore
3027
+ data = !isM ? [x, y ].concat( seg.slice(1)) : data;
3028
+
3029
+ // this segment is always ZERO
3030
+ if (isM) {
3031
+ // remember mx, my for Z
3032
+ // @ts-ignore
3033
+ (assign$1 = seg, mx = assign$1[1], my = assign$1[2]);
3034
+ if (distanceIsNumber && distance < 0.001) {
3035
+ return { x: mx, y: my };
3036
+ }
3037
+ } else if (pathCommand === 'L') {
3038
+ // @ts-ignore
3039
+ segLen = segmentLineFactory.apply(void 0, data);
3040
+ if (distanceIsNumber && totalLength + segLen >= distance) {
3041
+ // @ts-ignore
3042
+ return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] ));
3043
+ }
3044
+ totalLength += segLen;
3045
+ } else if (pathCommand === 'A') {
3046
+ // @ts-ignore
3047
+ segLen = segmentArcFactory.apply(void 0, data);
3048
+ if (distanceIsNumber && totalLength + segLen >= distance) {
3049
+ // @ts-ignore
3050
+ return segmentArcFactory.apply(void 0, data.concat( [distance - totalLength] ));
3051
+ }
3052
+ totalLength += segLen;
3053
+ } else if (pathCommand === 'C') {
3054
+ // @ts-ignore
3055
+ segLen = segmentCubicFactory.apply(void 0, data);
3056
+ if (distanceIsNumber && totalLength + segLen >= distance) {
3057
+ // @ts-ignore
3058
+ return segmentCubicFactory.apply(void 0, data.concat( [distance - totalLength] ));
3059
+ }
3060
+ totalLength += segLen;
3061
+ } else if (pathCommand === 'Q') {
3062
+ // @ts-ignore
3063
+ segLen = segmentQuadFactory.apply(void 0, data);
3064
+ if (distanceIsNumber && totalLength + segLen >= distance) {
3065
+ // @ts-ignore
3066
+ return segmentQuadFactory.apply(void 0, data.concat( [distance - totalLength] ));
3067
+ }
3068
+ totalLength += segLen;
3069
+ } else if (pathCommand === 'Z') {
3070
+ data = [x, y, mx, my];
3071
+ // @ts-ignore
3072
+ segLen = segmentLineFactory.apply(void 0, data);
3073
+ if (distanceIsNumber && totalLength + segLen >= distance) {
3074
+ // @ts-ignore
3075
+ return segmentLineFactory.apply(void 0, data.concat( [distance - totalLength] ));
3076
+ }
3077
+ totalLength += segLen;
3078
+ }
3079
+
3080
+ // @ts-ignore -- needed for the below
3081
+ (assign$2 = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my], x = assign$2[0], y = assign$2[1]);
3082
+ }
3083
+
3084
+ // native `getPointAtLength` behavior when the given distance
3085
+ // is higher than total length
3086
+ if (distanceIsNumber && distance >= totalLength) {
3087
+ return { x: x, y: y };
3088
+ }
3089
+
3090
+ return totalLength;
3091
+ }
3092
+
3093
+ /**
3094
+ * Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
3095
+ *
3096
+ * The `normalizePath` version is lighter, faster, more efficient and more accurate
3097
+ * with paths that are not `curveArray`.
3098
+ *
3099
+ * @param {string | SVGPath.pathArray} pathInput the target `pathArray`
3100
+ * @returns {number} the shape total length
3101
+ */
3102
+ function getTotalLength(pathInput) {
3103
+ // @ts-ignore - it's fine
3104
+ return pathLengthFactory(pathInput);
3105
+ }
3106
+
3107
+ /**
3108
+ * Returns [x,y] coordinates of a point at a given length of a shape.
3109
+ *
3110
+ * @param {string | SVGPath.pathArray} pathInput the `pathArray` to look into
3111
+ * @param {number} distance the length of the shape to look at
3112
+ * @returns {{x: number, y: number}} the requested {x, y} point coordinates
3113
+ */
3114
+ function getPointAtLength(pathInput, distance) {
3115
+ // @ts-ignore
3116
+ return pathLengthFactory(pathInput, distance);
3117
+ }
3118
+
3119
+ /**
3120
+ * Creates a new SVGPathCommander instance with the following properties:
3121
+ * * segments: `pathArray`
3122
+ * * round: number
3123
+ * * origin: [number, number, number?]
3124
+ *
3125
+ * @class
3126
+ * @author thednp <https://github.com/thednp/svg-path-commander>
3127
+ * @returns {SVGPathCommander} a new SVGPathCommander instance
3128
+ */
3129
+ var SVGPathCommander = function SVGPathCommander(pathValue, config) {
3130
+ var instanceOptions = config || {};
3131
+
3132
+ var undefPath = typeof pathValue === 'undefined';
3133
+
3134
+ if (undefPath || !pathValue.length) {
3135
+ throw TypeError((error + ": \"pathValue\" is " + (undefPath ? 'undefined' : 'empty')));
3136
+ }
3137
+
3138
+ var segments = parsePathString(pathValue);
3139
+ if (typeof segments === 'string') {
3140
+ throw TypeError(segments);
3141
+ }
3142
+
3143
+ /**
3144
+ * @type {SVGPath.pathArray}
3145
+ */
3146
+ this.segments = segments;
3147
+
3148
+ var ref = this.getBBox();
3149
+ var width = ref.width;
3150
+ var height = ref.height;
3151
+ var cx = ref.cx;
3152
+ var cy = ref.cy;
3153
+ var cz = ref.cz;
3154
+
3155
+ // set instance options.round
3156
+ var round = defaultOptions.round;
3157
+ var origin = defaultOptions.origin;
3158
+ var roundOption = instanceOptions.round;
3159
+ var originOption = instanceOptions.origin;
3160
+
3161
+ if (roundOption === 'auto') {
3162
+ var pathScale = (("" + (Math.floor(Math.max(width, height))))).length;
3163
+ round = pathScale >= 4 ? 0 : 4 - pathScale;
3164
+ } else if (Number.isInteger(roundOption) || roundOption === false) {
3165
+ round = roundOption;
3166
+ }
3167
+
3168
+ // set instance options.origin
3169
+ if (Array.isArray(originOption) && originOption.length >= 2) {
3170
+ var ref$1 = originOption.map(Number);
3171
+ var originX = ref$1[0];
3172
+ var originY = ref$1[1];
3173
+ var originZ = ref$1[2];
3174
+ origin = [
3175
+ !Number.isNaN(originX) ? originX : cx,
3176
+ !Number.isNaN(originY) ? originY : cy,
3177
+ !Number.isNaN(originZ) ? originZ : cz ];
3178
+ } else {
3179
+ origin = [cx, cy, cz];
3180
+ }
3181
+
3182
+ /**
3183
+ * @type {number | false}
3184
+ */
3185
+ this.round = round;
3186
+ this.origin = origin;
3187
+
3188
+ return this;
3189
+ };
3190
+
3191
+ /**
3192
+ * Returns the path bounding box, equivalent to native `path.getBBox()`.
3193
+ * @public
3194
+ * @returns {SVGPath.pathBBox}
3195
+ */
3196
+ SVGPathCommander.prototype.getBBox = function getBBox () {
3197
+ return getPathBBox(this.segments);
3198
+ };
3199
+
3200
+ /**
3201
+ * Returns the total path length, equivalent to native `path.getTotalLength()`.
3202
+ * @public
3203
+ * @returns {number}
3204
+ */
3205
+ SVGPathCommander.prototype.getTotalLength = function getTotalLength$1 () {
3206
+ return getTotalLength(this.segments);
3207
+ };
3208
+
3209
+ /**
3210
+ * Returns an `{x,y}` point in the path stroke at a given length,
3211
+ * equivalent to the native `path.getPointAtLength()`.
3212
+ *
3213
+ * @public
3214
+ * @param {number} length the length
3215
+ * @returns {{x: number, y:number}} the requested point
3216
+ */
3217
+ SVGPathCommander.prototype.getPointAtLength = function getPointAtLength$1 (length) {
3218
+ return getPointAtLength(this.segments, length);
3219
+ };
3220
+
3221
+ /**
3222
+ * Convert path to absolute values
3223
+ * @public
3224
+ */
3225
+ SVGPathCommander.prototype.toAbsolute = function toAbsolute () {
3226
+ var ref = this;
3227
+ var segments = ref.segments;
3228
+ this.segments = pathToAbsolute(segments);
3229
+ return this;
3230
+ };
3231
+
3232
+ /**
3233
+ * Convert path to relative values
3234
+ * @public
3235
+ */
3236
+ SVGPathCommander.prototype.toRelative = function toRelative () {
3237
+ var ref = this;
3238
+ var segments = ref.segments;
3239
+ this.segments = pathToRelative(segments);
3240
+ return this;
3241
+ };
3242
+
3243
+ /**
3244
+ * Convert path to cubic-bezier values. In addition, un-necessary `Z`
3245
+ * segment is removed if previous segment extends to the `M` segment.
3246
+ *
3247
+ * @public
3248
+ */
3249
+ SVGPathCommander.prototype.toCurve = function toCurve () {
3250
+ var ref = this;
3251
+ var segments = ref.segments;
3252
+ this.segments = pathToCurve(segments);
3253
+ return this;
3254
+ };
3255
+
3256
+ /**
3257
+ * Reverse the order of the segments and their values.
3258
+ * @param {boolean | number} onlySubpath option to reverse all sub-paths except first
3259
+ * @public
3260
+ */
3261
+ SVGPathCommander.prototype.reverse = function reverse (onlySubpath) {
3262
+ this.toAbsolute();
3263
+
3264
+ var ref = this;
3265
+ var segments = ref.segments;
3266
+ var split = splitPath(this.toString());
3267
+ var subPath = split.length > 1 ? split : 0;
3268
+
3269
+ // @ts-ignore
3270
+ var absoluteMultiPath = subPath && clonePath(subPath).map(function (x, i) {
3271
+ if (onlySubpath) {
3272
+ return i ? reversePath(x) : parsePathString(x);
3273
+ }
3274
+ return reversePath(x);
3275
+ });
3276
+
3277
+ var path = [];
3278
+ if (subPath) {
3279
+ path = absoluteMultiPath.flat(1);
3280
+ } else {
3281
+ path = onlySubpath ? segments : reversePath(segments);
3282
+ }
3283
+
3284
+ this.segments = clonePath(path);
3285
+ return this;
3286
+ };
3287
+
3288
+ /**
3289
+ * Normalize path in 2 steps:
3290
+ * * convert `pathArray`(s) to absolute values
3291
+ * * convert shorthand notation to standard notation
3292
+ * @public
3293
+ */
3294
+ SVGPathCommander.prototype.normalize = function normalize () {
3295
+ var ref = this;
3296
+ var segments = ref.segments;
3297
+ this.segments = normalizePath(segments);
3298
+ return this;
3299
+ };
3300
+
3301
+ /**
3302
+ * Optimize `pathArray` values:
3303
+ * * convert segments to absolute and/or relative values
3304
+ * * select segments with shortest resulted string
3305
+ * * round values to the specified `decimals` option value
3306
+ * @public
3307
+ */
3308
+ SVGPathCommander.prototype.optimize = function optimize () {
3309
+ var ref = this;
3310
+ var segments = ref.segments;
3311
+
3312
+ this.segments = optimizePath(segments, this.round);
3313
+ return this;
3314
+ };
3315
+
3316
+ /**
3317
+ * Transform path using values from an `Object` defined as `transformObject`.
3318
+ * @see SVGPath.transformObject for a quick refference
3319
+ *
3320
+ * @param {SVGPath.transformObject} source a `transformObject`as described above
3321
+ * @public
3322
+ */
3323
+ SVGPathCommander.prototype.transform = function transform (source) {
3324
+ if (!source || typeof source !== 'object' || (typeof source === 'object'
3325
+ && !['translate', 'rotate', 'skew', 'scale'].some(function (x) { return x in source; }))) { return this; }
3326
+
3327
+ /** @type {SVGPath.transformObject} */
3328
+ var transform = {};
3329
+ Object.keys(source).forEach(function (fn) {
3330
+ // @ts-ignore
3331
+ transform[fn] = Array.isArray(source[fn]) ? [].concat( source[fn] ) : Number(source[fn]);
3332
+ });
3333
+ var ref = this;
3334
+ var segments = ref.segments;
3335
+
3336
+ // if origin is not specified
3337
+ // it's important that we have one
3338
+ var ref$1 = this.origin;
3339
+ var cx = ref$1[0];
3340
+ var cy = ref$1[1];
3341
+ var cz = ref$1[2];
3342
+ var origin = transform.origin;
3343
+
3344
+ if (Array.isArray(origin) && origin.length >= 2) {
3345
+ var ref$2 = origin.map(Number);
3346
+ var originX = ref$2[0];
3347
+ var originY = ref$2[1];
3348
+ var originZ = ref$2[2];
3349
+ transform.origin = [
3350
+ !Number.isNaN(originX) ? originX : cx,
3351
+ !Number.isNaN(originY) ? originY : cy,
3352
+ originZ || cz ];
3353
+ } else {
3354
+ transform.origin = [cx, cy, cz];
3355
+ }
3356
+
3357
+ this.segments = transformPath(segments, transform);
3358
+ return this;
3359
+ };
3360
+
3361
+ /**
3362
+ * Rotate path 180deg horizontally
3363
+ * @public
3364
+ */
3365
+ SVGPathCommander.prototype.flipX = function flipX () {
3366
+ this.transform({ rotate: [180, 0, 0] });
3367
+ return this;
3368
+ };
3369
+
3370
+ /**
3371
+ * Rotate path 180deg vertically
3372
+ * @public
3373
+ */
3374
+ SVGPathCommander.prototype.flipY = function flipY () {
3375
+ this.transform({ rotate: [0, 180, 0] });
3376
+ return this;
3377
+ };
3378
+
3379
+ /**
3380
+ * Export the current path to be used
3381
+ * for the `d` (description) attribute.
3382
+ * @public
3383
+ * @return {String} the path string
3384
+ */
3385
+ SVGPathCommander.prototype.toString = function toString () {
3386
+ return pathToString(this.segments, this.round);
3387
+ };
3388
+
3389
+ /**
3390
+ * Returns the area of a single cubic-bezier segment.
3391
+ *
3392
+ * http://objectmix.com/graphics/133553-area-closed-bezier-curve.html
3393
+ *
3394
+ * @param {number} x1 the starting point X
3395
+ * @param {number} y1 the starting point Y
3396
+ * @param {number} c1x the first control point X
3397
+ * @param {number} c1y the first control point Y
3398
+ * @param {number} c2x the second control point X
3399
+ * @param {number} c2y the second control point Y
3400
+ * @param {number} x2 the ending point X
3401
+ * @param {number} y2 the ending point Y
3402
+ * @returns {number} the area of the cubic-bezier segment
3403
+ */
3404
+ function getCubicSegArea(x1, y1, c1x, c1y, c2x, c2y, x2, y2) {
3405
+ return (3 * ((y2 - y1) * (c1x + c2x) - (x2 - x1) * (c1y + c2y)
3406
+ + (c1y * (x1 - c2x)) - (c1x * (y1 - c2y))
3407
+ + (y2 * (c2x + x1 / 3)) - (x2 * (c2y + y1 / 3)))) / 20;
3408
+ }
3409
+
3410
+ /**
3411
+ * Returns the area of a shape.
3412
+ * @author Jürg Lehni & Jonathan Puckey
3413
+ *
3414
+ * @see https://github.com/paperjs/paper.js/blob/develop/src/path/Path.js
3415
+ *
3416
+ * @param {SVGPath.pathArray} path the shape `pathArray`
3417
+ * @returns {number} the length of the cubic-bezier segment
3418
+ */
3419
+ function getPathArea(path) {
3420
+ var x = 0; var y = 0; var len = 0;
3421
+
3422
+ return pathToCurve(path).map(function (seg) {
3423
+ var assign, assign$1;
3424
+
3425
+ switch (seg[0]) {
3426
+ case 'M':
3427
+ (assign = seg, x = assign[1], y = assign[2]);
3428
+ return 0;
3429
+ default:
3430
+ // @ts-ignore -- the utility will have proper amount of params
3431
+ len = getCubicSegArea.apply(void 0, [ x, y ].concat( seg.slice(1) ));
3432
+ // @ts-ignore -- the segment always has numbers
3433
+ (assign$1 = seg.slice(-2), x = assign$1[0], y = assign$1[1]);
3434
+ return len;
3435
+ }
3436
+ }).reduce(function (a, b) { return a + b; }, 0);
3437
+ }
3438
+
3439
+ /**
3440
+ * Returns the shape total length, or the equivalent to `shape.getTotalLength()`.
3441
+ *
3442
+ * This is the `pathToCurve` version which is faster and more efficient for
3443
+ * paths that are `curveArray`.
3444
+ *
3445
+ * @param {string | SVGPath.curveArray} path the target `pathArray`
3446
+ * @returns {number} the `curveArray` total length
3447
+ */
3448
+ function getPathLength(path) {
3449
+ var totalLength = 0;
3450
+ pathToCurve(path).forEach(function (s, i, curveArray) {
3451
+ var args = s[0] !== 'M' ? curveArray[i - 1].slice(-2).concat( s.slice(1)) : [];
3452
+ // @ts-ignore
3453
+ totalLength += s[0] === 'M' ? 0 : segmentCubicFactory.apply(void 0, args);
3454
+ });
3455
+ return totalLength;
3456
+ }
3457
+
3458
+ /**
3459
+ * Check if a path is drawn clockwise and returns true if so,
3460
+ * false otherwise.
3461
+ *
3462
+ * @param {SVGPath.pathArray} path the path string or `pathArray`
3463
+ * @returns {boolean} true when clockwise or false if not
3464
+ */
3465
+ function getDrawDirection(path) {
3466
+ return getPathArea(pathToCurve(path)) >= 0;
3467
+ }
3468
+
3469
+ /**
3470
+ * Returns the segment, its index and length as well as
3471
+ * the length to that segment at a given length in a path.
3472
+ *
3473
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3474
+ * @param {number=} distance the given length
3475
+ * @returns {SVGPath.segmentProperties=} the requested properties
3476
+ */
3477
+ function getPropertiesAtLength(pathInput, distance) {
3478
+ var pathArray = parsePathString(pathInput);
3479
+ var segments = [];
3480
+
3481
+ var pathTemp = [].concat( pathArray );
3482
+ // @ts-ignore
3483
+ var pathLength = getTotalLength(pathTemp);
3484
+ var index = pathTemp.length - 1;
3485
+ var lengthAtSegment = 0;
3486
+ var length = 0;
3487
+ /** @type {SVGPath.pathSegment} */
3488
+ var segment = pathArray[0];
3489
+ var ref = segment.slice(-2);
3490
+ var x = ref[0];
3491
+ var y = ref[1];
3492
+ var point = { x: x, y: y };
3493
+
3494
+ // If the path is empty, return 0.
3495
+ if (index <= 0 || !distance || !Number.isFinite(distance)) {
3496
+ return {
3497
+ // @ts-ignore
3498
+ segment: segment, index: 0, length: length, point: point, lengthAtSegment: lengthAtSegment,
3499
+ };
3500
+ }
3501
+
3502
+ if (distance >= pathLength) {
3503
+ pathTemp = pathArray.slice(0, -1);
3504
+ // @ts-ignore
3505
+ lengthAtSegment = getTotalLength(pathTemp);
3506
+ // @ts-ignore
3507
+ length = pathLength - lengthAtSegment;
3508
+ return {
3509
+ // @ts-ignore
3510
+ segment: pathArray[index], index: index, length: length, lengthAtSegment: lengthAtSegment,
3511
+ };
3512
+ }
3513
+
3514
+ while (index > 0) {
3515
+ segment = pathTemp[index];
3516
+ pathTemp = pathTemp.slice(0, -1);
3517
+ // @ts-ignore -- `pathTemp` === `pathSegment[]` === `pathArray`
3518
+ lengthAtSegment = getTotalLength(pathTemp);
3519
+ // @ts-ignore
3520
+ length = pathLength - lengthAtSegment;
3521
+ pathLength = lengthAtSegment;
3522
+ segments.push({
3523
+ segment: segment, index: index, length: length, lengthAtSegment: lengthAtSegment,
3524
+ });
3525
+ index -= 1;
3526
+ }
3527
+
3528
+ // @ts-ignore
3529
+ return segments.find(function (ref) {
3530
+ var l = ref.lengthAtSegment;
3531
+
3532
+ return l <= distance;
3533
+ });
3534
+ }
3535
+
3536
+ /**
3537
+ * Returns the point and segment in path closest to a given point as well as
3538
+ * the distance to the path stroke.
3539
+ * @see https://bl.ocks.org/mbostock/8027637
3540
+ *
3541
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3542
+ * @param {{x: number, y: number}} point the given point
3543
+ * @returns {SVGPath.pointProperties} the requested properties
3544
+ */
3545
+ function getPropertiesAtPoint(pathInput, point) {
3546
+ var path = fixPath(parsePathString(pathInput));
3547
+ var normalPath = normalizePath(path);
3548
+ var pathLength = getTotalLength(path);
3549
+ /** @param {{x: number, y: number}} p */
3550
+ var distanceTo = function (p) {
3551
+ var dx = p.x - point.x;
3552
+ var dy = p.y - point.y;
3553
+ return dx * dx + dy * dy;
3554
+ };
3555
+ var precision = 8;
3556
+ var scan = { x: 0, y: 0 };
3557
+ var scanDistance = 0;
3558
+ var closest = scan;
3559
+ var bestLength = 0;
3560
+ var bestDistance = Infinity;
3561
+
3562
+ // linear scan for coarse approximation
3563
+ for (var scanLength = 0; scanLength <= pathLength; scanLength += precision) {
3564
+ scan = getPointAtLength(normalPath, scanLength);
3565
+ scanDistance = distanceTo(scan);
3566
+ if (scanDistance < bestDistance) {
3567
+ closest = scan;
3568
+ bestLength = scanLength;
3569
+ bestDistance = scanDistance;
3570
+ }
3571
+ }
3572
+
3573
+ // binary search for precise estimate
3574
+ precision /= 2;
3575
+ var before = { x: 0, y: 0 };
3576
+ var after = before;
3577
+ var beforeLength = 0;
3578
+ var afterLength = 0;
3579
+ var beforeDistance = 0;
3580
+ var afterDistance = 0;
3581
+
3582
+ while (precision > 0.5) {
3583
+ beforeLength = bestLength - precision;
3584
+ before = getPointAtLength(normalPath, beforeLength);
3585
+ beforeDistance = distanceTo(before);
3586
+ afterLength = bestLength + precision;
3587
+ after = getPointAtLength(normalPath, afterLength);
3588
+ afterDistance = distanceTo(after);
3589
+ if (beforeLength >= 0 && beforeDistance < bestDistance) {
3590
+ closest = before;
3591
+ bestLength = beforeLength;
3592
+ bestDistance = beforeDistance;
3593
+ } else if (afterLength <= pathLength && afterDistance < bestDistance) {
3594
+ closest = after;
3595
+ bestLength = afterLength;
3596
+ bestDistance = afterDistance;
3597
+ } else {
3598
+ precision /= 2;
3599
+ }
3600
+ }
3601
+
3602
+ var segment = getPropertiesAtLength(path, bestLength);
3603
+ var distance = Math.sqrt(bestDistance);
3604
+
3605
+ return { closest: closest, distance: distance, segment: segment };
3606
+ }
3607
+
3608
+ /**
3609
+ * Returns the point in path closest to a given point.
3610
+ *
3611
+ * @param {string | SVGPath.pathArray} pathInput target `pathArray`
3612
+ * @param {{x: number, y: number}} point the given point
3613
+ * @returns {{x: number, y: number}} the best match
3614
+ */
3615
+ function getClosestPoint(pathInput, point) {
3616
+ return getPropertiesAtPoint(pathInput, point).closest;
3617
+ }
3618
+
3619
+ /**
3620
+ * Returns the path segment which contains a given point.
3621
+ *
3622
+ * @param {string | SVGPath.pathArray} path the `pathArray` to look into
3623
+ * @param {{x: number, y: number}} point the point of the shape to look for
3624
+ * @returns {SVGPath.pathSegment?} the requested segment
3625
+ */
3626
+ function getSegmentOfPoint(path, point) {
3627
+ var props = getPropertiesAtPoint(path, point);
3628
+ var segment = props.segment;
3629
+ return typeof segment !== 'undefined' ? segment.segment : null;
3630
+ }
3631
+
3632
+ /**
3633
+ * Returns the segment at a given length.
3634
+ * @param {string | SVGPath.pathArray} pathInput the target `pathArray`
3635
+ * @param {number} distance the distance in path to look at
3636
+ * @returns {SVGPath.pathSegment?} the requested segment
3637
+ */
3638
+ function getSegmentAtLength(pathInput, distance) {
3639
+ var props = getPropertiesAtLength(pathInput, distance);
3640
+ var ref = typeof props !== 'undefined' ? props : { segment: null };
3641
+ var segment = ref.segment;
3642
+ return segment;
3643
+ }
3644
+
3645
+ /**
3646
+ * Checks if a given point is in the stroke of a path.
3647
+ *
3648
+ * @param {string | SVGPath.pathArray} pathInput target path
3649
+ * @param {{x: number, y: number}} point the given `{x,y}` point
3650
+ * @returns {boolean} the query result
3651
+ */
3652
+ function isPointInStroke(pathInput, point) {
3653
+ var ref = getPropertiesAtPoint(pathInput, point);
3654
+ var distance = ref.distance;
3655
+ return Math.abs(distance) < 0.01;
3656
+ }
3657
+
3658
+ /**
3659
+ * Parses a path string value to determine its validity
3660
+ * then returns true if it's valid or false otherwise.
3661
+ *
3662
+ * @param {string} pathString the path string to be parsed
3663
+ * @returns {boolean} the path string validity
3664
+ */
3665
+ function isValidPath(pathString) {
3666
+ if (typeof pathString !== 'string') {
3667
+ return false;
3668
+ }
3669
+
3670
+ var path = new PathParser(pathString);
3671
+
3672
+ skipSpaces(path);
3673
+
3674
+ while (path.index < path.max && !path.err.length) {
3675
+ scanSegment(path);
3676
+ }
3677
+
3678
+ return !path.err.length && 'mM'.includes(path.segments[0][0]);
3679
+ }
3680
+
3681
+ /**
3682
+ * Supported shapes and their specific parameters.
3683
+ * @type {Object.<string, string[]>}
3684
+ */
3685
+ var shapeParams = {
3686
+ circle: ['cx', 'cy', 'r'],
3687
+ ellipse: ['cx', 'cy', 'rx', 'ry'],
3688
+ rect: ['width', 'height', 'x', 'y', 'rx', 'ry'],
3689
+ polygon: ['points'],
3690
+ polyline: ['points'],
3691
+ glyph: [],
3692
+ };
3693
+
3694
+ /**
3695
+ * Returns a new `pathArray` from line attributes.
3696
+ *
3697
+ * @param {SVGPath.lineAttr} attr shape configuration
3698
+ * @returns {SVGPath.pathArray} a new line `pathArray`
3699
+ */
3700
+ function getLinePath(attr) {
3701
+ var x1 = attr.x1;
3702
+ var y1 = attr.y1;
3703
+ var x2 = attr.x2;
3704
+ var y2 = attr.y2;
3705
+ return [['M', x1, y1], ['L', x2, y2]];
3706
+ }
3707
+
3708
+ /**
3709
+ * Returns a new `pathArray` like from polyline/polygon attributes.
3710
+ *
3711
+ * @param {SVGPath.polyAttr} attr shape configuration
3712
+ * @return {SVGPath.pathArray} a new polygon/polyline `pathArray`
3713
+ */
3714
+ function getPolyPath(attr) {
3715
+ /** @type {SVGPath.pathArray} */
3716
+ // @ts-ignore -- it's an empty `pathArray`
3717
+ var pathArray = [];
3718
+ var points = attr.points.trim().split(/[\s|,]/).map(Number);
3719
+
3720
+ var index = 0;
3721
+ while (index < points.length) {
3722
+ pathArray.push([(index ? 'L' : 'M'), (points[index]), (points[index + 1])]);
3723
+ index += 2;
3724
+ }
3725
+ // @ts-ignore -- it's a `pathArray`
3726
+ return attr.type === 'polygon' ? pathArray.concat( [['z']]) : pathArray;
3727
+ }
3728
+
3729
+ /**
3730
+ * Returns a new `pathArray` from circle attributes.
3731
+ *
3732
+ * @param {SVGPath.circleAttr} attr shape configuration
3733
+ * @return {SVGPath.pathArray} a circle `pathArray`
3734
+ */
3735
+ function getCirclePath(attr) {
3736
+ var cx = attr.cx;
3737
+ var cy = attr.cy;
3738
+ var r = attr.r;
3739
+
3740
+ return [
3741
+ ['M', (cx - r), cy],
3742
+ ['a', r, r, 0, 1, 0, (2 * r), 0],
3743
+ ['a', r, r, 0, 1, 0, (-2 * r), 0] ];
3744
+ }
3745
+
3746
+ /**
3747
+ * Returns a new `pathArray` from ellipse attributes.
3748
+ *
3749
+ * @param {SVGPath.ellipseAttr} attr shape configuration
3750
+ * @return {SVGPath.pathArray} an ellipse `pathArray`
3751
+ */
3752
+ function getEllipsePath(attr) {
3753
+ var cx = attr.cx;
3754
+ var cy = attr.cy;
3755
+ var rx = attr.rx;
3756
+ var ry = attr.ry;
3757
+
3758
+ return [
3759
+ ['M', (cx - rx), cy],
3760
+ ['a', rx, ry, 0, 1, 0, (2 * rx), 0],
3761
+ ['a', rx, ry, 0, 1, 0, (-2 * rx), 0] ];
3762
+ }
3763
+
3764
+ /**
3765
+ * Returns a new `pathArray` like from rect attributes.
3766
+ *
3767
+ * @param {SVGPath.rectAttr} attr object with properties above
3768
+ * @return {SVGPath.pathArray} a new `pathArray` from `<rect>` attributes
3769
+ */
3770
+ function getRectanglePath(attr) {
3771
+ var x = +attr.x || 0;
3772
+ var y = +attr.y || 0;
3773
+ var w = +attr.width;
3774
+ var h = +attr.height;
3775
+ var rx = +attr.rx;
3776
+ var ry = +attr.ry;
3777
+
3778
+ // Validity checks from http://www.w3.org/TR/SVG/shapes.html#RectElement:
3779
+ if (rx || ry) {
3780
+ rx = !rx ? ry : rx;
3781
+ ry = !ry ? rx : ry;
3782
+
3783
+ if (rx * 2 > w) { rx -= (rx * 2 - w) / 2; }
3784
+ if (ry * 2 > h) { ry -= (ry * 2 - h) / 2; }
3785
+
3786
+ return [
3787
+ ['M', x + rx, y],
3788
+ ['h', w - rx * 2],
3789
+ ['s', rx, 0, rx, ry],
3790
+ ['v', h - ry * 2],
3791
+ ['s', 0, ry, -rx, ry],
3792
+ ['h', -w + rx * 2],
3793
+ ['s', -rx, 0, -rx, -ry],
3794
+ ['v', -h + ry * 2],
3795
+ ['s', 0, -ry, rx, -ry] ];
3796
+ }
3797
+
3798
+ return [
3799
+ ['M', x, y],
3800
+ ['h', w],
3801
+ ['v', h],
3802
+ ['H', x],
3803
+ ['Z'] ];
3804
+ }
3805
+
3806
+ /**
3807
+ * Returns a new `<path>` element created from attributes of a `<line>`, `<polyline>`,
3808
+ * `<polygon>`, `<rect>`, `<ellipse>`, `<circle>` or `<glyph>`. If `replace` parameter
3809
+ * is `true`, it will replace the target.
3810
+ *
3811
+ * It can also work with an options object,
3812
+ * @see SVGPath.shapeOps
3813
+ *
3814
+ * The newly created `<path>` element keeps all non-specific
3815
+ * attributes like `class`, `fill`, etc.
3816
+ *
3817
+ * @param {SVGPath.shapeTypes | SVGPath.shapeOps} element target shape
3818
+ * @param {boolean=} replace option to replace target
3819
+ * @return {SVGPathElement | boolean} the newly created `<path>` element
3820
+ */
3821
+ function shapeToPath(element, replace) {
3822
+ var supportedShapes = Object.keys(shapeParams);
3823
+ var isElement = element instanceof Element;
3824
+
3825
+ if (isElement && !supportedShapes.some(function (s) { return element.tagName === s; })) {
3826
+ throw TypeError(("shapeToPath: \"" + element + "\" is not SVGElement"));
3827
+ }
3828
+
3829
+ var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
3830
+ /** @type {string} */
3831
+ var type = isElement ? element.tagName : element.type;
3832
+ /** @type {any} disables TS checking for something that's specific to shape */
3833
+ var config = {};
3834
+ config.type = type;
3835
+
3836
+ if (isElement) {
3837
+ var shapeAttrs = shapeParams[type];
3838
+ shapeAttrs.forEach(function (p) { config[p] = element.getAttribute(p); });
3839
+ // set no-specific shape attributes: fill, stroke, etc
3840
+ Object.values(element.attributes).forEach(function (ref) {
3841
+ var name = ref.name;
3842
+ var value = ref.value;
3843
+
3844
+ if (!shapeAttrs.includes(name)) { path.setAttribute(name, value); }
3845
+ });
3846
+ } else {
3847
+ Object.assign(config, element);
3848
+ }
3849
+
3850
+ // set d
3851
+ var description;
3852
+ var round = defaultOptions.round;
3853
+
3854
+ if (type === 'circle') { description = pathToString(getCirclePath(config), round); }
3855
+ else if (type === 'ellipse') { description = pathToString(getEllipsePath(config), round); }
3856
+ else if (['polyline', 'polygon'].includes(type)) { description = pathToString(getPolyPath(config), round); }
3857
+ else if (type === 'rect') { description = pathToString(getRectanglePath(config), round); }
3858
+ else if (type === 'line') { description = pathToString(getLinePath(config), round); }
3859
+ else if (type === 'glyph') { description = isElement ? element.getAttribute('d') : element.type; }
3860
+
3861
+ // replace target element
3862
+ if (description) {
3863
+ path.setAttribute('d', description);
3864
+ if (replace && isElement) {
3865
+ element.before(path, element);
3866
+ element.remove();
3867
+ }
3868
+ return path;
3869
+ }
3870
+ return false;
3871
+ }
3872
+
3873
+ /**
3874
+ * Reverses all segments of a `pathArray`
3875
+ * which consists of only C (cubic-bezier) path commands.
3876
+ *
3877
+ * @param {SVGPath.curveArray} path the source `pathArray`
3878
+ * @returns {SVGPath.curveArray} the reversed `pathArray`
3879
+ */
3880
+ function reverseCurve(path) {
3881
+ var rotatedCurve = path.slice(1)
3882
+ .map(function (x, i, curveOnly) { return (!i
3883
+ ? path[0].slice(1).concat( x.slice(1))
3884
+ : curveOnly[i - 1].slice(-2).concat( x.slice(1))); })
3885
+ .map(function (x) { return x.map(function (_, i) { return x[x.length - i - 2 * (1 - (i % 2))]; }); })
3886
+ .reverse();
3887
+
3888
+ // @ts-ignore -- expected on reverse operations
3889
+ return [['M' ].concat( rotatedCurve[0].slice(0, 2)) ].concat( rotatedCurve.map(function (x) { return ['C' ].concat( x.slice(2)); }));
3890
+ }
3891
+
3892
+ /**
3893
+ * @interface
3894
+ */
3895
+ var Util = {
3896
+ CSSMatrix: CSSMatrix,
3897
+ parsePathString: parsePathString,
3898
+ isPathArray: isPathArray,
3899
+ isCurveArray: isCurveArray,
3900
+ isAbsoluteArray: isAbsoluteArray,
3901
+ isRelativeArray: isRelativeArray,
3902
+ isNormalizedArray: isNormalizedArray,
3903
+ isValidPath: isValidPath,
3904
+ pathToAbsolute: pathToAbsolute,
3905
+ pathToRelative: pathToRelative,
3906
+ pathToCurve: pathToCurve,
3907
+ pathToString: pathToString,
3908
+ getDrawDirection: getDrawDirection,
3909
+ getPathArea: getPathArea,
3910
+ getPathBBox: getPathBBox,
3911
+ getTotalLength: getTotalLength,
3912
+ getPathLength: getPathLength,
3913
+ getPointAtLength: getPointAtLength,
3914
+ getClosestPoint: getClosestPoint,
3915
+ getSegmentOfPoint: getSegmentOfPoint,
3916
+ getPropertiesAtPoint: getPropertiesAtPoint,
3917
+ getPropertiesAtLength: getPropertiesAtLength,
3918
+ getSegmentAtLength: getSegmentAtLength,
3919
+ isPointInStroke: isPointInStroke,
3920
+ clonePath: clonePath,
3921
+ splitPath: splitPath,
3922
+ fixPath: fixPath,
3923
+ roundPath: roundPath,
3924
+ optimizePath: optimizePath,
3925
+ reverseCurve: reverseCurve,
3926
+ reversePath: reversePath,
3927
+ normalizePath: normalizePath,
3928
+ transformPath: transformPath,
3929
+ shapeToPath: shapeToPath,
3930
+ options: defaultOptions,
3931
+ };
3932
+
3933
+ var version = "0.2.0alpha2";
3934
+
3935
+ // @ts-ignore
3936
+
3937
+ /**
3938
+ * A global namespace for library version.
3939
+ * @type {string}
3940
+ */
3941
+ var Version = version;
3942
+
3943
+ // Export to global
3944
+ Object.assign(SVGPathCommander, Util, { Version: Version });
3945
+
3946
+ return SVGPathCommander;
3947
+
3948
+ }));