Piotr Migdal
Piotr Migdal

Reputation: 12822

Link to generated download file from SVG

I want to create a custom download (JavaScript-generated JSON file) from an SVG element (in my application interface is in SVG). However, while I can do it for plain HTML (vide Force download of 'data:text/plain' URL) it does not work for SVG.

An example (https://jsfiddle.net/stared/qzn7Ldme/):

HTML:

<a id="link_html" download="file.txt">download file (from HTML)</a>
<br/>
<svg height="100" width="300">
  <a id="link_svg" download="file.txt">
    <text x="0" y="50">download file (from SVG)</text>
  </a>
</svg>

JS:

var conent = "This is the file content.";
var header = "data:text/plain;charset=utf-8,"
var payload = header + encodeURIComponent(conent);

// works
d3.select("#link_html").on("click", function () {
    this.href = payload;
});

// does not work as intended
d3.select("#link_svg").on("click", function () {
  //// line below does nothing:
  // this["xlink:href"] = payload;

  // opens file in the same window, not as a downloaded file!
  d3.select("#link_svg").attr("xlink:href", payload);
});

If it matters, I use D3.js (3.x).

Is there a know solution / fix?

Upvotes: 1

Views: 2760

Answers (3)

Endless
Endless

Reputation: 37885

I copied @Fraser's answer but used FileSaver.js makes this a easy task:

var content = "This is the file content.";
var blob = new Blob([content]);

d3.select("#link_svg").on("click", function () {
  saveAs(blob, "file.txt");
});
<script src="https://cdn.rawgit.com/eligrey/FileSaver.js/master/FileSaver.min.js"></script>
<script src="https://d3js.org/d3.v3.js"></script>

<svg height="100" width="300">
  <a id="link_svg">
    <text x="0" y="50">download file (from SVG)</text>
  </a>
</svg>

Upvotes: 1

Fraser
Fraser

Reputation: 17094

You could simply use a utility function to create a link that behaves as you require. e.g.

SVG

<svg height="100" width="300">
  <a id="link_svg" download="file.txt">
    <text x="0" y="50">download file (from SVG)</text>
  </a>
</svg>

JS

var content = "This is the file content.";

d3.select("#link_svg").on("click", function () {
  downloadFile("file.txt", content);
});

var downloadFile = function(filename, content) {
  var blob = new Blob([content]);
  var event = new MouseEvent('click', {
    'view': window,
    'bubbles': true,
    'cancelable': true
  });
  var a = document.createElement("a");
  a.download = filename;
  a.href = URL.createObjectURL(blob);
  a.dispatchEvent(event);
};

Upvotes: 1

Klaujesi
Klaujesi

Reputation: 1836

You could change data by:

data:application/octet-stream

to force download. But download tag it's for HTML not for SVG markup. So you can't assign filename.ext before download.

<a id="link_html" download="file.txt">download file (from HTML)</a>
<br/>
<svg height="100" width="300">
  <a id="link_svg" download="file.txt" xlink:href="">
    <text x="0" y="50">download file (from SVG)</text>
  </a>
</svg>

<script>
        var conent = "This is the file content.";
        var header = 'data:application/octet-stream;charset=utf-8,'
        var payload = header + encodeURIComponent(conent);

        // works
        d3.select("#link_html").on("click", function () {
            this.href = payload;
        });

        d3.select("#link_svg").attr("xlink:href", payload)
</script>

need an utility function to do that. Take a look here.-

Upvotes: 0

Related Questions