svg-path-simplify 0.0.8 → 0.0.9

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 (34) hide show
  1. package/README.md +25 -5
  2. package/dist/svg-path-simplify.esm.js +576 -494
  3. package/dist/svg-path-simplify.esm.min.js +1 -1
  4. package/dist/svg-path-simplify.js +576 -494
  5. package/dist/svg-path-simplify.min.js +1 -1
  6. package/dist/svg-path-simplify.node.js +576 -494
  7. package/dist/svg-path-simplify.node.min.js +1 -1
  8. package/index.html +86 -29
  9. package/package.json +1 -1
  10. package/src/detect_input.js +17 -10
  11. package/src/index.js +3 -0
  12. package/src/pathData_simplify_cubic.js +113 -106
  13. package/src/pathData_simplify_cubic_extrapolate.js +25 -11
  14. package/src/pathSimplify-main.js +89 -182
  15. package/src/svgii/geometry_flatness.js +29 -36
  16. package/src/svgii/pathData_analyze.js +4 -0
  17. package/src/svgii/pathData_convert.js +26 -17
  18. package/src/svgii/pathData_interpolate.js +65 -0
  19. package/src/svgii/pathData_parse.js +25 -9
  20. package/src/svgii/pathData_parse_els.js +18 -12
  21. package/src/svgii/pathData_remove_collinear.js +31 -28
  22. package/src/svgii/pathData_remove_orphaned.js +5 -4
  23. package/src/svgii/pathData_remove_zerolength.js +8 -4
  24. package/src/svgii/pathData_reorder.js +6 -2
  25. package/src/svgii/pathData_simplify_refineCorners.js +160 -0
  26. package/src/svgii/{simplify_refineExtremes.js → pathData_simplify_refineExtremes.js} +78 -43
  27. package/src/svgii/pathData_split.js +42 -15
  28. package/src/svgii/pathData_stringify.js +3 -12
  29. package/src/svgii/rounding.js +16 -14
  30. package/src/svgii/svg_cleanup.js +1 -1
  31. package/src/pathData_simplify_cubic_arr.js +0 -50
  32. package/src/svgii/simplify.js +0 -248
  33. package/src/svgii/simplify_bezier.js +0 -470
  34. package/src/svgii/simplify_linetos.js +0 -93
@@ -32,7 +32,7 @@ export function revertCubicQuadratic(p0 = {}, cp1 = {}, cp2 = {}, p = {}) {
32
32
  let values = [cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y];
33
33
  let comN = {type, values}
34
34
 
35
- if (dist1 < threshold) {
35
+ if (dist1 && threshold && dist1 < threshold) {
36
36
  cp1_Q = checkLineIntersection(p0, cp1, p, cp2, false);
37
37
  if (cp1_Q) {
38
38
  //renderPoint(markers, cp1_Q )
@@ -55,13 +55,19 @@ export function convertPathData(pathData, {
55
55
  decimals = 3
56
56
  } = {}) {
57
57
 
58
+
59
+ //console.log(toShorthands, toRelative, decimals);
60
+
58
61
  //if(decimals>-1 && decimals<2) pathData = roundPathData(pathData, decimals);
59
62
  if (toShorthands) pathData = pathDataToShorthands(pathData);
60
63
 
61
64
  // pre round - before relative conversion to minimize distortions
62
- pathData = roundPathData(pathData, decimals);
65
+ if(decimals>-1 && toRelative) pathData = roundPathData(pathData, decimals);
63
66
  if (toRelative) pathData = pathDataToRelative(pathData);
64
67
  if (decimals > -1) pathData = roundPathData(pathData, decimals);
68
+
69
+
70
+
65
71
  return pathData
66
72
  }
67
73
 
@@ -374,7 +380,7 @@ export function pathDataToLonghands(pathData, decimals = -1, test = true) {
374
380
  * L, L, C, Q => H, V, S, T
375
381
  * reversed method: pathDataToLonghands()
376
382
  */
377
- export function pathDataToShorthands(pathData, decimals = -1, test = true) {
383
+ export function pathDataToShorthands(pathData, decimals = -1, test = false) {
378
384
 
379
385
  //pathData = JSON.parse(JSON.stringify(pathData))
380
386
  //console.log('has dec', pathData);
@@ -388,29 +394,28 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
388
394
  hasRel = /[astvqmhlc]/g.test(commandTokens);
389
395
  }
390
396
 
391
- pathData = test && hasRel ? pathDataToAbsolute(pathData, decimals) : pathData;
397
+ pathData = test && hasRel ? pathDataToAbsoluteOrRelative(pathData) : pathData;
398
+
399
+ let len = pathData.length
400
+ let pathDataShorts = new Array(len);
392
401
 
393
402
  let comShort = {
394
403
  type: "M",
395
404
  values: pathData[0].values
396
405
  };
397
406
 
398
- if (pathData[0].decimals) {
399
- //console.log('has dec');
400
- comShort.decimals = pathData[0].decimals
401
- }
402
-
403
- let pathDataShorts = [comShort];
407
+ pathDataShorts[0] = comShort;
404
408
 
405
409
  let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] };
406
410
  let p;
407
411
  let tolerance = 0.01
408
412
 
409
- for (let i = 1, len = pathData.length; i < len; i++) {
413
+ for (let i = 1; i < len; i++) {
410
414
 
411
415
  let com = pathData[i];
412
416
  let { type, values } = com;
413
- let valuesLast = values.slice(-2);
417
+ let valuesLen = values.length;
418
+ let valuesLast = [values[valuesLen-2], values[valuesLen-1]];
414
419
 
415
420
  // previoius command
416
421
  let comPrev = pathData[i - 1];
@@ -462,7 +467,8 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
462
467
  if (typePrev !== 'Q') {
463
468
  //console.log('skip T:', type, typePrev);
464
469
  p0 = { x: valuesLast[0], y: valuesLast[1] };
465
- pathDataShorts.push(com);
470
+ //pathDataShorts.push(com);
471
+ pathDataShorts[i] = com;
466
472
  continue;
467
473
  }
468
474
 
@@ -492,7 +498,9 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
492
498
 
493
499
  if (typePrev !== 'C') {
494
500
  //console.log('skip S', typePrev);
495
- pathDataShorts.push(com);
501
+ //pathDataShorts.push(com);
502
+ pathDataShorts[i] = com;
503
+
496
504
  p0 = { x: valuesLast[0], y: valuesLast[1] };
497
505
  continue;
498
506
  }
@@ -525,21 +533,22 @@ export function pathDataToShorthands(pathData, decimals = -1, test = true) {
525
533
  };
526
534
  }
527
535
 
528
-
529
536
  // add decimal info
530
537
  if (com.decimals || com.decimals === 0) {
531
538
  comShort.decimals = com.decimals
532
539
  }
533
540
 
534
-
535
541
  // round final values
536
542
  if (decimals > -1) {
537
543
  comShort.values = comShort.values.map(val => { return +val.toFixed(decimals) })
538
544
  }
539
545
 
540
546
  p0 = { x: valuesLast[0], y: valuesLast[1] };
541
- pathDataShorts.push(comShort);
547
+ pathDataShorts[i] = comShort;
548
+ //pathDataShorts.push(comShort);
542
549
  }
550
+
551
+ //console.log('pathDataShorts', pathDataShorts);
543
552
  return pathDataShorts;
544
553
  }
545
554
 
@@ -0,0 +1,65 @@
1
+ export function interpolatedPathData(pathData1, pathData2, t = 0.5) {
2
+
3
+ /**
4
+ * linear interpolation helper (LERP)
5
+ * respecting non-interpolatable
6
+ * Boolean values – required by arc commands
7
+ */
8
+ const interpolateValues = (values1 = [], values2 = [], t = 0) => {
9
+
10
+ // return start or end for t=0 or 1
11
+ if (t === 0) return values1;
12
+ if (t === 1) return values2;
13
+
14
+ let len = values1.length;
15
+ let isArc = len === 7;
16
+
17
+ // interpolated values: copy values1
18
+ let valuesI = values1.slice();
19
+
20
+ for (let i = 0; i < len; i++) {
21
+ let valI
22
+
23
+ // skip Boolean arc command values (largeArc and sweep)
24
+ if (isArc && (i === 3 || i === 4)) {
25
+ continue
26
+ }
27
+
28
+ // interpolate
29
+ valuesI[i] = (values2[i] - values1[i]) * t + values1[i];
30
+ }
31
+ return valuesI;
32
+ }
33
+
34
+
35
+ // interpolation impossible
36
+ if (pathData1.length !== pathData2.length) {
37
+ throw new Error("Paths are not compatible");
38
+ }
39
+
40
+
41
+ // interpolate command coordinates
42
+ let pathDataI = [];
43
+ pathData1.forEach((com, c) => {
44
+ let {
45
+ type,
46
+ values
47
+ } = com;
48
+ let [type2, values2] = [pathData2[c].type, pathData2[c].values];
49
+
50
+ // interpolate command values
51
+ let valuesInter = interpolateValues(values, values2, t);
52
+
53
+ pathDataI.push({
54
+ type: type,
55
+ values: valuesInter,
56
+ });
57
+ });
58
+
59
+ // serialize to "d" attribute string
60
+ let dInter = pathDataI.map(com => `${com.type} ${com.values.join(' ')}`).join(' ');
61
+ return {
62
+ pathData: pathDataI,
63
+ d: dInter
64
+ };
65
+ }
@@ -1,6 +1,7 @@
1
1
  //import { arcToBezier, quadratic2Cubic } from './convert.js';
2
2
  //import { getAngle, bezierhasExtreme, getDistance } from "./geometry";
3
3
  import { pathDataToAbsoluteOrRelative, pathDataToLonghands, pathDataArcsToCubics, pathDataQuadraticToCubic } from './pathData_convert.js';
4
+ import { pathDataToD } from './pathData_stringify.js';
4
5
 
5
6
 
6
7
 
@@ -15,10 +16,10 @@ export function normalizePathData(pathData = [],
15
16
  quadraticToCubic = false,
16
17
  arcToCubic = false,
17
18
  arcAccuracy = 2,
18
- } = {},
19
19
 
20
- {
20
+ // assume we need full normalization
21
21
  hasRelatives = true, hasShorthands = true, hasQuadratics = true, hasArcs = true, testTypes = false
22
+
22
23
  } = {}
23
24
  ) {
24
25
 
@@ -71,15 +72,29 @@ export function parsePathDataNormalized(d,
71
72
  ) {
72
73
 
73
74
 
74
- let pathDataObj = parsePathDataString(d);
75
- let { hasRelatives, hasShorthands, hasQuadratics, hasArcs } = pathDataObj;
76
- let pathData = pathDataObj.pathData;
75
+ // is already array
76
+ let isArray = Array.isArray(d);
77
+
78
+ // normalize native pathData to regular array
79
+ let hasConstructor = isArray && typeof d[0] === 'object' && typeof d[0].constructor === 'function'
80
+ /*
81
+ if (hasConstructor) {
82
+ d = d.map(com => { return { type: com.type, values: com.values } })
83
+ console.log('hasConstructor', hasConstructor, (typeof d[0].constructor), d);
84
+ }
85
+ */
86
+
87
+ let pathDataObj = isArray ? d : parsePathDataString(d);
88
+
89
+
90
+ let { hasRelatives = true, hasShorthands = true, hasQuadratics = true, hasArcs = true } = pathDataObj;
91
+ let pathData = hasConstructor ? pathDataObj : pathDataObj.pathData;
77
92
 
78
93
  // normalize
79
94
  pathData = normalizePathData(pathData,
80
- { toAbsolute, toLonghands, quadraticToCubic, arcToCubic, arcAccuracy },
81
- //{test:true}
82
- { hasRelatives, hasShorthands, hasQuadratics, hasArcs }
95
+ { toAbsolute, toLonghands, quadraticToCubic, arcToCubic, arcAccuracy,
96
+ hasRelatives, hasShorthands, hasQuadratics, hasArcs
97
+ },
83
98
  )
84
99
 
85
100
  return pathData;
@@ -450,7 +465,8 @@ export function parsePathDataString(d, debug = true) {
450
465
  if (debug === 'log') {
451
466
  console.log(feedback);
452
467
  } else {
453
- throw new Error(feedback)
468
+ //throw new Error(feedback)
469
+ console.warn(feedback)
454
470
  }
455
471
  }
456
472
 
@@ -1,22 +1,22 @@
1
1
  //import { pathDataToAbsoluteOrRelative, pathDataToLonghands, cubicToArc } from './pathData_convert.js';
2
2
  import { parsePathDataString, parsePathDataNormalized, stringifyPathData } from './pathData_parse.js';
3
3
 
4
- export function shapeElToPath(el){
4
+ export function shapeElToPath(el) {
5
5
 
6
6
  let nodeName = el.nodeName.toLowerCase();
7
- if(nodeName==='path')return el;
7
+ if (nodeName === 'path') return el;
8
8
 
9
9
  let pathData = getPathDataFromEl(el);
10
- let d = pathData.map(com=>{return `${com.type} ${com.values} `}).join(' ')
11
- let attributes = [...el.attributes].map(att=>att.name);
10
+ let d = pathData.map(com => { return `${com.type} ${com.values} ` }).join(' ')
11
+ let attributes = [...el.attributes].map(att => att.name);
12
12
 
13
13
  let pathN = document.createElementNS('http://www.w3.org/2000/svg', 'path');
14
- pathN.setAttribute('d', d );
14
+ pathN.setAttribute('d', d);
15
15
 
16
16
  let exclude = ['x', 'y', 'cx', 'cy', 'dx', 'dy', 'r', 'rx', 'ry', 'width', 'height', 'points']
17
17
 
18
- attributes.forEach(att=>{
19
- if(!exclude.includes(att)){
18
+ attributes.forEach(att => {
19
+ if (!exclude.includes(att)) {
20
20
  let val = el.getAttribute(att);
21
21
  pathN.setAttribute(att, val)
22
22
  }
@@ -29,7 +29,7 @@ export function shapeElToPath(el){
29
29
 
30
30
 
31
31
  // retrieve pathdata from svg geometry elements
32
- export function getPathDataFromEl(el, stringify=false) {
32
+ export function getPathDataFromEl(el, stringify = false) {
33
33
 
34
34
  let pathData = [];
35
35
  let type = el.nodeName;
@@ -190,7 +190,9 @@ export function getPathDataFromEl(el, stringify=false) {
190
190
  attNames = ['cx', 'cy', 'rx', 'ry', 'r'];
191
191
  ({ cx, cy, r, rx, ry } = getAtts(attNames));
192
192
 
193
- if (type === 'circle') {
193
+ let isCircle = type === 'circle';
194
+
195
+ if (isCircle) {
194
196
  r = r;
195
197
  rx = r
196
198
  ry = r
@@ -199,10 +201,14 @@ export function getPathDataFromEl(el, stringify=false) {
199
201
  ry = ry ? ry : r;
200
202
  }
201
203
 
204
+ // simplified radii for cirecles
205
+ let rxS = isCircle && r>=1 ? 1 : rx;
206
+ let ryS = isCircle && r>=1 ? 1 : rx;
207
+
202
208
  pathData = [
203
209
  { type: "M", values: [cx + rx, cy] },
204
- { type: "A", values: [rx, ry, 0, 1, 1, cx - rx, cy] },
205
- { type: "A", values: [rx, ry, 0, 1, 1, cx + rx, cy] },
210
+ { type: "A", values: [rxS, ryS, 0, 1, 1, cx - rx, cy] },
211
+ { type: "A", values: [rxS, ryS, 0, 1, 1, cx + rx, cy] },
206
212
  ];
207
213
 
208
214
  break;
@@ -234,6 +240,6 @@ export function getPathDataFromEl(el, stringify=false) {
234
240
  break;
235
241
  }
236
242
 
237
- return stringify ? stringifyPathData(pathData): pathData;
243
+ return stringify ? stringifyPathData(pathData) : pathData;
238
244
 
239
245
  };
@@ -3,21 +3,25 @@ import { getPolygonArea } from "./geometry_area.js";
3
3
  import { checkBezierFlatness, commandIsFlat } from "./geometry_flatness.js";
4
4
  import { renderPoint } from "./visualize.js";
5
5
 
6
- export function pathDataRemoveColinear(pathData, tolerance = 1, flatBezierToLinetos = true) {
6
+ export function pathDataRemoveColinear(pathData, {
7
+ tolerance = 1,
8
+ //toleranceCubics = null,
9
+ flatBezierToLinetos = true
10
+ }={}) {
7
11
 
12
+ //toleranceCubics = !toleranceCubics ? tolerance : toleranceCubics;
8
13
  let pathDataN = [pathData[0]];
9
14
 
10
-
11
- let lastType = 'L';
12
15
  let M = { x: pathData[0].values[0], y: pathData[0].values[1] }
13
16
  let p0 = M;
14
17
  let p = M
15
18
  let isClosed = pathData[pathData.length - 1].type.toLowerCase() === 'z'
16
19
 
17
20
  for (let c = 1, l = pathData.length; c < l; c++) {
18
- let comPrev = pathData[c - 1];
21
+ //let comPrev = pathData[c - 1];
19
22
  let com = pathData[c];
20
23
  let comN = pathData[c + 1] || pathData[l - 1];
24
+ //let p1 = comN.type.toLowerCase() === 'z' ? M : { x: comN.values[comN.values.length - 2], y: comN.values[comN.values.length - 1] }
21
25
  let p1 = comN.type.toLowerCase() === 'z' ? M : { x: comN.values[comN.values.length - 2], y: comN.values[comN.values.length - 1] }
22
26
 
23
27
  let { type, values } = com;
@@ -26,19 +30,18 @@ export function pathDataRemoveColinear(pathData, tolerance = 1, flatBezierToLine
26
30
 
27
31
  let area = getPolygonArea([p0, p, p1], true)
28
32
 
29
- let distSquare0 = getSquareDistance(p0, p)
30
- let distSquare1 = getSquareDistance(p, p1)
33
+ //let distSquare0 = getSquareDistance(p0, p)
34
+ //let distSquare1 = getSquareDistance(p, p1)
31
35
  let distSquare = getSquareDistance(p0, p1)
32
- //distSquare = (distSquare0+distSquare1) / 2;
36
+ //distSquare = (distSquare0+distSquare1) * 0.5
33
37
 
34
- let distMax = distSquare / 200 * tolerance
38
+ let distMax = distSquare ? distSquare / 333 * tolerance : 0
35
39
 
36
40
  let isFlat = area < distMax;
37
41
  let isFlatBez = false;
38
42
 
39
43
 
40
44
  if (!flatBezierToLinetos && type === 'C') isFlat = false;
41
- //let isFlat = flatBezierToLinetos && type === 'C' ? area < distMax : false
42
45
 
43
46
  // convert flat beziers to linetos
44
47
  if (flatBezierToLinetos && (type === 'C' || type === 'Q')) {
@@ -47,41 +50,41 @@ export function pathDataRemoveColinear(pathData, tolerance = 1, flatBezierToLine
47
50
  [{ x: values[0], y: values[1] }, { x: values[2], y: values[3] }] :
48
51
  (type === 'Q' ? [{ x: values[0], y: values[1] }] : []);
49
52
 
53
+ isFlatBez = commandIsFlat([p0, ...cpts, p],{tolerance});
50
54
 
51
- //let areaBez = getPolygonArea([p0, ...cpts, p], true)
52
-
53
- isFlatBez = checkBezierFlatness(p0, cpts, p)
54
- //isFlatBez = commandIsFlat([p0, ...cpts, p]).flat
55
- // console.log();
56
-
57
- //isFlatBez = areaBez < distMax * 0.25
58
- //console.log('isFlatBez', isFlatBez);
59
- //isFlatBez = false
60
-
61
- //&& comPrev.type !== 'C'
62
- if (isFlatBez && c < l - 1 && comPrev.type !== 'C') {
55
+ if (isFlatBez && c < l - 1 ) {
63
56
  type = "L"
64
57
  com.type = "L"
65
58
  com.values = valsL
66
-
67
- //renderPoint(markers, p)
59
+ //renderPoint(markers, p, 'cyan', '1%', '0.5')
68
60
  }
69
-
70
61
  }
71
62
 
72
- // update end point
73
- p0 = p;
74
63
 
75
64
  // colinear – exclude arcs (as always =) as semicircles won't have an area
76
65
  //&& comN.type==='L'
77
66
  if ( isFlat && c < l - 1 && (type === 'L' || (flatBezierToLinetos && isFlatBez)) ) {
78
- //console.log(area,distMax );
79
- //renderPoint(markers, p)
80
67
 
68
+ /*
69
+ console.log(area, distMax );
81
70
  //if(comN.type!=='L' ){}
71
+
72
+ if(p0.x === p.x && p0.y === p.y){
73
+
74
+ }
75
+
76
+ renderPoint(markers, p0, 'blue', '1.5%', '1')
77
+ renderPoint(markers, p, 'red', '1%', '1')
78
+ renderPoint(markers, p1, 'cyan', '0.5%', '1')
79
+ */
80
+
81
+
82
82
  continue;
83
83
  }
84
84
 
85
+ // update end point
86
+ p0 = p;
87
+
85
88
 
86
89
  if (type === 'M') {
87
90
  M = p
@@ -1,5 +1,6 @@
1
1
  export function removeOrphanedM(pathData) {
2
2
 
3
+ let pathDataN = []
3
4
  for (let i = 0, l = pathData.length; i < l; i++) {
4
5
  let com = pathData[i];
5
6
  if (!com) continue;
@@ -8,13 +9,13 @@ export function removeOrphanedM(pathData) {
8
9
  if ((type === 'M' || type === 'm')) {
9
10
 
10
11
  if (!comN || (comN && (comN.type === 'Z' || comN.type === 'z'))) {
11
- pathData[i] = null
12
- pathData[i + 1] = null
12
+ if(comN) i++
13
+ continue
13
14
  }
14
15
  }
16
+ pathDataN.push(com)
15
17
  }
16
18
 
17
- pathData = pathData.filter(Boolean);
18
- return pathData;
19
+ return pathDataN;
19
20
 
20
21
  }
@@ -26,20 +26,24 @@ export function removeZeroLengthLinetos(pathData) {
26
26
 
27
27
  for (let c = 1, l = pathData.length; c < l; c++) {
28
28
  let com = pathData[c];
29
+ let comPrev = pathData[c-1]
30
+ let comNext = pathData[c+1] || null
29
31
  let { type, values } = com;
30
32
 
33
+ // zero length segments are simetimes used in icons for dots
34
+ let isDot = comPrev.type.toLowerCase() ==='m' && !comNext;
35
+
31
36
  let valsLen = values.length;
32
- //let valsL = values.slice(-2);
33
- //p = { x: valsL[0], y: valsL[1] };
34
37
  p = { x: values[valsLen-2], y: values[valsLen-1] };
35
38
 
36
39
  // skip lineto
37
- if (type === 'L' && p.x === p0.x && p.y === p0.y) {
40
+ if (!isDot && type === 'L' && p.x === p0.x && p.y === p0.y) {
38
41
  continue
39
42
  }
40
43
 
44
+
41
45
  // skip minified zero length
42
- if (type === 'l' || type === 'v' || type === 'h') {
46
+ if (!isDot && (type === 'l' || type === 'v' || type === 'h')) {
43
47
  let noLength = type === 'l' ? (values.join('') === '00') : values[0] === 0;
44
48
  if(noLength) continue
45
49
  }
@@ -14,6 +14,8 @@ export function pathDataToTopLeft(pathData) {
14
14
  let len = pathData.length;
15
15
  let isClosed = pathData[len - 1].type.toLowerCase() === 'z'
16
16
 
17
+ //return pathData;
18
+
17
19
  // we can't change starting point for non closed paths
18
20
  if (!isClosed) {
19
21
  return pathData
@@ -54,6 +56,8 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
54
56
 
55
57
  let linetos = pathData.filter(com => com.type === 'L')
56
58
 
59
+ //return pathData;
60
+
57
61
 
58
62
  // check if order is ideal
59
63
  let penultimateCom = pathData[len - 2];
@@ -107,7 +111,7 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
107
111
  }
108
112
  // use top most command
109
113
  else {
110
- indices = indices.sort((a, b) => +a.y.toFixed(1) - +b.y.toFixed(1) || a.x - b.x);
114
+ indices = indices.sort((a, b) => +a.y.toFixed(8) - +b.y.toFixed(8) || a.x - b.x);
111
115
  newIndex = indices[0].index
112
116
  }
113
117
 
@@ -116,7 +120,7 @@ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder =
116
120
  }
117
121
 
118
122
 
119
- M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(7) }
123
+ M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(8) }
120
124
 
121
125
  len = pathData.length
122
126