使用D3.js(IE,Safari和Chrome)创建SVG后,如何保存/导出SVG文件?


69

我目前有一个使用D3的网站,我希望用户可以选择将SVG保存为SVG文件。我正在使用crowbar.js来执行此操作,但它仅适用于chrome。Safari没有任何反应,IE拒绝了click()crowbar.js中用于下载文件的方法的访问。

var e = document.createElement('script'); 

if (window.location.protocol === 'https:') { 
    e.setAttribute('src', 'https://raw.github.com/NYTimes/svg-crowbar/gh-pages/svg-crowbar.js'); 
} else { 
    e.setAttribute('src', 'http://nytimes.github.com/svg-crowbar/svg-crowbar.js'); 
}

e.setAttribute('class', 'svg-crowbar'); 
document.body.appendChild(e);

如何在我的网站上以safari,IE和chrome下载基于SVG元素的SVG文件?

Answers:


65

共有5个步骤。我经常使用这种方法来输出内嵌svg。

  1. 获取内联svg元素以输出。
  2. 通过XMLSerializer获取svg源。
  3. 添加svg和xlink的名称空间。
  4. 通过encodeURIComponent方法构造svg的URL数据方案。
  5. 将此URL设置为某些“ a”元素的href属性,然后右键单击此链接以下载svg文件。

//get svg element.
var svg = document.getElementById("svg");

//get svg source.
var serializer = new XMLSerializer();
var source = serializer.serializeToString(svg);

//add name spaces.
if(!source.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)){
    source = source.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
if(!source.match(/^<svg[^>]+"http\:\/\/www\.w3\.org\/1999\/xlink"/)){
    source = source.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
}

//add xml declaration
source = '<?xml version="1.0" standalone="no"?>\r\n' + source;

//convert svg source to URI data scheme.
var url = "data:image/svg+xml;charset=utf-8,"+encodeURIComponent(source);

//set url value to a element's href attribute.
document.getElementById("link").href = url;
//you can download svg file by right click menu.

1
谢谢您的回答!这为我下载了一个svg,尽管所有内容都变黑了,而且颜色非常奇怪。为什么是这样?您可以在我的网站上看到我的意思,我已经应用了建议的代码:servers.binf.ku.dk/hemaexplorerbeta-只需单击“提交”,然后单击“导出图”。非常感谢您
Vanquiza 2014年

2
这个例子很简单。如果您通过链接元素在外部CSS文件中使用CSS样式,则SVG和样式表的链接已损坏。因此,可以通过将样式数据附加到嵌入式svg来解决此问题。
defghi1977

1
“因此,将样式数据附加到嵌入式svg可以解决此问题。” 你能用另一种方式向我解释吗?我不太明白
Vanquiza 2014年

5
请参阅w3.org/TR/SVG11/styling.html#ReferencingExternalStyleSheets,因此,添加<?xml-stylesheet href =“ xxx.css” type =“ text / css”?>并进行转换,但是在这种情况下,svg文件不会是独立的。
defghi1977

7
注意:这在Chrome或Firefox中不再起作用,因为当它们在顶层使用时,它们现在都阻止了SVG的数据URI。
分心

62

我知道这个问题已经得到解答,并且该答案在大多数情况下都有效。但是我发现,如果svg图像过大(大约1MB),则无法在Chrome(而不是Firefox)上运行。如果您重新使用Blob构造方法(如此此处所述),它将起作用。唯一的区别是类型参数。在我的代码中,我希望按下一个按钮即可为用户下载svg,我完成了以下操作:

var svgData = $("#figureSvg")[0].outerHTML;
var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
var svgUrl = URL.createObjectURL(svgBlob);
var downloadLink = document.createElement("a");
downloadLink.href = svgUrl;
downloadLink.download = "newesttree.svg";
document.body.appendChild(downloadLink);
downloadLink.click();
document.body.removeChild(downloadLink);

2019年10月编辑: 注释表明,即使不附加此代码,也不会downloadLinkdocument.body之后将其删除,此代码将起作用click()。我相信该工具以前可以在Firefox上运行,但是到目前为止,它不再可用(Firefox要求您先添加然后删除downloadLink)。无论哪种方式,该代码均可在Chrome上运行。


1
这在Chrome中非常有效!我想给这个简单答案+100!
kashiraja

3
像它看起来工作没有追加和删除downloadLinkdocument.body
piotr_cz

1
.outerHTML在Internet Explorer中不起作用。但是您可以将XMLSerializer()as用作defghi1977。其他所有内容保持不变。
罗兰

XMLSerializer()的好选择!
V. Rubinetti '18

效果最好!很好的答案和易于使用的代码段。
凯Angevare

31

结合Dave和defghi1977的答案。这是一个可重用的函数:

function saveSvg(svgEl, name) {
    svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    var svgData = svgEl.outerHTML;
    var preface = '<?xml version="1.0" standalone="no"?>\r\n';
    var svgBlob = new Blob([preface, svgData], {type:"image/svg+xml;charset=utf-8"});
    var svgUrl = URL.createObjectURL(svgBlob);
    var downloadLink = document.createElement("a");
    downloadLink.href = svgUrl;
    downloadLink.download = name;
    document.body.appendChild(downloadLink);
    downloadLink.click();
    document.body.removeChild(downloadLink);
}

调用示例:

saveSvg(svg, 'test.svg')

1
svgEl.outerHTML在IE和Edge中将无法使用。他们不支持outerHTMLSVG元素。 来源
Dominus.Vobiscum

我想将SVG静默保存在服务器上的文件夹中,并且我不想触发用户如何完成下载,请协助我。谢谢!
Rehan

2

我在这里尝试了所有解决方案,但对我没有任何帮助。我的图片总是比我的d3.js画布小。

我必须设置画布widthheight然后在clearRect上进行画布context以使其起作用。这是我的工作版本

导出功能:

var svgHtml = document.getElementById("d3-canvas"),
    svgData = new XMLSerializer().serializeToString(svgHtml),
    svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"}),
    bounding = svgHtml.getBoundingClientRect(),
    width = bounding.width * 2,
    height = bounding.height * 2,
    canvas = document.createElement("canvas"),
    context = canvas.getContext("2d"),
    exportFileName = 'd3-graph-image.png';

//Set the canvas width and height before loading the new Image
canvas.width = width;
canvas.height = height;

var image = new Image();
image.onload = function() {
    //Clear the context
    context.clearRect(0, 0, width, height);
    context.drawImage(image, 0, 0, width, height);

    //Create blob and save if with FileSaver.js
    canvas.toBlob(function(blob) {
        saveAs(blob, exportFileName);
    });     
};
var svgUrl = URL.createObjectURL(svgBlob);
image.src = svgUrl;

它使用FileSaver.js保存文件。

这是我的画布创建,请注意我在这里解决了名称空间问题

d3.js画布创建:

var canvas = d3.select("body")
    .insert("svg")
    .attr('id', 'd3-canvas')
    //Solve the namespace issue (xmlns and xlink)
    .attr("xmlns", "http://www.w3.org/2000/svg")
    .attr("xmlns:xlink", "http://www.w3.org/1999/xlink")
    .attr("width", width)
    .attr("height", height);

2

解决了这个问题后,我创建了一个名为SaveSVG的小型库,该库可以帮助保存D3.js生成的SVG,该SVG使用外部样式表或外部定义文件(使用<use>def)标记。


1

为了使该代码段正常工作,您需要FileSaver.js。

function save_as_svg(){


        var svg_data = document.getElementById("svg").innerHTML //put id of your svg element here

        var head = '<svg title="graph" version="1.1" xmlns="http://www.w3.org/2000/svg">'

        //if you have some additional styling like graph edges put them inside <style> tag

        var style = '<style>circle {cursor: pointer;stroke-width: 1.5px;}text {font: 10px arial;}path {stroke: DimGrey;stroke-width: 1.5px;}</style>'

        var full_svg = head +  style + svg_data + "</svg>"
        var blob = new Blob([full_svg], {type: "image/svg+xml"});  
        saveAs(blob, "graph.svg");


};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.