svg-path-simplify 0.0.2 → 0.0.5

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.
@@ -7,12 +7,47 @@ import { renderPoint, renderPath } from './visualize.js';
7
7
  import { getPolygonArea } from './geometry_area.js';
8
8
 
9
9
 
10
+ export function pathDataToTopLeft(pathData) {
11
+
12
+ let len = pathData.length;
13
+ let isClosed = pathData[len - 1].type.toLowerCase() === 'z'
14
+
15
+ // we can't change starting point for non closed paths
16
+ if (!isClosed) {
17
+ return pathData
18
+ }
19
+
20
+ let newIndex = 0;
21
+
22
+ //get top most index
23
+ let indices = [];
24
+ for (let i = 0; i < len; i++) {
25
+ let com = pathData[i];
26
+ let { type, values } = com;
27
+ let valsLen = values.length
28
+ if (valsLen) {
29
+ let p = { type: type, x: values[valsLen-2], y: values[valsLen-1], index: 0}
30
+ p.index = i
31
+ indices.push(p)
32
+ }
33
+ }
34
+
35
+ // reorder to top left most
36
+ //|| a.x - b.x
37
+ indices = indices.sort((a, b) => +a.y.toFixed(3) - +b.y.toFixed(3) );
38
+ newIndex = indices[0].index
39
+
40
+ return newIndex ? shiftSvgStartingPoint(pathData, newIndex) : pathData;
41
+ }
10
42
 
11
- export function pathDataToTopLeft(pathData, removeFinalLineto = false, reorder = true) {
43
+
44
+
45
+
46
+ export function optimizeClosePath(pathData, removeFinalLineto = true, reorder = true) {
12
47
 
13
48
  let pathDataNew = [];
14
49
  let len = pathData.length;
15
- let M = { x: pathData[0].values[0], y: pathData[0].values[1] }
50
+ let M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(8) }
16
51
  let isClosed = pathData[len - 1].type.toLowerCase() === 'z'
17
52
 
18
53
  let linetos = pathData.filter(com => com.type === 'L')
@@ -21,18 +56,18 @@ export function pathDataToTopLeft(pathData, removeFinalLineto = false, reorder =
21
56
  // check if order is ideal
22
57
  let penultimateCom = pathData[len - 2];
23
58
  let penultimateType = penultimateCom.type;
24
- let penultimateComCoords = penultimateCom.values.slice(-2).map(val=>+val.toFixed(8))
59
+ let penultimateComCoords = penultimateCom.values.slice(-2).map(val => +val.toFixed(8))
25
60
 
26
61
  // last L command ends at M
27
- let isClosingCommand = penultimateComCoords[0] === M.x && penultimateComCoords[1] === M.y
62
+ let isClosingCommand = penultimateComCoords[0] === M.x && penultimateComCoords[1] === M.y
28
63
 
29
64
  // if last segment is not closing or a lineto
30
- let skipReorder = pathData[1].type!=='L' && (!isClosingCommand || penultimateType==='L' )
31
- skipReorder=false
65
+ let skipReorder = pathData[1].type !== 'L' && (!isClosingCommand || penultimateType === 'L')
66
+ skipReorder = false
32
67
 
33
68
 
34
69
  // we can't change starting point for non closed paths
35
- if (!isClosed ) {
70
+ if (!isClosed) {
36
71
  return pathData
37
72
  }
38
73
 
@@ -62,15 +97,15 @@ export function pathDataToTopLeft(pathData, removeFinalLineto = false, reorder =
62
97
  // find top most lineto
63
98
 
64
99
  if (linetos.length) {
65
- let curveAfterLine = indices.filter(com => (com.type !== 'L' && com.type !== 'M') && com.prevCom &&
66
- com.prevCom === 'L' || com.prevCom==='M' && penultimateType==='L' ).sort((a, b) => a.y - b.y || a.x-b.x)[0]
100
+ let curveAfterLine = indices.filter(com => (com.type !== 'L' && com.type !== 'M') && com.prevCom &&
101
+ com.prevCom === 'L' || com.prevCom === 'M' && penultimateType === 'L').sort((a, b) => a.y - b.y || a.x - b.x)[0]
67
102
 
68
103
  newIndex = curveAfterLine ? curveAfterLine.index - 1 : 0
69
104
 
70
105
  }
71
106
  // use top most command
72
107
  else {
73
- indices = indices.sort((a, b) => +a.y.toFixed(1) - +b.y.toFixed(1) || a.x - b.x );
108
+ indices = indices.sort((a, b) => +a.y.toFixed(1) - +b.y.toFixed(1) || a.x - b.x);
74
109
  newIndex = indices[0].index
75
110
  }
76
111
 
@@ -79,15 +114,19 @@ export function pathDataToTopLeft(pathData, removeFinalLineto = false, reorder =
79
114
  }
80
115
 
81
116
 
117
+ M = { x: +pathData[0].values[0].toFixed(8), y: +pathData[0].values[1].toFixed(7) }
118
+
82
119
  len = pathData.length
83
120
 
84
121
  // remove last lineto
85
122
  penultimateCom = pathData[len - 2];
86
123
  penultimateType = penultimateCom.type;
87
- penultimateComCoords = penultimateCom.values.slice(-2)
124
+ penultimateComCoords = penultimateCom.values.slice(-2).map(val=>+val.toFixed(8))
88
125
 
89
126
  isClosingCommand = penultimateType === 'L' && penultimateComCoords[0] === M.x && penultimateComCoords[1] === M.y
90
127
 
128
+ //console.log('penultimateCom', isClosingCommand, penultimateCom.values, M);
129
+
91
130
  if (removeFinalLineto && isClosingCommand) {
92
131
  pathData.splice(len - 2, 1)
93
132
  }
@@ -8,25 +8,27 @@ export function pathDataToD(pathData, optimize = 0) {
8
8
 
9
9
  optimize = parseFloat(optimize)
10
10
 
11
+
12
+
13
+ let len = pathData.length;
11
14
  let beautify = optimize > 1;
12
15
  let minify = beautify || optimize ? false : true;
13
16
 
14
17
  // Convert first "M" to "m" if followed by "l" (when minified)
18
+ /*
15
19
  if (pathData[1].type === "l" && minify) {
16
20
  pathData[0].type = "m";
17
21
  }
22
+ */
18
23
 
19
24
  let d = '';
20
- let suff = beautify ? `\n` : ' ';
25
+ let separator_command = beautify ? `\n` : (minify ? '' : ' ');
26
+ let separator_type = !minify ? ' ' : '';
21
27
 
28
+ d = `${pathData[0].type}${separator_type}${pathData[0].values.join(" ")}${separator_command}`;
22
29
 
23
- if (minify) {
24
- d = `${pathData[0].type} ${pathData[0].values.join(" ")}`;
25
- } else {
26
- d = `${pathData[0].type} ${pathData[0].values.join(" ")}${suff}`;
27
- }
28
30
 
29
- for (let i = 1, len = pathData.length; i < len; i++) {
31
+ for (let i = 1; i < len; i++) {
30
32
  let com0 = pathData[i - 1];
31
33
  let com = pathData[i];
32
34
  let { type, values } = com;
@@ -44,8 +46,6 @@ export function pathDataToD(pathData, optimize = 0) {
44
46
  type = (com0.type === com.type && com.type.toLowerCase() !== 'm' && minify)
45
47
  ? " "
46
48
  : (
47
- (com0.type === "m" && com.type === "l") ||
48
- (com0.type === "M" && com.type === "l") ||
49
49
  (com0.type === "M" && com.type === "L")
50
50
  ) && minify
51
51
  ? " "
@@ -79,17 +79,16 @@ export function pathDataToD(pathData, optimize = 0) {
79
79
  //console.log(isSmallFloat, prevWasFloat, valStr);
80
80
 
81
81
  valsString += valStr
82
- //.replace(/-0./g, '-.').replace(/ -./g, '-.')
83
82
  prevWasFloat = isSmallFloat;
84
83
  }
85
84
 
86
85
  //console.log('minify', valsString);
87
- d += `${type}${valsString}`;
86
+ d += `${type}${separator_type}${valsString}${separator_command}`;
88
87
 
89
88
  }
90
89
  // regular non-minified output
91
90
  else {
92
- d += `${type} ${values.join(' ')}${suff}`;
91
+ d += `${type}${separator_type}${values.join(' ')}${separator_command}`;
93
92
  }
94
93
  }
95
94
 
@@ -21,6 +21,8 @@ export function detectAccuracy(pathData) {
21
21
 
22
22
  //console.log('detectAccuracy');
23
23
 
24
+ let dims = new Set();
25
+
24
26
  // add average distances
25
27
  for (let i = 0, len = pathData.length; i < len; i++) {
26
28
  let com = pathData[i];
@@ -34,8 +36,10 @@ export function detectAccuracy(pathData) {
34
36
  //let dimA = +getDistAv(p0, p).toFixed(8)
35
37
  //console.log('dimA', dimA, com.dimA, type);
36
38
 
39
+ if(dimA) dims.add(dimA);
40
+
37
41
  if(dimA && dimA<minDim) minDim = dimA;
38
- //if(dimA && dimA>maxDim) maxDim = dimA;
42
+ if(dimA && dimA>maxDim) maxDim = dimA;
39
43
 
40
44
 
41
45
  if(type==='M'){
@@ -44,9 +48,15 @@ export function detectAccuracy(pathData) {
44
48
  p0 = p;
45
49
  }
46
50
 
47
- //minDim = +minDim.toFixed(8)
48
- let decimalsAuto = Math.floor(50 / minDim).toString().length
49
- //console.log('!!!minDim', minDim, 'maxDim', maxDim, decimalsAuto);
51
+
52
+ let dim_min = Array.from(dims).sort()
53
+ let sliceIdx = Math.ceil(dim_min.length/8);
54
+ dim_min = dim_min.slice(0, sliceIdx );
55
+
56
+ let dimVal = dim_min.reduce((a,b)=>a+b, 0) / sliceIdx;
57
+
58
+ let threshold = 50
59
+ let decimalsAuto = dimVal > threshold ? 0 : Math.floor(threshold / dimVal).toString().length
50
60
 
51
61
  // clamp
52
62
  return Math.min(Math.max(0, decimalsAuto), 8)
@@ -55,8 +65,6 @@ export function detectAccuracy(pathData) {
55
65
 
56
66
 
57
67
 
58
-
59
-
60
68
  export function detectAccuracy_back(pathData) {
61
69
 
62
70
  // Reference first MoveTo command (M)
@@ -1,4 +1,8 @@
1
- export function cleanUpSVG(svgMarkup, removeHidden=true) {
1
+ export function cleanUpSVG(svgMarkup, {
2
+ returnDom=false,
3
+ removeHidden=true,
4
+ removeUnused=true,
5
+ }={}) {
2
6
  svgMarkup = cleanSvgPrologue(svgMarkup);
3
7
 
4
8
  // replace namespaced refs
@@ -29,6 +33,8 @@ export function cleanUpSVG(svgMarkup, removeHidden=true) {
29
33
  }
30
34
  })
31
35
 
36
+ if(returnDom) return svg
37
+
32
38
  let markup = stringifySVG(svg)
33
39
  console.log(markup);
34
40