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.
- package/README.md +193 -11
- package/dist/svg-path-simplify.esm.js +890 -263
- package/dist/svg-path-simplify.esm.min.js +1 -1
- package/dist/svg-path-simplify.js +889 -263
- package/dist/svg-path-simplify.min.js +1 -1
- package/dist/svg-path-simplify.node.js +889 -263
- package/dist/svg-path-simplify.node.min.js +1 -1
- package/index.html +16 -8
- package/package.json +6 -3
- package/src/detect_input.js +2 -0
- package/src/dom-polyfill.js +29 -0
- package/src/dom-polyfill_back.js +22 -0
- package/src/index.js +11 -5
- package/src/pathData_simplify_cubic.js +1 -37
- package/src/pathData_simplify_cubic_extrapolate.js +45 -27
- package/src/pathSimplify-main.js +163 -68
- package/src/svgii/geometry.js +8 -155
- package/src/svgii/geometry_flatness.js +101 -0
- package/src/svgii/pathData_analyze.js +11 -596
- package/src/svgii/pathData_convert.js +7 -3
- package/src/svgii/pathData_parse_els.js +239 -0
- package/src/svgii/pathData_remove_collinear.js +13 -3
- package/src/svgii/pathData_remove_orphaned.js +20 -0
- package/src/svgii/pathData_remove_zerolength.js +28 -2
- package/src/svgii/pathData_reorder.js +3 -1
- package/src/svgii/pathData_split.js +5 -0
- package/src/svgii/pathData_toPolygon.js +98 -47
- package/src/svgii/poly_analyze.js +20 -16
- package/src/svgii/rounding.js +25 -19
- package/src/svgii/simplify_refineExtremes.js +173 -0
- package/src/svgii/svg_cleanup.js +14 -2
- package/test.js +14 -0
- package/testSVG.js +39 -0
- /package/src/svgii/{simplify_polygon.js → polygon_unite.js} +0 -0
|
@@ -3,7 +3,7 @@ import { getPathArea } from "./svgii/geometry_area";
|
|
|
3
3
|
import { pathDataToD } from "./svgii/pathData_stringify";
|
|
4
4
|
import { renderPath, renderPoint } from "./svgii/visualize";
|
|
5
5
|
|
|
6
|
-
export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
6
|
+
export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1, debug = false) {
|
|
7
7
|
|
|
8
8
|
// cubic Bézier derivative
|
|
9
9
|
const cubicDerivative = (p0, p1, p2, p3, t) => {
|
|
@@ -27,8 +27,10 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
27
27
|
let commands = [com1, com2]
|
|
28
28
|
|
|
29
29
|
// detect dominant
|
|
30
|
-
let dist1 =
|
|
31
|
-
let dist2 =
|
|
30
|
+
let dist1 = getDistAv(com1.p0, com1.p)
|
|
31
|
+
let dist2 = getDistAv(com2.p0, com2.p)
|
|
32
|
+
|
|
33
|
+
|
|
32
34
|
let reverse = dist1 > dist2;
|
|
33
35
|
|
|
34
36
|
//let ang1 = getAngle(com1.p0, com1.cp1)
|
|
@@ -42,6 +44,7 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
42
44
|
|
|
43
45
|
if (!ptI) {
|
|
44
46
|
//renderPoint(markers, com1.p, 'purple')
|
|
47
|
+
//console.log('nope');
|
|
45
48
|
return commands
|
|
46
49
|
}
|
|
47
50
|
|
|
@@ -95,13 +98,10 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
95
98
|
let r = sub(P, com1.p0);
|
|
96
99
|
|
|
97
100
|
//let t0_2 = t0 - dot(r, dP) / dot(dP, dP);
|
|
98
|
-
//console.log(t0, t0_2);
|
|
99
101
|
|
|
100
102
|
t0 -= dot(r, dP) / dot(dP, dP);
|
|
101
103
|
|
|
102
|
-
|
|
103
104
|
// construct merged cubic over [t0, 1]
|
|
104
|
-
|
|
105
105
|
let Q0 = pointAtT([com2.p0, com2.cp1, com2.cp2, com2.p], t0);
|
|
106
106
|
let Q3 = com2.p;
|
|
107
107
|
|
|
@@ -131,31 +131,38 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
|
|
134
|
-
let
|
|
134
|
+
let tMid = (1 - t0) * 0.5;
|
|
135
|
+
let tSplit = t0 - 1;
|
|
136
|
+
//tMid = 0.5;
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
let ptM = pointAtT([result.p0, result.cp1, result.cp2, result.p], tMid, false, true)
|
|
135
140
|
let seg1_cp2 = ptM.cpts[2]
|
|
136
141
|
//let seg2_cp1 = ptM.cpts[3]
|
|
137
142
|
|
|
138
|
-
|
|
139
143
|
let ptI_1 = checkLineIntersection(ptM, seg1_cp2, result.p0, ptI, false)
|
|
140
144
|
let ptI_2 = checkLineIntersection(ptM, seg1_cp2, result.p, ptI, false)
|
|
141
145
|
|
|
142
146
|
|
|
147
|
+
|
|
148
|
+
|
|
143
149
|
let cp1_2 = interpolate(result.p0, ptI_1, 1.333)
|
|
144
150
|
let cp2_2 = interpolate(result.p, ptI_2, 1.333)
|
|
145
151
|
|
|
146
152
|
// test self intersections and exit
|
|
147
|
-
let cp_intersection = checkLineIntersection(com1_o.p0, cp1_2, com2_o.p, cp2_2, true
|
|
148
|
-
if(cp_intersection){
|
|
153
|
+
let cp_intersection = checkLineIntersection(com1_o.p0, cp1_2, com2_o.p, cp2_2, true)
|
|
154
|
+
if (cp_intersection) {
|
|
149
155
|
//renderPoint(markers, cp_intersection )
|
|
150
156
|
return commands;
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
if (debug) renderPoint(markers, ptM, 'purple')
|
|
153
160
|
|
|
154
161
|
result.cp1 = cp1_2
|
|
155
162
|
result.cp2 = cp2_2
|
|
156
163
|
|
|
157
|
-
// check distances
|
|
158
164
|
|
|
165
|
+
// check distances between original starting point and extrapolated
|
|
159
166
|
let dist3 = getDistAv(com1_o.p0, result.p0)
|
|
160
167
|
let dist4 = getDistAv(com2_o.p, result.p)
|
|
161
168
|
let dist5 = (dist3 + dist4)
|
|
@@ -167,13 +174,29 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
167
174
|
result.corner = com2_o.corner
|
|
168
175
|
result.dimA = com2_o.dimA
|
|
169
176
|
result.directionChange = com2_o.directionChange
|
|
177
|
+
result.type = 'C'
|
|
170
178
|
result.values = [result.cp1.x, result.cp1.y, result.cp2.x, result.cp2.y, result.p.x, result.p.y]
|
|
171
179
|
|
|
172
180
|
|
|
173
|
-
|
|
174
|
-
// check if completely off
|
|
181
|
+
// extrapolated starting point is not completely off
|
|
175
182
|
if (dist5 < maxDist) {
|
|
176
183
|
|
|
184
|
+
// split t to meet original mid segment start point
|
|
185
|
+
let tSplit = reverse ? 1 + t0 : Math.abs(t0);
|
|
186
|
+
//console.log('t0', t0, tMid, 'tSplit', tSplit);
|
|
187
|
+
|
|
188
|
+
let ptSplit = pointAtT([result.p0, result.cp1, result.cp2, result.p], tSplit);
|
|
189
|
+
let distSplit = getDistAv(ptSplit, com1.p)
|
|
190
|
+
//console.log('distS', distS, maxDist );
|
|
191
|
+
|
|
192
|
+
// not close enough - exit
|
|
193
|
+
if (distSplit > maxDist * tolerance) {
|
|
194
|
+
//renderPoint(markers, ptSplit, 'cyan', '1%')
|
|
195
|
+
//renderPoint(markers, com1.p, 'red', '0.5%')
|
|
196
|
+
return commands;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
177
200
|
// compare combined with original area
|
|
178
201
|
let pathData0 = [
|
|
179
202
|
{ type: 'M', values: [com1_o.p0.x, com1_o.p0.y] },
|
|
@@ -190,28 +213,23 @@ export function getCombinedByDominant(com1, com2, maxDist = 0, tolerance = 1) {
|
|
|
190
213
|
let areaN = getPathArea(pathDataN)
|
|
191
214
|
let areaDiff = Math.abs(areaN / area0 - 1)
|
|
192
215
|
|
|
193
|
-
result.error = areaDiff *
|
|
216
|
+
result.error = areaDiff * 5 * tolerance;
|
|
194
217
|
//result.error = areaDiff + dist5;
|
|
195
218
|
|
|
196
|
-
let d = pathDataToD(pathDataN)
|
|
197
219
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
//renderPath(markers, d, 'orange')
|
|
202
|
-
//console.log('areaDiff', areaDiff);
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
// renderPath(markers, d, 'red')
|
|
206
|
-
// console.log('areaDiff', areaDiff);
|
|
220
|
+
if (debug) {
|
|
221
|
+
let d = pathDataToD(pathDataN)
|
|
222
|
+
renderPath(markers, d, 'orange')
|
|
207
223
|
}
|
|
208
224
|
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
// success!!!
|
|
226
|
+
if (areaDiff < 0.05 * tolerance) {
|
|
227
|
+
commands = [result];
|
|
228
|
+
//console.log('areaDiff', areaDiff);
|
|
229
|
+
}
|
|
211
230
|
}
|
|
212
231
|
|
|
213
232
|
|
|
214
|
-
|
|
215
233
|
//console.log(commands);
|
|
216
234
|
|
|
217
235
|
return commands
|
package/src/pathSimplify-main.js
CHANGED
|
@@ -2,27 +2,33 @@ import { detectInputType } from './detect_input';
|
|
|
2
2
|
import { combineCubicPairs } from './pathData_simplify_cubic';
|
|
3
3
|
import { getPathDataVertices, pointAtT } from './svgii/geometry';
|
|
4
4
|
import { getPolyBBox } from './svgii/geometry_bbox';
|
|
5
|
-
import { analyzePathData
|
|
5
|
+
import { analyzePathData } from './svgii/pathData_analyze';
|
|
6
6
|
import { combineArcs, convertPathData, cubicCommandToArc, revertCubicQuadratic } from './svgii/pathData_convert';
|
|
7
7
|
import { parsePathDataNormalized } from './svgii/pathData_parse';
|
|
8
|
+
import { shapeElToPath } from './svgii/pathData_parse_els';
|
|
8
9
|
import { pathDataRemoveColinear } from './svgii/pathData_remove_collinear';
|
|
10
|
+
import { removeOrphanedM } from './svgii/pathData_remove_orphaned';
|
|
9
11
|
import { removeZeroLengthLinetos } from './svgii/pathData_remove_zerolength';
|
|
10
12
|
import { optimizeClosePath, pathDataToTopLeft } from './svgii/pathData_reorder';
|
|
11
13
|
import { reversePathData } from './svgii/pathData_reverse';
|
|
12
14
|
import { addExtremePoints, splitSubpaths } from './svgii/pathData_split';
|
|
13
15
|
import { pathDataToD } from './svgii/pathData_stringify';
|
|
14
|
-
import { pathDataToPolyPlus } from './svgii/pathData_toPolygon';
|
|
16
|
+
//import { pathDataToPolyPlus, pathDataToPolySingle } from './svgii/pathData_toPolygon';
|
|
15
17
|
import { analyzePoly } from './svgii/poly_analyze';
|
|
16
18
|
import { getCurvePathData } from './svgii/poly_to_pathdata';
|
|
17
19
|
import { detectAccuracy } from './svgii/rounding';
|
|
18
|
-
import {
|
|
20
|
+
import { refineAdjacentExtremes } from './svgii/simplify_refineExtremes';
|
|
21
|
+
import { cleanUpSVG, removeEmptySVGEls, stringifySVG } from './svgii/svg_cleanup';
|
|
19
22
|
import { renderPoint } from './svgii/visualize';
|
|
20
23
|
|
|
21
24
|
export function svgPathSimplify(input = '', {
|
|
25
|
+
|
|
26
|
+
// return svg markup or object
|
|
27
|
+
getObject = false,
|
|
28
|
+
|
|
22
29
|
toAbsolute = true,
|
|
23
30
|
toRelative = true,
|
|
24
31
|
toShorthands = true,
|
|
25
|
-
decimals = 3,
|
|
26
32
|
//optimize = 0,
|
|
27
33
|
|
|
28
34
|
// not necessary unless you need cubics only
|
|
@@ -32,29 +38,36 @@ export function svgPathSimplify(input = '', {
|
|
|
32
38
|
arcToCubic = false,
|
|
33
39
|
cubicToArc = false,
|
|
34
40
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
keepExtremes = true,
|
|
38
|
-
keepCorners = true,
|
|
39
|
-
keepInflections = true,
|
|
40
|
-
extrapolateDominant = false,
|
|
41
|
-
addExtremes = false,
|
|
41
|
+
|
|
42
|
+
simplifyBezier = true,
|
|
42
43
|
optimizeOrder = true,
|
|
43
44
|
removeColinear = true,
|
|
44
|
-
simplifyBezier = true,
|
|
45
|
-
autoAccuracy = true,
|
|
46
45
|
flatBezierToLinetos = true,
|
|
47
46
|
revertToQuadratics = true,
|
|
47
|
+
|
|
48
|
+
refineExtremes = true,
|
|
49
|
+
keepExtremes = true,
|
|
50
|
+
keepCorners = true,
|
|
51
|
+
extrapolateDominant = true,
|
|
52
|
+
keepInflections = false,
|
|
53
|
+
addExtremes = false,
|
|
54
|
+
removeOrphanSubpaths = false,
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// svg path optimizations
|
|
58
|
+
decimals = 3,
|
|
59
|
+
autoAccuracy = true,
|
|
60
|
+
|
|
48
61
|
minifyD = 0,
|
|
49
62
|
tolerance = 1,
|
|
50
63
|
reverse = false,
|
|
51
64
|
|
|
52
65
|
// svg cleanup options
|
|
66
|
+
mergePaths = false,
|
|
53
67
|
removeHidden = true,
|
|
54
68
|
removeUnused = true,
|
|
69
|
+
shapesToPaths = true,
|
|
55
70
|
|
|
56
|
-
// return svg markup or object
|
|
57
|
-
getObject = false
|
|
58
71
|
|
|
59
72
|
} = {}) {
|
|
60
73
|
|
|
@@ -98,6 +111,14 @@ export function svgPathSimplify(input = '', {
|
|
|
98
111
|
svg = cleanUpSVG(input, { returnDom, removeHidden, removeUnused }
|
|
99
112
|
);
|
|
100
113
|
|
|
114
|
+
if(shapesToPaths){
|
|
115
|
+
let shapes = svg.querySelectorAll('polygon, polyline, line, rect, circle, ellipse');
|
|
116
|
+
shapes.forEach(shape=>{
|
|
117
|
+
let path = shapeElToPath(shape);
|
|
118
|
+
shape.replaceWith(path)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
101
122
|
// collect paths
|
|
102
123
|
let pathEls = svg.querySelectorAll('path')
|
|
103
124
|
pathEls.forEach(path => {
|
|
@@ -111,18 +132,37 @@ export function svgPathSimplify(input = '', {
|
|
|
111
132
|
/**
|
|
112
133
|
* process all paths
|
|
113
134
|
*/
|
|
135
|
+
|
|
136
|
+
// SVG optimization options
|
|
137
|
+
let pathOptions = {
|
|
138
|
+
toRelative,
|
|
139
|
+
toShorthands,
|
|
140
|
+
decimals,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// combinded path data for SVGs with mergePaths enabled
|
|
144
|
+
let pathData_merged = [];
|
|
145
|
+
|
|
114
146
|
paths.forEach(path => {
|
|
115
147
|
let { d, el } = path;
|
|
116
148
|
|
|
149
|
+
///let t0 = performance.now()
|
|
117
150
|
let pathDataO = parsePathDataNormalized(d, { quadraticToCubic, toAbsolute, arcToCubic });
|
|
118
|
-
//console.log(pathDataO);
|
|
119
|
-
|
|
120
|
-
// create clone for fallback
|
|
121
|
-
let pathData = JSON.parse(JSON.stringify(pathDataO));
|
|
151
|
+
//console.log('pathDataO', pathDataO);
|
|
122
152
|
|
|
123
153
|
// count commands for evaluation
|
|
124
154
|
let comCount = pathDataO.length
|
|
125
155
|
|
|
156
|
+
|
|
157
|
+
// create clone for fallback
|
|
158
|
+
//let pathData = JSON.parse(JSON.stringify(pathDataO));
|
|
159
|
+
let pathData = pathDataO;
|
|
160
|
+
//let t1 = performance.now() - t0;
|
|
161
|
+
//console.log('t1', t1);
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
if(removeOrphanSubpaths) pathData = removeOrphanedM(pathData);
|
|
165
|
+
|
|
126
166
|
/**
|
|
127
167
|
* get sub paths
|
|
128
168
|
*/
|
|
@@ -164,8 +204,17 @@ export function svgPathSimplify(input = '', {
|
|
|
164
204
|
//let pathDataN = pathData;
|
|
165
205
|
|
|
166
206
|
//console.log(pathDataPlus);
|
|
207
|
+
//let t0=performance.now()
|
|
208
|
+
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, extrapolateDominant, revertToQuadratics, tolerance, reverse }) : pathData;
|
|
209
|
+
//let t1=performance.now() - t0;
|
|
210
|
+
//console.log('t1', t1);
|
|
211
|
+
|
|
167
212
|
|
|
168
|
-
|
|
213
|
+
// refine extremes
|
|
214
|
+
if(refineExtremes){
|
|
215
|
+
let thresholdEx = (bb.width + bb.height) / 2 * 0.05
|
|
216
|
+
pathData = refineAdjacentExtremes(pathData, {threshold:thresholdEx, tolerance})
|
|
217
|
+
}
|
|
169
218
|
|
|
170
219
|
|
|
171
220
|
// cubic to arcs
|
|
@@ -189,6 +238,9 @@ export function svgPathSimplify(input = '', {
|
|
|
189
238
|
}
|
|
190
239
|
|
|
191
240
|
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
192
244
|
// simplify to quadratics
|
|
193
245
|
if (revertToQuadratics) {
|
|
194
246
|
pathData.forEach((com, c) => {
|
|
@@ -196,85 +248,122 @@ export function svgPathSimplify(input = '', {
|
|
|
196
248
|
if (type === 'C') {
|
|
197
249
|
//console.log(com);
|
|
198
250
|
let comQ = revertCubicQuadratic(p0, cp1, cp2, p)
|
|
199
|
-
if (comQ.type === 'Q')
|
|
251
|
+
if (comQ.type === 'Q') {
|
|
252
|
+
/*
|
|
253
|
+
comQ.p0 = com.p0
|
|
254
|
+
comQ.cp1 = {x:comQ.values[0], y:comQ.values[1]}
|
|
255
|
+
comQ.p = com.p
|
|
256
|
+
*/
|
|
257
|
+
comQ.extreme = com.extreme
|
|
258
|
+
comQ.corner = com.corner
|
|
259
|
+
comQ.dimA = com.dimA
|
|
260
|
+
|
|
261
|
+
pathData[c] = comQ
|
|
262
|
+
}
|
|
200
263
|
}
|
|
201
264
|
})
|
|
202
265
|
}
|
|
203
266
|
|
|
267
|
+
//if (removeColinear) pathDataSub = pathDataRemoveColinear(pathDataSub, tolerance, flatBezierToLinetos);
|
|
268
|
+
|
|
269
|
+
|
|
204
270
|
// optimize close path
|
|
205
|
-
if(optimizeOrder) pathData=optimizeClosePath(pathData)
|
|
271
|
+
if (optimizeOrder) pathData = optimizeClosePath(pathData)
|
|
272
|
+
|
|
273
|
+
// poly
|
|
274
|
+
//let poly = pathDataToPolySingle(pathData, true)
|
|
275
|
+
//console.log('poly', poly);
|
|
276
|
+
|
|
206
277
|
|
|
207
278
|
// update
|
|
208
279
|
pathDataArrN.push(pathData)
|
|
209
280
|
}
|
|
210
281
|
|
|
211
|
-
|
|
212
282
|
// flatten compound paths
|
|
213
283
|
pathData = pathDataArrN.flat();
|
|
214
284
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
decimals = detectAccuracy(pathData)
|
|
285
|
+
|
|
286
|
+
// collect for merged svg paths
|
|
287
|
+
if (el && mergePaths) {
|
|
288
|
+
pathData_merged.push(...pathData)
|
|
220
289
|
}
|
|
290
|
+
// single output
|
|
291
|
+
else {
|
|
221
292
|
|
|
293
|
+
/**
|
|
294
|
+
* detect accuracy
|
|
295
|
+
*/
|
|
296
|
+
if (autoAccuracy) {
|
|
297
|
+
decimals = detectAccuracy(pathData)
|
|
298
|
+
pathOptions.decimals = decimals
|
|
299
|
+
//console.log('!decimals', decimals);
|
|
300
|
+
}
|
|
222
301
|
|
|
223
|
-
|
|
224
|
-
let pathOptions = {
|
|
225
|
-
toRelative,
|
|
226
|
-
toShorthands,
|
|
227
|
-
decimals,
|
|
228
|
-
}
|
|
302
|
+
//console.log('autoAccuracy', autoAccuracy, decimals);
|
|
229
303
|
|
|
304
|
+
// optimize path data
|
|
305
|
+
pathData = convertPathData(pathData, pathOptions)
|
|
230
306
|
|
|
231
|
-
|
|
232
|
-
|
|
307
|
+
// remove zero-length segments introduced by rounding
|
|
308
|
+
pathData = removeZeroLengthLinetos(pathData);
|
|
233
309
|
|
|
310
|
+
// compare command count
|
|
311
|
+
let comCountS = pathData.length
|
|
234
312
|
|
|
235
|
-
|
|
236
|
-
|
|
313
|
+
let dOpt = pathDataToD(pathData, minifyD)
|
|
314
|
+
svgSizeOpt = new Blob([dOpt]).size;
|
|
315
|
+
compression = +(100 / svgSize * (svgSizeOpt)).toFixed(2)
|
|
237
316
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
317
|
+
|
|
318
|
+
path.d = dOpt
|
|
319
|
+
path.report = {
|
|
320
|
+
original: comCount,
|
|
321
|
+
new: comCountS,
|
|
322
|
+
saved: comCount - comCountS,
|
|
323
|
+
compression,
|
|
324
|
+
decimals,
|
|
325
|
+
//success: comCountS < comCount
|
|
245
326
|
}
|
|
246
|
-
})
|
|
247
327
|
|
|
248
|
-
|
|
328
|
+
// apply new path for svgs
|
|
329
|
+
if (el) el.setAttribute('d', dOpt)
|
|
330
|
+
}
|
|
331
|
+
});
|
|
249
332
|
|
|
333
|
+
/**
|
|
334
|
+
* stringify new SVG
|
|
335
|
+
*/
|
|
336
|
+
if (mode) {
|
|
250
337
|
|
|
251
|
-
|
|
252
|
-
|
|
338
|
+
if (pathData_merged.length) {
|
|
339
|
+
// optimize path data
|
|
340
|
+
let pathData = convertPathData(pathData_merged, pathOptions)
|
|
341
|
+
|
|
342
|
+
// remove zero-length segments introduced by rounding
|
|
343
|
+
//pathData = removeZeroLengthLinetos_post(pathData);
|
|
344
|
+
pathData = removeZeroLengthLinetos(pathData);
|
|
253
345
|
|
|
254
|
-
let dOpt = pathDataToD(pathData, minifyD)
|
|
255
|
-
svgSizeOpt = new Blob([dOpt]).size;
|
|
256
|
-
//compression = +(100/svgSize * (svgSize - svgSizeOpt)).toFixed(2)
|
|
257
|
-
compression = +(100 / svgSize * (svgSizeOpt)).toFixed(2)
|
|
258
346
|
|
|
347
|
+
let dOpt = pathDataToD(pathData, minifyD)
|
|
259
348
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
349
|
+
|
|
350
|
+
// apply new path for svgs
|
|
351
|
+
paths[0].el.setAttribute('d', dOpt)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
// remove other paths
|
|
355
|
+
for (let i = 1; i < paths.length; i++) {
|
|
356
|
+
let pathEl = paths[i].el
|
|
357
|
+
if (pathEl) pathEl.remove()
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// remove empty groups e.g groups
|
|
361
|
+
removeEmptySVGEls(svg);
|
|
268
362
|
}
|
|
269
363
|
|
|
270
|
-
// apply new path for svgs
|
|
271
|
-
if (el) el.setAttribute('d', dOpt)
|
|
272
364
|
|
|
273
|
-
});
|
|
274
365
|
|
|
275
|
-
|
|
276
|
-
if (mode) {
|
|
277
|
-
svg = new XMLSerializer().serializeToString(svg);
|
|
366
|
+
svg = stringifySVG(svg);
|
|
278
367
|
svgSizeOpt = new Blob([svg]).size
|
|
279
368
|
//compression = +(100/svgSize * (svgSize-svgSizeOpt)).toFixed(2)
|
|
280
369
|
compression = +(100 / svgSize * (svgSizeOpt)).toFixed(2)
|
|
@@ -299,7 +388,7 @@ export function svgPathSimplify(input = '', {
|
|
|
299
388
|
|
|
300
389
|
|
|
301
390
|
|
|
302
|
-
function
|
|
391
|
+
function simplifyPathDataCubic(pathData, {
|
|
303
392
|
keepExtremes = true,
|
|
304
393
|
keepInflections = true,
|
|
305
394
|
keepCorners = true,
|
|
@@ -347,6 +436,8 @@ function simplifyPathData(pathData, {
|
|
|
347
436
|
if (combined.length === 1) {
|
|
348
437
|
com = combined[0]
|
|
349
438
|
let offset = 1;
|
|
439
|
+
|
|
440
|
+
// add cumulative error to prevent distortions
|
|
350
441
|
error += com.error;
|
|
351
442
|
//console.log('!error', error);
|
|
352
443
|
|
|
@@ -365,6 +456,10 @@ function simplifyPathData(pathData, {
|
|
|
365
456
|
|
|
366
457
|
let combined = combineCubicPairs(com, comN, extrapolateDominant, tolerance)
|
|
367
458
|
if (combined.length === 1) {
|
|
459
|
+
// add cumulative error to prevent distortions
|
|
460
|
+
//console.log('combined', combined);
|
|
461
|
+
error += combined[0].error * 0.5;
|
|
462
|
+
//error += combined[0].error * 1;
|
|
368
463
|
offset++
|
|
369
464
|
}
|
|
370
465
|
com = combined[0]
|