【问题标题】:How do I save/export an SVG file after creating an SVG with D3.js (IE, safari and chrome)?使用 D3.js(IE、safari 和 chrome)创建 SVG 后,如何保存/导出 SVG 文件?
【发布时间】:2014-06-06 17:51:35
【问题描述】:

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

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 文件?

【问题讨论】:

    标签: javascript jquery svg d3.js


    【解决方案1】:

    有 5 个步骤。我经常用这种方法输出内联svg。

    1. 获取要输出的内联 svg 元素。
    2. 通过 XMLSerializer 获取 svg 源代码。
    3. 添加 svg 和 xlink 的命名空间。
    4. 通过encodeURIComponent方法构造svg的url数据方案。
    5. 将此网址设置为某些“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.
    

    【讨论】:

    • 感谢您的回答!这为我下载了一个 svg,尽管一切都变黑并且着色非常奇怪。为什么是这样?你可以在我的网站上看到我的意思,我已经应用了你建议的代码:servers.binf.ku.dk/hemaexplorerbeta - 只需点击“提交”,然后点击“导出图表”。非常感谢
    • 这个例子是简单的案例。如果您通过链接元素通过外部 css 文件使用 css 样式,则 svg 和样式表的链接被破坏。所以,这个问题将通过将样式数据附加到内联 svg 来解决。
    • "所以,这个问题将通过将样式数据附加到内联 svg 来解决。"你能用另一种方式向我解释吗?我不太明白。
    • w3.org/TR/SVG11/styling.html#ReferencingExternalStyleSheets 所以,添加 并转换,但在这种情况下,svg 文件将不被支持-独自一人。
    • 注意:这不再适用于 Chrome 或 Firefox,因为它们现在在顶层使用时都会阻止 SVG 的数据 URI。
    【解决方案2】:

    我知道这个问题已经得到解答,而且这个答案在大多数情况下都很有效。但是,我发现如果 svg 图像很大(大约 1MB),它在 Chrome(但不是 Firefox)上会失败。如果您返回使用Blob 构造,它会起作用,如herehere 所述。唯一的区别是类型参数。在我的代码中,我想要一个按钮来为用户下载 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 月编辑: 评论表明,即使没有将downloadLink 附加到document.body 并随后在click() 之后将其删除,此代码也可以工作。我相信这曾经在 Firefox 上工作,但现在它不再工作了(Firefox 要求您附加然后删除 downloadLink)。无论哪种方式,该代码都可以在 Chrome 上运行。

    【讨论】:

    • 这在 Chrome 中运行得非常好!对于这个简单的答案,我会给 +100!
    • 看起来它无需在document.body 中添加和删除downloadLink 即可工作
    • .outerHTML not 在 Internet Explorer 中不起作用。但是您可以将XMLSerializer() 用作defghi1977。其他一切都保持不变。
    • XMLSerializer() 的好替代品!
    • 这个效果最好!很好的答案和易于使用的 sn-p。
    【解决方案3】:

    结合 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')
    

    【讨论】:

    • svgEl.outerHTML 在 IE 和 Edge 中不起作用。他们不支持 outerHTML 用于 SVG 元素。 source
    • 我想将 SVG 静默保存在服务器上的一个文件夹中,我不想触发用户下载如何完成,请帮助我。谢谢!
    • @senz,如果 svg 包含图像怎么办。由于某种原因,这不起作用。检查我的例子jsfiddle.net/10Ljgrv7/3
    【解决方案4】:

    要让这个 sn-p 工作,您需要 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");
    
    
    };
    

    【讨论】:

      【解决方案5】:

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

      我必须设置画布widthheight,然后在context 上执行clearRect 以使其正常工作。这是我的工作版本

      导出功能:

      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);
      

      【讨论】:

        【解决方案6】:

        虽然已经回答了这个问题,但我创建了一个名为 SaveSVG 的小型库,它可以帮助保存使用外部样式表或外部定义文件(使用 &lt;use&gt;def)标签的 D3.js 生成的 SVG。

        【讨论】:

          【解决方案7】:

          基于@vasyl-vaskivskyi 的回答。

          <script src="../../assets/FileSaver.js"></script>
          <script>
          function save_as_svg(){
              fetch('path/../assets/chart.css')
              .then(response => response.text())
              .then(text => {
                  var svg_data = document.getElementById("svg").innerHTML
                  var head = '<svg title="graph" version="1.1" xmlns="http://www.w3.org/2000/svg">'
                  var style = "<style>" + text + "</style>"
                  var full_svg = head +  style + svg_data + "</svg>"
                  var blob = new Blob([full_svg], {type: "image/svg+xml"});  
                  saveAs(blob, "graph.svg");
              })
          };
          save_as_svg();
          </script>
          

          上面的代码读取了你的chart.css,然后将css代码嵌入到你的svg文件中。

          【讨论】:

            猜你喜欢
            • 2015-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-12-18
            • 2014-02-24
            • 2021-06-21
            • 1970-01-01
            • 2015-02-15
            相关资源
            最近更新 更多