svg-path-simplify 0.3.4 → 0.3.6
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/.github/ISSUE_TEMPLATE/bug_report.yml +28 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +35 -0
- package/dist/svg-path-simplify.esm.js +4104 -3481
- package/dist/svg-path-simplify.esm.min.js +2 -8
- package/dist/svg-path-simplify.js +4105 -3480
- package/dist/svg-path-simplify.min.js +2 -8
- package/dist/svg-path-simplify.pathdata.esm.js +1090 -1039
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -8
- package/index.html +493 -116
- package/package.json +1 -1
- package/site.webmanifest +21 -0
- package/src/constants.js +3 -1
- package/src/index.js +7 -1
- package/src/pathData_simplify_cubic.js +1 -10
- package/src/pathSimplify-main.js +71 -28
- package/src/pathSimplify-only-pathdata.js +2 -2
- package/src/svg-getAttributes.js +13 -0
- package/src/svg_flatten_transforms.js +43 -0
- package/src/svg_getViewbox.js +23 -11
- package/src/svg_rootSVG.js +9 -0
- package/src/svgii/convert_colors.js +98 -0
- package/src/svgii/convert_units.js +144 -0
- package/src/svgii/geometry.js +24 -4
- package/src/svgii/geometry_bbox.js +2 -1
- package/src/svgii/geometry_bbox_element.js +46 -0
- package/src/svgii/pathData_analyze.js +1 -1
- package/src/svgii/pathData_convert.js +143 -29
- package/src/svgii/pathData_parse.js +2 -99
- package/src/svgii/pathData_parse_els.js +198 -125
- package/src/svgii/pathData_simplify_refineCorners.js +72 -43
- package/src/svgii/pathData_stringify.js +6 -5
- package/src/svgii/poly_normalize.js +21 -1
- package/src/svgii/rounding.js +36 -5
- package/src/svgii/svg-styles-getTransforms.js +43 -5
- package/src/svgii/svg-styles-to-attributes-const.js +8 -3
- package/src/svgii/svg-styles-to-attributes.js +106 -9
- package/src/svgii/svg_cleanup.js +291 -35
- package/src/svgii/svg_el_parse_style_props.js +423 -0
- package/src/svgii/stringify.js +0 -103
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parse svg presentational attributes
|
|
3
|
+
* or CSS styles
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { rad2Deg } from "../constants";
|
|
7
|
+
import { getUnit, isNumericValue, normalizeUnits } from "./convert_units";
|
|
8
|
+
import { autoRound } from "./rounding";
|
|
9
|
+
import { attLookup, horizontalProps, strokeAtts, verticalProps } from "./svg-styles-to-attributes-const";
|
|
10
|
+
|
|
11
|
+
export function parseStylesProperties(el, {
|
|
12
|
+
removeNameSpaced = true,
|
|
13
|
+
autoRoundValues = true,
|
|
14
|
+
removeInvalid = true,
|
|
15
|
+
removeDefaults = true,
|
|
16
|
+
cleanUpStrokes = true,
|
|
17
|
+
exclude = [],
|
|
18
|
+
width = 0,
|
|
19
|
+
height = 0,
|
|
20
|
+
} = {}) {
|
|
21
|
+
|
|
22
|
+
let nodeName = el.nodeName.toLowerCase();
|
|
23
|
+
let attProps = getSvgPresentationAtts(el)
|
|
24
|
+
let cssProps = getSvgCssProps(el)
|
|
25
|
+
|
|
26
|
+
console.log('cssProps', cssProps);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* merge props
|
|
30
|
+
* CSS has higher specificity
|
|
31
|
+
*/
|
|
32
|
+
let props = {
|
|
33
|
+
...attProps,
|
|
34
|
+
...cssProps,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
delete props['style'];
|
|
38
|
+
exclude.push('style')
|
|
39
|
+
|
|
40
|
+
let remove = ['style']
|
|
41
|
+
|
|
42
|
+
let transformsStandalone = ['scale', 'translate', 'rotate'];
|
|
43
|
+
|
|
44
|
+
//let testProp = normalizeUnits(0.5, {unit:'turn'})
|
|
45
|
+
//console.log('testProp', testProp);
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* remove invalid properties
|
|
50
|
+
* e.g font-family for <path>
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
if (removeInvalid || removeDefaults || removeNameSpaced) {
|
|
54
|
+
let propsFilteredObj = filterSvgElProps(nodeName, props, { removeDefaults, removeNameSpaced, exclude, cleanUpStrokes, include: transformsStandalone })
|
|
55
|
+
props = propsFilteredObj.propsFiltered
|
|
56
|
+
remove.push(...propsFilteredObj.remove)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//console.log('!!!props', props, remove);
|
|
60
|
+
|
|
61
|
+
// sanitized prop array
|
|
62
|
+
let propArr = []
|
|
63
|
+
|
|
64
|
+
for (let prop in props) {
|
|
65
|
+
|
|
66
|
+
let valueStr = props[prop];
|
|
67
|
+
|
|
68
|
+
// we parse the path data separately
|
|
69
|
+
if (prop === 'd') continue;
|
|
70
|
+
|
|
71
|
+
let item = { prop, values: [] }
|
|
72
|
+
|
|
73
|
+
if (prop === 'transform') {
|
|
74
|
+
//let regex = /(\w+)\(([^)]+)\)/g;
|
|
75
|
+
//let match;
|
|
76
|
+
let transArr = []
|
|
77
|
+
|
|
78
|
+
//split transform functions
|
|
79
|
+
let transFormFunctions = valueStr.split(/(\w+)\(([^)]+)\)/).map(val => val.trim()).filter(Boolean)
|
|
80
|
+
//console.log(transFormFunctions);
|
|
81
|
+
|
|
82
|
+
for (let i = 1; i < transFormFunctions.length; i += 2) {
|
|
83
|
+
let fn = transFormFunctions[i - 1];
|
|
84
|
+
let values = transFormFunctions[i].split(/,| /).filter(Boolean)
|
|
85
|
+
let transItem = { fn, values: [] }
|
|
86
|
+
|
|
87
|
+
for (let v = 0; v < values.length; v++) {
|
|
88
|
+
//let { value, unit } = parseValue(values[v])
|
|
89
|
+
let transValues = parseValue(values[v])
|
|
90
|
+
//console.log('!!!transValues', transValues);
|
|
91
|
+
transItem.values.push(...transValues)
|
|
92
|
+
//transItem.units.push(unit)
|
|
93
|
+
}
|
|
94
|
+
transArr.push(transItem)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//item.transforms = transArr;
|
|
98
|
+
if (transArr.length) {
|
|
99
|
+
propArr.push({ prop: 'transforms', values: transArr })
|
|
100
|
+
}
|
|
101
|
+
//console.log('transArr', transArr);
|
|
102
|
+
}
|
|
103
|
+
// other propa
|
|
104
|
+
else {
|
|
105
|
+
item.values = parseValue(valueStr);
|
|
106
|
+
//item[prop] = (valueStr);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (item.values.length) {
|
|
110
|
+
propArr.push(item)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* normalize values to
|
|
117
|
+
* user units
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
console.log('!!!propArr', propArr);
|
|
121
|
+
|
|
122
|
+
let propsNorm = {}
|
|
123
|
+
let transFormOrigin = []
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < propArr.length; i++) {
|
|
126
|
+
let item = propArr[i];
|
|
127
|
+
let { prop, values } = item;
|
|
128
|
+
//let itemN = {prop}
|
|
129
|
+
let valsNew = [], valX = 0, valY = 0, unitX = '', unitY = '';
|
|
130
|
+
|
|
131
|
+
if (prop !== 'transforms') {
|
|
132
|
+
//console.log('---prop', prop, values, width, height);
|
|
133
|
+
|
|
134
|
+
if (prop === 'transform-origin') {
|
|
135
|
+
|
|
136
|
+
values.forEach((item, i) => {
|
|
137
|
+
let val = item.value
|
|
138
|
+
if (val === 'left') values[i].value = 0;
|
|
139
|
+
else if (val === 'right') values[i].value = width;
|
|
140
|
+
else if (val === 'top') values[i].value = 0;
|
|
141
|
+
else if (val === 'bottom') values[i].value = height;
|
|
142
|
+
else if (val === 'center') values[i].value = '50%';
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
valX = values[0].value;
|
|
146
|
+
valY = values[1] ? values[1].value : valX;
|
|
147
|
+
unitX = values[0].unit;
|
|
148
|
+
unitY = values[1] ? values[1].unit : unitX;
|
|
149
|
+
|
|
150
|
+
// normalize units for matrix calculation
|
|
151
|
+
valX = normalizeUnits(valX, { unit: unitX, width, height, isHorizontal: true, autoRoundValues })
|
|
152
|
+
valY = normalizeUnits(valY, { unit: unitY, width, height, isVertical: true, autoRoundValues })
|
|
153
|
+
|
|
154
|
+
transFormOrigin.push(valX, valY)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
} else {
|
|
158
|
+
|
|
159
|
+
for (let v = 0; v < values.length; v++) {
|
|
160
|
+
let val = values[v];
|
|
161
|
+
|
|
162
|
+
let unit = val.unit[v];
|
|
163
|
+
let valAbs = val.value;
|
|
164
|
+
|
|
165
|
+
let isHorizontal = horizontalProps.includes(prop)
|
|
166
|
+
let isVertical = verticalProps.includes(prop)
|
|
167
|
+
|
|
168
|
+
if (unit) {
|
|
169
|
+
valAbs = normalizeUnits(val.value, { unit, width, height, isHorizontal, isVertical, autoRoundValues })
|
|
170
|
+
//if (autoRoundValues) valAbs = autoRound(valAbs)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
valsNew.push(valAbs)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
//propsNorm[prop] = valsNew.length === 1 ? valsNew[0] : valsNew;
|
|
179
|
+
if (valsNew.length) propsNorm[prop] = valsNew;
|
|
180
|
+
|
|
181
|
+
} else {
|
|
182
|
+
|
|
183
|
+
let transforms = values || []
|
|
184
|
+
//console.log('transforms', transforms, prop, item);
|
|
185
|
+
|
|
186
|
+
let len = transforms.length
|
|
187
|
+
let transFormAll = []
|
|
188
|
+
for (let t = 0; len && t < len; t++) {
|
|
189
|
+
let { fn, values } = transforms[t];
|
|
190
|
+
let valsN = [], valX = 0, valY = 0, unitX = '', unitY = '', transformFunction = [];
|
|
191
|
+
|
|
192
|
+
// console.log('!!!values', values);
|
|
193
|
+
if (fn === 'scale' || fn === 'translate') {
|
|
194
|
+
valX = values[0].value;
|
|
195
|
+
valY = values[1] ? values[1].value : valX;
|
|
196
|
+
unitX = values[0].unit;
|
|
197
|
+
unitY = values[1] ? values[1].unit : unitX;
|
|
198
|
+
|
|
199
|
+
if (fn === 'scale') {
|
|
200
|
+
valX = unitX = '%' ? valX / 100 : valX
|
|
201
|
+
valY = unitY = '%' ? valY / 100 : valY
|
|
202
|
+
|
|
203
|
+
} else {
|
|
204
|
+
valX = normalizeUnits(valX, { unit: unitX, width, height, isHorizontal: true, autoRoundValues })
|
|
205
|
+
valY = normalizeUnits(valY, { unit: unitY, width, height, isVertical: true, autoRoundValues })
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
valsN.push(valX, valY)
|
|
209
|
+
|
|
210
|
+
transformFunction.push(`${fn}(${valsN.join(' ')})`)
|
|
211
|
+
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// SVG rotations may contain a transform origin
|
|
215
|
+
if (fn === 'rotate') {
|
|
216
|
+
|
|
217
|
+
let angle = values[0].value;
|
|
218
|
+
let unit = values[0].unit;
|
|
219
|
+
angle = normalizeUnits(angle, { unit, autoRoundValues })
|
|
220
|
+
//if(unit==='rad') angle = angle*rad2Deg;
|
|
221
|
+
let rot = [`${fn}(${angle})`]
|
|
222
|
+
|
|
223
|
+
if (values.length === 3) {
|
|
224
|
+
//console.log('has pivot point');
|
|
225
|
+
let cx = values[1].value
|
|
226
|
+
let cy = values[2].value
|
|
227
|
+
rot = [`translate(${cx} ${cy})`, rot[0], `translate(${-cx} ${-cy})`]
|
|
228
|
+
}
|
|
229
|
+
//transFormAll.push(...rot)
|
|
230
|
+
transformFunction = rot
|
|
231
|
+
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
//transFormAll.push(`${fn}(${valsN.join(' ')})`)
|
|
235
|
+
transFormAll.push(...transformFunction)
|
|
236
|
+
//console.log('transFormAll', transFormAll);
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
propsNorm['transform'] = transFormAll
|
|
241
|
+
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
//console.log('transFormOrigin', transFormOrigin);
|
|
246
|
+
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
// append standalone transforms
|
|
251
|
+
let translate = propsNorm['translate'] !== undefined ? `translate(${propsNorm['translate'].join(' ')})` : null;
|
|
252
|
+
let scale = propsNorm['scale'] !== undefined ? `scale(${propsNorm['scale'].join(' ')})` : null;
|
|
253
|
+
let rotate = propsNorm['rotate'] !== undefined ? `rotate(${propsNorm['rotate'].join(' ')})` : null;
|
|
254
|
+
|
|
255
|
+
let standaloneTransforms = [translate, rotate, scale].filter(Boolean)
|
|
256
|
+
if (standaloneTransforms.length) {
|
|
257
|
+
remove.push('translate', 'scale', 'rotate')
|
|
258
|
+
propsNorm['transform'] = [...propsNorm['transform'], ...standaloneTransforms ]
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
console.log('standaloneTransforms', standaloneTransforms);
|
|
262
|
+
//if()
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
// replace transform-origin with translates
|
|
266
|
+
if (transFormOrigin.length && propsNorm['transform'] !== undefined) {
|
|
267
|
+
//console.log('transFormOrigin', transFormOrigin);
|
|
268
|
+
propsNorm['transform'] = [`translate(${transFormOrigin[0]} ${transFormOrigin[1]})`, ...propsNorm['transform'], `translate(${-transFormOrigin[0]} ${-transFormOrigin[1]})`]
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
console.log('!!!propsNorm', propsNorm);
|
|
276
|
+
|
|
277
|
+
//console.log('parseStylesProperties', props);
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* filter out nonsense
|
|
286
|
+
* presentation attributes or
|
|
287
|
+
* style properties not valid
|
|
288
|
+
* for element type
|
|
289
|
+
*/
|
|
290
|
+
export function filterSvgElProps(elNodename = '', props = {}, {
|
|
291
|
+
removeInvalid = true,
|
|
292
|
+
removeDefaults = true,
|
|
293
|
+
allowDataAtts = true,
|
|
294
|
+
cleanUpStrokes = true,
|
|
295
|
+
include = ['id', 'class'],
|
|
296
|
+
exclude = [],
|
|
297
|
+
} = {}) {
|
|
298
|
+
let propsFiltered = {}
|
|
299
|
+
let remove = [];
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
let noStrokeColor = cleanUpStrokes ? (props['stroke'] === undefined) : false;
|
|
303
|
+
|
|
304
|
+
for (let prop in props) {
|
|
305
|
+
let value = props[prop];
|
|
306
|
+
//console.log(prop);
|
|
307
|
+
|
|
308
|
+
// filter out useless
|
|
309
|
+
let isValid = removeInvalid ?
|
|
310
|
+
(attLookup.atts[prop] ? attLookup.atts[prop].includes(elNodename) : false) :
|
|
311
|
+
false;
|
|
312
|
+
|
|
313
|
+
// allow data attributes
|
|
314
|
+
let isDataAtt = allowDataAtts ? prop.startsWith('data-') : false;
|
|
315
|
+
|
|
316
|
+
// filter out defaults
|
|
317
|
+
let isDefault = removeDefaults ?
|
|
318
|
+
(attLookup.defaults[prop] ? attLookup.defaults[prop] !== undefined && attLookup.defaults[prop].includes(value) : false) :
|
|
319
|
+
false;
|
|
320
|
+
|
|
321
|
+
if (isDataAtt || include.includes(prop)) isValid = true;
|
|
322
|
+
if (isDefault) isValid = false
|
|
323
|
+
if (exclude.length && exclude.includes(prop)) isValid = false;
|
|
324
|
+
if (noStrokeColor && strokeAtts.includes(prop)) isValid = false
|
|
325
|
+
|
|
326
|
+
if (isValid) {
|
|
327
|
+
propsFiltered[prop] = props[prop]
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
remove.push(prop)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
return { propsFiltered, remove }
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
export function parseValue(valStr = '') {
|
|
340
|
+
let valArr = valStr.split(/,| /);
|
|
341
|
+
|
|
342
|
+
for (let i = 0; i < valArr.length; i++) {
|
|
343
|
+
|
|
344
|
+
let valStr = valArr[i];
|
|
345
|
+
let val = { value: null, unit: '', numeric: false }
|
|
346
|
+
let isNumeric = isNumericValue(valStr);
|
|
347
|
+
if (!isNumeric) {
|
|
348
|
+
val.value = valStr
|
|
349
|
+
}
|
|
350
|
+
else if (isNumeric) {
|
|
351
|
+
let unit = getUnit(valStr)
|
|
352
|
+
let valNum = parseFloat(valStr)
|
|
353
|
+
val.value = valNum;
|
|
354
|
+
val.unit = unit;
|
|
355
|
+
val.numeric = true
|
|
356
|
+
}
|
|
357
|
+
valArr[i] = val;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return valArr;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
export function getSvgCssProps(el) {
|
|
366
|
+
let styleAtt = el.getAttribute('style')
|
|
367
|
+
let props = styleAtt ? parseInlineCss(styleAtt) : {}
|
|
368
|
+
return props
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function getSvgPresentationAtts(el) {
|
|
372
|
+
let props = {}
|
|
373
|
+
let atts = [...el.attributes].map((att) => att.name);
|
|
374
|
+
let l = atts.length;
|
|
375
|
+
if (!l) return props;
|
|
376
|
+
|
|
377
|
+
for (let i = 0; i < l; i++) {
|
|
378
|
+
let att = atts[i];
|
|
379
|
+
let value = el.getAttribute(att);
|
|
380
|
+
|
|
381
|
+
// test invalid transform functions
|
|
382
|
+
if (att === 'transform') {
|
|
383
|
+
let transformSan = [];
|
|
384
|
+
let transFormFunctions = value.split(/(\w+)\(([^)]+)\)/).map(val => val.trim()).filter(Boolean)
|
|
385
|
+
//console.log('!!transFormFunctions', el.nodeName, transFormFunctions);
|
|
386
|
+
for (let i = 1; i < transFormFunctions.length; i += 2) {
|
|
387
|
+
let prop = transFormFunctions[i - 1];
|
|
388
|
+
let val = transFormFunctions[i];
|
|
389
|
+
let units = val.split(/,| /).map(val => getUnit(val.trim())).filter(Boolean)
|
|
390
|
+
|
|
391
|
+
// remove invalid transform function
|
|
392
|
+
if (!units.length) {
|
|
393
|
+
transformSan.push(`${prop}(${val})`)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
value = transformSan.join(' ');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
props[att] = value.trim()
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
//console.log('!!!svg props', props, 'remove', remove);
|
|
403
|
+
return props;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
function parseInlineCss(styleAtt = '') {
|
|
408
|
+
|
|
409
|
+
let props = {}
|
|
410
|
+
if (!styleAtt) return props;
|
|
411
|
+
|
|
412
|
+
let styleArr = styleAtt.split(';').filter(Boolean).map(prop => prop.trim());
|
|
413
|
+
let l = styleArr.length
|
|
414
|
+
if (!l) return props;
|
|
415
|
+
|
|
416
|
+
for (let i = 0; l && i < l; i++) {
|
|
417
|
+
let style = styleArr[i]
|
|
418
|
+
let [prop, value] = style.split(':').filter(Boolean)
|
|
419
|
+
props[prop] = value;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return props
|
|
423
|
+
}
|
package/src/svgii/stringify.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Serialize pathData array to a minified "d" attribute string.
|
|
3
|
-
*/
|
|
4
|
-
export function pathDataToD(pathData, optimize = 1) {
|
|
5
|
-
|
|
6
|
-
let beautify = optimize>1;
|
|
7
|
-
let minify = beautify ? false : true;
|
|
8
|
-
|
|
9
|
-
// Convert first "M" to "m" if followed by "l" (when minified)
|
|
10
|
-
if (pathData[1].type === "l" && minify) {
|
|
11
|
-
pathData[0].type = "m";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let d = '';
|
|
15
|
-
if(beautify) {
|
|
16
|
-
d = `${pathData[0].type} ${pathData[0].values.join(" ")}\n`;
|
|
17
|
-
}else{
|
|
18
|
-
d = `${pathData[0].type}${pathData[0].values.join(" ")}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
for (let i = 1, len = pathData.length; i < len; i++) {
|
|
23
|
-
let com0 = pathData[i - 1];
|
|
24
|
-
let com = pathData[i];
|
|
25
|
-
let { type, values } = com;
|
|
26
|
-
|
|
27
|
-
// Minify Arc commands (A/a) – actually sucks!
|
|
28
|
-
if (minify && (type === 'A' || type === 'a')) {
|
|
29
|
-
values = [
|
|
30
|
-
values[0], values[1], values[2],
|
|
31
|
-
`${values[3]}${values[4]}${values[5]}`,
|
|
32
|
-
values[6]
|
|
33
|
-
];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Omit type for repeated commands
|
|
37
|
-
type = (com0.type === com.type && com.type.toLowerCase() !== 'm' && minify)
|
|
38
|
-
? " "
|
|
39
|
-
: (
|
|
40
|
-
(com0.type === "m" && com.type === "l") ||
|
|
41
|
-
(com0.type === "M" && com.type === "l") ||
|
|
42
|
-
(com0.type === "M" && com.type === "L")
|
|
43
|
-
) && minify
|
|
44
|
-
? " "
|
|
45
|
-
: com.type;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// concatenate subsequent floating point values
|
|
49
|
-
if (minify) {
|
|
50
|
-
|
|
51
|
-
//console.log(optimize, beautify, minify);
|
|
52
|
-
|
|
53
|
-
let valsString = '';
|
|
54
|
-
let prevWasFloat = false;
|
|
55
|
-
|
|
56
|
-
for (let v = 0, l = values.length; v < l; v++) {
|
|
57
|
-
let val = values[v];
|
|
58
|
-
let valStr = val.toString();
|
|
59
|
-
let isFloat = valStr.includes('.');
|
|
60
|
-
let isSmallFloat = isFloat && Math.abs(val) < 1;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Remove leading zero from small floats *only* if the previous was also a float
|
|
64
|
-
if (isSmallFloat && prevWasFloat) {
|
|
65
|
-
valStr = valStr.replace(/^0\./, '.');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Add space unless this is the first value OR previous was a small float
|
|
69
|
-
if (v > 0 && !(prevWasFloat && isSmallFloat)) {
|
|
70
|
-
valsString += ' ';
|
|
71
|
-
}
|
|
72
|
-
//console.log(isSmallFloat, prevWasFloat, valStr);
|
|
73
|
-
|
|
74
|
-
valsString += valStr
|
|
75
|
-
//.replace(/-0./g, '-.').replace(/ -./g, '-.')
|
|
76
|
-
prevWasFloat = isSmallFloat;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
//console.log('minify', valsString);
|
|
80
|
-
d += `${type}${valsString}`;
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
// regular non-minified output
|
|
84
|
-
else{
|
|
85
|
-
if(beautify) {
|
|
86
|
-
d += `${type} ${values.join(' ')}\n`;
|
|
87
|
-
}else{
|
|
88
|
-
d += `${type}${values.join(' ')}`;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (minify) {
|
|
94
|
-
d = d
|
|
95
|
-
.replace(/ 0\./g, " .") // Space before small decimals
|
|
96
|
-
.replace(/ -/g, "-") // Remove space before negatives
|
|
97
|
-
.replace(/-0\./g, "-.") // Remove leading zero from negative decimals
|
|
98
|
-
.replace(/Z/g, "z"); // Convert uppercase 'Z' to lowercase
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return d;
|
|
103
|
-
}
|