svg-path-simplify 0.4.1 → 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 +9 -0
- package/dist/svg-path-simplify.esm.js +528 -165
- package/dist/svg-path-simplify.esm.min.js +2 -2
- package/dist/svg-path-simplify.js +528 -165
- 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 +79 -16
- 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 +1 -0
- package/src/svgii/svg_cleanup.js +328 -36
- package/src/svgii/svg_el_parse_style_props.js +29 -3
- package/tests/testSVG_shape.js +59 -0
- package/tests/testSVG_transform.js +61 -0
|
@@ -1726,6 +1726,7 @@ const transHorizontal = ['scaleX', 'translateX', 'skewX'];
|
|
|
1726
1726
|
const transVertical = ['scaleY', 'translateY', 'skewY'];
|
|
1727
1727
|
|
|
1728
1728
|
const colorProps = ['fill', 'stroke', 'stop-color'];
|
|
1729
|
+
const geometryProps = ['d', 'points', 'cx', 'cy', 'x1', 'x2', 'y1', 'y2', 'width', 'height', 'r', 'rx', 'ry', 'x', 'y'];
|
|
1729
1730
|
|
|
1730
1731
|
const geometryEls = [
|
|
1731
1732
|
"path",
|
|
@@ -2067,7 +2068,14 @@ function svgElUnitsToPixel(el, {
|
|
|
2067
2068
|
|
|
2068
2069
|
let attributes = [...el.attributes];
|
|
2069
2070
|
let attNames = attributes.map(att => att.name);
|
|
2070
|
-
|
|
2071
|
+
|
|
2072
|
+
// doesn't work in node!
|
|
2073
|
+
|
|
2074
|
+
|
|
2075
|
+
let attValues = [];
|
|
2076
|
+
attNames.forEach(att=>{
|
|
2077
|
+
attValues.push(el.getAttribute(att));
|
|
2078
|
+
});
|
|
2071
2079
|
|
|
2072
2080
|
let isSquare = width === height;
|
|
2073
2081
|
|
|
@@ -3901,6 +3909,7 @@ function convertPathData(pathData, {
|
|
|
3901
3909
|
toShorthands = true,
|
|
3902
3910
|
toLonghands = false,
|
|
3903
3911
|
toRelative = true,
|
|
3912
|
+
toMixed = false,
|
|
3904
3913
|
toAbsolute = false,
|
|
3905
3914
|
decimals = 3,
|
|
3906
3915
|
arcToCubic = false,
|
|
@@ -3916,6 +3925,8 @@ function convertPathData(pathData, {
|
|
|
3916
3925
|
|
|
3917
3926
|
} = {}) {
|
|
3918
3927
|
|
|
3928
|
+
let pathDataAbs = [];
|
|
3929
|
+
|
|
3919
3930
|
// pathdata properties - test= true adds a manual test
|
|
3920
3931
|
if (testTypes) {
|
|
3921
3932
|
|
|
@@ -3943,12 +3954,38 @@ function convertPathData(pathData, {
|
|
|
3943
3954
|
|
|
3944
3955
|
if (hasQuadratics && quadraticToCubic) pathData = pathDataQuadraticToCubic(pathData);
|
|
3945
3956
|
|
|
3957
|
+
if(toMixed) toRelative = true;
|
|
3958
|
+
|
|
3946
3959
|
// pre round - before relative conversion to minimize distortions
|
|
3947
3960
|
if (decimals > -1 && toRelative) pathData = roundPathData(pathData, decimals);
|
|
3948
3961
|
|
|
3962
|
+
// clone absolute pathdata
|
|
3963
|
+
if(toMixed){
|
|
3964
|
+
pathDataAbs = JSON.parse(JSON.stringify(pathData));
|
|
3965
|
+
}
|
|
3966
|
+
|
|
3949
3967
|
if (toRelative) pathData = pathDataToRelative(pathData);
|
|
3950
3968
|
if (decimals > -1) pathData = roundPathData(pathData, decimals);
|
|
3951
3969
|
|
|
3970
|
+
// choose most compact commands: relative or absolute
|
|
3971
|
+
if(toMixed){
|
|
3972
|
+
for(let i=0; i<pathData.length; i++){
|
|
3973
|
+
let com = pathData[i];
|
|
3974
|
+
let comA = pathDataAbs[i];
|
|
3975
|
+
// compare Lengths
|
|
3976
|
+
let comStr = [com.type, com.values.join(' ')].join('').replaceAll(' -', '-').replaceAll(' 0.', ' .');
|
|
3977
|
+
let comStrA = [comA.type, comA.values.join(' ')].join('').replaceAll(' -', '-').replaceAll(' 0.', ' .');
|
|
3978
|
+
|
|
3979
|
+
let lenR = comStr.length;
|
|
3980
|
+
let lenA = comStrA.length;
|
|
3981
|
+
|
|
3982
|
+
if(lenA<lenR){
|
|
3983
|
+
|
|
3984
|
+
pathData[i] = pathDataAbs[i];
|
|
3985
|
+
}
|
|
3986
|
+
}
|
|
3987
|
+
}
|
|
3988
|
+
|
|
3952
3989
|
return pathData
|
|
3953
3990
|
}
|
|
3954
3991
|
|
|
@@ -3959,6 +3996,9 @@ function convertPathData(pathData, {
|
|
|
3959
3996
|
*/
|
|
3960
3997
|
|
|
3961
3998
|
function optimizeArcPathData(pathData = []) {
|
|
3999
|
+
|
|
4000
|
+
let remove =[];
|
|
4001
|
+
|
|
3962
4002
|
pathData.forEach((com, i) => {
|
|
3963
4003
|
let { type, values } = com;
|
|
3964
4004
|
if (type === 'A') {
|
|
@@ -3968,6 +4008,12 @@ function optimizeArcPathData(pathData = []) {
|
|
|
3968
4008
|
let M = { x: x0, y: y0 };
|
|
3969
4009
|
let p = { x, y };
|
|
3970
4010
|
|
|
4011
|
+
if(rx===0 || ry===0){
|
|
4012
|
+
pathData[i]= null;
|
|
4013
|
+
remove.push(i);
|
|
4014
|
+
|
|
4015
|
+
}
|
|
4016
|
+
|
|
3971
4017
|
// rx and ry are large enough
|
|
3972
4018
|
if (rx >= 1 && (x === x0 || y === y0)) {
|
|
3973
4019
|
let diff = Math.abs(rx - ry) / rx;
|
|
@@ -3990,6 +4036,8 @@ function optimizeArcPathData(pathData = []) {
|
|
|
3990
4036
|
}
|
|
3991
4037
|
}
|
|
3992
4038
|
});
|
|
4039
|
+
|
|
4040
|
+
if(remove.length) pathData = pathData.filter(Boolean);
|
|
3993
4041
|
return pathData;
|
|
3994
4042
|
}
|
|
3995
4043
|
|
|
@@ -5615,133 +5663,6 @@ function qrDecomposeMatrix(matrix, precision = 4) {
|
|
|
5615
5663
|
return transObj;
|
|
5616
5664
|
}
|
|
5617
5665
|
|
|
5618
|
-
function pathElToShape(el, {
|
|
5619
|
-
convert_rects = false,
|
|
5620
|
-
convert_ellipses = false,
|
|
5621
|
-
convert_poly = false,
|
|
5622
|
-
convert_lines = false
|
|
5623
|
-
} = {}) {
|
|
5624
|
-
|
|
5625
|
-
let pathData = parsePathDataNormalized(el.getAttribute('d'));
|
|
5626
|
-
let coms = Array.from(new Set(pathData.map(com => com.type))).join('');
|
|
5627
|
-
|
|
5628
|
-
let hasArcs = (/[a]/gi).test(coms);
|
|
5629
|
-
let hasBeziers = (/[csqt]/gi).test(coms);
|
|
5630
|
-
let hasLines = (/[l]/gi).test(coms);
|
|
5631
|
-
let isPoly = !(/[acqts]/gi).test(coms);
|
|
5632
|
-
let closed = (/[z]/gi).test(coms);
|
|
5633
|
-
let shape = null;
|
|
5634
|
-
let type = null;
|
|
5635
|
-
|
|
5636
|
-
let attributes = getElementAtts(el);
|
|
5637
|
-
let attsNew = {};
|
|
5638
|
-
let decimals = 7;
|
|
5639
|
-
|
|
5640
|
-
if (isPoly) {
|
|
5641
|
-
|
|
5642
|
-
// is line
|
|
5643
|
-
if (pathData.length === 2 && convert_lines) {
|
|
5644
|
-
type = 'line';
|
|
5645
|
-
shape = document.createElementNS(svgNs, type);
|
|
5646
|
-
let [x1, y1, x2, y2] = [...pathData[0].values, ...pathData[1].values].map(val => roundTo(val, decimals));
|
|
5647
|
-
attsNew = { x1, y1, x2, y2 };
|
|
5648
|
-
}
|
|
5649
|
-
// polygon, polyline or rect
|
|
5650
|
-
else {
|
|
5651
|
-
|
|
5652
|
-
let vertices = getPathDataVertices(pathData);
|
|
5653
|
-
let bb = getPolyBBox(vertices);
|
|
5654
|
-
let areaPoly = getPolygonArea(vertices, true);
|
|
5655
|
-
let areaRect = bb.width * bb.height;
|
|
5656
|
-
let areaDiff = Math.abs(1 - areaRect / areaPoly);
|
|
5657
|
-
|
|
5658
|
-
// is rect
|
|
5659
|
-
if (convert_rects && areaDiff < 0.01) {
|
|
5660
|
-
type = 'rect';
|
|
5661
|
-
shape = document.createElementNS(svgNs, type);
|
|
5662
|
-
let { x, y, width, height } = bb;
|
|
5663
|
-
attsNew = { x, y, width, height };
|
|
5664
|
-
|
|
5665
|
-
}
|
|
5666
|
-
// polyline or polygon
|
|
5667
|
-
else if(convert_poly) {
|
|
5668
|
-
type = closed ? 'polygon' : 'polyline';
|
|
5669
|
-
shape = document.createElementNS(svgNs, type);
|
|
5670
|
-
let points = vertices.map(pt => { return [pt.x, pt.y] }).flat().map(val => roundTo(val, decimals)).join(' ');
|
|
5671
|
-
attsNew = { points };
|
|
5672
|
-
}
|
|
5673
|
-
}
|
|
5674
|
-
}
|
|
5675
|
-
// circles or ellipses
|
|
5676
|
-
else if (!hasLines && convert_ellipses) {
|
|
5677
|
-
|
|
5678
|
-
// try to convert cubics to arcs
|
|
5679
|
-
if (!hasArcs && hasBeziers) {
|
|
5680
|
-
pathData = pathDataCubicsToArc(pathData, { areaThreshold: 2.5 });
|
|
5681
|
-
hasArcs = pathData.filter(com => com.type === 'A').length;
|
|
5682
|
-
}
|
|
5683
|
-
|
|
5684
|
-
if (hasArcs) {
|
|
5685
|
-
let pathData2 = getPathDataVerbose(pathData, { addArcParams: true });
|
|
5686
|
-
let arcComs = pathData2.filter(com => com.type === 'A');
|
|
5687
|
-
|
|
5688
|
-
let cxVals = new Set();
|
|
5689
|
-
let cyVals = new Set();
|
|
5690
|
-
let rxVals = new Set();
|
|
5691
|
-
let ryVals = new Set();
|
|
5692
|
-
|
|
5693
|
-
if (arcComs.length > 1) {
|
|
5694
|
-
|
|
5695
|
-
pathData2.forEach(com => {
|
|
5696
|
-
if (com.type === 'A') {
|
|
5697
|
-
|
|
5698
|
-
cxVals.add(roundTo(com.cx, decimals));
|
|
5699
|
-
cyVals.add(roundTo(com.cy, decimals));
|
|
5700
|
-
rxVals.add(roundTo(com.rx, decimals));
|
|
5701
|
-
ryVals.add(roundTo(com.ry, decimals));
|
|
5702
|
-
}
|
|
5703
|
-
});
|
|
5704
|
-
}
|
|
5705
|
-
|
|
5706
|
-
cxVals = Array.from(cxVals);
|
|
5707
|
-
cyVals = Array.from(cyVals);
|
|
5708
|
-
rxVals = Array.from(rxVals);
|
|
5709
|
-
ryVals = Array.from(ryVals);
|
|
5710
|
-
|
|
5711
|
-
if(cxVals.length===1 && cyVals.length===1 && rxVals.length===1 && ryVals.length===1){
|
|
5712
|
-
let [rx, ry, cx, cy] = [rxVals[0], ryVals[0], cxVals[0], cyVals[0]];
|
|
5713
|
-
type = rx===ry ? 'circle' : 'ellipse';
|
|
5714
|
-
shape = document.createElementNS(svgNs, type);
|
|
5715
|
-
attsNew = type==='circle' ? { r:rx, cx, cy } : {rx, ry, cx, cy};
|
|
5716
|
-
}
|
|
5717
|
-
}
|
|
5718
|
-
}
|
|
5719
|
-
|
|
5720
|
-
// if el could be replaced
|
|
5721
|
-
if (shape) {
|
|
5722
|
-
let ignore = ['id', 'class'];
|
|
5723
|
-
|
|
5724
|
-
// set shape attributes
|
|
5725
|
-
for (let att in attsNew) {
|
|
5726
|
-
shape.setAttribute(att, attsNew[att]);
|
|
5727
|
-
}
|
|
5728
|
-
|
|
5729
|
-
// copy old attributes
|
|
5730
|
-
for (let att in attributes) {
|
|
5731
|
-
|
|
5732
|
-
if (attLookup.atts[att].includes(type) || ignore.includes(att) || att.startsWith('data-')) {
|
|
5733
|
-
shape.setAttribute(att, attributes[att]);
|
|
5734
|
-
}
|
|
5735
|
-
}
|
|
5736
|
-
|
|
5737
|
-
// replace
|
|
5738
|
-
el = shape;
|
|
5739
|
-
}
|
|
5740
|
-
|
|
5741
|
-
return el;
|
|
5742
|
-
|
|
5743
|
-
}
|
|
5744
|
-
|
|
5745
5666
|
function shapeElToPath(el, { width = 0,
|
|
5746
5667
|
height = 0,
|
|
5747
5668
|
convert_rects = false,
|
|
@@ -5920,6 +5841,133 @@ function getPathDataFromEl(el, {
|
|
|
5920
5841
|
|
|
5921
5842
|
}
|
|
5922
5843
|
|
|
5844
|
+
function pathElToShape(el, {
|
|
5845
|
+
convert_rects = false,
|
|
5846
|
+
convert_ellipses = false,
|
|
5847
|
+
convert_poly = false,
|
|
5848
|
+
convert_lines = false
|
|
5849
|
+
} = {}) {
|
|
5850
|
+
|
|
5851
|
+
let pathData = parsePathDataNormalized(el.getAttribute('d'));
|
|
5852
|
+
let coms = Array.from(new Set(pathData.map(com => com.type))).join('');
|
|
5853
|
+
|
|
5854
|
+
let hasArcs = (/[a]/gi).test(coms);
|
|
5855
|
+
let hasBeziers = (/[csqt]/gi).test(coms);
|
|
5856
|
+
let hasLines = (/[l]/gi).test(coms);
|
|
5857
|
+
let isPoly = !(/[acqts]/gi).test(coms);
|
|
5858
|
+
let closed = (/[z]/gi).test(coms);
|
|
5859
|
+
let shape = null;
|
|
5860
|
+
let type = null;
|
|
5861
|
+
|
|
5862
|
+
let attributes = getElementAtts(el);
|
|
5863
|
+
let attsNew = {};
|
|
5864
|
+
let decimals = 7;
|
|
5865
|
+
|
|
5866
|
+
if (isPoly) {
|
|
5867
|
+
|
|
5868
|
+
// is line
|
|
5869
|
+
if (pathData.length === 2 && convert_lines) {
|
|
5870
|
+
type = 'line';
|
|
5871
|
+
shape = document.createElementNS(svgNs, type);
|
|
5872
|
+
let [x1, y1, x2, y2] = [...pathData[0].values, ...pathData[1].values].map(val => roundTo(val, decimals));
|
|
5873
|
+
attsNew = { x1, y1, x2, y2 };
|
|
5874
|
+
}
|
|
5875
|
+
// polygon, polyline or rect
|
|
5876
|
+
else {
|
|
5877
|
+
|
|
5878
|
+
let vertices = getPathDataVertices(pathData);
|
|
5879
|
+
let bb = getPolyBBox(vertices);
|
|
5880
|
+
let areaPoly = getPolygonArea(vertices, true);
|
|
5881
|
+
let areaRect = bb.width * bb.height;
|
|
5882
|
+
let areaDiff = Math.abs(1 - areaRect / areaPoly);
|
|
5883
|
+
|
|
5884
|
+
// is rect
|
|
5885
|
+
if (convert_rects && areaDiff < 0.01) {
|
|
5886
|
+
type = 'rect';
|
|
5887
|
+
shape = document.createElementNS(svgNs, type);
|
|
5888
|
+
let { x, y, width, height } = bb;
|
|
5889
|
+
attsNew = { x, y, width, height };
|
|
5890
|
+
|
|
5891
|
+
}
|
|
5892
|
+
// polyline or polygon
|
|
5893
|
+
else if(convert_poly) {
|
|
5894
|
+
type = closed ? 'polygon' : 'polyline';
|
|
5895
|
+
shape = document.createElementNS(svgNs, type);
|
|
5896
|
+
let points = vertices.map(pt => { return [pt.x, pt.y] }).flat().map(val => roundTo(val, decimals)).join(' ');
|
|
5897
|
+
attsNew = { points };
|
|
5898
|
+
}
|
|
5899
|
+
}
|
|
5900
|
+
}
|
|
5901
|
+
// circles or ellipses
|
|
5902
|
+
else if (!hasLines && convert_ellipses) {
|
|
5903
|
+
|
|
5904
|
+
// try to convert cubics to arcs
|
|
5905
|
+
if (!hasArcs && hasBeziers) {
|
|
5906
|
+
pathData = pathDataCubicsToArc(pathData, { areaThreshold: 2.5 });
|
|
5907
|
+
hasArcs = pathData.filter(com => com.type === 'A').length;
|
|
5908
|
+
}
|
|
5909
|
+
|
|
5910
|
+
if (hasArcs) {
|
|
5911
|
+
let pathData2 = getPathDataVerbose(pathData, { addArcParams: true });
|
|
5912
|
+
let arcComs = pathData2.filter(com => com.type === 'A');
|
|
5913
|
+
|
|
5914
|
+
let cxVals = new Set();
|
|
5915
|
+
let cyVals = new Set();
|
|
5916
|
+
let rxVals = new Set();
|
|
5917
|
+
let ryVals = new Set();
|
|
5918
|
+
|
|
5919
|
+
if (arcComs.length > 1) {
|
|
5920
|
+
|
|
5921
|
+
pathData2.forEach(com => {
|
|
5922
|
+
if (com.type === 'A') {
|
|
5923
|
+
|
|
5924
|
+
cxVals.add(roundTo(com.cx, decimals));
|
|
5925
|
+
cyVals.add(roundTo(com.cy, decimals));
|
|
5926
|
+
rxVals.add(roundTo(com.rx, decimals));
|
|
5927
|
+
ryVals.add(roundTo(com.ry, decimals));
|
|
5928
|
+
}
|
|
5929
|
+
});
|
|
5930
|
+
}
|
|
5931
|
+
|
|
5932
|
+
cxVals = Array.from(cxVals);
|
|
5933
|
+
cyVals = Array.from(cyVals);
|
|
5934
|
+
rxVals = Array.from(rxVals);
|
|
5935
|
+
ryVals = Array.from(ryVals);
|
|
5936
|
+
|
|
5937
|
+
if(cxVals.length===1 && cyVals.length===1 && rxVals.length===1 && ryVals.length===1){
|
|
5938
|
+
let [rx, ry, cx, cy] = [rxVals[0], ryVals[0], cxVals[0], cyVals[0]];
|
|
5939
|
+
type = rx===ry ? 'circle' : 'ellipse';
|
|
5940
|
+
shape = document.createElementNS(svgNs, type);
|
|
5941
|
+
attsNew = type==='circle' ? { r:rx, cx, cy } : {rx, ry, cx, cy};
|
|
5942
|
+
}
|
|
5943
|
+
}
|
|
5944
|
+
}
|
|
5945
|
+
|
|
5946
|
+
// if el could be replaced
|
|
5947
|
+
if (shape) {
|
|
5948
|
+
let ignore = ['id', 'class'];
|
|
5949
|
+
|
|
5950
|
+
// set shape attributes
|
|
5951
|
+
for (let att in attsNew) {
|
|
5952
|
+
shape.setAttribute(att, attsNew[att]);
|
|
5953
|
+
}
|
|
5954
|
+
|
|
5955
|
+
// copy old attributes
|
|
5956
|
+
for (let att in attributes) {
|
|
5957
|
+
|
|
5958
|
+
if (attLookup.atts[att].includes(type) || ignore.includes(att) || att.startsWith('data-')) {
|
|
5959
|
+
shape.setAttribute(att, attributes[att]);
|
|
5960
|
+
}
|
|
5961
|
+
}
|
|
5962
|
+
|
|
5963
|
+
// replace
|
|
5964
|
+
el = shape;
|
|
5965
|
+
}
|
|
5966
|
+
|
|
5967
|
+
return el;
|
|
5968
|
+
|
|
5969
|
+
}
|
|
5970
|
+
|
|
5923
5971
|
function pathDataRemoveColinear(pathData, {
|
|
5924
5972
|
tolerance = 1,
|
|
5925
5973
|
|
|
@@ -6782,6 +6830,10 @@ function parseStylesProperties(el, {
|
|
|
6782
6830
|
removeDefaults = true,
|
|
6783
6831
|
cleanUpStrokes = true,
|
|
6784
6832
|
normalizeTransforms = true,
|
|
6833
|
+
removeIds=false,
|
|
6834
|
+
removeClassNames=false,
|
|
6835
|
+
|
|
6836
|
+
include=[],
|
|
6785
6837
|
exclude = [],
|
|
6786
6838
|
width = 0,
|
|
6787
6839
|
height = 0,
|
|
@@ -6812,7 +6864,7 @@ function parseStylesProperties(el, {
|
|
|
6812
6864
|
*/
|
|
6813
6865
|
|
|
6814
6866
|
if (removeInvalid || removeDefaults || removeNameSpaced) {
|
|
6815
|
-
let propsFilteredObj = filterSvgElProps(nodeName, props, { removeDefaults, removeNameSpaced, exclude, cleanUpStrokes, include: transformsStandalone, cleanUpStrokes: false });
|
|
6867
|
+
let propsFilteredObj = filterSvgElProps(nodeName, props, { removeIds, removeClassNames, removeDefaults, removeNameSpaced, exclude, cleanUpStrokes, include: [...transformsStandalone, ...include], cleanUpStrokes: false });
|
|
6816
6868
|
props = propsFilteredObj.propsFiltered;
|
|
6817
6869
|
remove.push(...propsFilteredObj.remove);
|
|
6818
6870
|
}
|
|
@@ -7146,13 +7198,21 @@ function filterSvgElProps(elNodename = '', props = {}, {
|
|
|
7146
7198
|
removeInvalid = true,
|
|
7147
7199
|
removeDefaults = true,
|
|
7148
7200
|
allowDataAtts = true,
|
|
7201
|
+
allowMeta = false,
|
|
7202
|
+
allowAriaAtts = false,
|
|
7149
7203
|
cleanUpStrokes = true,
|
|
7150
|
-
|
|
7204
|
+
|
|
7205
|
+
include=[],
|
|
7206
|
+
removeIds=false,
|
|
7207
|
+
removeClassNames=false,
|
|
7151
7208
|
exclude = [],
|
|
7152
7209
|
} = {}) {
|
|
7153
7210
|
let propsFiltered = {};
|
|
7154
7211
|
let remove = [];
|
|
7155
7212
|
|
|
7213
|
+
if(!removeIds) include.push('id');
|
|
7214
|
+
if(!removeClassNames) include.push('class');
|
|
7215
|
+
|
|
7156
7216
|
// allow defaults for nested
|
|
7157
7217
|
|
|
7158
7218
|
let noStrokeColor = cleanUpStrokes ? (props['stroke'] === undefined) : false;
|
|
@@ -7167,25 +7227,35 @@ function filterSvgElProps(elNodename = '', props = {}, {
|
|
|
7167
7227
|
false;
|
|
7168
7228
|
|
|
7169
7229
|
// remove null transforms
|
|
7170
|
-
if(prop==='transform' && value==='matrix(1 0 0 1 0 0)') isValid = false;
|
|
7230
|
+
if (prop === 'transform' && value === 'matrix(1 0 0 1 0 0)') isValid = false;
|
|
7171
7231
|
|
|
7172
7232
|
// allow data attributes
|
|
7173
7233
|
let isDataAtt = allowDataAtts ? prop.startsWith('data-') : false;
|
|
7234
|
+
let isMeta = allowMeta && prop === 'title';
|
|
7235
|
+
let isAria = allowAriaAtts && prop.startsWith('aria-');
|
|
7174
7236
|
|
|
7175
7237
|
// filter out defaults
|
|
7176
7238
|
let isDefault = removeDefaults ?
|
|
7177
7239
|
(attLookup.defaults[prop] ? attLookup.defaults[prop] !== undefined && attLookup.defaults[prop].includes(value) : false) :
|
|
7178
7240
|
false;
|
|
7179
7241
|
|
|
7242
|
+
let isFutileStroke = noStrokeColor && strokeAtts.includes(prop);
|
|
7243
|
+
|
|
7244
|
+
if (isDefault || isDataAtt || isMeta || isAria || isFutileStroke) isValid = false;
|
|
7245
|
+
if (include.includes(prop)) isValid = true;
|
|
7246
|
+
|
|
7247
|
+
/*
|
|
7180
7248
|
if (isDataAtt || include.includes(prop)) isValid = true;
|
|
7181
|
-
if (isDefault) isValid = false
|
|
7249
|
+
if (isDefault) isValid = false
|
|
7182
7250
|
if (exclude.length && exclude.includes(prop)) isValid = false;
|
|
7183
|
-
if (noStrokeColor && strokeAtts.includes(prop)) isValid = false
|
|
7251
|
+
if (noStrokeColor && strokeAtts.includes(prop)) isValid = false
|
|
7252
|
+
*/
|
|
7184
7253
|
|
|
7185
7254
|
if (isValid) {
|
|
7186
7255
|
propsFiltered[prop] = props[prop];
|
|
7187
7256
|
}
|
|
7188
7257
|
else {
|
|
7258
|
+
|
|
7189
7259
|
remove.push(prop);
|
|
7190
7260
|
}
|
|
7191
7261
|
}
|
|
@@ -7284,6 +7354,23 @@ function parseInlineCss(styleAtt = '') {
|
|
|
7284
7354
|
return props
|
|
7285
7355
|
}
|
|
7286
7356
|
|
|
7357
|
+
function toCamelCase(str) {
|
|
7358
|
+
return str
|
|
7359
|
+
.split(/[-| ]/)
|
|
7360
|
+
.map((e,i) => i
|
|
7361
|
+
? e.charAt(0).toUpperCase() + e.slice(1).toLowerCase()
|
|
7362
|
+
: e.toLowerCase()
|
|
7363
|
+
)
|
|
7364
|
+
.join('')
|
|
7365
|
+
}
|
|
7366
|
+
|
|
7367
|
+
function toShortStr(str){
|
|
7368
|
+
if(isNumericValue(str)) return str
|
|
7369
|
+
let strShort = str.split('-').map(str=>{return str.replace(/a|e|i|o|u/g,'') }).join('-');
|
|
7370
|
+
strShort = toCamelCase(strShort);
|
|
7371
|
+
return strShort
|
|
7372
|
+
}
|
|
7373
|
+
|
|
7287
7374
|
function removeEmptySVGEls(svg) {
|
|
7288
7375
|
let els = svg.querySelectorAll('g, defs');
|
|
7289
7376
|
els.forEach(el => {
|
|
@@ -7295,6 +7382,8 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7295
7382
|
removeHidden = true,
|
|
7296
7383
|
|
|
7297
7384
|
stylesToAttributes = true,
|
|
7385
|
+
attributesToGroup = false,
|
|
7386
|
+
|
|
7298
7387
|
removePrologue = true,
|
|
7299
7388
|
removeIds = false,
|
|
7300
7389
|
removeClassNames = false,
|
|
@@ -7314,9 +7403,14 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7314
7403
|
|
|
7315
7404
|
mergePaths = false,
|
|
7316
7405
|
removeOffCanvas = true,
|
|
7406
|
+
|
|
7317
7407
|
cleanupSVGAtts = true,
|
|
7318
7408
|
removeNameSpaced = true,
|
|
7319
|
-
|
|
7409
|
+
|
|
7410
|
+
// meta
|
|
7411
|
+
allowMeta = false,
|
|
7412
|
+
allowDataAtts = true,
|
|
7413
|
+
allowAriaAtts = true,
|
|
7320
7414
|
|
|
7321
7415
|
shapeConvert = false,
|
|
7322
7416
|
convert_rects = false,
|
|
@@ -7331,6 +7425,8 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7331
7425
|
excludedEls = [],
|
|
7332
7426
|
} = {}) {
|
|
7333
7427
|
|
|
7428
|
+
if (attributesToGroup) stylesToAttributes = true;
|
|
7429
|
+
|
|
7334
7430
|
// replace namespaced refs
|
|
7335
7431
|
if (fixHref) svgMarkup = svgMarkup.replaceAll("xlink:href=", "href=");
|
|
7336
7432
|
|
|
@@ -7348,9 +7444,16 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7348
7444
|
normalizeTransforms,
|
|
7349
7445
|
removeDefaults: false,
|
|
7350
7446
|
cleanUpStrokes: false,
|
|
7447
|
+
allowMeta,
|
|
7448
|
+
allowDataAtts,
|
|
7449
|
+
allowAriaAtts,
|
|
7351
7450
|
autoRoundValues,
|
|
7451
|
+
removeIds,
|
|
7452
|
+
removeClassNames,
|
|
7352
7453
|
minifyRgbColors,
|
|
7353
7454
|
};
|
|
7455
|
+
|
|
7456
|
+
// root svg properties
|
|
7354
7457
|
let stylePropsSVG = parseStylesProperties(svg, propOptions);
|
|
7355
7458
|
|
|
7356
7459
|
// add svg font size for scaling relative
|
|
@@ -7362,11 +7465,9 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7362
7465
|
* be inherited by children
|
|
7363
7466
|
*/
|
|
7364
7467
|
let groups = svg.querySelectorAll('g');
|
|
7365
|
-
let groupProps = [];
|
|
7366
7468
|
|
|
7367
7469
|
groups.forEach(g => {
|
|
7368
7470
|
let stylePropsG = parseStylesProperties(g, propOptions);
|
|
7369
|
-
groupProps.push(stylePropsG);
|
|
7370
7471
|
let children = g.querySelectorAll(`${renderedEls.join(', ')}`);
|
|
7371
7472
|
|
|
7372
7473
|
// store parent styles to child property
|
|
@@ -7380,12 +7481,29 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7380
7481
|
|
|
7381
7482
|
if (cleanupSVGAtts) {
|
|
7382
7483
|
|
|
7383
|
-
let allowed = ['viewBox', 'xmlns', 'width', 'height'
|
|
7484
|
+
let allowed = new Set(['viewBox', 'xmlns', 'width', 'height']);
|
|
7485
|
+
|
|
7486
|
+
if (!removeIds) allowed.add('id');
|
|
7487
|
+
if (!removeClassNames) allowed.add('class');
|
|
7488
|
+
if (removeDimensions) {
|
|
7489
|
+
allowed.delete('width');
|
|
7490
|
+
allowed.delete('height');
|
|
7491
|
+
}
|
|
7492
|
+
|
|
7493
|
+
allowed = Array.from(allowed);
|
|
7384
7494
|
if (!stylesToAttributes) {
|
|
7385
7495
|
allowed.push('fill', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'font-size', 'font-family', 'font-style', 'style');
|
|
7386
7496
|
}
|
|
7387
7497
|
|
|
7388
|
-
removeExcludedAttribues(svg, allowed);
|
|
7498
|
+
removeExcludedAttribues(svg, { allowed, allowMeta, allowAriaAtts, allowDataAtts });
|
|
7499
|
+
}
|
|
7500
|
+
|
|
7501
|
+
// remove meta
|
|
7502
|
+
if (!allowMeta) {
|
|
7503
|
+
let metaEls = svg.querySelectorAll('meta, metadata, desc, title');
|
|
7504
|
+
metaEls.forEach(meta => {
|
|
7505
|
+
meta.remove();
|
|
7506
|
+
});
|
|
7389
7507
|
}
|
|
7390
7508
|
|
|
7391
7509
|
// add viewBox
|
|
@@ -7402,9 +7520,10 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7402
7520
|
if (removeOffCanvas) removeOffCanvasEls(svg, { x, y, width, height });
|
|
7403
7521
|
|
|
7404
7522
|
// always remove scripts
|
|
7405
|
-
let removeEls = ['metadata', 'script', ...excludedEls];
|
|
7406
7523
|
|
|
7407
|
-
|
|
7524
|
+
let removeEls = ['script', ...excludedEls];
|
|
7525
|
+
|
|
7526
|
+
removeSVGEls(svg, { remove: removeEls, removeNameSpaced });
|
|
7408
7527
|
|
|
7409
7528
|
// an array of all elements' properties
|
|
7410
7529
|
let svgElProps = [];
|
|
@@ -7430,6 +7549,7 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7430
7549
|
* to user units
|
|
7431
7550
|
*/
|
|
7432
7551
|
let styleProps = parseStylesProperties(el, propOptions);
|
|
7552
|
+
let stylePropsFiltered = {};
|
|
7433
7553
|
|
|
7434
7554
|
// get parent styles
|
|
7435
7555
|
let { parentStyleProps = [] } = el;
|
|
@@ -7455,27 +7575,25 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7455
7575
|
styleProps.transformArr = transFormInherited;
|
|
7456
7576
|
|
|
7457
7577
|
// merge with svg props
|
|
7578
|
+
|
|
7458
7579
|
styleProps = {
|
|
7459
7580
|
...stylePropsSVG,
|
|
7460
7581
|
...inheritedProps,
|
|
7461
7582
|
...styleProps
|
|
7462
7583
|
};
|
|
7463
7584
|
|
|
7585
|
+
// dont inherit class
|
|
7586
|
+
if (stylePropsSVG['class'] === styleProps['class']) {
|
|
7587
|
+
delete styleProps['class'];
|
|
7588
|
+
}
|
|
7589
|
+
|
|
7464
7590
|
// add combined transforms
|
|
7465
7591
|
addTransFormProps(styleProps, transFormInherited);
|
|
7466
7592
|
|
|
7467
7593
|
let { remove, matrix, transComponents } = styleProps;
|
|
7468
7594
|
|
|
7469
|
-
// mark attributes for removal
|
|
7470
|
-
if (removeClassNames) styleProps.remove.push('class');
|
|
7471
|
-
if (removeIds) styleProps.remove.push('id');
|
|
7472
|
-
if (removeDimensions) {
|
|
7473
|
-
styleProps.remove.push('width');
|
|
7474
|
-
styleProps.remove.push('height');
|
|
7475
|
-
}
|
|
7476
|
-
|
|
7477
7595
|
// styles to atts
|
|
7478
|
-
if (unGroup || convertTransforms || minifyRgbColors
|
|
7596
|
+
if (unGroup || convertTransforms || minifyRgbColors) stylesToAttributes = true;
|
|
7479
7597
|
|
|
7480
7598
|
if (stylesToAttributes) {
|
|
7481
7599
|
|
|
@@ -7498,7 +7616,6 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7498
7616
|
styleProps.cy[0] = [styleProps.cy[0] * scaleX + translateY];
|
|
7499
7617
|
|
|
7500
7618
|
if (styleProps.r) styleProps.r[0] = [styleProps.r[0] * scaleX];
|
|
7501
|
-
|
|
7502
7619
|
if (styleProps.rx) styleProps.rx[0] = [styleProps.rx[0] * scaleX];
|
|
7503
7620
|
if (styleProps.ry) styleProps.ry[0] = [styleProps.ry[0] * scaleX];
|
|
7504
7621
|
|
|
@@ -7520,6 +7637,12 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7520
7637
|
styleProps.height = [styleProps.height[0] * scaleX];
|
|
7521
7638
|
}
|
|
7522
7639
|
|
|
7640
|
+
// remove now obsolete transform properties
|
|
7641
|
+
delete styleProps.matrix;
|
|
7642
|
+
delete styleProps.transformArr;
|
|
7643
|
+
delete styleProps.transComponents;
|
|
7644
|
+
|
|
7645
|
+
// mark transform attribute for removal
|
|
7523
7646
|
remove.push('transform');
|
|
7524
7647
|
|
|
7525
7648
|
// scale props like stroke width or dash-array
|
|
@@ -7535,17 +7658,16 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7535
7658
|
* apply consolidated
|
|
7536
7659
|
* element attributes
|
|
7537
7660
|
*/
|
|
7538
|
-
|
|
7539
|
-
|
|
7540
|
-
{ removeDefaults: true, cleanUpStrokes });
|
|
7661
|
+
stylePropsFiltered = filterSvgElProps(name, styleProps,
|
|
7662
|
+
{ removeDefaults: true, cleanUpStrokes, allowMeta, allowAriaAtts, allowDataAtts, removeIds });
|
|
7541
7663
|
|
|
7542
7664
|
remove = [...remove, ...stylePropsFiltered.remove];
|
|
7543
7665
|
|
|
7544
7666
|
for (let prop in stylePropsFiltered.propsFiltered) {
|
|
7545
7667
|
let values = styleProps[prop];
|
|
7546
|
-
|
|
7547
7668
|
let val = values.length ? values.join(' ') : values[0];
|
|
7548
7669
|
el.setAttribute(prop, val);
|
|
7670
|
+
|
|
7549
7671
|
}
|
|
7550
7672
|
|
|
7551
7673
|
// remove obsolete attributes
|
|
@@ -7573,9 +7695,19 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7573
7695
|
});
|
|
7574
7696
|
} else {
|
|
7575
7697
|
groups.forEach((g, i) => {
|
|
7576
|
-
|
|
7698
|
+
|
|
7699
|
+
let atts = Object.keys(getElementAtts(g));
|
|
7700
|
+
|
|
7577
7701
|
atts.forEach(att => {
|
|
7578
|
-
|
|
7702
|
+
|
|
7703
|
+
let isData = !allowDataAtts && att.startsWith('data-');
|
|
7704
|
+
let isAria = !allowAriaAtts && att.startsWith('aria-');
|
|
7705
|
+
|
|
7706
|
+
remove.push('transform', 'style');
|
|
7707
|
+
|
|
7708
|
+
if (remove.includes(att) || isData || isAria) {
|
|
7709
|
+
g.removeAttribute(att);
|
|
7710
|
+
}
|
|
7579
7711
|
});
|
|
7580
7712
|
});
|
|
7581
7713
|
|
|
@@ -7619,7 +7751,7 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7619
7751
|
el.replaceWith(path);
|
|
7620
7752
|
|
|
7621
7753
|
name = 'path';
|
|
7622
|
-
el = path;
|
|
7754
|
+
el = path; // required for node
|
|
7623
7755
|
|
|
7624
7756
|
}
|
|
7625
7757
|
|
|
@@ -7630,14 +7762,217 @@ function cleanUpSVG(svgMarkup, {
|
|
|
7630
7762
|
let paths = svg.querySelectorAll('path');
|
|
7631
7763
|
paths.forEach(path => {
|
|
7632
7764
|
let shape = pathElToShape(path, { convert_rects, convert_ellipses, convert_poly, convert_lines });
|
|
7633
|
-
|
|
7765
|
+
|
|
7634
7766
|
path = shape;
|
|
7635
7767
|
});
|
|
7636
7768
|
|
|
7637
7769
|
}
|
|
7638
7770
|
|
|
7771
|
+
/**
|
|
7772
|
+
* combine styles
|
|
7773
|
+
* store in node property
|
|
7774
|
+
*/
|
|
7775
|
+
|
|
7776
|
+
if (mergePaths || attributesToGroup) {
|
|
7777
|
+
|
|
7778
|
+
let options = { allowMeta, allowAriaAtts, removeIds, removeClassNames, allowDataAtts };
|
|
7779
|
+
|
|
7780
|
+
/**
|
|
7781
|
+
* exclude properties for
|
|
7782
|
+
* adjacent path merging
|
|
7783
|
+
* e.g ignore classnames or ids
|
|
7784
|
+
*/
|
|
7785
|
+
if(mergePaths){
|
|
7786
|
+
options.removeIds = true;
|
|
7787
|
+
options.removeClassNames = true;
|
|
7788
|
+
options.allowAriaAtts = false;
|
|
7789
|
+
options.allowMeta = false;
|
|
7790
|
+
}
|
|
7791
|
+
|
|
7792
|
+
stylePropsFiltered = filterSvgElProps(name, styleProps, options).propsFiltered;
|
|
7793
|
+
|
|
7794
|
+
for (let prop in stylePropsFiltered) {
|
|
7795
|
+
|
|
7796
|
+
if (geometryProps.includes(prop)) continue;
|
|
7797
|
+
|
|
7798
|
+
let values = stylePropsFiltered[prop];
|
|
7799
|
+
let val = values.length ? values.join(' ') : values[0];
|
|
7800
|
+
|
|
7801
|
+
let propShort = toShortStr(prop);
|
|
7802
|
+
let valShort = toShortStr(val);
|
|
7803
|
+
let propStr = `${propShort}-${valShort}`;
|
|
7804
|
+
|
|
7805
|
+
// store in node property
|
|
7806
|
+
if (!el.styleSet) el.styleSet = new Set();
|
|
7807
|
+
el.styleSet.add(propStr);
|
|
7808
|
+
}
|
|
7809
|
+
|
|
7810
|
+
}
|
|
7811
|
+
|
|
7639
7812
|
}//endof element loop
|
|
7640
7813
|
|
|
7814
|
+
/**
|
|
7815
|
+
* merge paths with same styles
|
|
7816
|
+
*/
|
|
7817
|
+
if (mergePaths) {
|
|
7818
|
+
let paths = svg.querySelectorAll('path');
|
|
7819
|
+
let len = paths.length;
|
|
7820
|
+
|
|
7821
|
+
if (len) {
|
|
7822
|
+
let path0 = paths[0];
|
|
7823
|
+
let d0 = path0.getAttribute('d');
|
|
7824
|
+
let stylePrev = path0.styleSet !== undefined ? [...path0.styleSet].join('_') : '';
|
|
7825
|
+
|
|
7826
|
+
for (let i = 1; i < len; i++) {
|
|
7827
|
+
let path = paths[i];
|
|
7828
|
+
let style = path.styleSet !== undefined ? [...path.styleSet].join('_') : '';
|
|
7829
|
+
let isSibling = path.previousElementSibling === path0;
|
|
7830
|
+
let d = path.getAttribute('d');
|
|
7831
|
+
let isAbs = d.startsWith('M');
|
|
7832
|
+
|
|
7833
|
+
if (isSibling && style === stylePrev) {
|
|
7834
|
+
let dAbs = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ');
|
|
7835
|
+
|
|
7836
|
+
d0 += dAbs;
|
|
7837
|
+
path0.setAttribute('d', d0);
|
|
7838
|
+
path.remove();
|
|
7839
|
+
|
|
7840
|
+
} else {
|
|
7841
|
+
path0 = path;
|
|
7842
|
+
d0 = isAbs ? d : parsePathDataString(d).pathData.map(com => `${com.type} ${com.values.join(' ')}`).join(' ');
|
|
7843
|
+
}
|
|
7844
|
+
|
|
7845
|
+
// update style
|
|
7846
|
+
stylePrev = style;
|
|
7847
|
+
}
|
|
7848
|
+
}
|
|
7849
|
+
|
|
7850
|
+
/**
|
|
7851
|
+
* shared styles to group
|
|
7852
|
+
*/
|
|
7853
|
+
|
|
7854
|
+
if (attributesToGroup) {
|
|
7855
|
+
let els = svg.querySelectorAll(geometryEls.join(', '));
|
|
7856
|
+
let len = els.length;
|
|
7857
|
+
|
|
7858
|
+
let el0 = els[0] || null;
|
|
7859
|
+
let stylePrev = el0.styleSet !== undefined ? [...el0.styleSet].join('_') : '';
|
|
7860
|
+
|
|
7861
|
+
// all props
|
|
7862
|
+
let allProps = {};
|
|
7863
|
+
|
|
7864
|
+
// find attributes shared by all
|
|
7865
|
+
let globalAtts = [];
|
|
7866
|
+
|
|
7867
|
+
if (len) {
|
|
7868
|
+
|
|
7869
|
+
let groups = [[el0]];
|
|
7870
|
+
let idx = 0;
|
|
7871
|
+
let elPrev = el0;
|
|
7872
|
+
|
|
7873
|
+
for (let i = 0; i < len; i++) {
|
|
7874
|
+
let el = els[i];
|
|
7875
|
+
let atts = getElementAtts(el);
|
|
7876
|
+
for (let att in atts) {
|
|
7877
|
+
let att_str = `${att}_${atts[att]}`;
|
|
7878
|
+
|
|
7879
|
+
if (!allProps[att_str]) {
|
|
7880
|
+
allProps[att_str] = [];
|
|
7881
|
+
}
|
|
7882
|
+
allProps[att_str].push(el);
|
|
7883
|
+
//
|
|
7884
|
+
if (allProps[att_str].length === len) {
|
|
7885
|
+
globalAtts.push(att);
|
|
7886
|
+
}
|
|
7887
|
+
}
|
|
7888
|
+
}
|
|
7889
|
+
|
|
7890
|
+
// apply global to parent SVG
|
|
7891
|
+
if (globalAtts.length) {
|
|
7892
|
+
let atts0 = getElementAtts(el0);
|
|
7893
|
+
for (let att in atts0) {
|
|
7894
|
+
// &&
|
|
7895
|
+
if (globalAtts.includes(att) && att !== 'transform') {
|
|
7896
|
+
svg.setAttribute(att, atts0[att]);
|
|
7897
|
+
}
|
|
7898
|
+
}
|
|
7899
|
+
}
|
|
7900
|
+
|
|
7901
|
+
// detect groups
|
|
7902
|
+
for (let i = 1; i < len; i++) {
|
|
7903
|
+
let el = els[i];
|
|
7904
|
+
let styleArr = el.styleSet !== undefined ? [...el.styleSet] : [];
|
|
7905
|
+
let style = styleArr.length ? styleArr.join('_') : '';
|
|
7906
|
+
|
|
7907
|
+
// same style add to group
|
|
7908
|
+
if (style === stylePrev && elPrev.nextElementSibling === el) {
|
|
7909
|
+
groups[idx].push(el);
|
|
7910
|
+
}
|
|
7911
|
+
// start new group
|
|
7912
|
+
else {
|
|
7913
|
+
groups.push([el]);
|
|
7914
|
+
idx++;
|
|
7915
|
+
}
|
|
7916
|
+
// update style
|
|
7917
|
+
stylePrev = style;
|
|
7918
|
+
elPrev = el;
|
|
7919
|
+
|
|
7920
|
+
}// endof el loop
|
|
7921
|
+
|
|
7922
|
+
// create groups
|
|
7923
|
+
for (let i = 0; i < groups.length; i++) {
|
|
7924
|
+
let children = groups[i];
|
|
7925
|
+
let child0 = children[0];
|
|
7926
|
+
let atts = getElementAtts(child0);
|
|
7927
|
+
let groupEl = child0.parentNode.closest('g');
|
|
7928
|
+
|
|
7929
|
+
if (children.length === 1) {
|
|
7930
|
+
if (globalAtts.length) {
|
|
7931
|
+
let globalTransform = globalAtts.includes('transform');
|
|
7932
|
+
if (globalTransform) {
|
|
7933
|
+
|
|
7934
|
+
groupEl.setAttribute('transform', atts['transform']);
|
|
7935
|
+
}
|
|
7936
|
+
|
|
7937
|
+
for (let att in atts) {
|
|
7938
|
+
|
|
7939
|
+
if (globalAtts.includes(att)) {
|
|
7940
|
+
child0.removeAttribute(att);
|
|
7941
|
+
}
|
|
7942
|
+
}
|
|
7943
|
+
}
|
|
7944
|
+
continue
|
|
7945
|
+
}
|
|
7946
|
+
|
|
7947
|
+
// create new group
|
|
7948
|
+
if (!groupEl) {
|
|
7949
|
+
|
|
7950
|
+
groupEl = document.createElementNS(svgNs, 'g');
|
|
7951
|
+
child0.parentNode.insertBefore(groupEl, child0);
|
|
7952
|
+
groupEl.append(...children);
|
|
7953
|
+
}
|
|
7954
|
+
|
|
7955
|
+
// move attributes to group
|
|
7956
|
+
for (let att in atts) {
|
|
7957
|
+
let val = atts[att];
|
|
7958
|
+
|
|
7959
|
+
if (!geometryProps.includes(att)) {
|
|
7960
|
+
if (!globalAtts.includes(att) || att === 'transform') {
|
|
7961
|
+
groupEl.setAttribute(att, val);
|
|
7962
|
+
}
|
|
7963
|
+
children.forEach(child => {
|
|
7964
|
+
child.removeAttribute(att);
|
|
7965
|
+
});
|
|
7966
|
+
}
|
|
7967
|
+
}
|
|
7968
|
+
|
|
7969
|
+
} // endof groups
|
|
7970
|
+
|
|
7971
|
+
}
|
|
7972
|
+
}
|
|
7973
|
+
|
|
7974
|
+
}
|
|
7975
|
+
|
|
7641
7976
|
// remove futile clip-paths
|
|
7642
7977
|
if (cleanupClip) removeFutileClipPaths(svg, { x, y, width, height });
|
|
7643
7978
|
|
|
@@ -7783,21 +8118,41 @@ function removeSVGEls(svg, {
|
|
|
7783
8118
|
remove = ['metadata', 'script'],
|
|
7784
8119
|
removeNameSpaced = true,
|
|
7785
8120
|
} = {}) {
|
|
8121
|
+
|
|
7786
8122
|
let els = svg.querySelectorAll('*');
|
|
8123
|
+
|
|
8124
|
+
let allowMeta = !remove.includes('metadata');
|
|
8125
|
+
|
|
7787
8126
|
els.forEach(el => {
|
|
7788
8127
|
let nodeName = el.nodeName;
|
|
7789
|
-
|
|
7790
|
-
|
|
8128
|
+
let isMeta = allowMeta && el.closest('metadata');
|
|
8129
|
+
if (
|
|
8130
|
+
!isMeta &&
|
|
8131
|
+
((removeNameSpaced && nodeName.includes(':')) ||
|
|
8132
|
+
remove.includes(nodeName))
|
|
7791
8133
|
) {
|
|
7792
8134
|
el.remove();
|
|
7793
8135
|
}
|
|
7794
8136
|
});
|
|
7795
8137
|
}
|
|
7796
8138
|
|
|
7797
|
-
function removeExcludedAttribues(el,
|
|
8139
|
+
function removeExcludedAttribues(el, {
|
|
8140
|
+
allowed = ['viewBox', 'xmlns', 'width', 'height', 'id', 'class'],
|
|
8141
|
+
allowAriaAtts = true,
|
|
8142
|
+
allowDataAtts = true,
|
|
8143
|
+
allowMeta = false
|
|
8144
|
+
} = {}) {
|
|
7798
8145
|
let atts = [...el.attributes].map((att) => att.name);
|
|
7799
8146
|
atts.forEach((att) => {
|
|
7800
|
-
|
|
8147
|
+
|
|
8148
|
+
let isMeta = allowMeta && (att === 'title');
|
|
8149
|
+
let isAria = allowAriaAtts && att.startsWith('aria-');
|
|
8150
|
+
let isData = allowDataAtts && att.startsWith('data-');
|
|
8151
|
+
|
|
8152
|
+
if (
|
|
8153
|
+
!allowed.includes(att) &&
|
|
8154
|
+
!isAria && !isData && !isMeta
|
|
8155
|
+
) {
|
|
7801
8156
|
el.removeAttribute(att);
|
|
7802
8157
|
}
|
|
7803
8158
|
});
|
|
@@ -9840,6 +10195,7 @@ function svgPathSimplify(input = '', {
|
|
|
9840
10195
|
|
|
9841
10196
|
toAbsolute = false,
|
|
9842
10197
|
toRelative = true,
|
|
10198
|
+
toMixed = false,
|
|
9843
10199
|
toShorthands = true,
|
|
9844
10200
|
toLonghands = false,
|
|
9845
10201
|
|
|
@@ -9905,7 +10261,7 @@ function svgPathSimplify(input = '', {
|
|
|
9905
10261
|
tolerance = 1,
|
|
9906
10262
|
reversePath = false,
|
|
9907
10263
|
|
|
9908
|
-
minifyRgbColors =
|
|
10264
|
+
minifyRgbColors = true,
|
|
9909
10265
|
removePrologue = true,
|
|
9910
10266
|
removeHidden = true,
|
|
9911
10267
|
removeUnused = true,
|
|
@@ -9918,6 +10274,11 @@ function svgPathSimplify(input = '', {
|
|
|
9918
10274
|
legacyHref = false,
|
|
9919
10275
|
removeNameSpaced = true,
|
|
9920
10276
|
|
|
10277
|
+
allowMeta = false,
|
|
10278
|
+
allowDataAtts = true,
|
|
10279
|
+
allowAriaAtts = true,
|
|
10280
|
+
|
|
10281
|
+
attributesToGroup = false,
|
|
9921
10282
|
removeOffCanvas = false,
|
|
9922
10283
|
unGroup = false,
|
|
9923
10284
|
mergePaths = false,
|
|
@@ -10018,7 +10379,7 @@ function svgPathSimplify(input = '', {
|
|
|
10018
10379
|
|
|
10019
10380
|
// convert all shapes to paths
|
|
10020
10381
|
if (shapesToPaths) {
|
|
10021
|
-
shapeConvert =
|
|
10382
|
+
shapeConvert = 'toPaths';
|
|
10022
10383
|
convert_rects = true;
|
|
10023
10384
|
convert_ellipses = true;
|
|
10024
10385
|
convert_poly = true;
|
|
@@ -10027,7 +10388,8 @@ function svgPathSimplify(input = '', {
|
|
|
10027
10388
|
|
|
10028
10389
|
let svgPropObject = cleanUpSVG(input, {
|
|
10029
10390
|
removeIds, removeClassNames, removeDimensions, cleanupSVGAtts, cleanUpStrokes, removeHidden, removeUnused, removeNameSpaced, stylesToAttributes, removePrologue, fixHref, mergePaths, convertTransforms, legacyHref, cleanupDefs, cleanupClip, addViewBox, removeOffCanvas, addDimensions,
|
|
10030
|
-
shapeConvert, convert_rects, convert_ellipses, convert_poly, convert_lines, minifyRgbColors, unGroup, convertTransforms
|
|
10391
|
+
shapeConvert, convert_rects, convert_ellipses, convert_poly, convert_lines, minifyRgbColors, unGroup, convertTransforms,
|
|
10392
|
+
allowMeta, allowDataAtts, allowAriaAtts, allowMeta, attributesToGroup
|
|
10031
10393
|
}
|
|
10032
10394
|
);
|
|
10033
10395
|
svg = svgPropObject.svg;
|
|
@@ -10052,6 +10414,7 @@ function svgPathSimplify(input = '', {
|
|
|
10052
10414
|
// SVG optimization options
|
|
10053
10415
|
let pathOptions = {
|
|
10054
10416
|
toRelative,
|
|
10417
|
+
toMixed,
|
|
10055
10418
|
toAbsolute,
|
|
10056
10419
|
toLonghands,
|
|
10057
10420
|
toShorthands,
|