JMa*_*Man 2 html javascript css svg save
在我的HTML上我有一个SVG元素.它使用d3js渲染,并在CSS中应用了样式.
当我在浏览器中右键单击时,我可以选择"保存图像".此操作会保存使用所有css样式渲染的图像.
我一直在寻找一种保存文件的好方法
但是当我将文件送到磁盘时,我的css中的额外样式不会应用于保存的图像.
问题:如何在应用了css的浏览器中保存我的SVG.
CSS解析不是一件容易的事,CSS规则很复杂......
我试着为我的SVG2Bitmap小脚本编写一些东西,但它还远未完美......
基本上,它解析文档中的所有样式表,并检查svg的任何节点是否与规则匹配(感谢querySelector和Element.matches()方法).
问题是,一旦附加到svg doc中,规则可能不再匹配(例如,body>svg>rect将失败).我仍然没有找到一种优雅的方式来处理它,如果有人有,请告诉我.
我遇到的另一个问题是无效规则会使之前提到的方法抛出错误.这不应该是太关注,但一些浏览器(Chrome浏览器不告诉它的名字)接受像一些哈克规则,[xlink\\:href]但它保存在cssRules为[xlink\:href]将失败,从而引发错误...
然而,由于该XMLSerializer对象,"保存为文件"部分更容易,这将使浏览器创建一个独立版本的解析,只需要所需的一切.
要制作100%有效的svg文件,您还需要在文档顶部设置Doctype.
所以让我们跳进代码:
var exportSVG = function(svg) {
// first create a clone of our svg node so we don't mess the original one
var clone = svg.cloneNode(true);
// parse the styles
parseStyles(clone);
// create a doctype
var svgDocType = document.implementation.createDocumentType('svg', "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd");
// a fresh svg document
var svgDoc = document.implementation.createDocument('http://www.w3.org/2000/svg', 'svg', svgDocType);
// replace the documentElement with our clone
svgDoc.replaceChild(clone, svgDoc.documentElement);
// get the data
var svgData = (new XMLSerializer()).serializeToString(svgDoc);
// now you've got your svg data, the following will depend on how you want to download it
// e.g yo could make a Blob of it for FileSaver.js
/*
var blob = new Blob([svgData.replace(/></g, '>\n\r<')]);
saveAs(blob, 'myAwesomeSVG.svg');
*/
// here I'll just make a simple a with download attribute
var a = document.createElement('a');
a.href = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData.replace(/></g, '>\n\r<'));
a.download = 'myAwesomeSVG.svg';
a.innerHTML = 'download the svg file';
document.body.appendChild(a);
};
var parseStyles = function(svg) {
var styleSheets = [];
var 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) {
return;
}
var defs = svg.querySelector('defs') || document.createElementNS('http://www.w3.org/2000/svg', 'defs');
if (!defs.parentNode) {
svg.insertBefore(defs, svg.firstElementChild);
}
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++) {
var currentStyle = styleSheets[i]
var rules;
try {
rules = currentStyle.cssRules;
} catch (e) {
continue;
}
// create a new style element
var style = document.createElement('style');
// some stylesheets can't be accessed and will throw a security error
var l = rules && 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;
// probably an external stylesheet we can't access
if (!selector) {
continue;
}
// is it our svg node or one of its children ?
if ((svg.matches && svg.matches(selector)) || svg.querySelector(selector)) {
var cssText = rules[j].cssText;
// append it to our <style> node
style.innerHTML += cssText + '\n';
}
}
// if we got some rules
if (style.innerHTML) {
// append the style node to the clone's defs
defs.appendChild(style);
}
}
};
exportSVG(document.getElementById('mySVG'));Run Code Online (Sandbox Code Playgroud)
svg >rect {
fill: yellow
}
/* this will fail, it could work with a check for document.querySelector instead of svg.querySelector, but that would just be a kill for performances with a lot of cssRules..., and would need to set the elements' style attribute instead of using a <style> tag */
body > svg >rect {
stroke: red
}Run Code Online (Sandbox Code Playgroud)
<svg width="120" height="120" viewBox="0 0 120 120" id="mySVG">
<rect x="10" y="10" width="100" height="100" />
</svg>Run Code Online (Sandbox Code Playgroud)
Ps:这个片段的下载部分在FF中不起作用,你可以试试这个小提琴.
| 归档时间: |
|
| 查看次数: |
5858 次 |
| 最近记录: |