Hoe bewaar/exporteer ik een SVG-bestand nadat ik een SVG heb gemaakt met D3.js (IE, safari en chrome)?

Ik heb momenteel een website die D3 gebruikt en ik wil dat de gebruiker de mogelijkheid heeft om de SVG op te slaan als een SVG-bestand. Ik gebruik crowbar.js om dit te doen, maar het werkt alleen op chrome. Er gebeurt niets met safari en IE geeft een toegang geweigerd op de click()-methode die wordt gebruikt in crowbar.js om het bestand te downloaden.

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

Hoe download ik een SVG-bestand op basis van het SVG-element op mijn website in safari, IE en chrome?


Antwoord 1, autoriteit 100%

Er zijn 5 stappen. Ik gebruik deze methode vaak om inline svg uit te voeren.

  1. krijg inline svg-element om uit te voeren.
  2. verkrijg de svg-bron door XMLSerializer.
  3. voeg naamruimten van svg en xlink toe.
  4. maak url-gegevensschema van svg volgens de encodeURIComponent-methode.
  5. stel deze url in op href-attribuut van een “a”-element en klik met de rechtermuisknop op deze link om het svg-bestand te downloaden.

//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.

Antwoord 2, autoriteit 90%

Ik weet dat dit al is beantwoord, en dat antwoord werkt meestal goed. Ik ontdekte echter dat het mislukte in Chrome (maar niet in Firefox) als de svg-afbeelding groot was (ongeveer 1 MB). Het werkt als je teruggaat naar het gebruik van een Blob-constructie, zoals beschreven hieren hier . Het enige verschil is het typeargument. In mijn code wilde ik een enkele druk op de knop om de svg voor de gebruiker te downloaden, wat ik deed met:

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

Oktober 2019 bewerken:
Opmerkingen hebben aangegeven dat deze code zelfs zal werken zonder downloadLinktoe te voegen aan document.bodyen deze vervolgens te verwijderen na click(). Ik geloof dat dat vroeger in Firefox werkte, maar vanaf nu niet meer (Firefox vereist dat je downloadLinktoevoegt en vervolgens verwijdert). De code werkt hoe dan ook in Chrome.


Antwoord 3, autoriteit 52%

De antwoorden van Dave en defghi1977 combineren. Hier is een herbruikbare functie:

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

Voorbeeld van aanroep:

saveSvg(svg, 'test.svg')

Antwoord 4, autoriteit 4%

Om dit fragment te laten werken, heeft u FileSaver.js nodig.

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

Antwoord 5, autoriteit 4%

Ik heb hier elke oplossing geprobeerden niets werkte voor mij. Mijn foto was altijd kleiner dan mijn d3.js canvas.

Ik moest het canvas width, heightinstellen en vervolgens een clearRectdoen in de contextom het te maken werken. Hier is mijn werkende versie

Exportfunctie:

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;

Het gebruikt FileSaver.jsom het bestand op te slaan.

Dit is mijn canvas-creatie, merk op dat ik het probleem met de naamruimte hier oplos

d3.js canvas maken:

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

Antwoord 6, autoriteit 4%

Terwijl deze vraag is beantwoord, heb ik een kleine bibliotheek gemaakt met de naam SaveSVGdie kan helpen D3 te redden .js genereerde SVG die externe stylesheets of externe definitiebestanden gebruiken (met behulp van <use>en def) tags.


Antwoord 7, autoriteit 2%

Gebaseerd op het antwoord van @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>

De bovenstaande code leest uw chart.css en sluit de css-code vervolgens in uw svg-bestand in.

Other episodes