4

I've got an application that builds a bar chart using svg, and I want to download a PNG image to the user. I'm using the FileSaver.js and canvas-to-blob.min.js polyfills to get support for canvas.toBlob() and window.saveAs().

Here's the snippet of code attached to the download button:

$('#download-button').on('click', function(e) {
    e.preventDefault();
    var chart = $('#bar-chart')
        .attr('xmlns', 'http://www.w3.org/2000/svg');
    var width = chart.width();
    var height = chart.height();
    var data = new XMLSerializer().serializeToString(chart.get(0));
    var svg = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
    var url = URL.createObjectURL(svg);

    var img = $('<img />')
        .width(width)
        .height(height)
        .on('load', function() {
            var canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(img.get(0), 0, 0);
            canvas.toBlob(function(blob) {
                saveAs(blob, "test.png");
            });
        });
    img.attr('src', url);
});

It extracts out the XML for the SVG image, wraps it in a blob and creates and object URL for the blob. Then it creates an image object and sets its src to the object URL. The load event handler then creates a canvas and uses drawImage() to render the image onto the canvas. Finally, it extracts the image data to a second blob and uses saveAs() to download it as "test.png".

Everything appears to work, but the downloaded PNG file doesn't have the whole image -- just a piece of the upper left corner. Could the browser be firing the "load" event before the SVG has been fully rendered? Or am I just missing something here?

Here is a jsFiddle demonstrating the problem.

tshepang
  • 12,111
  • 21
  • 91
  • 136
scottb
  • 1,135
  • 11
  • 17
  • The 100% width of the SVG element is interpreted as 100 pixels. You can see this if you console.log the width/height. Setting absolute width is one way to solve the problem. –  Nov 26 '13 at 07:41

1 Answers1

3

(Moving comment to answer so question can be closed:)

The 100% width of the SVG element is interpreted as 100 pixels. You can see this if you console.log the width/height.

Setting absolute width is one way to solve the problem.

  • Not to be confused with the height and width in the style attribute of the element. Setting the height and width attributes of the element is the trick. Example: ` ... ` – Nikhil Girraj Nov 04 '14 at 08:01