svg-path-simplify 0.4.0 → 0.4.2
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 +14 -0
- package/README.md +36 -10
- package/dist/svg-path-simplify.esm.js +534 -167
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +534 -167
- package/dist/svg-path-simplify.min.js +2 -2
- package/dist/svg-path-simplify.pathdata.esm.js +40 -0
- package/dist/svg-path-simplify.pathdata.esm.min.js +2 -2
- package/index.html +82 -17
- package/package.json +5 -2
- package/src/pathSimplify-main.js +15 -4
- package/src/string_helpers.js +18 -0
- package/src/svgii/convert_units.js +8 -2
- package/src/svgii/pathData_convert.js +38 -0
- package/src/svgii/pathData_parse_els.js +135 -133
- package/src/svgii/svg-styles-to-attributes-const.js +2 -1
- package/src/svgii/svg_cleanup.js +328 -35
- package/src/svgii/svg_el_parse_style_props.js +35 -5
- package/tests/testSVG_shape.js +59 -0
- package/tests/testSVG_transform.js +61 -0
package/src/svgii/svg_cleanup.js
CHANGED
|
@@ -9,12 +9,13 @@ import { parsePathDataString } from "./pathData_parse";
|
|
|
9
9
|
import { parsePathDataNormalized } from "./pathData_convert";
|
|
10
10
|
import { pathElToShape, shapeElToPath } from "./pathData_parse_els";
|
|
11
11
|
//import { scaleProps } from "./svg-styles-to-attributes";
|
|
12
|
-
import { geometryEls, renderedEls, shapeEls, strokeAtts } from "./svg-styles-to-attributes-const";
|
|
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
14
|
import { autoRound } 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
|
+
import { toCamelCase, toShortStr } from "../string_helpers";
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
export function removeEmptySVGEls(svg) {
|
|
@@ -31,6 +32,8 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
31
32
|
removeHidden = true,
|
|
32
33
|
//removeUnused = true,
|
|
33
34
|
stylesToAttributes = true,
|
|
35
|
+
attributesToGroup = false,
|
|
36
|
+
|
|
34
37
|
removePrologue = true,
|
|
35
38
|
removeIds = false,
|
|
36
39
|
removeClassNames = false,
|
|
@@ -50,9 +53,15 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
50
53
|
|
|
51
54
|
mergePaths = false,
|
|
52
55
|
removeOffCanvas = true,
|
|
56
|
+
|
|
53
57
|
cleanupSVGAtts = true,
|
|
54
58
|
removeNameSpaced = true,
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
// meta
|
|
61
|
+
allowMeta = false,
|
|
62
|
+
allowDataAtts = true,
|
|
63
|
+
allowAriaAtts = true,
|
|
64
|
+
|
|
56
65
|
//shapesToPaths = false,
|
|
57
66
|
shapeConvert = false,
|
|
58
67
|
convert_rects = false,
|
|
@@ -68,7 +77,7 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
68
77
|
} = {}) {
|
|
69
78
|
|
|
70
79
|
//attributesToGroup = cleanupSVGAtts ? true : false;
|
|
71
|
-
|
|
80
|
+
if (attributesToGroup) stylesToAttributes = true;
|
|
72
81
|
|
|
73
82
|
// replace namespaced refs
|
|
74
83
|
if (fixHref) svgMarkup = svgMarkup.replaceAll("xlink:href=", "href=");
|
|
@@ -89,15 +98,25 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
89
98
|
normalizeTransforms,
|
|
90
99
|
removeDefaults: false,
|
|
91
100
|
cleanUpStrokes: false,
|
|
101
|
+
allowMeta,
|
|
102
|
+
allowDataAtts,
|
|
103
|
+
allowAriaAtts,
|
|
92
104
|
autoRoundValues,
|
|
105
|
+
removeIds,
|
|
106
|
+
removeClassNames,
|
|
93
107
|
minifyRgbColors,
|
|
94
108
|
}
|
|
109
|
+
|
|
110
|
+
// root svg properties
|
|
95
111
|
let stylePropsSVG = parseStylesProperties(svg, propOptions)
|
|
112
|
+
//console.log('stylePropsSVG', stylePropsSVG);
|
|
113
|
+
|
|
96
114
|
|
|
97
115
|
// add svg font size for scaling relative
|
|
98
116
|
propOptions.fontSize = stylePropsSVG['font-size'] ? stylePropsSVG['font-size'][0] : 16;
|
|
99
117
|
|
|
100
118
|
|
|
119
|
+
|
|
101
120
|
/**
|
|
102
121
|
* get group styles
|
|
103
122
|
* especially transformations to
|
|
@@ -124,12 +143,31 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
124
143
|
|
|
125
144
|
if (cleanupSVGAtts) {
|
|
126
145
|
//console.log('cleanupSVGAtts');
|
|
127
|
-
let allowed = ['viewBox', 'xmlns', 'width', 'height'
|
|
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)
|
|
128
156
|
if (!stylesToAttributes) {
|
|
129
157
|
allowed.push('fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'font-size', 'font-family', 'font-style', 'style');
|
|
130
158
|
}
|
|
131
159
|
|
|
132
|
-
|
|
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
|
+
})
|
|
133
171
|
}
|
|
134
172
|
|
|
135
173
|
// add viewBox
|
|
@@ -149,9 +187,10 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
149
187
|
|
|
150
188
|
|
|
151
189
|
// always remove scripts
|
|
152
|
-
let removeEls = ['metadata', 'script', ...excludedEls]
|
|
190
|
+
//let removeEls = ['metadata', 'script', ...excludedEls]
|
|
191
|
+
let removeEls = ['script', ...excludedEls]
|
|
153
192
|
|
|
154
|
-
removeSVGEls(svg, { removeEls, removeNameSpaced });
|
|
193
|
+
removeSVGEls(svg, { remove: removeEls, removeNameSpaced });
|
|
155
194
|
|
|
156
195
|
// an array of all elements' properties
|
|
157
196
|
let svgElProps = []
|
|
@@ -180,6 +219,7 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
180
219
|
* to user units
|
|
181
220
|
*/
|
|
182
221
|
let styleProps = parseStylesProperties(el, propOptions)
|
|
222
|
+
let stylePropsFiltered = {}
|
|
183
223
|
|
|
184
224
|
// get parent styles
|
|
185
225
|
let { parentStyleProps = [] } = el;
|
|
@@ -209,33 +249,29 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
209
249
|
|
|
210
250
|
|
|
211
251
|
// merge with svg props
|
|
252
|
+
|
|
212
253
|
styleProps = {
|
|
213
254
|
...stylePropsSVG,
|
|
214
255
|
...inheritedProps,
|
|
215
256
|
...styleProps
|
|
216
257
|
}
|
|
217
258
|
|
|
218
|
-
//console.log('inheritedProps', inheritedProps, name);
|
|
219
259
|
|
|
260
|
+
// dont inherit class
|
|
261
|
+
if (stylePropsSVG['class'] === styleProps['class']) {
|
|
262
|
+
delete styleProps['class']
|
|
263
|
+
}
|
|
220
264
|
|
|
221
265
|
// add combined transforms
|
|
222
266
|
addTransFormProps(styleProps, transFormInherited);
|
|
267
|
+
//console.log('transFormInherited', transFormInherited);
|
|
268
|
+
//console.log('styleProps', styleProps);
|
|
223
269
|
|
|
224
270
|
|
|
225
271
|
let { remove, matrix, transComponents } = styleProps;
|
|
226
272
|
|
|
227
|
-
// mark attributes for removal
|
|
228
|
-
if (removeClassNames) styleProps.remove.push('class')
|
|
229
|
-
if (removeIds) styleProps.remove.push('id')
|
|
230
|
-
if (removeDimensions) {
|
|
231
|
-
styleProps.remove.push('width')
|
|
232
|
-
styleProps.remove.push('height')
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
273
|
// styles to atts
|
|
237
|
-
if (unGroup || convertTransforms || minifyRgbColors
|
|
238
|
-
|
|
274
|
+
if (unGroup || convertTransforms || minifyRgbColors) stylesToAttributes = true;
|
|
239
275
|
|
|
240
276
|
if (stylesToAttributes) {
|
|
241
277
|
|
|
@@ -251,7 +287,6 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
251
287
|
let unProportional = scaleX !== scaleY;
|
|
252
288
|
let scalableByAtt = ['circle', 'ellipse', 'rect']
|
|
253
289
|
let needsTrans = convertTransforms || (name === 'g') || (hasRot) || unProportional
|
|
254
|
-
//needsTrans = true
|
|
255
290
|
|
|
256
291
|
if (!needsTrans && scalableByAtt.includes(name)) {
|
|
257
292
|
|
|
@@ -260,7 +295,6 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
260
295
|
styleProps.cy[0] = [styleProps.cy[0] * scaleX + translateY]
|
|
261
296
|
|
|
262
297
|
if (styleProps.r) styleProps.r[0] = [styleProps.r[0] * scaleX]
|
|
263
|
-
|
|
264
298
|
if (styleProps.rx) styleProps.rx[0] = [styleProps.rx[0] * scaleX]
|
|
265
299
|
if (styleProps.ry) styleProps.ry[0] = [styleProps.ry[0] * scaleX]
|
|
266
300
|
|
|
@@ -282,6 +316,12 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
282
316
|
styleProps.height = [styleProps.height[0] * scaleX]
|
|
283
317
|
}
|
|
284
318
|
|
|
319
|
+
// remove now obsolete transform properties
|
|
320
|
+
delete styleProps.matrix
|
|
321
|
+
delete styleProps.transformArr
|
|
322
|
+
delete styleProps.transComponents
|
|
323
|
+
|
|
324
|
+
// mark transform attribute for removal
|
|
285
325
|
remove.push('transform')
|
|
286
326
|
|
|
287
327
|
// scale props like stroke width or dash-array
|
|
@@ -298,30 +338,30 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
298
338
|
* apply consolidated
|
|
299
339
|
* element attributes
|
|
300
340
|
*/
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
{ removeDefaults: true, cleanUpStrokes });
|
|
341
|
+
stylePropsFiltered = filterSvgElProps(name, styleProps,
|
|
342
|
+
{ removeDefaults: true, cleanUpStrokes, allowMeta, allowAriaAtts, allowDataAtts, removeIds });
|
|
304
343
|
|
|
305
344
|
remove = [...remove, ...stylePropsFiltered.remove];
|
|
306
345
|
|
|
307
346
|
for (let prop in stylePropsFiltered.propsFiltered) {
|
|
308
347
|
let values = styleProps[prop]
|
|
309
|
-
//console.log('add', prop);
|
|
310
348
|
let val = values.length ? values.join(' ') : values[0]
|
|
311
349
|
el.setAttribute(prop, val)
|
|
350
|
+
|
|
312
351
|
}
|
|
313
352
|
|
|
353
|
+
|
|
314
354
|
// remove obsolete attributes
|
|
315
355
|
for (let i = 0; i < remove.length; i++) {
|
|
316
356
|
let att = remove[i];
|
|
317
357
|
if (!stylesToAttributes && att === 'style') continue
|
|
318
|
-
|
|
319
358
|
//console.log('remove att', att, name);
|
|
320
359
|
el.removeAttribute(att)
|
|
321
360
|
}
|
|
322
361
|
|
|
323
362
|
|
|
324
363
|
|
|
364
|
+
|
|
325
365
|
/**
|
|
326
366
|
* remove group styles
|
|
327
367
|
* copied to children
|
|
@@ -339,9 +379,19 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
339
379
|
})
|
|
340
380
|
} else {
|
|
341
381
|
groups.forEach((g, i) => {
|
|
342
|
-
let atts = [...Object.keys(groupProps[i]), 'style', 'transform'];
|
|
382
|
+
//let atts = [...Object.keys(groupProps[i]), 'style', 'transform', 'id'];
|
|
383
|
+
let atts = Object.keys(getElementAtts(g));
|
|
384
|
+
|
|
343
385
|
atts.forEach(att => {
|
|
344
|
-
|
|
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
|
+
}
|
|
345
395
|
})
|
|
346
396
|
})
|
|
347
397
|
|
|
@@ -388,8 +438,7 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
388
438
|
el.replaceWith(path)
|
|
389
439
|
|
|
390
440
|
name = 'path'
|
|
391
|
-
el = path;
|
|
392
|
-
|
|
441
|
+
el = path; // required for node
|
|
393
442
|
|
|
394
443
|
}
|
|
395
444
|
|
|
@@ -400,18 +449,241 @@ export function cleanUpSVG(svgMarkup, {
|
|
|
400
449
|
let paths = svg.querySelectorAll('path')
|
|
401
450
|
paths.forEach(path => {
|
|
402
451
|
let shape = pathElToShape(path, { convert_rects, convert_ellipses, convert_poly, convert_lines })
|
|
403
|
-
path.replaceWith(shape)
|
|
452
|
+
//path.replaceWith(shape)
|
|
404
453
|
path = shape;
|
|
405
454
|
})
|
|
406
455
|
|
|
407
456
|
}
|
|
408
457
|
|
|
409
458
|
|
|
459
|
+
/**
|
|
460
|
+
* combine styles
|
|
461
|
+
* store in node property
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
if (mergePaths || attributesToGroup) {
|
|
465
|
+
|
|
466
|
+
let options = { allowMeta, allowAriaAtts, removeIds, removeClassNames, allowDataAtts }
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* exclude properties for
|
|
470
|
+
* adjacent path merging
|
|
471
|
+
* e.g ignore classnames or ids
|
|
472
|
+
*/
|
|
473
|
+
if(mergePaths){
|
|
474
|
+
options.removeIds = true;
|
|
475
|
+
options.removeClassNames = true;
|
|
476
|
+
options.allowAriaAtts = false;
|
|
477
|
+
options.allowMeta = false;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
stylePropsFiltered = filterSvgElProps(name, styleProps, options).propsFiltered
|
|
481
|
+
|
|
482
|
+
for (let prop in stylePropsFiltered) {
|
|
483
|
+
|
|
484
|
+
if (geometryProps.includes(prop)) continue;
|
|
485
|
+
|
|
486
|
+
let values = stylePropsFiltered[prop]
|
|
487
|
+
let val = values.length ? values.join(' ') : values[0]
|
|
488
|
+
|
|
489
|
+
let propShort = toShortStr(prop)
|
|
490
|
+
let valShort = toShortStr(val)
|
|
491
|
+
let propStr = `${propShort}-${valShort}`;
|
|
492
|
+
|
|
493
|
+
// store in node property
|
|
494
|
+
if (!el.styleSet) el.styleSet = new Set()
|
|
495
|
+
el.styleSet.add(propStr)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
}
|
|
499
|
+
|
|
410
500
|
|
|
411
501
|
}//endof element loop
|
|
412
502
|
|
|
413
503
|
|
|
414
504
|
|
|
505
|
+
/**
|
|
506
|
+
* merge paths with same styles
|
|
507
|
+
*/
|
|
508
|
+
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
|
+
}
|
|
535
|
+
|
|
536
|
+
// update style
|
|
537
|
+
stylePrev = style
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* shared styles to group
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
if (attributesToGroup) {
|
|
547
|
+
let els = svg.querySelectorAll(geometryEls.join(', '))
|
|
548
|
+
let len = els.length;
|
|
549
|
+
|
|
550
|
+
let el0 = els[0] || null
|
|
551
|
+
let stylePrev = el0.styleSet !== undefined ? [...el0.styleSet].join('_') : ''
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
// all props
|
|
555
|
+
let allProps = {}
|
|
556
|
+
|
|
557
|
+
// find attributes shared by all
|
|
558
|
+
let globalAtts = []
|
|
559
|
+
|
|
560
|
+
if (len) {
|
|
561
|
+
|
|
562
|
+
let groups = [[el0]];
|
|
563
|
+
let idx = 0;
|
|
564
|
+
let elPrev = el0
|
|
565
|
+
|
|
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]}`
|
|
571
|
+
|
|
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
|
+
}
|
|
582
|
+
|
|
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
|
+
}
|
|
596
|
+
|
|
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
|
+
|
|
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
|
|
616
|
+
|
|
617
|
+
}// endof el loop
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
//console.log('groups', groups);
|
|
626
|
+
|
|
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')
|
|
633
|
+
|
|
634
|
+
|
|
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
|
+
|
|
643
|
+
for (let att in atts) {
|
|
644
|
+
//&& att!=='transform'
|
|
645
|
+
if (globalAtts.includes(att)) {
|
|
646
|
+
child0.removeAttribute(att)
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
continue
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
|
|
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)
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
// move attributes to group
|
|
665
|
+
for (let att in atts) {
|
|
666
|
+
let val = atts[att];
|
|
667
|
+
//console.log('att', atts, val);
|
|
668
|
+
|
|
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
|
+
|
|
680
|
+
} // endof groups
|
|
681
|
+
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
}
|
|
686
|
+
|
|
415
687
|
|
|
416
688
|
|
|
417
689
|
// remove futile clip-paths
|
|
@@ -714,11 +986,18 @@ export function removeSVGEls(svg, {
|
|
|
714
986
|
remove = ['metadata', 'script'],
|
|
715
987
|
removeNameSpaced = true,
|
|
716
988
|
} = {}) {
|
|
989
|
+
|
|
717
990
|
let els = svg.querySelectorAll('*')
|
|
991
|
+
|
|
992
|
+
let allowMeta = !remove.includes('metadata');
|
|
993
|
+
|
|
718
994
|
els.forEach(el => {
|
|
719
995
|
let nodeName = el.nodeName;
|
|
720
|
-
|
|
721
|
-
|
|
996
|
+
let isMeta = allowMeta && el.closest('metadata')
|
|
997
|
+
if (
|
|
998
|
+
!isMeta &&
|
|
999
|
+
((removeNameSpaced && nodeName.includes(':')) ||
|
|
1000
|
+
remove.includes(nodeName))
|
|
722
1001
|
) {
|
|
723
1002
|
el.remove()
|
|
724
1003
|
}
|
|
@@ -740,10 +1019,24 @@ function cleanSvgPrologue(svgString) {
|
|
|
740
1019
|
);
|
|
741
1020
|
}
|
|
742
1021
|
|
|
743
|
-
function removeExcludedAttribues(el,
|
|
1022
|
+
function removeExcludedAttribues(el, {
|
|
1023
|
+
allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class'],
|
|
1024
|
+
allowAriaAtts = true,
|
|
1025
|
+
allowDataAtts = true,
|
|
1026
|
+
allowMeta = false
|
|
1027
|
+
} = {}) {
|
|
744
1028
|
let atts = [...el.attributes].map((att) => att.name);
|
|
745
1029
|
atts.forEach((att) => {
|
|
746
|
-
|
|
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
|
+
) {
|
|
747
1040
|
el.removeAttribute(att);
|
|
748
1041
|
}
|
|
749
1042
|
});
|
|
@@ -21,6 +21,10 @@ export function parseStylesProperties(el, {
|
|
|
21
21
|
removeDefaults = true,
|
|
22
22
|
cleanUpStrokes = true,
|
|
23
23
|
normalizeTransforms = true,
|
|
24
|
+
removeIds=false,
|
|
25
|
+
removeClassNames=false,
|
|
26
|
+
|
|
27
|
+
include=[],
|
|
24
28
|
exclude = [],
|
|
25
29
|
width = 0,
|
|
26
30
|
height = 0,
|
|
@@ -57,7 +61,7 @@ export function parseStylesProperties(el, {
|
|
|
57
61
|
*/
|
|
58
62
|
|
|
59
63
|
if (removeInvalid || removeDefaults || removeNameSpaced) {
|
|
60
|
-
let propsFilteredObj = filterSvgElProps(nodeName, props, { removeDefaults, removeNameSpaced, exclude, cleanUpStrokes, include: transformsStandalone, cleanUpStrokes: false })
|
|
64
|
+
let propsFilteredObj = filterSvgElProps(nodeName, props, { removeIds, removeClassNames, removeDefaults, removeNameSpaced, exclude, cleanUpStrokes, include: [...transformsStandalone, ...include], cleanUpStrokes: false })
|
|
61
65
|
props = propsFilteredObj.propsFiltered
|
|
62
66
|
remove.push(...propsFilteredObj.remove)
|
|
63
67
|
}
|
|
@@ -392,7 +396,7 @@ export function parseStylesProperties(el, {
|
|
|
392
396
|
* consolidate transforms to matrix
|
|
393
397
|
*/
|
|
394
398
|
export function addTransFormProps(propsObj = {}, transformArr = []) {
|
|
395
|
-
if (propsObj.transformArr === undefined
|
|
399
|
+
if (propsObj.transformArr === undefined || !transformArr.length) return;
|
|
396
400
|
|
|
397
401
|
// take existing array or custom
|
|
398
402
|
transformArr = transformArr.length ? transformArr : propsObj.transformArr;
|
|
@@ -415,13 +419,22 @@ export function filterSvgElProps(elNodename = '', props = {}, {
|
|
|
415
419
|
removeInvalid = true,
|
|
416
420
|
removeDefaults = true,
|
|
417
421
|
allowDataAtts = true,
|
|
422
|
+
allowMeta = false,
|
|
423
|
+
allowAriaAtts = false,
|
|
418
424
|
cleanUpStrokes = true,
|
|
419
|
-
include = ['id', 'class'],
|
|
425
|
+
//include = ['id', 'class'],
|
|
426
|
+
include=[],
|
|
427
|
+
removeIds=false,
|
|
428
|
+
removeClassNames=false,
|
|
420
429
|
exclude = [],
|
|
421
430
|
} = {}) {
|
|
422
431
|
let propsFiltered = {}
|
|
423
432
|
let remove = [];
|
|
424
433
|
|
|
434
|
+
if(!removeIds) include.push('id')
|
|
435
|
+
if(!removeClassNames) include.push('class')
|
|
436
|
+
//console.log('???include', 'removeIds', removeIds, include);
|
|
437
|
+
|
|
425
438
|
// allow defaults for nested
|
|
426
439
|
//removeDefaults = false;
|
|
427
440
|
|
|
@@ -429,32 +442,49 @@ export function filterSvgElProps(elNodename = '', props = {}, {
|
|
|
429
442
|
//console.log('noStrokeColor', elNodename, 'cleanUpStrokes', cleanUpStrokes);
|
|
430
443
|
|
|
431
444
|
for (let prop in props) {
|
|
432
|
-
let
|
|
433
|
-
|
|
445
|
+
let values = props[prop]
|
|
446
|
+
let value = Array.isArray(values) ? values[0] : values;
|
|
447
|
+
//console.log(prop, Array.isArray(values));
|
|
434
448
|
|
|
435
449
|
// filter out useless
|
|
436
450
|
let isValid = removeInvalid ?
|
|
437
451
|
(attLookup.atts[prop] ? attLookup.atts[prop].includes(elNodename) : false) :
|
|
438
452
|
false;
|
|
439
453
|
|
|
454
|
+
// remove null transforms
|
|
455
|
+
if (prop === 'transform' && value === 'matrix(1 0 0 1 0 0)') isValid = false;
|
|
456
|
+
|
|
440
457
|
// allow data attributes
|
|
441
458
|
let isDataAtt = allowDataAtts ? prop.startsWith('data-') : false;
|
|
459
|
+
let isMeta = allowMeta && prop === 'title'
|
|
460
|
+
let isAria = allowAriaAtts && prop.startsWith('aria-')
|
|
442
461
|
|
|
443
462
|
// filter out defaults
|
|
444
463
|
let isDefault = removeDefaults ?
|
|
445
464
|
(attLookup.defaults[prop] ? attLookup.defaults[prop] !== undefined && attLookup.defaults[prop].includes(value) : false) :
|
|
446
465
|
false;
|
|
447
466
|
|
|
467
|
+
let isFutileStroke = noStrokeColor && strokeAtts.includes(prop);
|
|
468
|
+
|
|
469
|
+
if (isDefault || isDataAtt || isMeta || isAria || isFutileStroke) isValid = false
|
|
470
|
+
if (include.includes(prop)) isValid = true;
|
|
448
471
|
|
|
472
|
+
//console.log('!valid', prop, isValid);
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
/*
|
|
449
476
|
if (isDataAtt || include.includes(prop)) isValid = true;
|
|
450
477
|
if (isDefault) isValid = false
|
|
451
478
|
if (exclude.length && exclude.includes(prop)) isValid = false;
|
|
452
479
|
if (noStrokeColor && strokeAtts.includes(prop)) isValid = false
|
|
480
|
+
*/
|
|
481
|
+
|
|
453
482
|
|
|
454
483
|
if (isValid) {
|
|
455
484
|
propsFiltered[prop] = props[prop]
|
|
456
485
|
}
|
|
457
486
|
else {
|
|
487
|
+
//console.log('remove', prop);
|
|
458
488
|
remove.push(prop)
|
|
459
489
|
}
|
|
460
490
|
}
|