svg-path-simplify 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +6 -4
  3. package/dist/svg-path-simplify.esm.js +2450 -888
  4. package/dist/svg-path-simplify.esm.min.js +2 -2
  5. package/dist/svg-path-simplify.js +2450 -888
  6. package/dist/svg-path-simplify.min.js +2 -2
  7. package/dist/svg-path-simplify.pathdata.esm.js +167 -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 +333 -132
  11. package/package.json +5 -2
  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 +246 -262
  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 +144 -0
  22. package/src/svgii/convert_units.js +8 -2
  23. package/src/svgii/geometry.js +182 -3
  24. package/src/svgii/geometry_length.js +237 -0
  25. package/src/svgii/pathData_convert.js +43 -1
  26. package/src/svgii/pathData_fix_directions.js +6 -0
  27. package/src/svgii/pathData_fromPoly.js +3 -3
  28. package/src/svgii/pathData_getLength.js +86 -0
  29. package/src/svgii/pathData_parse.js +2 -0
  30. package/src/svgii/pathData_parse_els.js +189 -189
  31. package/src/svgii/pathData_split_to_groups.js +168 -0
  32. package/src/svgii/pathData_stringify.js +26 -64
  33. package/src/svgii/pathData_toPolygon.js +3 -4
  34. package/src/svgii/poly_analyze.js +61 -0
  35. package/src/svgii/poly_normalize.js +11 -2
  36. package/src/svgii/poly_to_pathdata.js +85 -24
  37. package/src/svgii/rounding.js +8 -7
  38. package/src/svgii/svg-styles-to-attributes-const.js +1 -0
  39. package/src/svgii/svg_cleanup.js +467 -421
  40. package/src/svgii/svg_cleanup_convertPathLength.js +32 -0
  41. package/src/svgii/svg_cleanup_general_svg_atts.js +97 -0
  42. package/src/svgii/svg_cleanup_normalize_transforms.js +83 -0
  43. package/src/svgii/svg_cleanup_remove_els_and_atts.js +72 -0
  44. package/src/svgii/svg_cleanup_ungroup.js +36 -0
  45. package/src/svgii/svg_el_parse_style_props.js +76 -28
  46. package/src/svgii/svg_getElementLength.js +67 -0
  47. package/tests/testSVG_shape.js +59 -0
  48. package/tests/testSVG_transform.js +61 -0
@@ -0,0 +1,243 @@
1
+ export let settingsDefaults = {
2
+
3
+ // SVG elements
4
+ removeComments: true,
5
+ removeOffCanvas: false,
6
+
7
+ // attributes
8
+ removeDimensions: false,
9
+ removeIds: false,
10
+ removeClassNames: false,
11
+ omitNamespace: false,
12
+ cleanUpStrokes: true,
13
+ addViewBox: true,
14
+ addDimensions: false,
15
+ removePrologue: true,
16
+ removeHidden: true,
17
+ removeUnused: true,
18
+ cleanupDefs: true,
19
+ cleanupClip: true,
20
+ cleanupSVGAtts: true,
21
+ removeNameSpaced: true,
22
+ removeNameSpacedAtts: true,
23
+ attributesToGroup: false,
24
+ minifyRgbColors: true,
25
+ stylesToAttributes: false,
26
+ fixHref: false,
27
+ legacyHref: false,
28
+ allowMeta: false,
29
+ allowDataAtts: true,
30
+ allowAriaAtts: true,
31
+ //pathlength conversion
32
+ convertPathLength: false,
33
+
34
+ // custom removal
35
+ removeElements: [],
36
+ removeSVGAttributes: [],
37
+ removeElAttributes: [],
38
+
39
+ // merging/splitting
40
+ unGroup: false,
41
+ mergePaths: false,
42
+ splitCompound: false,
43
+
44
+
45
+
46
+ // shape conversions
47
+ shapesToPaths: false,
48
+ shapeConvert: 0,
49
+ convertShapes: ['rect', 'ellipse', 'circle', 'line', 'polygon', 'polyline'],
50
+
51
+
52
+ // simplify
53
+ keepSmaller: true,
54
+ simplifyBezier: true,
55
+ optimizeOrder: true,
56
+ autoClose: false,
57
+ removeZeroLength: true,
58
+ refineClosing: true,
59
+ removeColinear: true,
60
+ flatBezierToLinetos: true,
61
+ revertToQuadratics: true,
62
+ refineExtremes: false,
63
+ simplifyCorners: false,
64
+ keepExtremes: true,
65
+ keepCorners: true,
66
+ keepInflections: false,
67
+ addExtremes: false,
68
+
69
+ // draw direction
70
+ fixDirections: false,
71
+ reversePath: false,
72
+
73
+
74
+ // pathdata
75
+ toAbsolute: false,
76
+ toRelative: true,
77
+ toMixed: false,
78
+ toShorthands: true,
79
+ toLonghands: false,
80
+ quadraticToCubic: true,
81
+ arcToCubic: false,
82
+ cubicToArc: false,
83
+ lineToCubic: false,
84
+
85
+ // minification
86
+ decimals: 3,
87
+ autoAccuracy: true,
88
+ minifyD: 0,
89
+ tolerance: 1,
90
+
91
+
92
+ // polygon
93
+ toPolygon: false,
94
+ smoothPoly: false,
95
+ polyFormat: 'object',
96
+ precisionPoly: 1,
97
+ simplifyRD: 0,
98
+ simplifyRDP: 0,
99
+ harmonizeCpts: false,
100
+ removeOrphanSubpaths: false,
101
+ simplifyRound: false,
102
+
103
+ //svg scaling
104
+ scale: 1,
105
+ scaleTo: 0,
106
+ crop: false,
107
+ alignToOrigin: false,
108
+
109
+ // flatten transforms
110
+ convertTransforms: false,
111
+
112
+
113
+ }
114
+
115
+ const settingsNull = {}
116
+
117
+ for (let prop in settingsDefaults) {
118
+ let val = settingsDefaults[prop];
119
+ let isBoolean = val === false || val === true;
120
+ let isNum = !isNaN(val)
121
+ let isArray = Array.isArray(val)
122
+
123
+ if (isBoolean) val = false
124
+ else if (!isArray && isNum) val = val===1 ? 1 : (prop==='decimals'? -1 : 0);
125
+ else if (isArray) val = []
126
+ settingsNull[prop] = val;
127
+ }
128
+
129
+
130
+ export const presetSettings = {
131
+ default: settingsDefaults,
132
+
133
+ education: {
134
+ ...settingsDefaults,
135
+ ...{
136
+ keepSmaller: false,
137
+ toRelative: false,
138
+ toMixed: false,
139
+ toShorthands: false,
140
+ fixHref: true,
141
+ legacyHref: false,
142
+ addViewBox: true,
143
+ addDimensions: true,
144
+ removeComments: false,
145
+ decimals: 3,
146
+ minifyD: 2
147
+ }
148
+ },
149
+
150
+ null: settingsNull,
151
+
152
+ editor: {
153
+ ...settingsDefaults,
154
+ ...{
155
+ keepSmaller: false,
156
+ toRelative: true,
157
+ toMixed: true,
158
+ toShorthands: true,
159
+ //fixHref: true,
160
+ legacyHref: true,
161
+ addViewBox: true,
162
+ addDimensions: true,
163
+ removeComments: true,
164
+ autoAccuracy: true,
165
+ //decimals:5,
166
+ minifyD: 0.5
167
+ }
168
+ },
169
+
170
+ noSimplification: {
171
+ ...settingsDefaults,
172
+ ...{
173
+ simplifyBezier: false,
174
+ quadraticToCubic: false,
175
+ toRelative: true,
176
+ toShorthands: true,
177
+ fixHref: true,
178
+ optimizeOrder: false,
179
+ removeZeroLength: false,
180
+ refineExtremes: false,
181
+ refineClosing: false,
182
+ removeColinear: false,
183
+ flatBezierToLinetos: false,
184
+ //addViewBox: false,
185
+ addDimensions: false,
186
+ removeComments: true,
187
+ minifyD: 0
188
+ }
189
+
190
+ },
191
+ path: {
192
+ ...settingsDefaults,
193
+ ...{
194
+ shapeConvert: 'toPaths',
195
+ convertShapes: ['rect', 'ellipse', 'circle', 'line', 'polygon', 'polyline'],
196
+ addViewBox: true,
197
+ minifyD: 0.5
198
+ }
199
+ },
200
+
201
+ poly: {
202
+ ...settingsDefaults,
203
+ ...{
204
+ toPolygon: true,
205
+ }
206
+ },
207
+
208
+ curvefit: {
209
+ ...settingsDefaults,
210
+ ...{
211
+ smoothPoly: true,
212
+ }
213
+ },
214
+
215
+ detransform: {
216
+ ...settingsDefaults,
217
+ ...{
218
+ convertTransforms: true,
219
+ addViewBox: true,
220
+ minifyD: 0.5
221
+ }
222
+ },
223
+
224
+ high: {
225
+ ...settingsDefaults,
226
+ ...{
227
+ tolerance: 1.2,
228
+ toMixed: true,
229
+ refineExtremes: true,
230
+ simplifyCorners: true,
231
+ simplifyRound: true,
232
+ removeClassNames: true,
233
+ cubicToArc: true,
234
+ removeComments: true,
235
+ removeHidden: true,
236
+ removeOffCanvas: true,
237
+ addViewBox: true,
238
+ removeDimensions: true,
239
+ minifyD: 0
240
+ }
241
+ }
242
+
243
+ }
@@ -9,13 +9,16 @@
9
9
  */
10
10
 
11
11
  import { harmonizeCubicCpts, harmonizeCubicCptsThird } from "./pathData_simplify_harmonize_cpts";
12
- import { getAngle, getDistance, getSquareDistance, pointAtT, rotatePoint } from "./svgii/geometry";
12
+ import { checkLineIntersection, getAngle, getDistance, getSquareDistance, pointAtT, reducePoints, rotatePoint } from "./svgii/geometry";
13
13
  import { getPolygonArea } from "./svgii/geometry_area";
14
+ import { detectRegularPolygon, getPolyCentroid } from "./svgii/poly_analyze";
14
15
  import { renderPath, renderPoint } from "./svgii/visualize";
15
16
 
16
17
 
17
18
 
18
19
 
20
+
21
+
19
22
  /**
20
23
  * Fit one or more Bezier curves to a set of pts.
21
24
  *
@@ -50,17 +53,18 @@ export function fitCurveSchneider(pts, {
50
53
 
51
54
  // create pathdata
52
55
  let pathData = bezierPtsToPathData(beziers)
53
-
54
-
55
-
56
56
  let cp1, cp2;
57
57
 
58
58
  adjustCpts = false
59
- harmonize = false;
59
+ //harmonize = false;
60
+
61
+ adjustCpts = true;
62
+ //harmonize = true;
63
+
60
64
 
61
65
  if (adjustCpts) {
62
66
 
63
- console.log('refine cpts');
67
+ //console.log('refine cpts');
64
68
 
65
69
  let len2 = pathData.length;
66
70
  let com1 = pathData[0]
@@ -91,13 +95,16 @@ export function fitCurveSchneider(pts, {
91
95
  com2.values[3] = cp2.y
92
96
  }
93
97
 
98
+ /*
94
99
  // harmonize too tight tangents
95
- //let harmonize= true;
100
+ let harmonize = true;
101
+ harmonize = false;
96
102
  if (harmonize) {
97
103
  pathData = harmonizeCubicCptsThird([{ type: 'M', values: [pts[0].x, pts[0].y] },
98
104
  ...pathData])
99
105
  pathData.shift()
100
106
  }
107
+ */
101
108
 
102
109
  }
103
110
 
@@ -0,0 +1,102 @@
1
+ import { getSquareDistance, reducePoints } from "./svgii/geometry";
2
+ import { getPolygonArea } from "./svgii/geometry_area";
3
+ import { getPolyBBox } from "./svgii/geometry_bbox";
4
+
5
+ export function simplifyRC(pts, quality = 1, shiftStart = true) {
6
+
7
+ if (pts.length < 4) return pts;
8
+
9
+ let l = pts.length;
10
+
11
+
12
+ // starting point
13
+ let M = pts[0];
14
+
15
+ // last point
16
+ let Z = pts[l - 1];
17
+
18
+ // remove unnecessary closing point
19
+ if (M.x === Z.x && M.y === Z.y) {
20
+ pts.pop();
21
+ l--;
22
+ Z = pts[l - 1];
23
+ }
24
+
25
+ // init new point array
26
+ let ptsSmp = [M];
27
+ let pt0 = M;
28
+ let pt1, pt2;
29
+
30
+ // loop through vertices by triangles
31
+ for (let i = 2; i < l; i++) {
32
+ pt1 = pts[i - 1];
33
+ pt2 = pts[i];
34
+ let isLast = i === l - 1;
35
+
36
+ /**
37
+ * 1. Skip zero-length segments
38
+ */
39
+ if ((pt1.x === pt0.x && pt1.y === pt0.y) || (pt1.x === pt2.x && pt1.y === pt2.y)) {
40
+ continue;
41
+ }
42
+
43
+ /**
44
+ * 2. Check for perfectly flat
45
+ * vertical/horizontal segments
46
+ */
47
+ let isVertical = (pt0.x === pt1.x);
48
+ let isHorizontal = (pt0.y === pt1.y);
49
+
50
+ if (isVertical || isHorizontal) {
51
+
52
+ let isVertical2 = (pt1.x === pt2.x);
53
+ let isHorizontal2 = (pt1.y === pt2.y);
54
+
55
+ if (((isVertical && isVertical2) || (isHorizontal && isHorizontal2))) {
56
+
57
+ // perfectly flat segment - skip
58
+ if (!isLast) continue;
59
+
60
+ // flat but last – add last and skip colinearity check
61
+ if (isLast && M.x !== pt2.x && M.y !== pt2.y) {
62
+
63
+ ptsSmp.push(pt2);
64
+ continue
65
+ }
66
+
67
+ }
68
+ }
69
+
70
+ // check area
71
+ let area = getPolygonArea([pt0, pt1, pt2], true)
72
+ let thresh = getSquareDistance(pt0, pt2) * 0.005;
73
+
74
+ // flat
75
+ if ( area <= thresh && i<l-1) {
76
+ //console.log(area, thresh, pt0, pt1, pt2, i);
77
+ pt0 = pt1;
78
+ continue
79
+ }
80
+
81
+ // no simplification - add mid pt
82
+ ptsSmp.push(pt1);
83
+
84
+ // add last point if not first
85
+ if (isLast && M.x !== pt2.x && M.y !== pt2.y) {
86
+ // console.log('add last', M, pt2);
87
+ ptsSmp.push(pt2);
88
+ }
89
+
90
+ // update previous point
91
+ pt0 = pt1;
92
+
93
+ }
94
+
95
+ // 1st and last are colinear
96
+ let area0 = getPolygonArea([ptsSmp[1], M, ptsSmp[ptsSmp.length-1]], true)
97
+ let thresh0 = getSquareDistance (ptsSmp[1], ptsSmp[ptsSmp.length-1]) * 0.005
98
+ // remove first point
99
+ if(area0 < thresh0) ptsSmp.shift()
100
+
101
+ return ptsSmp;
102
+ }
@@ -3,6 +3,113 @@ import { getPolyBBox } from "./svgii/geometry_bbox";
3
3
  import { renderPoint } from "./svgii/visualize";
4
4
 
5
5
 
6
+
7
+ export function simplifyRDP_rel(pts, quality = 0.9, width = 0, height = 0) {
8
+
9
+ /**
10
+ * switch between absolute or
11
+ * quality based relative thresholds
12
+ */
13
+ let isAbsolute = false;
14
+
15
+ if (typeof quality === 'string') {
16
+ isAbsolute = true;
17
+ quality = parseFloat(quality);
18
+ }
19
+
20
+ if (pts.length < 4 ) return pts;
21
+
22
+ // convert quality to squaredistance tolerance
23
+ let tolerance = quality;
24
+ //console.log('simplifyRDP', tolerance);
25
+
26
+ if (!isAbsolute) {
27
+
28
+ //tolerance = 1 - quality;
29
+ tolerance = quality;
30
+
31
+ // adjust for higher qualities
32
+ if (quality > 0.5) tolerance /= 2;
33
+
34
+ /**
35
+ * approximate dimensions
36
+ * adjust tolerance for
37
+ * very small polygons e.g geodata
38
+ */
39
+ if (!width && !height) {
40
+ let polyS = reducePoints(pts, 12);
41
+ ({ width, height } = getPolyBBox(polyS));
42
+ }
43
+
44
+ // average side lengths
45
+ let dimAvg = (width + height) / 2;
46
+ let scale = dimAvg / 100;
47
+ tolerance = (tolerance * (scale)) ** 2
48
+
49
+ console.log('!!!tolerance', tolerance);
50
+
51
+
52
+ }
53
+
54
+
55
+ // Square distance from point to segment
56
+ const segmentSquareDistance = (p, p1, p2) => {
57
+ let x = p1.x, y = p1.y;
58
+ let dx = p2.x - x, dy = p2.y - y;
59
+
60
+ if (dx !== 0 || dy !== 0) {
61
+ let t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy);
62
+ if (t > 1) {
63
+ x = p2.x;
64
+ y = p2.y;
65
+ } else if (t > 0) {
66
+ x += dx * t;
67
+ y += dy * t;
68
+ }
69
+ }
70
+
71
+ return (p.x - x) ** 2 + (p.y - y) ** 2;
72
+ };
73
+
74
+
75
+ // start collecting ptsSmp polyline
76
+ let ptsSmp = [pts[0]];
77
+
78
+ // create processing stack
79
+ let stack = [];
80
+ stack.push([0, pts.length - 1]);
81
+
82
+ while (stack.length > 0) {
83
+ let [first, last] = stack.pop();
84
+ let maxDist = tolerance;
85
+ let index = -1;
86
+
87
+ // Find point with maximum distance
88
+ for (let i = first + 1; i < last; i++) {
89
+ let currentDist = segmentSquareDistance(pts[i], pts[first], pts[last]);
90
+ if (currentDist > maxDist) {
91
+ index = i;
92
+ maxDist = currentDist;
93
+ }
94
+ }
95
+
96
+ // If max distance > tolerance, split and process
97
+ if (maxDist > tolerance) {
98
+ stack.push([index, last]);
99
+ stack.push([first, index]);
100
+ } else {
101
+ ptsSmp.push(pts[last]);
102
+ }
103
+
104
+ }
105
+
106
+ return ptsSmp;
107
+ }
108
+
109
+
110
+
111
+
112
+
6
113
  export function simplifyPolyRDP(pts, {quality = 0.9, width = 0, height = 0}={}) {
7
114
 
8
115
  /**
@@ -16,7 +123,8 @@ export function simplifyPolyRDP(pts, {quality = 0.9, width = 0, height = 0}={})
16
123
  quality = parseFloat(quality);
17
124
  }
18
125
 
19
- if (pts.length < 4 || (!isAbsolute && quality) >= 1) return pts;
126
+ //|| (!isAbsolute && quality) >= 1
127
+ if (pts.length < 4 ) return pts;
20
128
 
21
129
  // convert quality to squaredistance tolerance
22
130
  let tolerance = quality;
@@ -31,7 +31,8 @@ export function simplifyPolyRD(pts, {quality = 0.9, width = 0, height = 0}={}) {
31
31
  }
32
32
 
33
33
  // nothing to do - exit
34
- if (pts.length < 4 || (!isAbsolute && quality) >= 1) return pts;
34
+ //|| (!isAbsolute && quality) >= 1
35
+ if (pts.length < 4 ) return pts;
35
36
 
36
37
  let p0 = pts[0];
37
38
  let pt;
@@ -43,8 +44,7 @@ export function simplifyPolyRD(pts, {quality = 0.9, width = 0, height = 0}={}) {
43
44
  if (!isAbsolute) {
44
45
 
45
46
  // quality to tolerance
46
- tolerance = 1 - quality;
47
-
47
+ tolerance = quality;
48
48
 
49
49
  /**
50
50
  * approximate dimensions
@@ -0,0 +1,144 @@
1
+ import { isNumericValue } from "./svgii/convert_units"
2
+
3
+ export function toCamelCase(str) {
4
+ return str
5
+ .split(/[-| ]/)
6
+ .map((e, i) => i
7
+ ? e.charAt(0).toUpperCase() + e.slice(1).toLowerCase()
8
+ : e.toLowerCase()
9
+ )
10
+ .join('')
11
+ }
12
+
13
+ export function toShortStr(str) {
14
+ if (isNumericValue(str)) return str
15
+ let strShort = str.split('-').map(str => { return str.replace(/a|e|i|o|u/g, '') }).join('-')
16
+ strShort = toCamelCase(strShort)
17
+ return strShort
18
+ }
19
+
20
+
21
+ export function stringifySVG(svg, {
22
+ omitNamespace = false,
23
+ removeComments = true,
24
+ format = 0,
25
+ } = {}) {
26
+
27
+
28
+ let markup = '';
29
+
30
+ if (format < 2) {
31
+ markup = new XMLSerializer().serializeToString(svg);
32
+ //if (format === 0) markup = minifySVGMarkup(markup, { removeComments })
33
+ markup = minifySVGMarkup(markup, { removeComments })
34
+
35
+ } else {
36
+ markup = serializeSVGPretty(svg)
37
+ }
38
+
39
+
40
+ if (omitNamespace) {
41
+ markup = markup.replaceAll('xmlns="http://www.w3.org/2000/svg"', '')
42
+ }
43
+
44
+ if (removeComments) {
45
+ markup = markup
46
+ .replace(/(<!--.*?-->)|(<!--[\S\s]+?-->)|(<!--[\S\s]*?$)/g, '')
47
+ }
48
+
49
+ /*
50
+ markup = markup
51
+ .replace(/\t/g, "")
52
+ .replace(/[\n\r|]/g, "\n")
53
+ .replace(/\n\s*\n/g, '\n')
54
+ .replace(/ +/g, ' ')
55
+ //.replace(/ +/g, ' ')
56
+ .replace(/> </g, '><')
57
+ .trim()
58
+ // sanitize linebreaks within pathdata
59
+ .replaceAll('&#10;', '\n');
60
+ */
61
+
62
+ //console.log(markup);
63
+
64
+ return markup
65
+ }
66
+
67
+
68
+
69
+ export function minifySVGMarkup(svg, {
70
+ removeComments = true,
71
+ } = {}) {
72
+
73
+ if (removeComments) {
74
+ svg = svg.replace(/<!--[\s\S]*?-->/g, '')
75
+ }
76
+
77
+ // Remove whitespace between tags
78
+ svg = svg.replace(/>\s+</g, '><')
79
+ // Trim leading/trailing whitespace
80
+ .trim()
81
+ // Remove extra whitespace within tags (attributes)
82
+ .replace(/\s+([=])\s+/g, '$1')
83
+ .replace(/\s+(?=[^<]*>)/g, ' ')
84
+ // Collapse multiple spaces to single space
85
+ .replace(/\s{2,}/g, ' ')
86
+ // Remove spaces around = signs in attributes
87
+ .replace(/\s*=\s*/g, '=');
88
+
89
+ return svg
90
+ }
91
+
92
+ export function serializeSVGPretty(xmlDoc, {
93
+ indentSize = 2 } = {}) {
94
+ if (typeof xmlDoc === 'string') {
95
+ xmlDoc = new DOMParser().parseFromString(xmlDoc, 'image/svg+xml').querySelector('svg')
96
+ }
97
+ return formatXMLNode(xmlDoc, 0, indentSize);
98
+ }
99
+
100
+
101
+ function formatXMLNode(node, level, indentSize) {
102
+ let indent = " ".repeat(level * indentSize);
103
+
104
+ if (node.nodeType === Node.TEXT_NODE) {
105
+ let text = node.textContent.trim();
106
+ return text ? text : "";
107
+ }
108
+
109
+ if (node.nodeType === Node.ELEMENT_NODE) {
110
+ let hasChildren = node.children.length > 0;
111
+ let hasTextContent = node.textContent.trim().length > 0 && node.children.length === 0;
112
+
113
+ let result = `${indent}<${node.nodeName}`;
114
+
115
+ // Add attributes
116
+ for (let i = 0; i < node.attributes.length; i++) {
117
+ let att = node.attributes[i];
118
+ result += ` ${att.name}="${att.value}"`;
119
+ }
120
+
121
+ if (!hasChildren && !hasTextContent) {
122
+ return result + " />\n";
123
+ }
124
+
125
+ result += ">";
126
+
127
+ if (hasChildren) {
128
+ result += "\n";
129
+ for (let child of node.children) {
130
+ result += formatXMLNode(child, level + 1, indentSize);
131
+ }
132
+ result += `${indent}</${node.nodeName}>\n`;
133
+ } else if (hasTextContent) {
134
+ result += node.textContent.trim();
135
+ result += `</${node.nodeName}>\n`;
136
+ } else {
137
+ result += `</${node.nodeName}>\n`;
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ return "";
144
+ }
@@ -16,8 +16,14 @@ export function svgElUnitsToPixel(el, {
16
16
 
17
17
  let attributes = [...el.attributes];
18
18
  let attNames = attributes.map(att => att.name)
19
- let attValues = attributes.map(att => att.nodeValue)
20
- //console.log('attributes', attributes);
19
+
20
+ // doesn't work in node!
21
+ //let attValues = attributes.map(att => att.nodeValue)
22
+
23
+ let attValues = []
24
+ attNames.forEach(att=>{
25
+ attValues.push(el.getAttribute(att))
26
+ })
21
27
 
22
28
  let isSquare = width === height;
23
29