svg-path-simplify 0.0.5 → 0.0.8

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.
@@ -11,7 +11,7 @@ export function detectAccuracy(pathData) {
11
11
 
12
12
  // Reference first MoveTo command (M)
13
13
  let M = { x: pathData[0].values[0], y: pathData[0].values[1] };
14
- let p0 = M
14
+ let p0 = M
15
15
  let p = M
16
16
  pathData[0].decimals = 0
17
17
  let lastDec = 0;
@@ -29,34 +29,40 @@ export function detectAccuracy(pathData) {
29
29
  let { type, values } = com;
30
30
 
31
31
  let lastVals = values.length ? values.slice(-2) : [M.x, M.y];
32
- p={x:lastVals[0], y:lastVals[1]}
32
+ p = { x: lastVals[0], y: lastVals[1] }
33
33
 
34
34
  // use existing averave dimension value or calculate
35
- let dimA = com.dimA ? +com.dimA.toFixed(8) : type!=='M' ? +getDistAv(p0, p).toFixed(8) : 0
35
+ let dimA = com.dimA ? +com.dimA.toFixed(8) : type !== 'M' ? +getDistAv(p0, p).toFixed(8) : 0
36
36
  //let dimA = +getDistAv(p0, p).toFixed(8)
37
37
  //console.log('dimA', dimA, com.dimA, type);
38
38
 
39
- if(dimA) dims.add(dimA);
39
+ if (dimA) dims.add(dimA);
40
+
41
+ if (dimA && dimA < minDim) minDim = dimA;
42
+ if (dimA && dimA > maxDim) maxDim = dimA;
40
43
 
41
- if(dimA && dimA<minDim) minDim = dimA;
42
- if(dimA && dimA>maxDim) maxDim = dimA;
43
-
44
44
 
45
- if(type==='M'){
46
- M=p;
45
+ if (type === 'M') {
46
+ M = p;
47
47
  }
48
48
  p0 = p;
49
49
  }
50
50
 
51
51
 
52
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
53
 
56
- let dimVal = dim_min.reduce((a,b)=>a+b, 0) / sliceIdx;
54
+ /*
55
+ let minVal = dim_min.length > 15 ?
56
+ (dim_min[0] + dim_min[2]) / 2 :
57
+ dim_min[0];
58
+ */
59
+
60
+ let sliceIdx = Math.ceil(dim_min.length / 10);
61
+ dim_min = dim_min.slice(0, sliceIdx);
62
+ let minVal = dim_min.reduce((a, b) => a + b, 0) / sliceIdx;
57
63
 
58
- let threshold = 50
59
- let decimalsAuto = dimVal > threshold ? 0 : Math.floor(threshold / dimVal).toString().length
64
+ let threshold = 40
65
+ let decimalsAuto = minVal > threshold*1.5 ? 0 : Math.floor(threshold / minVal).toString().length
60
66
 
61
67
  // clamp
62
68
  return Math.min(Math.max(0, decimalsAuto), 8)
@@ -145,16 +151,16 @@ export function roundPathData(pathData, decimals = -1) {
145
151
  let hasDecimal = decimals == 'auto' && pathData[0].hasOwnProperty('decimals') ? true : false;
146
152
  //console.log('decimals', decimals, hasDecimal);
147
153
 
148
- for(let c=0, len=pathData.length; c<len; c++){
149
- let com=pathData[c];
150
- let {type, values} = com
154
+ for (let c = 0, len = pathData.length; c < len; c++) {
155
+ let com = pathData[c];
156
+ let { type, values } = com
151
157
 
152
- if (decimals >-1 || hasDecimal) {
158
+ if (decimals > -1 || hasDecimal) {
153
159
  decimals = hasDecimal ? com.decimals : decimals;
154
160
 
155
161
 
156
162
  //console.log('decimals', type, decimals);
157
- pathData[c].values = com.values.map(val=>{return val ? +val.toFixed(decimals) : val });
163
+ pathData[c].values = com.values.map(val => { return val ? +val.toFixed(decimals) : val });
158
164
 
159
165
  }
160
166
  };
@@ -0,0 +1,173 @@
1
+ import { getCombinedByDominant } from "../pathData_simplify_cubic_extrapolate";
2
+ import { getDistAv, interpolate } from "./geometry";
3
+ import { getPathArea } from "./geometry_area";
4
+ import { getPathDataBBox } from "./geometry_bbox";
5
+ import { renderPoint } from "./visualize";
6
+
7
+ export function refineAdjacentExtremes(pathData, {
8
+ threshold = null, tolerance = 1
9
+ } = {}) {
10
+
11
+ //dimA = dimA ? dimA :
12
+ if (!threshold) {
13
+ let bb = getPathDataBBox(pathData);
14
+ threshold = (bb.width + bb.height) / 2 * 0.05
15
+ //console.log('new threshold', threshold);
16
+ }
17
+
18
+ let l = pathData.length
19
+
20
+ for (let i = 0; i < l; i++) {
21
+ let com = pathData[i];
22
+ let { type, values, extreme, corner=false, dimA, p0, p } = com;
23
+ let comN = pathData[i + 1] ? pathData[i + 1] : null;
24
+
25
+
26
+ // adjacent
27
+ //&& comN.extreme
28
+ if (comN && type === 'C' && comN.type === 'C' && extreme && !corner) {
29
+
30
+ // check dist
31
+ let diff = getDistAv(p, comN.p)
32
+ let isCose = diff < threshold;
33
+
34
+
35
+ if (isCose) {
36
+ //renderPoint(markers, comN.p, 'cyan', '1%', '0.5')
37
+ //console.log(comN);
38
+ //console.log(diff, threshold);
39
+
40
+ let dx1 = (com.cp1.x - comN.p0.x)
41
+ let dy1 = (com.cp1.y - comN.p0.y)
42
+
43
+ let horizontal = Math.abs(dy1) < Math.abs(dx1);
44
+
45
+ let pN = comN.p;
46
+ let ptI;
47
+ let t = 1;
48
+
49
+ if (comN.extreme) {
50
+
51
+ // extend cp2
52
+ if (horizontal) {
53
+ t = Math.abs(Math.abs(comN.cp2.x - comN.p.x) / Math.abs(com.cp2.x - com.p.x))
54
+ //console.log('t', t);
55
+ ptI = interpolate(comN.p, com.cp2, 1 + t)
56
+ com.cp2.x = ptI.x
57
+ //renderPoint(markers, com.cp2, 'cyan', '1%', '0.5')
58
+ //renderPoint(markers, ptI, 'orange', '1%', '0.5')
59
+ }
60
+ else {
61
+ //renderPoint(markers, comN.p0, 'cyan', '1%', '0.5')
62
+ t = Math.abs(Math.abs(comN.cp2.y - comN.p.y) / Math.abs(com.cp2.y - com.p.y))
63
+ ptI = interpolate(comN.p, com.cp2, 1 + t)
64
+ com.cp2.y = ptI.y
65
+ }
66
+
67
+ //merge commands
68
+ pathData[i + 1].values = [com.cp1.x, com.cp1.y, com.cp2.x, com.cp2.y, pN.x, pN.y]
69
+ pathData[i + 1].cp1 = com.cp1
70
+ pathData[i + 1].cp2 = com.cp2
71
+ pathData[i + 1].p0 = com.p0
72
+ pathData[i + 1].p = pN
73
+ pathData[i + 1].extreme = true
74
+
75
+ // nullify 1st
76
+ pathData[i] = null;
77
+ continue
78
+
79
+ }
80
+
81
+ // extend fist command
82
+ else {
83
+
84
+ let comN2 = pathData[i + 2] ? pathData[i + 2] : null;
85
+ if (!comN2 && comN2.type !== 'C') continue
86
+
87
+ //continue
88
+
89
+ // extrapolate
90
+ let comEx = getCombinedByDominant(comN, comN2, threshold, tolerance, false)
91
+ //console.log('comEx', comEx);
92
+
93
+ if (comEx.length === 1) {
94
+ pathData[i + 1] = null;
95
+
96
+ comEx = comEx[0]
97
+
98
+ pathData[i + 2].values = [comEx.cp1.x, comEx.cp1.y, comEx.cp2.x, comEx.cp2.y, comEx.p.x, comEx.p.y]
99
+ pathData[i + 2].cp1 = comEx.cp1
100
+ pathData[i + 2].cp2 = comEx.cp2
101
+ pathData[i + 2].p0 = comEx.p0
102
+ pathData[i + 2].p = comEx.p
103
+ pathData[i + 2].extreme = comEx.extreme
104
+
105
+ i++
106
+ continue
107
+ }
108
+
109
+ }
110
+
111
+ }
112
+ }
113
+ }
114
+
115
+ // remove commands
116
+ pathData = pathData.filter(Boolean)
117
+ l = pathData.length
118
+
119
+
120
+
121
+ /**
122
+ * refine closing commands
123
+ */
124
+
125
+ let closed = pathData[l - 1].type.toLowerCase() === 'z';
126
+ let lastIdx = closed ? l - 2 : l - 1;
127
+ let lastCom = pathData[lastIdx];
128
+ let penultimateCom = pathData[lastIdx - 1] || null;
129
+ let M = { x: pathData[0].values[0], y: pathData[0].values[1] }
130
+
131
+ let dec = 8
132
+ let lastVals = lastCom.values.slice(-2);
133
+ let isClosingTo = +lastVals[0].toFixed(dec) === +M.x.toFixed(dec) && +lastVals[1].toFixed(dec) === +M.y.toFixed(dec)
134
+ let fistExt = pathData[1].type === 'C' && pathData[1].extreme ? pathData[1] : null;
135
+
136
+
137
+ //renderPoint(markers, M, 'blue')
138
+ //renderPoint(markers, fistExt.cp1, 'blue')
139
+ //renderPoint(markers, fistExt.p0, 'blue')
140
+
141
+
142
+
143
+ let diff = getDistAv(lastCom.p0, lastCom.p)
144
+ let isCose = diff < threshold;
145
+
146
+
147
+ if (penultimateCom && penultimateCom.type === 'C' && isCose && isClosingTo && fistExt) {
148
+
149
+ let dx1 = Math.abs(fistExt.cp1.x - M.x)
150
+ let dy1 = Math.abs(fistExt.cp1.y - M.y)
151
+
152
+ let horizontal = dy1 < dx1;
153
+ //console.log(dx1, dx2);
154
+ //console.log('isCose', isCose, diff, dimA);
155
+
156
+ let comEx = getCombinedByDominant(penultimateCom, lastCom, threshold, tolerance, false)
157
+ console.log('comEx', comEx);
158
+
159
+ if (comEx.length === 1) {
160
+ pathData[lastIdx - 1] = comEx[0];
161
+ pathData[lastIdx] = null;
162
+ pathData = pathData.filter(Boolean)
163
+ }
164
+
165
+
166
+ }
167
+
168
+
169
+ //console.log('pathData ex', pathData);
170
+
171
+ return pathData
172
+
173
+ }
@@ -1,3 +1,15 @@
1
+
2
+
3
+
4
+ export function removeEmptySVGEls(svg) {
5
+ let els = svg.querySelectorAll('g, defs');
6
+ els.forEach(el => {
7
+ if (!el.children.length) el.remove()
8
+ })
9
+ }
10
+
11
+
12
+
1
13
  export function cleanUpSVG(svgMarkup, {
2
14
  returnDom=false,
3
15
  removeHidden=true,
@@ -13,7 +25,7 @@ export function cleanUpSVG(svgMarkup, {
13
25
  .querySelector("svg");
14
26
 
15
27
 
16
- let allowed=['viewBox', 'xmlns', 'width', 'height', 'id', 'class'];
28
+ let allowed=['viewBox', 'xmlns', 'width', 'height', 'id', 'class', 'fill', 'stroke', 'stroke-width'];
17
29
  removeExcludedAttribues(svg, allowed)
18
30
 
19
31
  let removeEls = ['metadata', 'script']
@@ -74,7 +86,7 @@ function removeNameSpaceAtts(el) {
74
86
  });
75
87
  }
76
88
 
77
- function stringifySVG(svg){
89
+ export function stringifySVG(svg){
78
90
  let markup = new XMLSerializer().serializeToString(svg);
79
91
  markup = markup
80
92
  .replace(/\t/g, "")
package/test.js ADDED
@@ -0,0 +1,14 @@
1
+ import { svgPathSimplify } from 'svg-path-simplify';
2
+
3
+ let pathDataString =
4
+ `
5
+ M 57.13 15.5
6
+ c 13.28 0 24.53 8.67 28.42 20.65
7
+ c 0.94 2.91 1.45 6.01 1.45 9.23
8
+ `
9
+
10
+ // try to simplify
11
+ let pathDataOpt = svgPathSimplify(pathDataString);
12
+
13
+ // simplified pathData
14
+ console.log(pathDataOpt)
package/testSVG.js ADDED
@@ -0,0 +1,39 @@
1
+ // add suport for DOM manipulations
2
+ import { DOMParser, parseHTML } from 'linkedom';
3
+ //import { XMLSerializerPoly, DOMParserPoly } from 'svg-path-simplify/dom_polyfills.js';
4
+ import { svgPathSimplify } from 'svg-path-simplify';
5
+
6
+
7
+
8
+
9
+ let svgMarkup =
10
+ `<?xml version="1.0" encoding="utf-8"?>
11
+ <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
12
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
13
+ <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px"
14
+ height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
15
+ <g id="garamond">
16
+ <path id="path1" d="M16.2 125.7 L16.2 125.7 Q12.1 125.7 8.4 123.8 Q4.6 122 2.3 119.1 Q0 116.2 0.2 113.1 L0.2 113.1 L0.4 112.6 Q2.2 111.2 5 109.3 Q7.8 107.4 11.4 105.1 Q15 102.8 19.1 100.4 L19.1 100.4 L19.2 99.5 Q16.8 98.1 15.5 94.7 Q14.1 91.3 14.1 86.7 L14.1 86.7 Q14.1 81.1 16 75.5 Q17.9 70 21.1 65.5 Q24.2 61 28.1 58.3 Q32 55.6 35.9 55.6 L35.9 55.6 L46.1 57.2 L47.2 54.7 L47.7 54.6 L50.8 56.1 L51.6 57 Q49.2 61.4 47.6 65.1 Q45.9 68.9 45 72 Q44 75.1 43.7 77.8 L43.7 77.8 Q43.4 80.3 43.2 83.7 Q43 87.1 42.8 90.6 Q42.6 94.2 42.5 97.1 Q42.3 100.1 42.1 101.6 L42.1 101.6 Q41.7 105.1 40 108.5 Q38.2 112 35.6 115.1 Q32.9 118.2 29.7 120.6 Q26.5 123 23 124.3 Q19.5 125.7 16.2 125.7 ZM19.5 119.9 L19.5 119.9 Q25.9 119.9 30.4 115.3 Q34.9 110.7 35.9 102.7 L35.9 102.7 L38.4 82 L37.6 81.8 Q34.5 87.5 32.3 91 Q30 94.6 28 96.8 Q25.9 99 23.5 100.8 L23.5 100.8 Q20.4 103.1 16.8 105.3 Q13.2 107.6 10.7 109.4 Q8.1 111.3 8.1 112.3 L8.1 112.3 Q8.1 114 9.9 115.8 Q11.6 117.5 14.3 118.7 Q16.9 119.9 19.5 119.9 ZM24.8 92.9 L24.8 92.9 Q26.3 92.9 29 89.4 Q31.6 86 35.2 79.5 Q38.7 73.1 42.9 64.1 L42.9 64.1 Q40.9 63.1 39.1 62.4 Q37.2 61.7 35.7 61.3 Q34.1 61 32.8 61 L32.8 61 Q29.8 61 27.1 64 Q24.4 67.1 22.7 71.9 Q21 76.7 21 82 L21 82 Q21 86.3 22.2 89.6 Q23.3 92.9 24.8 92.9 Z "/>
17
+ </g>
18
+ </svg>`
19
+
20
+
21
+ /*
22
+ */
23
+ let document = new DOMParser().parseFromString(svgMarkup, 'image/svg+xml');
24
+ let svg = document.querySelector('svg');
25
+ let path = svg.querySelector('path');
26
+ let d = path.getAttribute('d')
27
+
28
+ let markup = document.toString()
29
+ markup = new XMLSerializer().serializeToString(svg)
30
+
31
+ console.log(markup);
32
+
33
+ /*
34
+ // try to simplify
35
+ let svgOpt = svgPathSimplify(svgMarkup);
36
+
37
+ // simplified pathData
38
+ console.log(svgOpt)
39
+ */