Javascript 使用D3.js(即safari和chrome)创建SVG后,如何保存/导出SVG文件?

Javascript 使用D3.js(即safari和chrome)创建SVG后,如何保存/导出SVG文件?,javascript,jquery,svg,d3.js,Javascript,Jquery,Svg,D3.js,我目前有一个使用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://r

我目前有一个使用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文件?

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

  • 获取要输出的内联svg元素
  • 通过XMLSerializer获取svg源代码
  • 添加svg和xlink的名称空间
  • 采用组件方法构造svg的url数据方案
  • 将此url设置为某个“a”元素的href属性,然后右键单击此链接下载svg文件

  • //获取svg元素。
    var svg=document.getElementById(“svg”);
    //获取svg源代码。
    var serializer=新的XMLSerializer();
    var source=serializer.serializeToString(svg);
    //添加名称空间。
    如果(!source.match(/^]+xmlns=“http\:\/\/www\.w3\.org\/2000\/svg/){
    
    source=source.replace(/^我知道这个问题已经得到了回答,而且这个答案在大多数情况下都很有效。但是我发现如果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月编辑:
    评论指出,即使不将
    downloadLink
    附加到
    document.body
    并在
    click()
    后将其删除,此代码也能正常工作。我相信这在Firefox上可以使用,但到目前为止它已不再有效(Firefox要求您附加并删除
    downloadLink
    )。该代码在Chrome上运行。

    结合了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);
    }
    

    要使此代码段正常工作,您需要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");
    
    
    };
    
    函数将_另存为_svg(){
    var svg_data=document.getElementById(“svg”).innerHTML//将svg元素的id放在此处
    变量头=“”
    //若你们有一些额外的样式,比如图边,把它们放在标签里面
    var style='圆圈{光标:指针;笔划宽度:1.5px;}文本{字体:10px arial;}路径{笔划:DimGrey;笔划宽度:1.5px;}'
    var full_svg=头部+样式+svg_数据+“”
    var blob=new blob([full_svg],{type:“image/svg+xml”});
    saveAs(blob,graph.svg);
    };
    
    我尝试了这里的所有解决方案,但没有任何效果。我的图片总是比我的d3.js画布小

    我必须设置画布的
    宽度
    高度
    ,然后在
    上下文
    上执行
    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;
    
    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);
    
    它用于保存文件

    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);
    
    这是我的画布创建,请注意,我在这里解决了名称空间问题

    d3.js画布创建:

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

    在回答这个问题的同时,我创建了一个名为的小库,它可以帮助保存D3.js生成的SVG,该SVG使用外部样式表或外部定义文件(使用
    def
    )标记。

    基于@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>
    
    
    函数save_as_svg(){
    fetch('path/./assets/chart.css')
    .then(response=>response.text())
    。然后(文本=>{
    var svg_data=document.getElementById(“svg”).innerHTML
    变量头=“”
    var style=”“+文本+“”
    var full_svg=头部+样式+svg_数据+“”
    var blob=new blob([full_svg],{type:“image/svg+xml”});
    saveAs(blob,graph.svg);
    })
    };
    将_另存为_svg();
    

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

    谢谢您的回答!这为我下载了一个svg,尽管所有内容都变黑了,颜色也非常鲜艳。为什么会这样?您可以在我的网站上看到我的意思,我已经应用了您建议的代码:-只需单击“提交”,然后单击“导出图形”。非常感谢此示例非常简单。如果您通过链接元素使用外部css文件的css样式,则svg和样式表的链接已断开。因此,此问题将通过向内联svg添加样式数据来解决。“因此,此问题将通过向内联svg添加样式数据来解决。”你能用另一种方式向我解释一下吗?我不太明白。看吧,添加和转换,但在这种情况下svg文件将不再是独立的。注意:这在Chrome或Firefox中不再起作用,因为它们现在在顶层使用时都会阻止svg的数据URI。这在Chrome中非常有效!对于这个简单的答案,我会给出+100!看起来像它不需要在
    文档中追加和删除
    下载链接
    。body
    。outerHTML
    在internet explorer中不起作用。但是您可以使用
    XMLSerializer()
    作为。其他一切都保持不变。XMLSerializer()的良好替代品!这是最有效的!回答很好,代码段也很容易使用。
    svgEl.outerHTML
    在IE和Edge中不起作用。他们不支持SVG元素的
    outerHTML
    。我想将SVG静默保存在服务器上的文件夹中,我不想触发用户下载。如何完成请帮助我。谢谢!@senz,如果SVG包含ima呢由于某种原因,这不起作用。请检查我的示例。