Quiero crear una descarga personalizada (archivo JSON generado por JavaScript) desde un elemento SVG (en la interfaz mi aplicación está en SVG). Sin embargo, si bien puedo hacerlo para HTML simple (vide Forzar descarga de 'datos: texto / URL 'simple) no funciona para SVG.

Un ejemplo (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);
});

Si es importante, uso D3.js (3.x).

¿Existe una solución / solución conocida?

1
Piotr Migdal 7 jun. 2016 a las 19:43

3 respuestas

La mejor respuesta

Copié la respuesta de @ Fraser pero usé FileSaver.js hace que esta sea una tarea fácil:

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>
1
Fraser 13 jun. 2016 a las 15:43

Puede cambiar los datos por:

data:application/octet-stream

Para forzar la descarga. Pero la etiqueta download es para HTML, no para marcado SVG. Por lo tanto, no puede asignar filename.ext antes de la descarga.

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

Necesito una función de utilidad para hacer eso. Eche un vistazo aquí.-

0
Community 23 may. 2017 a las 12:15

Simplemente puede usar una función de utilidad para crear un enlace que se comporte como lo requiera. p.ej.

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);
};
1
Fraser 11 jun. 2016 a las 09:03