svg-path-simplify 0.3.6 → 0.4.1
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 +24 -0
- package/README.md +38 -85
- package/dist/svg-path-simplify.esm.js +1405 -528
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +1405 -528
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +76 -15
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/docs/api.md +127 -0
- package/index.html +216 -277
- package/package.json +1 -1
- package/src/constants.js +8 -1
- package/src/pathData_simplify_cubic.js +0 -8
- package/src/pathSimplify-main.js +25 -9
- package/src/svg_flatten_transforms.js +1 -1
- package/src/svgii/convert_colors.js +52 -5
- package/src/svgii/convert_units.js +25 -10
- package/src/svgii/pathData_analyze.js +33 -13
- package/src/svgii/pathData_convert.js +62 -6
- package/src/svgii/pathData_parse_els.js +21 -5
- package/src/svgii/pathData_toPolygon.js +3 -1
- package/src/svgii/pathData_transform.js +307 -0
- package/src/svgii/svg-styles-getTransforms.js +119 -8
- package/src/svgii/svg-styles-to-attributes-const.js +19 -4
- package/src/svgii/svg_cleanup.js +319 -97
- package/src/svgii/svg_el_parse_style_props.js +218 -76
- package/src/svgii/transform_qr_decompose.js +74 -0
- package/src/svgii/pathData_scale.js +0 -42
- package/src/svgii/svg-styles-to-attributes.js +0 -236
package/src/svgii/svg_cleanup.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { getElementAtts } from "../svg-getAttributes";
|
|
2
2
|
import { flattenTransforms } from "../svg_flatten_transforms";
|
|
3
3
|
import { getViewBox } from "../svg_getViewbox";
|
|
4
|
-
import { normalizeUnits } from "./convert_units";
|
|
4
|
+
import { isNumericValue, normalizeUnits } from "./convert_units";
|
|
5
5
|
import { getPathDataVertices } from "./geometry";
|
|
6
6
|
import { checkBBoxIntersections, getPathDataBBox, getPolyBBox } from "./geometry_bbox";
|
|
7
7
|
import { getElBBox } from "./geometry_bbox_element";
|
|
8
8
|
import { parsePathDataString } from "./pathData_parse";
|
|
9
9
|
import { parsePathDataNormalized } from "./pathData_convert";
|
|
10
10
|
import { pathElToShape, shapeElToPath } from "./pathData_parse_els";
|
|
11
|
-
import {
|
|
12
|
-
import { strokeAtts } from "./svg-styles-to-attributes-const";
|
|
13
|
-
import { parseStylesProperties } from "./svg_el_parse_style_props";
|
|
11
|
+
//import { scaleProps } from "./svg-styles-to-attributes";
|
|
12
|
+
import { geometryEls, renderedEls, shapeEls, strokeAtts } from "./svg-styles-to-attributes-const";
|
|
13
|
+
import { addTransFormProps, filterSvgElProps, parseStylesProperties } from "./svg_el_parse_style_props";
|
|
14
|
+
import { autoRound } from "./rounding";
|
|
15
|
+
import { getMatrixFromTransform } from "./svg-styles-getTransforms";
|
|
16
|
+
import { qrDecomposeMatrix } from "./transform_qr_decompose";
|
|
17
|
+
import { svgNs } from "../constants";
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
export function removeEmptySVGEls(svg) {
|
|
@@ -22,6 +26,7 @@ export function removeEmptySVGEls(svg) {
|
|
|
22
26
|
|
|
23
27
|
//const DOMParserPoly = globalThis.DOMParser;
|
|
24
28
|
|
|
29
|
+
|
|
25
30
|
export function cleanUpSVG(svgMarkup, {
|
|
26
31
|
removeHidden = true,
|
|
27
32
|
//removeUnused = true,
|
|
@@ -36,6 +41,12 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
36
41
|
cleanupClip = true,
|
|
37
42
|
addViewBox = false,
|
|
38
43
|
addDimensions = false,
|
|
44
|
+
minifyRgbColors = false,
|
|
45
|
+
|
|
46
|
+
normalizeTransforms = true,
|
|
47
|
+
autoRoundValues = true,
|
|
48
|
+
|
|
49
|
+
unGroup = false,
|
|
39
50
|
|
|
40
51
|
mergePaths = false,
|
|
41
52
|
removeOffCanvas = true,
|
|
@@ -47,20 +58,22 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
47
58
|
convert_rects = false,
|
|
48
59
|
convert_ellipses = false,
|
|
49
60
|
convert_poly = false,
|
|
50
|
-
convert_lines=false,
|
|
61
|
+
convert_lines = false,
|
|
51
62
|
|
|
52
63
|
convertTransforms = false,
|
|
64
|
+
removeDefaults = true,
|
|
53
65
|
cleanUpStrokes = true,
|
|
54
66
|
decimals = -1,
|
|
55
67
|
excludedEls = [],
|
|
56
68
|
} = {}) {
|
|
57
69
|
|
|
58
|
-
attributesToGroup = cleanupSVGAtts ? true : false;
|
|
70
|
+
//attributesToGroup = cleanupSVGAtts ? true : false;
|
|
59
71
|
|
|
60
72
|
|
|
61
73
|
// replace namespaced refs
|
|
62
74
|
if (fixHref) svgMarkup = svgMarkup.replaceAll("xlink:href=", "href=");
|
|
63
75
|
|
|
76
|
+
|
|
64
77
|
let svg = new DOMParser()
|
|
65
78
|
.parseFromString(svgMarkup, "text/html")
|
|
66
79
|
.querySelector("svg");
|
|
@@ -69,16 +82,60 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
69
82
|
let { x, y, width, height } = viewBox;
|
|
70
83
|
|
|
71
84
|
|
|
85
|
+
// get svg styles
|
|
86
|
+
let propOptions = {
|
|
87
|
+
width: width,
|
|
88
|
+
height: height,
|
|
89
|
+
normalizeTransforms,
|
|
90
|
+
removeDefaults: false,
|
|
91
|
+
cleanUpStrokes: false,
|
|
92
|
+
autoRoundValues,
|
|
93
|
+
minifyRgbColors,
|
|
94
|
+
}
|
|
95
|
+
let stylePropsSVG = parseStylesProperties(svg, propOptions)
|
|
96
|
+
|
|
97
|
+
// add svg font size for scaling relative
|
|
98
|
+
propOptions.fontSize = stylePropsSVG['font-size'] ? stylePropsSVG['font-size'][0] : 16;
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* get group styles
|
|
103
|
+
* especially transformations to
|
|
104
|
+
* be inherited by children
|
|
105
|
+
*/
|
|
106
|
+
let groups = svg.querySelectorAll('g')
|
|
107
|
+
let groupProps = [];
|
|
108
|
+
|
|
109
|
+
groups.forEach(g => {
|
|
110
|
+
let stylePropsG = parseStylesProperties(g, propOptions)
|
|
111
|
+
groupProps.push(stylePropsG);
|
|
112
|
+
let children = g.querySelectorAll(`${renderedEls.join(', ')}`)
|
|
113
|
+
|
|
114
|
+
// store parent styles to child property
|
|
115
|
+
children.forEach(child => {
|
|
116
|
+
if (child.parentStyleProps === undefined) {
|
|
117
|
+
child.parentStyleProps = []
|
|
118
|
+
}
|
|
119
|
+
child.parentStyleProps.push(stylePropsG)
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
72
125
|
if (cleanupSVGAtts) {
|
|
73
126
|
//console.log('cleanupSVGAtts');
|
|
74
|
-
let allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class'
|
|
127
|
+
let allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class'];
|
|
128
|
+
if (!stylesToAttributes) {
|
|
129
|
+
allowed.push('fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'font-size', 'font-family', 'font-style', 'style');
|
|
130
|
+
}
|
|
131
|
+
|
|
75
132
|
removeExcludedAttribues(svg, allowed)
|
|
76
133
|
}
|
|
77
134
|
|
|
78
135
|
// add viewBox
|
|
79
136
|
if (addViewBox) addSvgViewBox(svg, { x, y, width, height })
|
|
80
137
|
if (addDimensions) {
|
|
81
|
-
svg.setAttribute('width', width);
|
|
138
|
+
svg.setAttribute('width', width);
|
|
82
139
|
svg.setAttribute('height', height);
|
|
83
140
|
}
|
|
84
141
|
|
|
@@ -94,44 +151,20 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
94
151
|
// always remove scripts
|
|
95
152
|
let removeEls = ['metadata', 'script', ...excludedEls]
|
|
96
153
|
|
|
97
|
-
|
|
154
|
+
removeSVGEls(svg, { removeEls, removeNameSpaced });
|
|
98
155
|
|
|
99
156
|
// an array of all elements' properties
|
|
100
157
|
let svgElProps = []
|
|
101
|
-
|
|
102
|
-
let geometryElements = ['polygon', 'polyline', 'line', 'rect', 'circle', 'ellipse']
|
|
103
|
-
|
|
104
|
-
//console.log('shapeConvert', shapeConvert);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
/** convert paths to shapes */
|
|
108
|
-
if(shapeConvert === 'toShapes'){
|
|
109
|
-
let paths = svg.querySelectorAll('path')
|
|
110
|
-
paths.forEach(path=>{
|
|
111
|
-
let shape = pathElToShape(path, {convert_rects, convert_ellipses, convert_poly, convert_lines})
|
|
112
|
-
path.replaceWith(shape)
|
|
113
|
-
path = shape;
|
|
114
|
-
//console.log('path', path);
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
}
|
|
158
|
+
let els = svg.querySelectorAll(`${renderedEls.join(', ')}`)
|
|
118
159
|
|
|
119
160
|
|
|
120
161
|
for (let i = 0; i < els.length; i++) {
|
|
121
162
|
let el = els[i];
|
|
122
163
|
|
|
123
164
|
let name = el.nodeName.toLowerCase();
|
|
165
|
+
//console.log(name);
|
|
124
166
|
|
|
125
|
-
//
|
|
126
|
-
if (shapeConvert === 'toPaths' && name !== 'path' && geometryElements.includes(name)) {
|
|
127
|
-
let path = shapeElToPath(el, { width, height, convert_rects, convert_ellipses, convert_poly, convert_lines });
|
|
128
|
-
el.replaceWith(path)
|
|
129
|
-
name = 'path'
|
|
130
|
-
el = path;
|
|
131
|
-
//console.log('shapesToPaths', el.outerHTML);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// remove hidden elements
|
|
167
|
+
// 1. remove hidden elements
|
|
135
168
|
let style = el.getAttribute('style') || ''
|
|
136
169
|
let isHiddenByStyle = style ? style.trim().includes('display:none') : false;
|
|
137
170
|
let isHidden = (el.getAttribute('display') && el.getAttribute('display') === 'none') || isHiddenByStyle;
|
|
@@ -146,94 +179,241 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
146
179
|
* convert relative or physical units
|
|
147
180
|
* to user units
|
|
148
181
|
*/
|
|
182
|
+
let styleProps = parseStylesProperties(el, propOptions)
|
|
183
|
+
|
|
184
|
+
// get parent styles
|
|
185
|
+
let { parentStyleProps = [] } = el;
|
|
186
|
+
let inheritedProps = {}
|
|
187
|
+
let transFormInherited = []
|
|
149
188
|
|
|
150
189
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
190
|
+
/** inherit transforms
|
|
191
|
+
* and styles from group
|
|
192
|
+
*/
|
|
193
|
+
parentStyleProps.forEach(props => {
|
|
194
|
+
// transforms from groups are applied cumulatively
|
|
195
|
+
let { transformArr = [] } = props
|
|
196
|
+
transFormInherited.push(...transformArr)
|
|
197
|
+
|
|
198
|
+
// merge
|
|
199
|
+
inheritedProps = {
|
|
200
|
+
...inheritedProps,
|
|
201
|
+
...props
|
|
202
|
+
};
|
|
155
203
|
})
|
|
156
|
-
*/
|
|
157
204
|
|
|
158
205
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
*/
|
|
206
|
+
//merge transforms
|
|
207
|
+
transFormInherited = [...transFormInherited, ...styleProps.transformArr]
|
|
208
|
+
styleProps.transformArr = transFormInherited
|
|
163
209
|
|
|
164
210
|
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
211
|
+
// merge with svg props
|
|
212
|
+
styleProps = {
|
|
213
|
+
...stylePropsSVG,
|
|
214
|
+
...inheritedProps,
|
|
215
|
+
...styleProps
|
|
170
216
|
}
|
|
217
|
+
//console.log('inheritedProps', inheritedProps, name);
|
|
171
218
|
|
|
172
|
-
|
|
219
|
+
// add combined transforms
|
|
220
|
+
addTransFormProps(styleProps, transFormInherited);
|
|
221
|
+
|
|
222
|
+
//console.log('transFormInherited', transFormInherited);
|
|
223
|
+
//console.log('styleProps', styleProps);
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
let { remove, matrix, transComponents } = styleProps;
|
|
227
|
+
|
|
228
|
+
// mark attributes for removal
|
|
229
|
+
if (removeClassNames) styleProps.remove.push('class')
|
|
230
|
+
if (removeIds) styleProps.remove.push('id')
|
|
231
|
+
if (removeDimensions) {
|
|
232
|
+
styleProps.remove.push('width')
|
|
233
|
+
styleProps.remove.push('height')
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
// styles to atts
|
|
238
|
+
if (unGroup || convertTransforms || minifyRgbColors ) stylesToAttributes = true;
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
if (stylesToAttributes) {
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* normalize transforms
|
|
245
|
+
*/
|
|
246
|
+
if (normalizeTransforms && matrix) {
|
|
247
|
+
let { rotate, scaleX, scaleY, skewX, translateX, translateY } = transComponents;
|
|
248
|
+
//console.log(rotate, scaleX, scaleY, skewX, skewY, translateX, translateY);
|
|
249
|
+
|
|
250
|
+
// scale attributes instead of transform
|
|
251
|
+
let hasRot = rotate !== 0 || skewX !== 0;
|
|
252
|
+
let unProportional = scaleX !== scaleY;
|
|
253
|
+
let scalableByAtt = ['circle', 'ellipse', 'rect']
|
|
254
|
+
let needsTrans = convertTransforms || (name === 'g') || (hasRot) || unProportional
|
|
255
|
+
//needsTrans = true
|
|
256
|
+
|
|
257
|
+
if (!needsTrans && scalableByAtt.includes(name)) {
|
|
258
|
+
|
|
259
|
+
if (name === 'circle' || name === 'ellipse') {
|
|
260
|
+
styleProps.cx[0] = [styleProps.cx[0] * scaleX + translateX]
|
|
261
|
+
styleProps.cy[0] = [styleProps.cy[0] * scaleX + translateY]
|
|
262
|
+
|
|
263
|
+
if (styleProps.r) styleProps.r[0] = [styleProps.r[0] * scaleX]
|
|
173
264
|
|
|
265
|
+
if (styleProps.rx) styleProps.rx[0] = [styleProps.rx[0] * scaleX]
|
|
266
|
+
if (styleProps.ry) styleProps.ry[0] = [styleProps.ry[0] * scaleX]
|
|
174
267
|
|
|
268
|
+
}
|
|
269
|
+
else if (name === 'rect') {
|
|
270
|
+
let x = styleProps.x ? styleProps.x[0] + translateX : translateX;
|
|
271
|
+
let y = styleProps.y ? styleProps.y[0] + translateY : translateY;
|
|
272
|
+
|
|
273
|
+
let rx = styleProps.rx ? styleProps.rx[0] * scaleX : 0;
|
|
274
|
+
let ry = styleProps.ry ? styleProps.ry[0] * scaleY : 0;
|
|
275
|
+
|
|
276
|
+
styleProps.x = [x]
|
|
277
|
+
styleProps.y = [y]
|
|
278
|
+
|
|
279
|
+
styleProps.rx = [rx]
|
|
280
|
+
styleProps.ry = [ry]
|
|
175
281
|
|
|
176
|
-
|
|
177
|
-
|
|
282
|
+
styleProps.width = [styleProps.width[0] * scaleX]
|
|
283
|
+
styleProps.height = [styleProps.height[0] * scaleX]
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
remove.push('transform')
|
|
178
287
|
|
|
179
|
-
|
|
288
|
+
// scale props like stroke width or dash-array
|
|
289
|
+
styleProps = scaleProps(styleProps, { props: ['stroke-width', 'stroke-dasharray'], scale: scaleX })
|
|
180
290
|
|
|
181
|
-
|
|
182
|
-
|
|
291
|
+
} else {
|
|
292
|
+
el.setAttribute('transform', transComponents.matrixAtt)
|
|
293
|
+
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* apply consolidated
|
|
300
|
+
* element attributes
|
|
301
|
+
*/
|
|
302
|
+
|
|
303
|
+
let stylePropsFiltered = filterSvgElProps(name, styleProps,
|
|
304
|
+
{ removeDefaults: true, cleanUpStrokes });
|
|
305
|
+
|
|
306
|
+
remove = [...remove, ...stylePropsFiltered.remove];
|
|
307
|
+
|
|
308
|
+
for (let prop in stylePropsFiltered.propsFiltered) {
|
|
309
|
+
let values = styleProps[prop]
|
|
310
|
+
//console.log('add', prop);
|
|
311
|
+
let val = values.length ? values.join(' ') : values[0]
|
|
312
|
+
el.setAttribute(prop, val)
|
|
313
|
+
}
|
|
183
314
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
315
|
+
// remove obsolete attributes
|
|
316
|
+
for (let i = 0; i < remove.length; i++) {
|
|
317
|
+
let att = remove[i];
|
|
318
|
+
if (!stylesToAttributes && att === 'style') continue
|
|
187
319
|
|
|
188
|
-
|
|
189
|
-
|
|
320
|
+
//console.log('remove att', att, name);
|
|
321
|
+
el.removeAttribute(att)
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* remove group styles
|
|
328
|
+
* copied to children
|
|
329
|
+
* or remove nesting
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
if (unGroup) {
|
|
333
|
+
groups.forEach((g, i) => {
|
|
334
|
+
let children = [...g.children];
|
|
335
|
+
|
|
336
|
+
children.forEach(child => {
|
|
337
|
+
g.parentNode.insertBefore(child, g)
|
|
338
|
+
})
|
|
339
|
+
g.remove()
|
|
190
340
|
})
|
|
341
|
+
} else {
|
|
342
|
+
groups.forEach((g, i) => {
|
|
343
|
+
let atts = [...Object.keys(groupProps[i]), 'style', 'transform'];
|
|
344
|
+
atts.forEach(att => {
|
|
345
|
+
g.removeAttribute(att)
|
|
346
|
+
})
|
|
347
|
+
})
|
|
348
|
+
|
|
191
349
|
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
} // endof style processing
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* element conversions:
|
|
357
|
+
* shapes to paths or
|
|
358
|
+
* paths to shapes
|
|
359
|
+
*/
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
// force shape conversion when transform conversion is enabled
|
|
363
|
+
if (convertTransforms) {
|
|
364
|
+
shapeConvert = 'toPaths';
|
|
365
|
+
convert_rects = true;
|
|
366
|
+
convert_ellipses = true;
|
|
367
|
+
convert_poly = true;
|
|
368
|
+
convert_lines = true;
|
|
192
369
|
}
|
|
193
|
-
}
|
|
194
370
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
moveAttributesToGroup(svgElProps, mergePaths)
|
|
198
|
-
}
|
|
371
|
+
// convert shapes to paths
|
|
372
|
+
if (shapeConvert === 'toPaths') {
|
|
199
373
|
|
|
200
|
-
|
|
201
|
-
svg.removeAttribute('width')
|
|
202
|
-
svg.removeAttribute('height')
|
|
203
|
-
}
|
|
374
|
+
let { matrix = null, transComponents = null } = styleProps;
|
|
204
375
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
376
|
+
if (matrix && transComponents) {
|
|
377
|
+
// scale props like stroke width or dash-array before conversion
|
|
378
|
+
['stroke-width', 'stroke-dasharray'].forEach(att => {
|
|
379
|
+
let attVal = el.getAttribute(att)
|
|
380
|
+
let vals = attVal ? attVal.split(' ').filter(Boolean).map(Number).map(val => val * transComponents.scaleX) : []
|
|
381
|
+
if (vals.length) el.setAttribute(att, vals.join(' '))
|
|
382
|
+
})
|
|
383
|
+
}
|
|
214
384
|
|
|
215
|
-
|
|
385
|
+
// convert paths only if a matrix transform is required
|
|
386
|
+
if (matrix ? geometryEls.includes(name) : shapeEls.includes(name)) {
|
|
216
387
|
|
|
388
|
+
let path = shapeElToPath(el, { width, height, convert_rects, convert_ellipses, convert_poly, convert_lines, matrix });
|
|
389
|
+
el.replaceWith(path)
|
|
217
390
|
|
|
391
|
+
name = 'path'
|
|
392
|
+
el = path;
|
|
218
393
|
|
|
219
|
-
/**
|
|
220
|
-
* refine properties
|
|
221
|
-
* such as transforms or properties including units
|
|
222
|
-
*/
|
|
223
394
|
|
|
224
|
-
|
|
225
|
-
for(let i=0; i<svgElProps.length; i++){
|
|
226
|
-
let item = svgElProps[i];
|
|
227
|
-
let {propsFiltered} = item;
|
|
395
|
+
}
|
|
228
396
|
|
|
229
|
-
|
|
397
|
+
}
|
|
230
398
|
|
|
231
|
-
|
|
399
|
+
// convert paths to shapes
|
|
400
|
+
else if (shapeConvert === 'toShapes') {
|
|
401
|
+
let paths = svg.querySelectorAll('path')
|
|
402
|
+
paths.forEach(path => {
|
|
403
|
+
let shape = pathElToShape(path, { convert_rects, convert_ellipses, convert_poly, convert_lines })
|
|
404
|
+
path.replaceWith(shape)
|
|
405
|
+
path = shape;
|
|
406
|
+
})
|
|
232
407
|
|
|
233
408
|
}
|
|
234
409
|
|
|
235
|
-
|
|
236
|
-
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
}//endof element loop
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
|
|
237
417
|
|
|
238
418
|
// remove futile clip-paths
|
|
239
419
|
if (cleanupClip) removeFutileClipPaths(svg, { x, y, width, height })
|
|
@@ -457,7 +637,7 @@ function moveAttributesToGroup(svgElProps = [], mergePaths = true) {
|
|
|
457
637
|
|
|
458
638
|
// wrap in group if not existent
|
|
459
639
|
if (!g) {
|
|
460
|
-
g = document.createElementNS(
|
|
640
|
+
g = document.createElementNS(svgNs, 'g');
|
|
461
641
|
el0.parentNode.insertBefore(g, el0)
|
|
462
642
|
group.forEach(item => {
|
|
463
643
|
g.append(item.el)
|
|
@@ -518,6 +698,35 @@ function moveAttributesToGroup(svgElProps = [], mergePaths = true) {
|
|
|
518
698
|
}
|
|
519
699
|
|
|
520
700
|
|
|
701
|
+
export function scaleProps(styleProps = {}, { props = [], scale = 1 } = {}) {
|
|
702
|
+
if (scale === 1 || !props.length) return props;
|
|
703
|
+
|
|
704
|
+
for (let i = 0; i < props.length; i++) {
|
|
705
|
+
let prop = props[i];
|
|
706
|
+
|
|
707
|
+
if (styleProps[prop] !== undefined) {
|
|
708
|
+
styleProps[prop] = styleProps[prop].map(val => val * scale)
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return styleProps
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
export function removeSVGEls(svg, {
|
|
715
|
+
remove = ['metadata', 'script'],
|
|
716
|
+
removeNameSpaced = true,
|
|
717
|
+
} = {}) {
|
|
718
|
+
let els = svg.querySelectorAll('*')
|
|
719
|
+
els.forEach(el => {
|
|
720
|
+
let nodeName = el.nodeName;
|
|
721
|
+
if ((removeNameSpaced && nodeName.includes(':')) ||
|
|
722
|
+
remove.includes(nodeName)
|
|
723
|
+
) {
|
|
724
|
+
el.remove()
|
|
725
|
+
}
|
|
726
|
+
})
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
|
|
521
730
|
function cleanSvgPrologue(svgString) {
|
|
522
731
|
return (
|
|
523
732
|
svgString
|
|
@@ -552,22 +761,32 @@ function removeAtts(el, exclude = [], include = []) {
|
|
|
552
761
|
}
|
|
553
762
|
|
|
554
763
|
|
|
555
|
-
function removeNameSpaceAtts(el
|
|
764
|
+
function removeNameSpaceAtts(el, {
|
|
765
|
+
include = ['xlink:href']
|
|
766
|
+
} = {}) {
|
|
556
767
|
let atts = [...el.attributes].map((att) => att.name);
|
|
557
768
|
atts.forEach((att) => {
|
|
558
|
-
if (att.includes(":")) {
|
|
769
|
+
if (att.includes(":") && !include.includes(att)) {
|
|
559
770
|
el.removeAttribute(att);
|
|
560
771
|
}
|
|
561
772
|
});
|
|
562
773
|
}
|
|
563
774
|
|
|
564
|
-
export function stringifySVG(svg,
|
|
775
|
+
export function stringifySVG(svg, {
|
|
776
|
+
omitNamespace = false,
|
|
777
|
+
removeComments = true,
|
|
778
|
+
} = {}) {
|
|
565
779
|
let markup = new XMLSerializer().serializeToString(svg);
|
|
566
780
|
|
|
567
781
|
if (omitNamespace) {
|
|
568
782
|
markup = markup.replaceAll('xmlns="http://www.w3.org/2000/svg"', '')
|
|
569
783
|
}
|
|
570
784
|
|
|
785
|
+
if (removeComments) {
|
|
786
|
+
markup = markup
|
|
787
|
+
.replace(/(<!--.*?-->)|(<!--[\S\s]+?-->)|(<!--[\S\s]*?$)/g, '')
|
|
788
|
+
}
|
|
789
|
+
|
|
571
790
|
markup = markup
|
|
572
791
|
.replace(/\t/g, "")
|
|
573
792
|
.replace(/[\n\r|]/g, "\n")
|
|
@@ -576,9 +795,12 @@ export function stringifySVG(svg, omitNamespace = false) {
|
|
|
576
795
|
//.replace(/ +/g, ' ')
|
|
577
796
|
.replace(/> </g, '><')
|
|
578
797
|
.trim()
|
|
579
|
-
|
|
798
|
+
// sanitize linebreaks within pathdata
|
|
580
799
|
.replaceAll(' ', '\n');
|
|
581
800
|
|
|
582
801
|
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
583
805
|
return markup
|
|
584
806
|
}
|