svg-path-simplify 0.4.2 → 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.
Files changed (44) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -4
  3. package/dist/svg-path-simplify.esm.js +2139 -940
  4. package/dist/svg-path-simplify.esm.min.js +2 -2
  5. package/dist/svg-path-simplify.js +2139 -940
  6. package/dist/svg-path-simplify.min.js +2 -2
  7. package/dist/svg-path-simplify.pathdata.esm.js +127 -85
  8. package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
  9. package/docs/privacy-webapp.md +24 -0
  10. package/index.html +290 -152
  11. package/package.json +1 -1
  12. package/src/css_parse.js +317 -0
  13. package/src/detect_input.js +34 -4
  14. package/src/pathData_simplify_harmonize_cpts.js +77 -1
  15. package/src/pathSimplify-main.js +242 -269
  16. package/src/pathSimplify-presets.js +243 -0
  17. package/src/poly-fit-curve-schneider.js +14 -7
  18. package/src/simplify_poly_RC.js +102 -0
  19. package/src/simplify_poly_RDP.js +109 -1
  20. package/src/simplify_poly_radial_distance.js +3 -3
  21. package/src/string_helpers.js +130 -4
  22. package/src/svgii/geometry.js +182 -3
  23. package/src/svgii/geometry_length.js +237 -0
  24. package/src/svgii/pathData_convert.js +5 -1
  25. package/src/svgii/pathData_fix_directions.js +6 -0
  26. package/src/svgii/pathData_fromPoly.js +3 -3
  27. package/src/svgii/pathData_getLength.js +86 -0
  28. package/src/svgii/pathData_parse.js +2 -0
  29. package/src/svgii/pathData_parse_els.js +66 -68
  30. package/src/svgii/pathData_split_to_groups.js +168 -0
  31. package/src/svgii/pathData_stringify.js +26 -64
  32. package/src/svgii/pathData_toPolygon.js +3 -4
  33. package/src/svgii/poly_analyze.js +61 -0
  34. package/src/svgii/poly_normalize.js +11 -2
  35. package/src/svgii/poly_to_pathdata.js +85 -24
  36. package/src/svgii/rounding.js +8 -7
  37. package/src/svgii/svg_cleanup.js +374 -620
  38. package/src/svgii/svg_cleanup_convertPathLength.js +32 -0
  39. package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
  40. package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
  41. package/src/svgii/svg_cleanup_remove_els_and_atts.js +72 -0
  42. package/src/svgii/svg_cleanup_ungroup.js +36 -0
  43. package/src/svgii/svg_el_parse_style_props.js +65 -43
  44. package/src/svgii/svg_getElementLength.js +67 -0
@@ -11,21 +11,18 @@ import { pathElToShape, shapeElToPath } from "./pathData_parse_els";
11
11
  //import { scaleProps } from "./svg-styles-to-attributes";
12
12
  import { geometryEls, geometryProps, renderedEls, shapeEls, strokeAtts } from "./svg-styles-to-attributes-const";
13
13
  import { addTransFormProps, filterSvgElProps, parseStylesProperties } from "./svg_el_parse_style_props";
14
- import { autoRound } from "./rounding";
14
+ import { autoRound, roundTo } from "./rounding";
15
15
  import { getMatrixFromTransform } from "./svg-styles-getTransforms";
16
16
  import { qrDecomposeMatrix } from "./transform_qr_decompose";
17
17
  import { svgNs } from "../constants";
18
18
  import { toCamelCase, toShortStr } from "../string_helpers";
19
-
20
-
21
- export function removeEmptySVGEls(svg) {
22
- let els = svg.querySelectorAll('g, defs');
23
- els.forEach(el => {
24
- if (!el.children.length) el.remove()
25
- })
26
- }
27
-
28
- //const DOMParserPoly = globalThis.DOMParser;
19
+ import { getElementLength } from "./svg_getElementLength";
20
+ import { removeHiddenSvgEls, removeSvgAtts, removeSvgChildAtts, removeSvgEls } from "./svg_cleanup_remove_els_and_atts";
21
+ import { cleanupSVGAttributes, removeElAtts } from "./svg_cleanup_general_svg_atts";
22
+ import { convertPathLengthAtt } from "./svg_cleanup_convertPathLength";
23
+ import { removeGroupProps, ungroupElements } from "./svg_cleanup_ungroup";
24
+ import { parseSvgCss } from "../css_parse";
25
+ import { setNormalizedTransformsToEl } from "./svg_cleanup_normalize_transforms";
29
26
 
30
27
 
31
28
  export function cleanUpSVG(svgMarkup, {
@@ -56,6 +53,8 @@ export function cleanUpSVG(svgMarkup, {
56
53
 
57
54
  cleanupSVGAtts = true,
58
55
  removeNameSpaced = true,
56
+ removeNameSpacedAtts = true,
57
+ convertPathLength = false,
59
58
 
60
59
  // meta
61
60
  allowMeta = false,
@@ -64,10 +63,14 @@ export function cleanUpSVG(svgMarkup, {
64
63
 
65
64
  //shapesToPaths = false,
66
65
  shapeConvert = false,
67
- convert_rects = false,
68
- convert_ellipses = false,
69
- convert_poly = false,
70
- convert_lines = false,
66
+ convertShapes = [],
67
+
68
+ // remove elements
69
+ removeElements = [],
70
+
71
+ // remove attributes
72
+ removeSVGAttributes = [],
73
+ removeElAttributes = [],
71
74
 
72
75
  convertTransforms = false,
73
76
  removeDefaults = true,
@@ -76,8 +79,13 @@ export function cleanUpSVG(svgMarkup, {
76
79
  excludedEls = [],
77
80
  } = {}) {
78
81
 
79
- //attributesToGroup = cleanupSVGAtts ? true : false;
80
- if (attributesToGroup) stylesToAttributes = true;
82
+
83
+
84
+ // resolve dependencies
85
+ if (unGroup || convertTransforms || minifyRgbColors || attributesToGroup)
86
+ stylesToAttributes = true;
87
+
88
+ if(stylesToAttributes) cleanUpStrokes = true;
81
89
 
82
90
  // replace namespaced refs
83
91
  if (fixHref) svgMarkup = svgMarkup.replaceAll("xlink:href=", "href=");
@@ -87,17 +95,39 @@ export function cleanUpSVG(svgMarkup, {
87
95
  .parseFromString(svgMarkup, "text/html")
88
96
  .querySelector("svg");
89
97
 
98
+
90
99
  let viewBox = getViewBox(svg)
91
100
  let { x, y, width, height } = viewBox;
101
+ let remove = []
102
+
103
+
104
+
105
+ // add viewBox
106
+ if (addViewBox) addSvgViewBox(svg, { x, y, width, height })
107
+ if (addDimensions) {
108
+ svg.setAttribute('width', width);
109
+ svg.setAttribute('height', height);
110
+ }
111
+
112
+ // remove unused defs or optimize order
113
+ if (cleanupDefs) cleanupSvgDefs(svg, { x, y, width, height, cleanupClip });
92
114
 
93
115
 
94
- // get svg styles
116
+ // remove off canvas
117
+ if (removeOffCanvas) removeOffCanvasEls(svg, { x, y, width, height });
118
+
119
+
120
+ /**
121
+ * collect svg styles
122
+ * and properties
123
+ */
95
124
  let propOptions = {
96
- width: width,
97
- height: height,
125
+ width,
126
+ height,
98
127
  normalizeTransforms,
99
128
  removeDefaults: false,
100
129
  cleanUpStrokes: false,
130
+ //cleanUpStrokes,
101
131
  allowMeta,
102
132
  allowDataAtts,
103
133
  allowAriaAtts,
@@ -105,18 +135,54 @@ export function cleanUpSVG(svgMarkup, {
105
135
  removeIds,
106
136
  removeClassNames,
107
137
  minifyRgbColors,
138
+ stylesheetProps: {},
139
+ exclude:[]
108
140
  }
109
141
 
110
- // root svg properties
142
+ // root svg inline style properties
111
143
  let stylePropsSVG = parseStylesProperties(svg, propOptions)
112
144
  //console.log('stylePropsSVG', stylePropsSVG);
113
145
 
146
+ let styleEl = svg.querySelector('style')
147
+ let cssStylePropsSVG = {}
148
+
149
+ if (styleEl) {
150
+ cssStylePropsSVG = parseSvgCss(styleEl, { parent: svg })
151
+
152
+ //save stylesheet dependencies in node
153
+ for (let selector in cssStylePropsSVG) {
154
+ let els = svg.querySelectorAll(`${selector}`);
155
+ els.forEach(el => {
156
+ if (!el['cssRules']) el['cssRules'] = [];
157
+ el['cssRules'].push(selector)
158
+
159
+ // remove class names only used for styling
160
+ if (stylesToAttributes) {
161
+ let className = selector.substring(1)
162
+ el.classList.remove(className)
163
+ }
164
+ })
165
+ }
166
+
167
+ //console.log('cssStylePropsSVG', cssStylePropsSVG);
168
+
169
+ // remove style element from element
170
+ if (stylesToAttributes) {
171
+ styleEl.remove()
172
+ }
173
+ }
174
+ // remove style element from root SVG
175
+ if (stylesToAttributes) svg.removeAttribute('style')
176
+
177
+
178
+ // add stylesheet props
179
+ propOptions.stylesheetProps = cssStylePropsSVG;
180
+
114
181
 
115
182
  // add svg font size for scaling relative
116
183
  propOptions.fontSize = stylePropsSVG['font-size'] ? stylePropsSVG['font-size'][0] : 16;
117
184
 
118
185
 
119
-
120
186
  /**
121
187
  * get group styles
122
188
  * especially transformations to
@@ -126,7 +192,10 @@ export function cleanUpSVG(svgMarkup, {
126
192
  let groupProps = [];
127
193
 
128
194
  groups.forEach(g => {
195
+ //propOptions.exclude.push('class', 'id');
129
196
  let stylePropsG = parseStylesProperties(g, propOptions)
197
+ //console.log('stylePropsG', stylePropsG);
198
+
130
199
  groupProps.push(stylePropsG);
131
200
  let children = g.querySelectorAll(`${renderedEls.join(', ')}`)
132
201
 
@@ -141,85 +210,36 @@ export function cleanUpSVG(svgMarkup, {
141
210
 
142
211
 
143
212
 
144
- if (cleanupSVGAtts) {
145
- //console.log('cleanupSVGAtts');
146
- let allowed = new Set(['viewBox', 'xmlns', 'width', 'height']);
147
-
148
- if (!removeIds) allowed.add('id')
149
- if (!removeClassNames) allowed.add('class')
150
- if (removeDimensions) {
151
- allowed.delete('width')
152
- allowed.delete('height')
153
- }
154
-
155
- allowed = Array.from(allowed)
156
- if (!stylesToAttributes) {
157
- allowed.push('fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'font-size', 'font-family', 'font-style', 'style');
158
- }
159
-
160
- //console.log(allowed);
161
- //if(allow)
162
- removeExcludedAttribues(svg, { allowed, allowMeta, allowAriaAtts, allowDataAtts })
163
- }
164
-
165
- // remove meta
166
- if (!allowMeta) {
167
- let metaEls = svg.querySelectorAll('meta, metadata, desc, title')
168
- metaEls.forEach(meta => {
169
- meta.remove()
170
- })
171
- }
172
-
173
- // add viewBox
174
- if (addViewBox) addSvgViewBox(svg, { x, y, width, height })
175
- if (addDimensions) {
176
- svg.setAttribute('width', width);
177
- svg.setAttribute('height', height);
178
- }
179
-
180
-
181
- // remove unused defs or optimize order
182
- if (cleanupDefs) cleanupSvgDefs(svg, { x, y, width, height, cleanupClip });
183
-
184
-
185
- // remove off canvas
186
- if (removeOffCanvas) removeOffCanvasEls(svg, { x, y, width, height });
187
-
188
-
189
- // always remove scripts
190
- //let removeEls = ['metadata', 'script', ...excludedEls]
191
- let removeEls = ['script', ...excludedEls]
192
-
193
- removeSVGEls(svg, { remove: removeEls, removeNameSpaced });
194
-
195
- // an array of all elements' properties
213
+ // collect all elements' properties
196
214
  let svgElProps = []
197
215
  let els = svg.querySelectorAll(`${renderedEls.join(', ')}`)
198
216
 
199
217
 
218
+ /**
219
+ * loop all geometry elements
220
+ */
200
221
  for (let i = 0; i < els.length; i++) {
201
222
  let el = els[i];
202
223
 
203
224
  let name = el.nodeName.toLowerCase();
204
225
  //console.log(name);
205
226
 
206
- // 1. remove hidden elements
207
- let style = el.getAttribute('style') || ''
208
- let isHiddenByStyle = style ? style.trim().includes('display:none') : false;
209
- let isHidden = (el.getAttribute('display') && el.getAttribute('display') === 'none') || isHiddenByStyle;
210
- if (name.includes(':') || removeEls.includes(name) || (removeHidden && isHidden)) {
211
- el.remove();
212
- continue;
213
- }
214
-
215
-
216
227
  /**
217
- * get all style properties
228
+ * get all element style properties
218
229
  * convert relative or physical units
219
230
  * to user units
220
231
  */
221
232
  let styleProps = parseStylesProperties(el, propOptions)
222
233
  let stylePropsFiltered = {}
234
+ //console.log('styleProps', name, styleProps);
235
+
236
+
237
+ // convert pathLength before transforming
238
+ if (convertPathLength) {
239
+ styleProps = convertPathLengthAtt(el, { styleProps });
240
+ remove = [...new Set([...remove, ...styleProps.remove])];
241
+ }
242
+
223
243
 
224
244
  // get parent styles
225
245
  let { parentStyleProps = [] } = el;
@@ -227,7 +247,10 @@ export function cleanUpSVG(svgMarkup, {
227
247
  let transFormInherited = []
228
248
 
229
249
 
230
- /** inherit transforms
250
+
251
+ /**
252
+ * consolidate all properties:
253
+ * merge with inherited transforms
231
254
  * and styles from group
232
255
  */
233
256
  parentStyleProps.forEach(props => {
@@ -243,13 +266,16 @@ export function cleanUpSVG(svgMarkup, {
243
266
  })
244
267
 
245
268
 
246
- //merge transforms
269
+ // merge all transforms
247
270
  transFormInherited = [...transFormInherited, ...styleProps.transformArr]
248
271
  styleProps.transformArr = transFormInherited
249
272
 
250
273
 
251
- // merge with svg props
274
+ // don't inherit class from SVG
275
+ if (stylePropsSVG['class']) delete stylePropsSVG['class']
276
+ if (stylePropsSVG['id']) delete stylePropsSVG['id']
252
277
 
278
+ // merge with svg props
253
279
  styleProps = {
254
280
  ...stylePropsSVG,
255
281
  ...inheritedProps,
@@ -257,164 +283,110 @@ export function cleanUpSVG(svgMarkup, {
257
283
  }
258
284
 
259
285
 
260
- // dont inherit class
261
- if (stylePropsSVG['class'] === styleProps['class']) {
262
- delete styleProps['class']
263
- }
264
-
265
286
  // add combined transforms
266
287
  addTransFormProps(styleProps, transFormInherited);
267
288
  //console.log('transFormInherited', transFormInherited);
268
289
  //console.log('styleProps', styleProps);
269
290
 
291
+ remove = [...new Set([...remove, ...styleProps.remove])];
270
292
 
271
- let { remove, matrix, transComponents } = styleProps;
272
293
 
273
- // styles to atts
274
- if (unGroup || convertTransforms || minifyRgbColors) stylesToAttributes = true;
275
-
276
- if (stylesToAttributes) {
294
+ /**
295
+ * remove els and attributes
296
+ */
277
297
 
278
- /**
279
- * normalize transforms
280
- */
281
- if (normalizeTransforms && matrix) {
282
- let { rotate, scaleX, scaleY, skewX, translateX, translateY } = transComponents;
283
- //console.log(rotate, scaleX, scaleY, skewX, skewY, translateX, translateY);
298
+ // remove meta
299
+ if (!allowMeta) removeElements.push('meta', 'metadata', 'desc', 'title')
284
300
 
285
- // scale attributes instead of transform
286
- let hasRot = rotate !== 0 || skewX !== 0;
287
- let unProportional = scaleX !== scaleY;
288
- let scalableByAtt = ['circle', 'ellipse', 'rect']
289
- let needsTrans = convertTransforms || (name === 'g') || (hasRot) || unProportional
301
+ if (removeClassNames) {
302
+ removeSVGAttributes.push('class');
303
+ removeElAttributes.push('class');
304
+ }
290
305
 
291
- if (!needsTrans && scalableByAtt.includes(name)) {
306
+ if (removeIds) {
307
+ removeSVGAttributes.push('id')
308
+ removeElAttributes.push('id')
309
+ }
292
310
 
293
- if (name === 'circle' || name === 'ellipse') {
294
- styleProps.cx[0] = [styleProps.cx[0] * scaleX + translateX]
295
- styleProps.cy[0] = [styleProps.cy[0] * scaleX + translateY]
296
311
 
297
- if (styleProps.r) styleProps.r[0] = [styleProps.r[0] * scaleX]
298
- if (styleProps.rx) styleProps.rx[0] = [styleProps.rx[0] * scaleX]
299
- if (styleProps.ry) styleProps.ry[0] = [styleProps.ry[0] * scaleX]
312
+ // remove hidden elements
313
+ removeHiddenSvgEls(svg)
300
314
 
301
- }
302
- else if (name === 'rect') {
303
- let x = styleProps.x ? styleProps.x[0] + translateX : translateX;
304
- let y = styleProps.y ? styleProps.y[0] + translateY : translateY;
315
+ // remove SVG elements
316
+ removeSvgEls(svg, { removeElements, removeNameSpaced });
305
317
 
306
- let rx = styleProps.rx ? styleProps.rx[0] * scaleX : 0;
307
- let ry = styleProps.ry ? styleProps.ry[0] * scaleY : 0;
318
+ // remove SVG attributes
319
+ removeSvgAtts(svg, removeSVGAttributes);
308
320
 
309
- styleProps.x = [x]
310
- styleProps.y = [y]
321
+ // remove SVG child element attributes
322
+ removeSvgChildAtts(svg, removeElAttributes);
311
323
 
312
- styleProps.rx = [rx]
313
- styleProps.ry = [ry]
314
324
 
315
- styleProps.width = [styleProps.width[0] * scaleX]
316
- styleProps.height = [styleProps.height[0] * scaleX]
317
- }
325
+ // general cleanup
326
+ if (cleanupSVGAtts) cleanupSVGAttributes(svg, { removeIds, removeClassNames, removeDimensions, stylesToAttributes, allowMeta, allowAriaAtts, allowDataAtts });
318
327
 
319
- // remove now obsolete transform properties
320
- delete styleProps.matrix
321
- delete styleProps.transformArr
322
- delete styleProps.transComponents
323
328
 
324
- // mark transform attribute for removal
325
- remove.push('transform')
326
329
 
327
- // scale props like stroke width or dash-array
328
- styleProps = scaleProps(styleProps, { props: ['stroke-width', 'stroke-dasharray'], scale: scaleX })
330
+ if (stylesToAttributes) {
329
331
 
330
- } else {
331
- el.setAttribute('transform', transComponents.matrixAtt)
332
+ /**
333
+ * normalize transforms
334
+ */
335
+ if (normalizeTransforms) {
336
+ styleProps = setNormalizedTransformsToEl(el, { styleProps });
337
+ //remove = styleProps.remove;
338
+ remove = [...new Set([...remove, ...styleProps.remove])];
332
339
 
333
- }
334
340
  }
335
341
 
336
-
337
342
  /**
338
343
  * apply consolidated
339
344
  * element attributes
345
+ * remove non-supported element props
340
346
  */
341
347
  stylePropsFiltered = filterSvgElProps(name, styleProps,
342
348
  { removeDefaults: true, cleanUpStrokes, allowMeta, allowAriaAtts, allowDataAtts, removeIds });
343
349
 
344
- remove = [...remove, ...stylePropsFiltered.remove];
350
+ //remove = [...remove, ...stylePropsFiltered.remove];
351
+ remove = [...new Set([...remove, ...stylePropsFiltered.remove])];
352
+ //console.log('el remove', name, remove);
353
+ //console.log('!!stylePropsFiltered', name, stylePropsFiltered);
345
354
 
346
355
  for (let prop in stylePropsFiltered.propsFiltered) {
347
356
  let values = styleProps[prop]
348
357
  let val = values.length ? values.join(' ') : values[0]
349
358
  el.setAttribute(prop, val)
350
-
351
359
  }
352
360
 
353
361
 
354
- // remove obsolete attributes
355
- for (let i = 0; i < remove.length; i++) {
356
- let att = remove[i];
357
- if (!stylesToAttributes && att === 'style') continue
358
- //console.log('remove att', att, name);
359
- el.removeAttribute(att)
360
- }
361
-
362
-
363
-
364
-
365
362
  /**
366
- * remove group styles
367
- * copied to children
368
- * or remove nesting
363
+ * remove obsolete
364
+ * attributes
369
365
  */
366
+ //removeSvgChildAtts(svg, remove)
370
367
 
371
- if (unGroup) {
372
- groups.forEach((g, i) => {
373
- let children = [...g.children];
374
-
375
- children.forEach(child => {
376
- g.parentNode.insertBefore(child, g)
377
- })
378
- g.remove()
379
- })
380
- } else {
381
- groups.forEach((g, i) => {
382
- //let atts = [...Object.keys(groupProps[i]), 'style', 'transform', 'id'];
383
- let atts = Object.keys(getElementAtts(g));
384
-
385
- atts.forEach(att => {
386
- //console.log('remove', remove);
387
- let isData = !allowDataAtts && att.startsWith('data-')
388
- let isAria = !allowAriaAtts && att.startsWith('aria-')
389
- //console.log(isData, att);
390
- remove.push('transform', 'style')
391
-
392
- if (remove.includes(att) || isData || isAria) {
393
- g.removeAttribute(att)
394
- }
395
- })
396
- })
397
-
368
+ for (let i = 0; i < remove.length; i++) {
369
+ let att = remove[i];
370
+ //if (att === 'style') continue
371
+ //console.log('--remove att', remove, att, name);
372
+ el.removeAttribute(att)
398
373
  }
399
374
 
400
375
 
401
376
  } // endof style processing
402
377
 
403
378
 
379
+
404
380
  /**
405
381
  * element conversions:
406
382
  * shapes to paths or
407
383
  * paths to shapes
408
384
  */
409
385
 
410
-
411
386
  // force shape conversion when transform conversion is enabled
412
387
  if (convertTransforms) {
413
388
  shapeConvert = 'toPaths';
414
- convert_rects = true;
415
- convert_ellipses = true;
416
- convert_poly = true;
417
- convert_lines = true;
389
+ convertShapes = ['path', 'rect', 'ellipse', 'circle', 'line', 'polygon', 'polyline'];
418
390
  }
419
391
 
420
392
  // convert shapes to paths
@@ -422,8 +394,8 @@ export function cleanUpSVG(svgMarkup, {
422
394
 
423
395
  let { matrix = null, transComponents = null } = styleProps;
424
396
 
397
+ // scale props like stroke width or dash-array before conversion
425
398
  if (matrix && transComponents) {
426
- // scale props like stroke width or dash-array before conversion
427
399
  ['stroke-width', 'stroke-dasharray'].forEach(att => {
428
400
  let attVal = el.getAttribute(att)
429
401
  let vals = attVal ? attVal.split(' ').filter(Boolean).map(Number).map(val => val * transComponents.scaleX) : []
@@ -433,10 +405,9 @@ export function cleanUpSVG(svgMarkup, {
433
405
 
434
406
  // convert paths only if a matrix transform is required
435
407
  if (matrix ? geometryEls.includes(name) : shapeEls.includes(name)) {
436
-
437
- let path = shapeElToPath(el, { width, height, convert_rects, convert_ellipses, convert_poly, convert_lines, matrix });
408
+ //console.log('detrans', name, el.id, matrix);
409
+ let path = shapeElToPath(el, { width, height, convertShapes, matrix });
438
410
  el.replaceWith(path)
439
-
440
411
  name = 'path'
441
412
  el = path; // required for node
442
413
 
@@ -444,15 +415,19 @@ export function cleanUpSVG(svgMarkup, {
444
415
 
445
416
  }
446
417
 
447
- // convert paths to shapes
418
+ /**
419
+ * Reverse conversion:
420
+ * paths to shapes
421
+ */
448
422
  else if (shapeConvert === 'toShapes') {
449
423
  let paths = svg.querySelectorAll('path')
450
424
  paths.forEach(path => {
451
- let shape = pathElToShape(path, { convert_rects, convert_ellipses, convert_poly, convert_lines })
452
- //path.replaceWith(shape)
425
+ let shape = pathElToShape(path, { convertShapes })
426
+ path.replaceWith(shape)
453
427
  path = shape;
428
+ //name = shape.nodeName.toLowerCase()
429
+ //console.log('shape', shape);
454
430
  })
455
-
456
431
  }
457
432
 
458
433
 
@@ -460,7 +435,6 @@ export function cleanUpSVG(svgMarkup, {
460
435
  * combine styles
461
436
  * store in node property
462
437
  */
463
-
464
438
  if (mergePaths || attributesToGroup) {
465
439
 
466
440
  let options = { allowMeta, allowAriaAtts, removeIds, removeClassNames, allowDataAtts }
@@ -470,7 +444,7 @@ export function cleanUpSVG(svgMarkup, {
470
444
  * adjacent path merging
471
445
  * e.g ignore classnames or ids
472
446
  */
473
- if(mergePaths){
447
+ if (mergePaths) {
474
448
  options.removeIds = true;
475
449
  options.removeClassNames = true;
476
450
  options.allowAriaAtts = false;
@@ -486,226 +460,253 @@ export function cleanUpSVG(svgMarkup, {
486
460
  let values = stylePropsFiltered[prop]
487
461
  let val = values.length ? values.join(' ') : values[0]
488
462
 
489
- let propShort = toShortStr(prop)
490
- let valShort = toShortStr(val)
491
- let propStr = `${propShort}-${valShort}`;
463
+ if(prop!=='class' && prop!=='id'){
492
464
 
493
- // store in node property
494
- if (!el.styleSet) el.styleSet = new Set()
495
- el.styleSet.add(propStr)
465
+ let propShort = toShortStr(prop)
466
+ let valShort = toShortStr(val)
467
+ let propStr = `${propShort}-${valShort}`;
468
+
469
+ // store in node property
470
+ if (!el.styleSet) el.styleSet = new Set()
471
+ if(propStr) el.styleSet.add(propStr)
472
+ }
496
473
  }
497
474
 
498
475
  }
499
476
 
500
-
501
477
  }//endof element loop
502
478
 
503
479
 
480
+ /**
481
+ * remove group styles
482
+ * copied to children
483
+ * or remove nesting
484
+ */
485
+
486
+ if (unGroup) {
487
+ ungroupElements(groups)
488
+ } else {
489
+
490
+ if (stylesToAttributes) {
491
+ groups.forEach(g => {
492
+ removeElAtts(g, ['style', 'transform']);
493
+ })
494
+ }
495
+ //removeGroupProps(groups, { remove, allowDataAtts, allowAriaAtts })
496
+ }
497
+
498
+
499
+ // styles to group
500
+ if (attributesToGroup) sharedAttributesToGroup(svg);
504
501
 
505
502
  /**
506
503
  * merge paths with same styles
507
504
  */
508
505
  if (mergePaths) {
509
- let paths = svg.querySelectorAll('path')
510
- let len = paths.length;
511
-
512
- if (len) {
513
- let path0 = paths[0]
514
- let d0 = path0.getAttribute('d')
515
- let stylePrev = path0.styleSet !== undefined ? [...path0.styleSet].join('_') : ''
516
-
517
- for (let i = 1; i < len; i++) {
518
- let path = paths[i];
519
- let style = path.styleSet !== undefined ? [...path.styleSet].join('_') : ''
520
- let isSibling = path.previousElementSibling === path0;
521
- let d = path.getAttribute('d');
522
- let isAbs = d.startsWith('M')
523
-
524
- if (isSibling && style === stylePrev) {
525
- let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
526
- //console.log('same style', dAbs, isAbs);
527
- d0 += dAbs;
528
- path0.setAttribute('d', d0)
529
- path.remove();
530
-
531
- } else {
532
- path0 = path
533
- d0 = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
534
- }
506
+ mergePathsWithSameProps(svg)
507
+ }
535
508
 
536
- // update style
537
- stylePrev = style
538
- }
539
- }
509
+ //console.log('svg', svg);
540
510
 
511
+ // remove futile clip-paths
512
+ if (cleanupClip) removeFutileClipPaths(svg, { x, y, width, height })
541
513
 
542
- /**
543
- * shared styles to group
544
- */
514
+ // replace href attributes with namespace - required by many older applications
515
+ if (legacyHref) hrefToXlink(svg);
545
516
 
546
- if (attributesToGroup) {
547
- let els = svg.querySelectorAll(geometryEls.join(', '))
548
- let len = els.length;
549
517
 
550
- let el0 = els[0] || null
551
- let stylePrev = el0.styleSet !== undefined ? [...el0.styleSet].join('_') : ''
518
+ // remove empty class attributes
519
+ removeEmptyClassAtts(svg);
520
+ return { svg, svgElProps }
552
521
 
522
+ }
553
523
 
554
- // all props
555
- let allProps = {}
556
524
 
557
- // find attributes shared by all
558
- let globalAtts = []
559
525
 
560
- if (len) {
526
+ function removeEmptyClassAtts(svg) {
527
+ let emptyClassEls = svg.querySelectorAll('[class=""');
528
+ emptyClassEls.forEach(el => {
529
+ el.removeAttribute('class')
530
+ })
531
+ }
561
532
 
562
- let groups = [[el0]];
563
- let idx = 0;
564
- let elPrev = el0
565
533
 
566
- for (let i = 0; i < len; i++) {
567
- let el = els[i];
568
- let atts = getElementAtts(el)
569
- for (let att in atts) {
570
- let att_str = `${att}_${atts[att]}`
534
+ /**
535
+ * shared styles to group
536
+ */
537
+ function sharedAttributesToGroup(svg) {
571
538
 
572
- if (!allProps[att_str]) {
573
- allProps[att_str] = []
574
- }
575
- allProps[att_str].push(el)
576
- //
577
- if (allProps[att_str].length === len) {
578
- globalAtts.push(att)
579
- }
580
- }
581
- }
539
+ let els = svg.querySelectorAll(renderedEls.join(', '))
540
+ let len = els.length;
541
+ if(len===1) return;
582
542
 
583
- //console.log('allProps', allProps);
584
- //console.log('globalAtts', globalAtts);
585
-
586
- // apply global to parent SVG
587
- if (globalAtts.length) {
588
- let atts0 = getElementAtts(el0)
589
- for (let att in atts0) {
590
- // &&
591
- if (globalAtts.includes(att) && att !== 'transform') {
592
- svg.setAttribute(att, atts0[att])
593
- }
594
- }
595
- }
543
+ let el0 = els[0] || null
544
+ let stylePrev = el0.styleSet !== undefined ? [...el0.styleSet].join('_') : ''
596
545
 
597
- // detect groups
598
- for (let i = 1; i < len; i++) {
599
- let el = els[i];
600
- let styleArr = el.styleSet !== undefined ? [...el.styleSet] : [];
601
- let style = styleArr.length ? styleArr.join('_') : '';
602
- //console.log('style', style);
603
546
 
604
- // same style add to group
605
- if (style === stylePrev && elPrev.nextElementSibling === el) {
606
- groups[idx].push(el)
607
- }
608
- // start new group
609
- else {
610
- groups.push([el])
611
- idx++
612
- }
613
- // update style
614
- stylePrev = style
615
- elPrev = el
547
+ // all props
548
+ let allProps = {}
549
+
550
+ // find attributes shared by all
551
+ let globalAtts = []
552
+
553
+ if (len) {
616
554
 
617
- }// endof el loop
555
+ let groups = [[el0]];
556
+ let idx = 0;
557
+ let elPrev = el0
618
558
 
559
+ for (let i = 0; i < len; i++) {
560
+ let el = els[i];
561
+ let atts = getElementAtts(el)
562
+ for (let att in atts) {
563
+ let att_str = `${att}_${atts[att]}`
619
564
 
565
+ if (!allProps[att_str]) {
566
+ allProps[att_str] = []
567
+ }
568
+ allProps[att_str].push(el)
569
+ //
570
+ if (allProps[att_str].length === len) {
571
+ globalAtts.push(att)
572
+ }
573
+ }
574
+ }
620
575
 
576
+ //console.log('allProps', allProps);
577
+ //console.log('globalAtts', globalAtts);
621
578
 
579
+ // apply global to parent SVG
580
+ if (globalAtts.length) {
581
+ let atts0 = getElementAtts(el0)
582
+ for (let att in atts0) {
583
+ if (globalAtts.includes(att) && att !== 'transform') {
584
+ svg.setAttribute(att, atts0[att])
585
+ }
586
+ }
587
+ }
622
588
 
589
+ // detect groups
590
+ for (let i = 1; i < len; i++) {
591
+ let el = els[i];
592
+ let styleArr = el.styleSet !== undefined ? [...el.styleSet] : [];
593
+ let style = styleArr.length ? styleArr.join('_') : '';
594
+ //console.log('style', style);
595
+ //console.log('style === stylePrev', style, stylePrev);
596
+
597
+ // same style add to group
598
+ if (style === stylePrev && elPrev.nextElementSibling === el) {
599
+ groups[idx].push(el)
600
+ }
601
+ // start new group
602
+ else {
603
+ groups.push([el])
604
+ idx++
605
+ }
606
+ // update style
607
+ stylePrev = style
608
+ elPrev = el
623
609
 
610
+ }// endof el loop
624
611
 
625
- //console.log('groups', groups);
612
+ //console.log('g', groups);
626
613
 
627
- // create groups
628
- for (let i = 0; i < groups.length; i++) {
629
- let children = groups[i];
630
- let child0 = children[0]
631
- let atts = getElementAtts(child0)
632
- let groupEl = child0.parentNode.closest('g')
614
+ // create groups
615
+ for (let i = 0; i < groups.length; i++) {
616
+ let children = groups[i];
617
+ let child0 = children[0]
618
+ let atts = getElementAtts(child0)
619
+ let groupEl = child0.parentNode.closest('g')
633
620
 
621
+ // only 1 child - nothing to group
622
+ if (children.length === 1) continue
634
623
 
635
- if (children.length === 1) {
636
- if (globalAtts.length) {
637
- let globalTransform = globalAtts.includes('transform')
638
- if (globalTransform) {
639
- //console.log(globalTransform, globalAtts);
640
- groupEl.setAttribute('transform', atts['transform'])
641
- }
642
624
 
643
- for (let att in atts) {
644
- //&& att!=='transform'
645
- if (globalAtts.includes(att)) {
646
- child0.removeAttribute(att)
647
- }
648
- }
649
- }
650
- continue
651
- }
625
+ // create new group
626
+ if (!groupEl || groups.length>1) {
627
+ //console.log('new group');
628
+ groupEl = document.createElementNS(svgNs, 'g')
629
+ child0.parentNode.insertBefore(groupEl, child0)
630
+ groupEl.append(...children)
631
+ }
652
632
 
633
+ // move attributes to group
634
+ for (let att in atts) {
635
+ let val = atts[att];
636
+ //console.log('att', atts, val);
653
637
 
654
- // create new group
655
- if (!groupEl) {
656
- //console.log('new group');
657
- groupEl = document.createElementNS(svgNs, 'g')
658
- child0.parentNode.insertBefore(groupEl, child0)
659
- groupEl.append(...children)
638
+ //|| att === 'transform'
639
+ let excludeAtts = ['id', 'class'];
640
+ if (!geometryProps.includes(att) && !excludeAtts.includes(att)) {
641
+ if (!globalAtts.includes(att) || att === 'transform') {
642
+ groupEl.setAttribute(att, val)
660
643
  }
644
+ children.forEach(child => {
645
+ child.removeAttribute(att)
646
+ })
647
+ }
648
+ }
661
649
 
662
650
 
651
+ } // endof groups
663
652
 
664
- // move attributes to group
665
- for (let att in atts) {
666
- let val = atts[att];
667
- //console.log('att', atts, val);
653
+ }
654
+ }
668
655
 
669
- //|| att === 'transform'
670
- if (!geometryProps.includes(att)) {
671
- if (!globalAtts.includes(att) || att === 'transform') {
672
- groupEl.setAttribute(att, val)
673
- }
674
- children.forEach(child => {
675
- child.removeAttribute(att)
676
- })
677
- }
678
- }
679
656
 
680
- } // endof groups
657
+ // merge adjacent paths
658
+ function mergePathsWithSameProps(svg) {
659
+ let paths = svg.querySelectorAll('path')
660
+ let len = paths.length;
681
661
 
682
- }
683
- }
662
+ if (len) {
663
+ let path0 = paths[0]
664
+ let d0 = path0.getAttribute('d')
665
+ let stylePrev = path0.styleSet !== undefined ? [...path0.styleSet].join(' ') : ''
666
+ //console.log('path0', path0);
684
667
 
685
- }
668
+ let remove = []
686
669
 
670
+ for (let i = 1; i < len; i++) {
671
+ let path = paths[i];
672
+ let style = path.styleSet !== undefined ? [...path.styleSet].join(' ') : ''
673
+ let isSibling = path.previousElementSibling === path0;
674
+ let d = path.getAttribute('d');
675
+ let isAbs = d.startsWith('M')
676
+ //console.log('path.previousElementSibling', path.previousElementSibling);
677
+ //console.log(isSibling, style, stylePrev, path.id);
678
+
679
+ if (isSibling && style === stylePrev) {
680
+ let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
681
+ //console.log('same style', dAbs, isAbs);
682
+ d0 += dAbs;
683
+ path0.setAttribute('d', d0)
684
+ //console.log('remove', path);
685
+ remove.push(path)
686
+ //path.remove();
687
687
 
688
+ } else {
689
+ path0 = path
690
+ //console.log('path0', path0, path);
691
+ d0 = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
688
692
 
689
- // remove futile clip-paths
690
- if (cleanupClip) removeFutileClipPaths(svg, { x, y, width, height })
693
+ }
691
694
 
695
+ // update style
696
+ stylePrev = style
697
+ }
692
698
 
693
- // replace href attributes with namespace - required by many older applications
694
- if (legacyHref) {
695
- svg.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink")
696
- let hrefs = svg.querySelectorAll('[href]')
697
- hrefs.forEach(el => {
698
- let href = el.getAttribute('href')
699
- el.setAttribute('xlink:href', href)
700
- el.removeAttribute('href')
699
+
700
+ //console.log('remove', remove);
701
+ remove.forEach(el => {
702
+ el.remove()
701
703
  })
704
+
702
705
  }
703
706
 
707
+ }
704
708
 
705
709
 
706
- return { svg, svgElProps }
707
-
708
- }
709
710
 
710
711
 
711
712
  function removeOffCanvasEls(svg, { x = 0, y = 0, width = 0, height = 0 } = {}) {
@@ -733,6 +734,13 @@ function addSvgViewBox(svg, { x = 0, y = 0, width = 0, height = 0 } = {}) {
733
734
  svg.setAttribute('viewBox', [x, y, width, height].join(' '))
734
735
  }
735
736
 
737
+ export function removeEmptySVGEls(svg) {
738
+ let els = svg.querySelectorAll('g, defs');
739
+ els.forEach(el => {
740
+ if (!el.children.length) el.remove()
741
+ })
742
+ }
743
+
736
744
 
737
745
  function cleanupSvgDefs(svg, { x = 0, y = 0, width = 0, height = 0, cleanupClip = true } = {}) {
738
746
  let defs = svg.querySelectorAll('defs')
@@ -769,9 +777,6 @@ function cleanupSvgDefs(svg, { x = 0, y = 0, width = 0, height = 0, cleanupClip
769
777
  }
770
778
  })
771
779
 
772
- // remove futile clip-paths
773
- //if (cleanupClip) removeFutileClipPaths(svg, {x, y, width, height})
774
-
775
780
  }
776
781
 
777
782
 
@@ -825,274 +830,23 @@ function removeFutileClipPaths(svg, { x = 0, y = 0, width = 0, height = 0 } = {}
825
830
  }
826
831
 
827
832
 
828
-
829
- function moveAttributesToGroup(svgElProps = [], mergePaths = true) {
830
-
831
- let combine = [[svgElProps[0]]]
832
- let idx = 0;
833
- let lastProps = '';
834
- let l = svgElProps.length;
835
- let itemsWithProps = svgElProps.filter(item => item.propstr)
836
- let path0;
837
-
838
-
839
- // merge paths without properties
840
- let dCombined = ''
841
- if (!itemsWithProps.length && mergePaths) {
842
- let path0 = null;
843
-
844
- for (let i = 0; i < l; i++) {
845
- let item = svgElProps[i]
846
- if (item.name !== 'path') continue;
847
- let remove = true;
848
-
849
-
850
- let path = item.el;
851
-
852
- // set 1st path
853
- if (!path0) {
854
- path0 = path;
855
- remove = false;
856
- }
857
-
858
- let d = item.propsFiltered.d
859
- let isAbs = d.startsWith('M')
860
- let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
861
-
862
- dCombined += dAbs;
863
-
864
- // delete path el
865
- if (remove) path.remove();
866
- }
867
-
868
- //console.log('dCombined', dCombined);
869
- if (path0) path0.setAttribute('d', dCombined)
870
- return
871
- }
872
-
873
-
874
- // add to combine chunks
875
- for (let i = 0; i < l; i++) {
876
- let item = svgElProps[i];
877
- let props = item.propsFiltered;
878
- let propstr = [];
879
- for (let prop in props) {
880
- if (prop !== 'd' && prop !== 'id') {
881
- propstr.push(`${prop}:${props[prop]}`)
882
- }
883
- }
884
- propstr = propstr.join('_')
885
- item.propstr = propstr;
886
-
887
- if (l > 1 && propstr === lastProps) {
888
- combine[idx].push(item)
889
- } else {
890
- if (l > 1 && combine[idx].length) {
891
- combine.push([])
892
- idx++
893
- }
894
- }
895
- lastProps = propstr;
896
- }
897
-
898
-
899
- // add att groups
900
- for (let i = 0; i < combine.length; i++) {
901
- let group = combine[i]
902
-
903
- if (group.length > 1) {
904
- // 1st el
905
- let el0 = group[0].el;
906
- let props = group[0].propsFiltered;
907
- let g = el0.parentNode.closest('g') ? el0.parentNode.closest('g') : null;
908
-
909
- // wrap in group if not existent
910
- if (!g) {
911
- g = document.createElementNS(svgNs, 'g');
912
- el0.parentNode.insertBefore(g, el0)
913
- group.forEach(item => {
914
- g.append(item.el)
915
- })
916
- }
917
-
918
- let children = [...g.children]
919
- for (let prop in props) {
920
- if (prop !== 'd' && prop !== 'id') {
921
- let value = props[prop]
922
- // apply to parent group
923
- g.setAttribute(prop, value)
924
-
925
- // remove from children
926
- children.forEach(el => {
927
- if (el.getAttribute(prop) === value) {
928
- el.removeAttribute(prop)
929
- }
930
- })
931
- }
932
-
933
-
934
- if (mergePaths) {
935
- group = group.filter(Boolean)
936
- let l = group.length
937
- // nothing to merge
938
- if (l === 1) return group[0].el;
939
-
940
- path0 = group[0].el;
941
- let dCombined = group[0].propsFiltered.d;
942
-
943
- for (let i = 1; i < l; i++) {
944
- let item = group[i]
945
- let path = item.el;
946
- let d = item.propsFiltered.d
947
- let isAbs = d.startsWith('M')
948
-
949
- let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ')
950
-
951
- console.log('dAbs', dAbs);
952
-
953
- //console.log(isAbs, dAbs);
954
- // concat pathdata string
955
- dCombined += dAbs;
956
-
957
- // delete path el
958
- path.remove();
959
- }
960
-
961
- path0.setAttribute('d', dCombined)
962
-
963
- }
964
-
965
- }
966
- }
967
- }
968
-
969
- }
970
-
971
-
972
- export function scaleProps(styleProps = {}, { props = [], scale = 1 } = {}) {
973
- if (scale === 1 || !props.length) return props;
974
-
975
- for (let i = 0; i < props.length; i++) {
976
- let prop = props[i];
977
-
978
- if (styleProps[prop] !== undefined) {
979
- styleProps[prop] = styleProps[prop].map(val => val * scale)
980
- }
981
- }
982
- return styleProps
983
- }
984
-
985
- export function removeSVGEls(svg, {
986
- remove = ['metadata', 'script'],
987
- removeNameSpaced = true,
988
- } = {}) {
989
-
990
- let els = svg.querySelectorAll('*')
991
-
992
- let allowMeta = !remove.includes('metadata');
993
-
994
- els.forEach(el => {
995
- let nodeName = el.nodeName;
996
- let isMeta = allowMeta && el.closest('metadata')
997
- if (
998
- !isMeta &&
999
- ((removeNameSpaced && nodeName.includes(':')) ||
1000
- remove.includes(nodeName))
1001
- ) {
1002
- el.remove()
1003
- }
833
+ function hrefToXlink(svg) {
834
+ svg.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink")
835
+ let hrefs = svg.querySelectorAll('[href]')
836
+ hrefs.forEach(el => {
837
+ let href = el.getAttribute('href')
838
+ el.setAttribute('xlink:href', href)
839
+ //el.removeAttribute('href')
1004
840
  })
1005
841
  }
1006
842
 
1007
843
 
1008
- function cleanSvgPrologue(svgString) {
1009
- return (
1010
- svgString
1011
- // Remove XML prologues like <?xml ... ?>
1012
- .replace(/<\?xml[\s\S]*?\?>/gi, "")
1013
- // Remove DOCTYPE declarations
1014
- .replace(/<!DOCTYPE[\s\S]*?>/gi, "")
1015
- // Remove comments <!-- ... -->
1016
- .replace(/<!--[\s\S]*?-->/g, "")
1017
- // Trim extra whitespace
1018
- .trim()
1019
- );
1020
- }
1021
844
 
1022
- function removeExcludedAttribues(el, {
1023
- allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class'],
1024
- allowAriaAtts = true,
1025
- allowDataAtts = true,
1026
- allowMeta = false
1027
- } = {}) {
1028
- let atts = [...el.attributes].map((att) => att.name);
1029
- atts.forEach((att) => {
1030
-
1031
- let isMeta = allowMeta && (att === 'title')
1032
- let isAria = allowAriaAtts && att.startsWith('aria-')
1033
- let isData = allowDataAtts && att.startsWith('data-')
1034
- //console.log(att, isData, 'allowDataAtts', allowDataAtts);
1035
-
1036
- if (
1037
- !allowed.includes(att) &&
1038
- !isAria && !isData && !isMeta
1039
- ) {
1040
- el.removeAttribute(att);
1041
- }
1042
- });
1043
- }
1044
-
1045
-
1046
- function removeAtts(el, exclude = [], include = []) {
1047
- let atts = [...el.attributes].map((att) => att.name);
1048
- atts.forEach((att) => {
1049
- if (exclude.includes(att) && !include.includes(att)) {
1050
- el.removeAttribute(att);
1051
- }
1052
- });
1053
- }
1054
845
 
1055
846
 
1056
- function removeNameSpaceAtts(el, {
1057
- include = ['xlink:href']
1058
- } = {}) {
1059
- let atts = [...el.attributes].map((att) => att.name);
1060
- atts.forEach((att) => {
1061
- if (att.includes(":") && !include.includes(att)) {
1062
- el.removeAttribute(att);
1063
- }
1064
- });
1065
- }
1066
-
1067
- export function stringifySVG(svg, {
1068
- omitNamespace = false,
1069
- removeComments = true,
1070
- } = {}) {
1071
- let markup = new XMLSerializer().serializeToString(svg);
1072
-
1073
- if (omitNamespace) {
1074
- markup = markup.replaceAll('xmlns="http://www.w3.org/2000/svg"', '')
1075
- }
1076
-
1077
- if (removeComments) {
1078
- markup = markup
1079
- .replace(/(<!--.*?-->)|(<!--[\S\s]+?-->)|(<!--[\S\s]*?$)/g, '')
1080
- }
1081
847
 
1082
- markup = markup
1083
- .replace(/\t/g, "")
1084
- .replace(/[\n\r|]/g, "\n")
1085
- .replace(/\n\s*\n/g, '\n')
1086
- .replace(/ +/g, ' ')
1087
- //.replace(/ +/g, ' ')
1088
- .replace(/> </g, '><')
1089
- .trim()
1090
- // sanitize linebreaks within pathdata
1091
- .replaceAll('&#10;', '\n');
1092
848
 
1093
849
 
1094
850
 
1095
851
 
1096
852
 
1097
- return markup
1098
- }