问题
I have inline svg with is loaded dynamically from server. I want that svg to be manupulated or modifed using inline css. I have searched for converting that modified svg into png or base64 image. After long search i have decided to stick with Canvg.
Now the problem is that it renders the inline style attributes like background and border radius.
This is my svg.
<svg height="550" width="550" viewBox="0 0 512 512" id="svg">
<path d="m309 139c0-111-32-139-53-139-21 0-53 28-53 139l-173 122c-2 1-4 4-4 7l0 46c0 6 5 10 11 9l166-37c6 49 16 93 23 139l-63 49c-2 1-4 4-4 6l0 23c0 7 6 11 12 8l85-38 85 38c6 3 12-1 12-8l0-23c0-2-2-5-4-6l-63-49c7-46 17-90 23-139l166 37c6 1 11-3 11-9l0-46c0-3-2-6-4-7z m-53-88c-11 0-21 3-30 7 3-13 15-22 30-22 15 0 27 9 30 22-9-4-19-7-30-7z"></path>
</svg>
Which looks like this:
Remember the path is dynamically loaded from server. So cannot modify it.
Now i want to manupulate it something like this.
<svg style="background: grey none repeat scroll 0% 0%; fill: white; padding: 70px; border-radius: 98px;" height="550" width="550" viewBox="0 0 512 512" id="svg">
<path d="m309 139c0-111-32-139-53-139-21 0-53 28-53 139l-173 122c-2 1-4 4-4 7l0 46c0 6 5 10 11 9l166-37c6 49 16 93 23 139l-63 49c-2 1-4 4-4 6l0 23c0 7 6 11 12 8l85-38 85 38c6 3 12-1 12-8l0-23c0-2-2-5-4-6l-63-49c7-46 17-90 23-139l166 37c6 1 11-3 11-9l0-46c0-3-2-6-4-7z m-53-88c-11 0-21 3-30 7 3-13 15-22 30-22 15 0 27 9 30 22-9-4-19-7-30-7z"></path> </svg>
Which would look like this:
But after rendering using canvg script. It renders as raw file. It just includes the fill color. Nothing else.
Is there any other way to do that. Using canvas or svg elements.
Please Help!!! Thanks in advance
回答1:
Most svg to canvas libraries don't support external resources (xlink attributes, images, and CSS).
The only way I've found to do it is to append those external resources into the svg node, then use the canvas.toDataURL()
method to draw your svg onto the canvas.
I am writing a small script that do handle this and here is a dump of the CSS parser I made which will loop through all document's stylesheets and only append the ones that do have an influence on inner elements.
var parseStyles = function() {
var styleSheets = [],
i;
// get the stylesheets of the document (ownerDocument in case svg is in <iframe> or <object>)
var docStyles = svg.ownerDocument.styleSheets;
// transform the live StyleSheetList to an array to avoid endless loop
for (i = 0; i < docStyles.length; i++) {
styleSheets.push(docStyles[i]);
}
if (styleSheets.length) {
// getDef() will return an svg <defs> element if already into the node, or will create it otherwise
getDef();
svg.matches = svg.matches || svg.webkitMatchesSelector || svg.mozMatchesSelector || svg.msMatchesSelector || svg.oMatchesSelector;
}
// iterate through all document's stylesheets
for (i = 0; i < styleSheets.length; i++) {
// create a new style element
var style = document.createElement('style');
// some stylesheets can't be accessed and will throw a security error
try {
var rules = styleSheets[i].cssRules,
l = rules.length;
// iterate through each cssRules of this stylesheet
for (var j = 0; j < l; j++) {
// get the selector of this cssRules
var selector = rules[j].selectorText;
// is it our svg node or one of its children ?
if ((svg.matches && svg.matches(selector)) || svg.querySelector(selector)) {
// append it to our <style> node
style.innerHTML += rules[j].cssText + '\n';
}
}
// if we got some rules
if (style.innerHTML) {
// append the style node to the clone's defs
defs.appendChild(style);
}
} catch (e) {
console.warn('unable to get some cssRules : ', e);
}
}
// small hack to avoid border and margins being applied inside the <img>
var s = clone.style;
s.border = s.padding = s.margin = 0;
s.transform = 'initial';
};
var svg = document.querySelector('svg');
var doSomethingWith = function(canvas) {
document.body.appendChild(canvas)
};
var parseStyles = function() {
var styleSheets = [],
i;
// get the stylesheets of the document (ownerDocument in case svg is in <iframe> or <object>)
var docStyles = svg.ownerDocument.styleSheets;
// transform the live StyleSheetList to an array to avoid endless loop
for (i = 0; i < docStyles.length; i++) {
styleSheets.push(docStyles[i]);
}
if (styleSheets.length) {
// getDef() will return an svg <defs> element if already into the node, or will create it otherwise
getDef();
svg.matches = svg.matches || svg.webkitMatchesSelector || svg.mozMatchesSelector || svg.msMatchesSelector || svg.oMatchesSelector;
}
// iterate through all document's stylesheets
for (i = 0; i < styleSheets.length; i++) {
// create a new style element
var style = document.createElement('style');
// some stylesheets can't be accessed and will throw a security error
try {
var rules = styleSheets[i].cssRules,
l = rules.length;
// iterate through each cssRules of this stylesheet
for (var j = 0; j < l; j++) {
// get the selector of this cssRules
var selector = rules[j].selectorText;
// is it our svg node or one of its children ?
if ((svg.matches && svg.matches(selector)) || svg.querySelector(selector)) {
// append it to our <style> node
style.innerHTML += rules[j].cssText + '\n';
}
}
// if we got some rules
if (style.innerHTML) {
// append the style node to the clone's defs
defs.appendChild(style);
}
} catch (e) {
console.warn('unable to get some cssRules : ', e);
}
}
// small hack to avoid border and margins being applied inside the <img>
var s = svg.style;
s.border = s.padding = s.margin = 0;
s.transform = 'initial';
exportDoc();
};
var defs;
var getDef = function() {
// Do we have a `<defs>` element already ?
defs = svg.querySelector('defs') || document.createElementNS('http://www.w3.org/2000/svg', 'defs');
if (!defs.parentNode) {
svg.insertBefore(defs, svg.firstElementChild);
}
};
var exportDoc = function() {
// check if our svgNode has width and height properties set to absolute values
// otherwise, canvas won't be able to draw it
var bbox = svg.getBoundingClientRect();
if (svg.width.baseVal.unitType !== 1) svg.setAttribute('width', bbox.width);
if (svg.height.baseVal.unitType !== 1) svg.setAttribute('height', bbox.height);
// serialize our node
var svgData = (new XMLSerializer()).serializeToString(svg);
// remember to encode special chars
var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);
var svgImg = new Image();
svgImg.onload = function() {
var canvas = document.createElement('canvas');
// IE11 doesn't set a width on svg images...
canvas.width = this.width || bbox.width;
canvas.height = this.height || bbox.height;
canvas.getContext('2d').drawImage(svgImg, 0, 0, canvas.width, canvas.height);
doSomethingWith(canvas)
};
svgImg.src = svgURL;
};
parseStyles();
rect {
fill: red;
padding: 25em;
border: 25px solid yellow;
}
canvas {
border: 1px solid green;
}
svg{
background-color: skyblue;
}
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect x="0" y="0" width="100" height="100" />
</svg>
回答2:
You can use Javascript and the DOM to modify any element in the current page; regardless wether it's server generated a file or anything else. http://www.i-programmer.info/programming/graphics-and-imaging/3254-svg-javascript-and-the-dom.html
来源:https://stackoverflow.com/questions/34121022/canvg-not-supporting-css