svg-path-simplify 0.4.1 → 0.4.3
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/CHANGELOG.md +19 -0
- package/README.md +6 -4
- package/dist/svg-path-simplify.esm.js +2450 -888
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +2450 -888
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +167 -85
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/docs/privacy-webapp.md +24 -0
- package/index.html +333 -132
- package/package.json +5 -2
- package/src/css_parse.js +317 -0
- package/src/detect_input.js +34 -4
- package/src/pathData_simplify_harmonize_cpts.js +77 -1
- package/src/pathSimplify-main.js +246 -262
- package/src/pathSimplify-presets.js +243 -0
- package/src/poly-fit-curve-schneider.js +14 -7
- package/src/simplify_poly_RC.js +102 -0
- package/src/simplify_poly_RDP.js +109 -1
- package/src/simplify_poly_radial_distance.js +3 -3
- package/src/string_helpers.js +144 -0
- package/src/svgii/convert_units.js +8 -2
- package/src/svgii/geometry.js +182 -3
- package/src/svgii/geometry_length.js +237 -0
- package/src/svgii/pathData_convert.js +43 -1
- package/src/svgii/pathData_fix_directions.js +6 -0
- package/src/svgii/pathData_fromPoly.js +3 -3
- package/src/svgii/pathData_getLength.js +86 -0
- package/src/svgii/pathData_parse.js +2 -0
- package/src/svgii/pathData_parse_els.js +189 -189
- package/src/svgii/pathData_split_to_groups.js +168 -0
- package/src/svgii/pathData_stringify.js +26 -64
- package/src/svgii/pathData_toPolygon.js +3 -4
- package/src/svgii/poly_analyze.js +61 -0
- package/src/svgii/poly_normalize.js +11 -2
- package/src/svgii/poly_to_pathdata.js +85 -24
- package/src/svgii/rounding.js +8 -7
- package/src/svgii/svg-styles-to-attributes-const.js +1 -0
- package/src/svgii/svg_cleanup.js +467 -421
- package/src/svgii/svg_cleanup_convertPathLength.js +32 -0
- package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
- package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
- package/src/svgii/svg_cleanup_remove_els_and_atts.js +72 -0
- package/src/svgii/svg_cleanup_ungroup.js +36 -0
- package/src/svgii/svg_el_parse_style_props.js +76 -28
- package/src/svgii/svg_getElementLength.js +67 -0
- package/tests/testSVG_shape.js +59 -0
- package/tests/testSVG_transform.js +61 -0
package/src/pathSimplify-main.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { detectInputType } from './detect_input';
|
|
2
2
|
import { simplifyPathDataCubic } from './pathData_simplify_cubic';
|
|
3
|
-
import { getDistManhattan, getDistance, getPathDataVertices, interpolate, pointAtT } from './svgii/geometry';
|
|
3
|
+
import { getDistManhattan, getDistance, getPathDataVertices, interpolate, pointAtT, reducePoints, svgArcToCenterParam, toParametricAngle } from './svgii/geometry';
|
|
4
4
|
import { getPolyBBox } from './svgii/geometry_bbox';
|
|
5
|
-
import { analyzePathData } from './svgii/pathData_analyze';
|
|
5
|
+
import { analyzePathData, getPathDataVerbose } from './svgii/pathData_analyze';
|
|
6
6
|
import { normalizePathData, parsePathDataNormalized, convertPathData } from './svgii/pathData_convert';
|
|
7
7
|
import { shapeElToPath } from './svgii/pathData_parse_els';
|
|
8
8
|
import { pathDataRemoveColinear } from './svgii/pathData_remove_collinear';
|
|
@@ -12,9 +12,9 @@ import { optimizeClosePath, pathDataToTopLeft } from './svgii/pathData_reorder';
|
|
|
12
12
|
import { reversePathData } from './svgii/pathData_reverse';
|
|
13
13
|
import { addExtremePoints, splitSubpaths } from './svgii/pathData_split';
|
|
14
14
|
import { pathDataToD } from './svgii/pathData_stringify';
|
|
15
|
-
import { detectAccuracy, roundPathData } from './svgii/rounding';
|
|
15
|
+
import { detectAccuracy, roundPathData, roundTo } from './svgii/rounding';
|
|
16
16
|
import { refineAdjacentExtremes } from './svgii/pathData_simplify_refineExtremes';
|
|
17
|
-
import { cleanUpSVG, removeEmptySVGEls
|
|
17
|
+
import { cleanUpSVG, removeEmptySVGEls } from './svgii/svg_cleanup';
|
|
18
18
|
import { refineRoundedCorners } from './svgii/pathData_simplify_refineCorners';
|
|
19
19
|
import { refineRoundSegments } from './svgii/pathData_refine_round';
|
|
20
20
|
import { refineClosingCommand } from './svgii/pathData_remove_short';
|
|
@@ -23,144 +23,51 @@ import { getViewBox } from './svg_getViewbox';
|
|
|
23
23
|
import { pathDataRevertCubicToQuadratic } from './pathData_simplify_revertToquadratics';
|
|
24
24
|
import { pathDataCubicsToArc } from './pathData_simplify_cubicsToArcs';
|
|
25
25
|
import { harmonizeCubicCpts } from './pathData_simplify_harmonize_cpts';
|
|
26
|
-
import {
|
|
26
|
+
import { pathDataToPolygonOpt } from './svgii/pathData_toPolygon';
|
|
27
27
|
import { pathDataLineToCubic } from './svgii/pathData_line_to_cubic';
|
|
28
28
|
import { fixPathDataDirections } from './svgii/pathData_fix_directions';
|
|
29
29
|
import { simplifyPolyChunks, getCurvePathData, simplifyPolygonToPathData } from './svgii/poly_to_pathdata';
|
|
30
30
|
import { pathDataFromPoly } from './svgii/pathData_fromPoly';
|
|
31
|
-
import { normalizePoly } from './svgii/poly_normalize';
|
|
31
|
+
import { normalizePoly, polyPtsToArray } from './svgii/poly_normalize';
|
|
32
32
|
import { simplifyPolyRD } from './simplify_poly_radial_distance';
|
|
33
|
-
import { simplifyPolyRDP } from './simplify_poly_RDP';
|
|
33
|
+
import { simplifyPolyRDP, simplifyPolyRDP__, simplifyRDP_rel } from './simplify_poly_RDP';
|
|
34
|
+
import { getEllipseLengthLG, getLegendreGaussValues, getLength, waArr_global } from './svgii/geometry_length';
|
|
35
|
+
import { deg2rad } from './constants';
|
|
36
|
+
import { getPathDataLength } from './svgii/pathData_getLength';
|
|
37
|
+
import { stringifySVG } from './string_helpers';
|
|
38
|
+
import { presetSettings, settingsDefaults } from './pathSimplify-presets';
|
|
39
|
+
import { splitCompundGroups } from './svgii/pathData_split_to_groups';
|
|
34
40
|
//import { getPolyChunks } from "./svgii/poly_analyze_get_chunks";
|
|
35
41
|
|
|
36
42
|
|
|
37
43
|
//import { installDOMPolyfills } from './dom-polyfill';
|
|
38
44
|
|
|
39
|
-
export function svgPathSimplify(input = '', {
|
|
45
|
+
export function svgPathSimplify(input = '', settings = {}) {
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
let preset = settings['preset'] !== undefined && settings['preset'] ? settings['preset'] : null;
|
|
48
|
+
let defaults = preset && presetSettings[preset] !== undefined ? presetSettings[preset] : presetSettings['default'];
|
|
43
49
|
|
|
44
|
-
toAbsolute = false,
|
|
45
|
-
toRelative = true,
|
|
46
|
-
toShorthands = true,
|
|
47
|
-
toLonghands = false,
|
|
48
50
|
|
|
49
|
-
//
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// mostly a fallback if arc calculations fail
|
|
55
|
-
arcToCubic = false,
|
|
56
|
-
cubicToArc = false,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
simplifyBezier = true,
|
|
60
|
-
optimizeOrder = true,
|
|
61
|
-
autoClose = false,
|
|
62
|
-
removeZeroLength = true,
|
|
63
|
-
refineClosing = true,
|
|
64
|
-
removeColinear = true,
|
|
65
|
-
flatBezierToLinetos = true,
|
|
66
|
-
revertToQuadratics = true,
|
|
67
|
-
|
|
68
|
-
refineExtremes = true,
|
|
69
|
-
simplifyCorners = false,
|
|
70
|
-
removeDimensions = false,
|
|
71
|
-
removeIds = false,
|
|
72
|
-
removeClassNames = false,
|
|
73
|
-
omitNamespace = false,
|
|
74
|
-
|
|
75
|
-
fixDirections = false,
|
|
76
|
-
|
|
77
|
-
keepExtremes = true,
|
|
78
|
-
keepCorners = true,
|
|
79
|
-
extrapolateDominant = true,
|
|
80
|
-
keepInflections = false,
|
|
81
|
-
addExtremes = false,
|
|
82
|
-
addSemiExtremes = false,
|
|
83
|
-
|
|
84
|
-
toPolygon = false,
|
|
85
|
-
smoothPoly = false,
|
|
86
|
-
polyFormat = 'points',
|
|
87
|
-
precisionPoly = 1,
|
|
88
|
-
|
|
89
|
-
simplifyRD = 1,
|
|
90
|
-
simplifyRDP = 1,
|
|
91
|
-
|
|
92
|
-
harmonizeCpts = false,
|
|
93
|
-
|
|
94
|
-
removeOrphanSubpaths = false,
|
|
95
|
-
simplifyRound = false,
|
|
96
|
-
|
|
97
|
-
//svg scaling
|
|
98
|
-
scale = 1,
|
|
99
|
-
scaleTo = 0,
|
|
100
|
-
crop = false,
|
|
101
|
-
alignToOrigin = false,
|
|
102
|
-
|
|
103
|
-
// flatten transforms
|
|
104
|
-
convertTransforms = false,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
//svg path optimizations
|
|
109
|
-
decimals = 3,
|
|
110
|
-
autoAccuracy = true,
|
|
111
|
-
|
|
112
|
-
// experimental
|
|
113
|
-
//roundSub = false,
|
|
114
|
-
|
|
115
|
-
minifyD = 0,
|
|
116
|
-
tolerance = 1,
|
|
117
|
-
reversePath = false,
|
|
118
|
-
|
|
119
|
-
//svg cleanup options
|
|
120
|
-
minifyRgbColors = false,
|
|
121
|
-
removePrologue = true,
|
|
122
|
-
removeHidden = true,
|
|
123
|
-
removeUnused = true,
|
|
124
|
-
cleanupDefs = true,
|
|
125
|
-
cleanupClip = true,
|
|
126
|
-
cleanupSVGAtts = true,
|
|
127
|
-
|
|
128
|
-
stylesToAttributes = false,
|
|
129
|
-
fixHref = false,
|
|
130
|
-
legacyHref = false,
|
|
131
|
-
removeNameSpaced = true,
|
|
132
|
-
|
|
133
|
-
//attributesToGroup = false,
|
|
134
|
-
removeOffCanvas = false,
|
|
135
|
-
unGroup = false,
|
|
136
|
-
mergePaths = false,
|
|
137
|
-
|
|
138
|
-
// shape conversions
|
|
139
|
-
shapesToPaths = false,
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
//toPaths || toShapes
|
|
143
|
-
shapeConvert = 0,
|
|
144
|
-
convert_rects = false,
|
|
145
|
-
convert_ellipses = false,
|
|
146
|
-
convert_poly = false,
|
|
147
|
-
convert_lines = false,
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
lineToCubic = false,
|
|
152
|
-
cleanUpStrokes = true,
|
|
153
|
-
addViewBox = false,
|
|
154
|
-
addDimensions = false,
|
|
51
|
+
// merge settings
|
|
52
|
+
settings = {
|
|
53
|
+
...defaults,
|
|
54
|
+
...settings
|
|
55
|
+
}
|
|
155
56
|
|
|
156
|
-
removeComments = true,
|
|
157
57
|
|
|
158
|
-
|
|
58
|
+
let { getObject = false, removeComments, removeOffCanvas, unGroup, mergePaths, removeElements, removeDimensions, removeIds, removeClassNames, omitNamespace, cleanUpStrokes, addViewBox, addDimensions, removePrologue, removeHidden, removeUnused, cleanupDefs, cleanupClip, cleanupSVGAtts, removeNameSpaced, removeNameSpacedAtts, attributesToGroup, minifyRgbColors, stylesToAttributes, fixHref, legacyHref, allowMeta, allowDataAtts, allowAriaAtts, convertPathLength, removeSVGAttributes, removeElAttributes, shapesToPaths, shapeConvert, convertShapes, simplifyBezier, optimizeOrder, autoClose, removeZeroLength, refineClosing, removeColinear, flatBezierToLinetos, revertToQuadratics, refineExtremes, simplifyCorners, fixDirections, keepExtremes, keepCorners, keepInflections, addExtremes, reversePath, toAbsolute, toRelative, toMixed, toShorthands, toLonghands, quadraticToCubic, arcToCubic, cubicToArc, lineToCubic, decimals, autoAccuracy, minifyD, tolerance, toPolygon, smoothPoly, polyFormat, precisionPoly, simplifyRD, simplifyRDP, harmonizeCpts, removeOrphanSubpaths, simplifyRound, scale, scaleTo, crop, alignToOrigin, convertTransforms, keepSmaller, splitCompound } = settings;
|
|
159
59
|
|
|
60
|
+
//toAbsolute = !toRelative;
|
|
160
61
|
|
|
161
62
|
// clamp tolerance and scale
|
|
162
63
|
tolerance = Math.max(0.1, tolerance);
|
|
163
64
|
scale = Math.max(0.001, scale)
|
|
65
|
+
if(fixDirections) keepSmaller = false;
|
|
66
|
+
if (scale !== 1 || scaleTo || crop || alignToOrigin) {
|
|
67
|
+
convertTransforms = true;
|
|
68
|
+
settings.convertTransforms = true
|
|
69
|
+
}
|
|
70
|
+
|
|
164
71
|
|
|
165
72
|
let inputType = detectInputType(input);
|
|
166
73
|
let svg = '';
|
|
@@ -175,8 +82,11 @@ export function svgPathSimplify(input = '', {
|
|
|
175
82
|
// pathdata superset array - containing additional data
|
|
176
83
|
let pathDataPlusArr_global = []
|
|
177
84
|
let paths = []
|
|
85
|
+
let isPoly = false;
|
|
178
86
|
let polys = []
|
|
87
|
+
let poly = []
|
|
179
88
|
let dStr = '';
|
|
89
|
+
let dOriginal = ''
|
|
180
90
|
|
|
181
91
|
/**
|
|
182
92
|
* normalize input
|
|
@@ -200,29 +110,66 @@ export function svgPathSimplify(input = '', {
|
|
|
200
110
|
arcToCubic = toPolygon ? true : arcToCubic;
|
|
201
111
|
autoClose = false;
|
|
202
112
|
let accuracyArr = []
|
|
203
|
-
|
|
113
|
+
//console.log(inputType);
|
|
114
|
+
|
|
115
|
+
// validate point JSON
|
|
116
|
+
if (inputType === 'json') {
|
|
117
|
+
let pts = [];
|
|
118
|
+
let needsQuotes = /([{,]\s*)(x|y)(\s*:)/.test(input)
|
|
119
|
+
if (needsQuotes) input = input.replaceAll('x:', '"x":').replaceAll('y:', '"y":')
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
pts = JSON.parse(input)
|
|
123
|
+
} catch {
|
|
124
|
+
console.warn('No valid JSON');
|
|
125
|
+
}
|
|
126
|
+
if (pts.length) {
|
|
127
|
+
inputType = 'polyArray'
|
|
128
|
+
input = normalizePoly(pts);
|
|
129
|
+
isPoly = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
204
132
|
|
|
205
133
|
//console.log('inputType', inputType);
|
|
206
134
|
|
|
135
|
+
|
|
207
136
|
// single path or polys
|
|
208
|
-
if (inputType !== 'svgMarkup') {
|
|
137
|
+
if (inputType !== 'svgMarkup' && inputType !== 'symbol') {
|
|
209
138
|
if (inputType === 'pathDataString') {
|
|
210
139
|
d = input
|
|
211
140
|
} else if (inputType === 'polyString') {
|
|
212
|
-
|
|
141
|
+
splitCompound = false;
|
|
142
|
+
isPoly = true;
|
|
143
|
+
poly = normalizePoly(input)
|
|
144
|
+
d = pathDataFromPoly(poly, closed)
|
|
145
|
+
//console.log(poly);
|
|
146
|
+
|
|
213
147
|
}
|
|
214
148
|
|
|
215
149
|
else if (inputType === 'polyArray' || inputType === 'polyObjectArray' || inputType === 'polyComplexArray' || inputType === 'polyComplexObjectArray') {
|
|
150
|
+
splitCompound = false;
|
|
216
151
|
|
|
217
152
|
// normalize poly input to object array
|
|
218
|
-
|
|
153
|
+
poly = normalizePoly(input)
|
|
219
154
|
|
|
220
155
|
// convert to pathdata
|
|
221
|
-
|
|
156
|
+
let closed = true;
|
|
157
|
+
|
|
158
|
+
isPoly = true;
|
|
159
|
+
//polys.push(poly)
|
|
222
160
|
|
|
223
161
|
// calculate size
|
|
162
|
+
d = pathDataFromPoly(poly, closed)
|
|
224
163
|
dStr = d.map(com => { return `${com.type} ${com.values.join(' ')}` }).join(' ');
|
|
164
|
+
dOriginal = dStr;
|
|
225
165
|
svgSize = dStr.length;
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
d=''
|
|
169
|
+
dOriginal = '';
|
|
170
|
+
svgSize = input.length;
|
|
171
|
+
*/
|
|
172
|
+
|
|
226
173
|
}
|
|
227
174
|
|
|
228
175
|
else if (inputType === 'pathData') {
|
|
@@ -231,6 +178,12 @@ export function svgPathSimplify(input = '', {
|
|
|
231
178
|
// stringify to compare lengths
|
|
232
179
|
dStr = Array.from(d).map(com => { return `${com.type} ${com.values.join(' ')}` }).join(' ');
|
|
233
180
|
svgSize = dStr.length;
|
|
181
|
+
isPoly = false;
|
|
182
|
+
|
|
183
|
+
}
|
|
184
|
+
// not valid - set dummy path data
|
|
185
|
+
else {
|
|
186
|
+
d = 'M0 0 h0'
|
|
234
187
|
}
|
|
235
188
|
|
|
236
189
|
paths.push({ d, el: null })
|
|
@@ -239,37 +192,48 @@ export function svgPathSimplify(input = '', {
|
|
|
239
192
|
// mode:1 – process complete svg DOM
|
|
240
193
|
else {
|
|
241
194
|
|
|
195
|
+
|
|
196
|
+
// convert symbol temporarily to SVG
|
|
197
|
+
if (inputType === 'symbol') {
|
|
198
|
+
input = input.replaceAll('<symbol', '<svg').replaceAll('</symbol', '</svg')
|
|
199
|
+
// ids are mandatory for symbols
|
|
200
|
+
removeIds = false
|
|
201
|
+
removeDimensions = true
|
|
202
|
+
}
|
|
203
|
+
|
|
242
204
|
// convert all shapes to paths
|
|
243
205
|
if (shapesToPaths) {
|
|
244
|
-
shapeConvert =
|
|
206
|
+
shapeConvert = 'toPaths'
|
|
245
207
|
convert_rects = true
|
|
246
208
|
convert_ellipses = true
|
|
247
209
|
convert_poly = true
|
|
248
210
|
convert_lines = true
|
|
249
211
|
}
|
|
250
212
|
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
);
|
|
213
|
+
//console.log('shapesToPaths', shapesToPaths, 'shapeConvert', shapeConvert, convert_rects, convert_ellipses, convert_poly);
|
|
214
|
+
|
|
215
|
+
// sanitize SVG - clone/decouple settings
|
|
216
|
+
let svgPropObject = cleanUpSVG(input, JSON.parse(JSON.stringify(settings)));
|
|
217
|
+
|
|
218
|
+
//console.log('settings', settings);
|
|
219
|
+
//console.log('svgPropObject', svgPropObject);
|
|
257
220
|
|
|
258
221
|
let { svgElProps } = svgPropObject
|
|
259
222
|
svg = svgPropObject.svg;
|
|
260
|
-
|
|
223
|
+
//console.log(svgPropObject);
|
|
261
224
|
|
|
262
225
|
|
|
263
226
|
// collect paths
|
|
264
227
|
let pathEls = svg.querySelectorAll('path')
|
|
265
228
|
//let pathEls2 = svg.getElementsByTagName('path')
|
|
266
|
-
//console.log(
|
|
229
|
+
//console.log(pathEls);
|
|
267
230
|
|
|
268
231
|
pathEls.forEach((path, i) => {
|
|
269
|
-
|
|
232
|
+
let d = path.getAttribute('d');
|
|
233
|
+
//console.log(d, path.nodeName, path.id);
|
|
234
|
+
paths.push({ d, el: path, idx: i })
|
|
270
235
|
})
|
|
271
236
|
|
|
272
|
-
|
|
273
237
|
// get viewBox/dimensions
|
|
274
238
|
viewBox = getViewBox(svg, decimals)
|
|
275
239
|
|
|
@@ -285,14 +249,11 @@ export function svgPathSimplify(input = '', {
|
|
|
285
249
|
// SVG optimization options
|
|
286
250
|
let pathOptions = {
|
|
287
251
|
toRelative,
|
|
288
|
-
|
|
289
|
-
toLonghands,
|
|
252
|
+
toMixed,
|
|
290
253
|
toShorthands,
|
|
291
254
|
decimals,
|
|
292
255
|
}
|
|
293
|
-
|
|
294
|
-
// combinded path data for SVGs with mergePaths enabled
|
|
295
|
-
let pathData_merged = [];
|
|
256
|
+
//console.log('pathOptions', pathOptions);
|
|
296
257
|
|
|
297
258
|
|
|
298
259
|
for (let i = 0, l = paths.length; l && i < l; i++) {
|
|
@@ -301,10 +262,14 @@ export function svgPathSimplify(input = '', {
|
|
|
301
262
|
let path = paths[i];
|
|
302
263
|
let { d, el } = path;
|
|
303
264
|
let dN = ''
|
|
265
|
+
let isPoly = false;
|
|
304
266
|
|
|
305
|
-
|
|
267
|
+
// if polygon we already heave absolute coordinates
|
|
268
|
+
//let isPolyPath = !mode && isPoly && Array.isArray(d)
|
|
269
|
+
//let pathData = !isPolyPath ? parsePathDataNormalized(d, { quadraticToCubic, arcToCubic }) : d;
|
|
306
270
|
let pathData = parsePathDataNormalized(d, { quadraticToCubic, arcToCubic });
|
|
307
271
|
//console.log('!!!pathData', pathData, arcToCubic);
|
|
272
|
+
//console.log(isPoly);
|
|
308
273
|
|
|
309
274
|
// get polygon bbox
|
|
310
275
|
let bb_poly = smoothPoly || toPolygon ? getPolyBBox(getPathDataVertices(pathData)) : null
|
|
@@ -343,7 +308,8 @@ export function svgPathSimplify(input = '', {
|
|
|
343
308
|
// count commands for evaluation
|
|
344
309
|
let comCount = pathData.length
|
|
345
310
|
|
|
346
|
-
if (removeOrphanSubpaths) pathData = removeOrphanedM(pathData);
|
|
311
|
+
if (!isPoly && removeOrphanSubpaths) pathData = removeOrphanedM(pathData);
|
|
312
|
+
|
|
347
313
|
|
|
348
314
|
|
|
349
315
|
/**
|
|
@@ -351,7 +317,6 @@ export function svgPathSimplify(input = '', {
|
|
|
351
317
|
*/
|
|
352
318
|
let subPathArr = splitSubpaths(pathData);
|
|
353
319
|
let lenSub = subPathArr.length;
|
|
354
|
-
|
|
355
320
|
//console.log('subPathArr', subPathArr);
|
|
356
321
|
|
|
357
322
|
|
|
@@ -361,27 +326,29 @@ export function svgPathSimplify(input = '', {
|
|
|
361
326
|
//let { pathData, bb } = subPathArr[i];
|
|
362
327
|
let pathDataSub = subPathArr[i];
|
|
363
328
|
let poly = []
|
|
364
|
-
|
|
365
329
|
let coms = Array.from(new Set(pathDataSub.map(com => com.type))).join('')
|
|
366
|
-
|
|
367
|
-
let closed =
|
|
330
|
+
isPoly = !(/[acqts]/gi).test(coms)
|
|
331
|
+
let closed = isPoly ? true : false;
|
|
368
332
|
|
|
369
|
-
if (isPoly) {
|
|
333
|
+
if (isPoly && !mode) {
|
|
370
334
|
|
|
371
335
|
poly = getPathDataVertices(pathDataSub);
|
|
372
|
-
|
|
336
|
+
let bb = getPolyBBox(reducePoints(poly, 64))
|
|
337
|
+
//console.log(poly, bb);
|
|
373
338
|
|
|
374
339
|
// simplify polygon
|
|
375
340
|
if (simplifyRD > 0) {
|
|
376
|
-
poly = simplifyPolyRD(poly, { quality: simplifyRD
|
|
341
|
+
poly = simplifyPolyRD(poly, { quality: simplifyRD, width: bb.width, height: bb.height })
|
|
377
342
|
}
|
|
378
343
|
|
|
379
344
|
if (simplifyRDP > 0) {
|
|
380
|
-
poly = simplifyPolyRDP(poly, { quality: simplifyRDP
|
|
345
|
+
poly = simplifyPolyRDP(poly, { quality: simplifyRDP, width: bb.width, height: bb.height })
|
|
346
|
+
//poly = simplifyRDP_rel(poly, simplifyRDP, bb.width, bb.height)
|
|
381
347
|
}
|
|
382
348
|
|
|
349
|
+
toPolygon = false;
|
|
383
350
|
pathDataSub = pathDataFromPoly(poly, closed)
|
|
384
|
-
|
|
351
|
+
//pathDataSub[0].bb = bb
|
|
385
352
|
}
|
|
386
353
|
|
|
387
354
|
|
|
@@ -394,33 +361,25 @@ export function svgPathSimplify(input = '', {
|
|
|
394
361
|
smoothPoly = false;
|
|
395
362
|
harmonizeCpts = false;
|
|
396
363
|
|
|
397
|
-
|
|
398
|
-
//console.log(pathDataSub);
|
|
399
|
-
|
|
400
|
-
let pathDataSubPlus = analyzePathData(pathDataSub)
|
|
401
|
-
let { bb, pathData } = pathDataSubPlus;
|
|
402
|
-
pathDataSub = pathData;
|
|
364
|
+
pathDataSub = getPathDataVerbose(pathDataSub);
|
|
403
365
|
|
|
404
|
-
|
|
405
|
-
let polyData = pathDataToPolygon(pathDataSub, {
|
|
366
|
+
let polyData = pathDataToPolygonOpt(pathDataSub, {
|
|
406
367
|
precisionPoly,
|
|
407
368
|
autoAccuracy,
|
|
408
|
-
polyFormat,
|
|
409
|
-
decimals,
|
|
369
|
+
//polyFormat,
|
|
370
|
+
//decimals,
|
|
410
371
|
simplifyRD,
|
|
411
372
|
simplifyRDP
|
|
412
373
|
})
|
|
413
374
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
//poly.push(polyData.poly)
|
|
417
|
-
polys.push(polyData.poly)
|
|
375
|
+
//console.log('toPolygon');
|
|
376
|
+
//polys.push(polyData.poly)
|
|
418
377
|
pathDataSub = polyData.pathData
|
|
378
|
+
isPoly = true;
|
|
419
379
|
|
|
420
380
|
}
|
|
421
381
|
|
|
422
382
|
|
|
423
|
-
|
|
424
383
|
/**
|
|
425
384
|
* poly to beziers via
|
|
426
385
|
* Philip J. Schneider's
|
|
@@ -448,21 +407,22 @@ export function svgPathSimplify(input = '', {
|
|
|
448
407
|
simplifyRD,
|
|
449
408
|
simplifyRDP,
|
|
450
409
|
}
|
|
410
|
+
|
|
411
|
+
//console.log('smooth');
|
|
451
412
|
pathDataSub = simplifyPolygonToPathData(poly, optionsPoly)
|
|
413
|
+
// flag as non poly as we're smoothing to curves
|
|
414
|
+
//isPoly = false
|
|
452
415
|
}
|
|
453
416
|
}
|
|
454
417
|
|
|
455
418
|
|
|
456
|
-
|
|
457
419
|
// harmonize cpts
|
|
458
420
|
// if (harmonizeCpts) pathDataSub = harmonizeCubicCpts(pathDataSub)
|
|
459
421
|
|
|
460
|
-
|
|
461
422
|
// remove zero length linetos
|
|
462
423
|
if (removeColinear || removeZeroLength) pathDataSub = removeZeroLengthLinetos(pathDataSub)
|
|
463
424
|
|
|
464
425
|
|
|
465
|
-
|
|
466
426
|
// sort to top left
|
|
467
427
|
if (optimizeOrder) pathDataSub = pathDataToTopLeft(pathDataSub);
|
|
468
428
|
|
|
@@ -471,8 +431,8 @@ export function svgPathSimplify(input = '', {
|
|
|
471
431
|
if (removeColinear) pathDataSub = pathDataRemoveColinear(pathDataSub, { tolerance, flatBezierToLinetos: false });
|
|
472
432
|
|
|
473
433
|
let tMin = 0, tMax = 1;
|
|
474
|
-
if (addExtremes
|
|
475
|
-
{ tMin, tMax, addExtremes,
|
|
434
|
+
if (addExtremes) pathDataSub = addExtremePoints(pathDataSub,
|
|
435
|
+
{ tMin, tMax, addExtremes, angles: [30] })
|
|
476
436
|
|
|
477
437
|
|
|
478
438
|
|
|
@@ -481,23 +441,39 @@ export function svgPathSimplify(input = '', {
|
|
|
481
441
|
pathDataSub = reversePathData(pathDataSub)
|
|
482
442
|
}
|
|
483
443
|
|
|
444
|
+
// analyze pathdata to add info about significant properties such as extremes, corners
|
|
445
|
+
let pathDataPlus = { bb: {}, dimA: 0, pathData: [] }
|
|
446
|
+
|
|
447
|
+
if (!isPoly) {
|
|
448
|
+
pathDataPlus = analyzePathData(pathDataSub);
|
|
449
|
+
}
|
|
450
|
+
// we skip detailed analysis for native polygons
|
|
451
|
+
else {
|
|
452
|
+
if (!poly.length) {
|
|
453
|
+
let pathDataCubic = convertPathData(JSON.parse(JSON.stringify(pathDataSub)), { toLonghands: true, toAbsolute: true, arcToCubic: true, testTypes: true })
|
|
454
|
+
pathDataPlus.bb = getPolyBBox(getPathDataVertices(pathDataCubic))
|
|
455
|
+
}
|
|
456
|
+
pathDataPlus.dimA = pathDataPlus.bb.width + pathDataPlus.bb.height;
|
|
457
|
+
pathDataPlus.pathData = getPathDataVerbose(pathDataSub, {
|
|
458
|
+
addSquareLength: false,
|
|
459
|
+
addArea: false,
|
|
460
|
+
addAverageDim: false
|
|
461
|
+
})
|
|
462
|
+
}
|
|
463
|
+
|
|
484
464
|
|
|
485
|
-
// analyze pathdata to add info about signicant properties such as extremes, corners
|
|
486
|
-
let pathDataPlus = analyzePathData(pathDataSub, {
|
|
487
|
-
detectSemiExtremes: addSemiExtremes,
|
|
488
|
-
});
|
|
489
465
|
|
|
490
466
|
|
|
491
467
|
// simplify beziers
|
|
492
468
|
let { pathData, bb, dimA } = pathDataPlus;
|
|
469
|
+
|
|
493
470
|
xArr.push(bb.x, bb.x + bb.width)
|
|
494
471
|
yArr.push(bb.y, bb.y + bb.height)
|
|
495
472
|
|
|
496
473
|
|
|
497
474
|
if (refineClosing) pathData = refineClosingCommand(pathData, { threshold: dimA * 0.001 })
|
|
498
475
|
|
|
499
|
-
|
|
500
|
-
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, extrapolateDominant, revertToQuadratics, tolerance }) : pathData;
|
|
476
|
+
pathData = simplifyBezier ? simplifyPathDataCubic(pathData, { simplifyBezier, keepInflections, keepExtremes, keepCorners, revertToQuadratics, tolerance }) : pathData;
|
|
501
477
|
|
|
502
478
|
|
|
503
479
|
// refine extremes
|
|
@@ -544,10 +520,6 @@ export function svgPathSimplify(input = '', {
|
|
|
544
520
|
//let decimalsSub = Math.max(2, detectAccuracy(pathData));
|
|
545
521
|
let decimalsSub = detectAccuracy(pathData);
|
|
546
522
|
accuracyArr.push(decimalsSub);
|
|
547
|
-
//let decimalsSub = detectAccuracy(pathData);
|
|
548
|
-
|
|
549
|
-
// pre round sub path
|
|
550
|
-
//if(roundSub) pathData = roundPathData(pathData, decimalsSub);
|
|
551
523
|
|
|
552
524
|
}
|
|
553
525
|
|
|
@@ -556,6 +528,7 @@ export function svgPathSimplify(input = '', {
|
|
|
556
528
|
|
|
557
529
|
} // end sup paths
|
|
558
530
|
|
|
531
|
+
|
|
559
532
|
// sort subpaths to top left
|
|
560
533
|
let xMin = Math.min(...xArr)
|
|
561
534
|
let yMin = Math.min(...yArr)
|
|
@@ -569,6 +542,11 @@ export function svgPathSimplify(input = '', {
|
|
|
569
542
|
//console.log(i, pathDataPlusArr);
|
|
570
543
|
|
|
571
544
|
|
|
545
|
+
// fix path directions - before reordering
|
|
546
|
+
if (fixDirections) {
|
|
547
|
+
pathDataPlusArr = fixPathDataDirections(pathDataPlusArr);
|
|
548
|
+
}
|
|
549
|
+
|
|
572
550
|
|
|
573
551
|
// prefer top to bottom priority for portrait aspect ratios
|
|
574
552
|
if (optimizeOrder) {
|
|
@@ -576,16 +554,12 @@ export function svgPathSimplify(input = '', {
|
|
|
576
554
|
}
|
|
577
555
|
|
|
578
556
|
|
|
579
|
-
// fix path directions
|
|
580
|
-
if (fixDirections) {
|
|
581
|
-
pathDataPlusArr = fixPathDataDirections(pathDataPlusArr);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
557
|
|
|
585
558
|
|
|
586
559
|
// flatten compound paths
|
|
587
560
|
pathData = [];
|
|
588
561
|
|
|
562
|
+
|
|
589
563
|
// add to global array - including multiple path elements
|
|
590
564
|
pathDataPlusArr_global.push(pathDataPlusArr);
|
|
591
565
|
|
|
@@ -603,99 +577,88 @@ export function svgPathSimplify(input = '', {
|
|
|
603
577
|
pathOptions.decimals = decimals
|
|
604
578
|
}
|
|
605
579
|
|
|
580
|
+
// add simplified poly - if not populated by toPoly conversion
|
|
581
|
+
if (isPoly) {
|
|
582
|
+
//console.log('5. isPoly', isPoly);
|
|
583
|
+
|
|
584
|
+
pathDataPlusArr.forEach(sub => {
|
|
585
|
+
let poly = getPathDataVertices(sub.pathData, false, decimals)
|
|
586
|
+
if (polyFormat === 'array') {
|
|
587
|
+
poly = polyPtsToArray(poly)
|
|
588
|
+
}
|
|
589
|
+
polys.push(poly)
|
|
590
|
+
})
|
|
606
591
|
|
|
607
|
-
// collect for merged svg paths
|
|
608
|
-
mergePaths = false
|
|
609
|
-
if (el && mergePaths) {
|
|
610
|
-
pathData_merged.push(...pathData)
|
|
611
592
|
}
|
|
612
|
-
// single output
|
|
613
|
-
else {
|
|
614
593
|
|
|
615
|
-
// clone pathdata
|
|
616
|
-
//pathData = pathData.map(com => ({ type: com.type, values: [...com.values] }));
|
|
617
|
-
pathData = JSON.parse(JSON.stringify(pathData));
|
|
618
594
|
|
|
619
|
-
|
|
620
|
-
|
|
595
|
+
// split into sub paths - returns svg with multiple paths
|
|
596
|
+
if (splitCompound && !mode && pathDataPlusArr.length > 1) {
|
|
597
|
+
let pathDataSplit = splitCompundGroups(pathDataPlusArr, { toRelative, toShorthands, decimals, addDimensions });
|
|
598
|
+
svg = new DOMParser().parseFromString(pathDataSplit.svg, 'image/svg+xml').querySelector('svg');
|
|
599
|
+
// switch output type
|
|
600
|
+
mode = 1;
|
|
601
|
+
inputType = 'splitPath'
|
|
602
|
+
}
|
|
621
603
|
|
|
622
|
-
// remove zero-length segments introduced by rounding
|
|
623
|
-
if (removeZeroLength) pathData = removeZeroLengthLinetos(pathData);
|
|
624
604
|
|
|
625
|
-
|
|
626
|
-
|
|
605
|
+
// clone pathdata
|
|
606
|
+
pathData = JSON.parse(JSON.stringify(pathData));
|
|
627
607
|
|
|
628
|
-
|
|
629
|
-
|
|
608
|
+
// optimize path data
|
|
609
|
+
pathData = convertPathData(pathData, pathOptions)
|
|
630
610
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
}
|
|
611
|
+
// remove zero-length segments introduced by rounding
|
|
612
|
+
if (removeZeroLength) pathData = removeZeroLengthLinetos(pathData);
|
|
634
613
|
|
|
614
|
+
// realign path to zero origin
|
|
615
|
+
if (alignToOrigin) {
|
|
635
616
|
|
|
636
|
-
|
|
637
|
-
|
|
617
|
+
pathData[0].values[0] = roundTo((pathData[0].values[0] - bb_global.x), decimals)
|
|
618
|
+
pathData[0].values[1] = roundTo((pathData[0].values[1] - bb_global.y), decimals)
|
|
638
619
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
620
|
+
bb_global.x = 0
|
|
621
|
+
bb_global.y = 0
|
|
622
|
+
}
|
|
642
623
|
|
|
643
|
-
compression = +(100 / svgSize * (svgSizeOpt)).toFixed(2)
|
|
644
624
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
original: comCount,
|
|
648
|
-
new: comCountS,
|
|
649
|
-
saved: comCount - comCountS,
|
|
650
|
-
compression,
|
|
651
|
-
decimals,
|
|
652
|
-
//success: comCountS < comCount
|
|
653
|
-
}
|
|
625
|
+
// compare command count
|
|
626
|
+
let comCountS = pathData.length
|
|
654
627
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
628
|
+
let dOpt = pathDataToD(pathData, minifyD)
|
|
629
|
+
//svgSizeOpt = new Blob([dOpt]).size;
|
|
630
|
+
svgSizeOpt = dOpt.length
|
|
631
|
+
|
|
632
|
+
compression = +(100 / svgSize * (svgSizeOpt)).toFixed(2)
|
|
633
|
+
|
|
634
|
+
path.d = dOpt
|
|
635
|
+
path.report = {
|
|
636
|
+
original: comCount,
|
|
637
|
+
new: comCountS,
|
|
638
|
+
saved: comCount - comCountS,
|
|
639
|
+
compression,
|
|
640
|
+
decimals,
|
|
641
|
+
//success: comCountS < comCount
|
|
660
642
|
}
|
|
661
643
|
|
|
644
|
+
// apply new path for svgs
|
|
645
|
+
if (el) {
|
|
646
|
+
el.setAttribute('d', dOpt)
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
|
|
662
650
|
} // end path array
|
|
663
651
|
|
|
664
652
|
/**
|
|
665
653
|
* stringify new SVG
|
|
666
654
|
*/
|
|
667
|
-
if (mode) {
|
|
668
|
-
|
|
669
|
-
//console.log(pathData_merged);
|
|
670
|
-
if (pathData_merged.length) {
|
|
671
|
-
|
|
672
|
-
// optimize path data
|
|
673
|
-
let pathData = convertPathData(pathData_merged, pathOptions)
|
|
674
|
-
|
|
675
|
-
// remove zero-length segments introduced by rounding
|
|
676
|
-
pathData = removeZeroLengthLinetos(pathData);
|
|
677
|
-
|
|
678
|
-
let dOpt = pathDataToD(pathData, minifyD)
|
|
679
|
-
|
|
680
|
-
// apply new path for svgs
|
|
681
|
-
paths[0].el.setAttribute('d', dOpt)
|
|
655
|
+
if (mode || inputType === 'symbol') {
|
|
682
656
|
|
|
683
|
-
|
|
684
|
-
for (let i = 1; i < paths.length; i++) {
|
|
685
|
-
let pathEl = paths[i].el
|
|
686
|
-
if (pathEl) pathEl.remove()
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// remove empty groups e.g groups
|
|
690
|
-
removeEmptySVGEls(svg);
|
|
691
|
-
}
|
|
657
|
+
//console.log('process', inputType);
|
|
692
658
|
|
|
693
659
|
// adjust viewBox and width for scale
|
|
694
660
|
if (scale) {
|
|
695
|
-
|
|
696
661
|
let { x, y, width, height, w, h, hasViewBox, hasWidth, hasHeight, widthUnit, heightUnit } = viewBox;
|
|
697
|
-
//console.log('bb_global', bb_global);
|
|
698
|
-
|
|
699
662
|
if (crop) {
|
|
700
663
|
x = bb_global.x
|
|
701
664
|
y = bb_global.y
|
|
@@ -706,14 +669,14 @@ export function svgPathSimplify(input = '', {
|
|
|
706
669
|
}
|
|
707
670
|
|
|
708
671
|
if (hasViewBox) {
|
|
709
|
-
svg.setAttribute('viewBox', [x, y, width, height].map(val =>
|
|
672
|
+
svg.setAttribute('viewBox', [x, y, width, height].map(val => roundTo(val * scale, decimals)).join(' '))
|
|
710
673
|
}
|
|
711
674
|
if (hasWidth) {
|
|
712
|
-
svg.setAttribute('width',
|
|
675
|
+
svg.setAttribute('width', roundTo(w * scale, decimals) + widthUnit)
|
|
713
676
|
}
|
|
714
677
|
|
|
715
678
|
if (hasHeight) {
|
|
716
|
-
svg.setAttribute('height',
|
|
679
|
+
svg.setAttribute('height', roundTo(h * scale, decimals) + heightUnit)
|
|
717
680
|
}
|
|
718
681
|
}
|
|
719
682
|
|
|
@@ -726,9 +689,12 @@ export function svgPathSimplify(input = '', {
|
|
|
726
689
|
})
|
|
727
690
|
}
|
|
728
691
|
|
|
692
|
+
//console.log(svg);
|
|
693
|
+
if (removeSVGAttributes.includes('xmlns')) omitNamespace = true;
|
|
729
694
|
|
|
730
|
-
svg = stringifySVG(svg, { omitNamespace, removeComments });
|
|
731
695
|
|
|
696
|
+
svg = stringifySVG(svg, { omitNamespace, removeComments, format: minifyD });
|
|
697
|
+
//console.log('!!!svg', svg);
|
|
732
698
|
|
|
733
699
|
//svgSizeOpt = new Blob([svg]).size
|
|
734
700
|
svgSizeOpt = svg.length;
|
|
@@ -738,13 +704,22 @@ export function svgPathSimplify(input = '', {
|
|
|
738
704
|
svgSize = +(svgSize / 1024).toFixed(3)
|
|
739
705
|
svgSizeOpt = +(svgSizeOpt / 1024).toFixed(3)
|
|
740
706
|
|
|
707
|
+
|
|
741
708
|
report = {
|
|
742
709
|
svgSize,
|
|
743
710
|
svgSizeOpt,
|
|
744
711
|
compression,
|
|
745
|
-
decimals
|
|
712
|
+
decimals,
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (keepSmaller && svgSize < svgSizeOpt && !splitCompound) {
|
|
716
|
+
//console.log('Original is smaller!');
|
|
717
|
+
svg = input
|
|
718
|
+
report.node = 'Original is smaller!'
|
|
746
719
|
}
|
|
747
720
|
|
|
721
|
+
|
|
722
|
+
|
|
748
723
|
} else {
|
|
749
724
|
({ d, report } = paths[0]);
|
|
750
725
|
}
|
|
@@ -753,7 +728,16 @@ export function svgPathSimplify(input = '', {
|
|
|
753
728
|
polys = polys[0]
|
|
754
729
|
}
|
|
755
730
|
|
|
756
|
-
|
|
731
|
+
|
|
732
|
+
//console.log('---simplify', input);
|
|
733
|
+
//console.log('5. svg', svg);
|
|
734
|
+
|
|
735
|
+
if (polyFormat === 'string' && polys.length) {
|
|
736
|
+
polys = polys.flat().map(pt => `${pt.x},${pt.y}`).join(' ')
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
return !getObject ? (d ? d : svg) : { svg, d, polys, report, pathDataPlusArr: pathDataPlusArr_global, inputType, dOriginal };
|
|
757
741
|
|
|
758
742
|
}
|
|
759
743
|
|