0

I try to: create an SVG element with D3, click a button to convert it to an image using CANVAS, so it could be right clicked and "saved as" image.

The problem: the [object HTMLImageElement] object is not visible by Internet Explorer as "image" so when I right click on it, it doesn't prompt the "Save image as..." option. In Chrome and Firefox it works ok.

I have the following HTML code:

<input type="button" id="toPngBtn" value="Save" /><br />
<div id="myDiv"></div>
<div id="exportDiv"></div>

And the following javascript code:

    //Make an SVG Container
    var svgContainer = d3.select("#myDiv").append("svg")
        .attr("id", "myCircle")
        .attr("width", 60)
        .attr("height", 60);

     //Draw the Circle
     var circle = svgContainer.append("circle")
        .attr("cx", 30)
        .attr("cy", 30)
        .attr("r", 20);

    // Save button to 
     d3.select("#toPngBtn").on("click", function () {
        var svg = document.getElementById('myCircle');
        var xml = new XMLSerializer().serializeToString(svg);
        var data = "data:image/svg+xml;base64," + btoa(xml);
        var image = new Image;
        image.src = data;
        var imgWidth = image.width;
        var imgHeigth = image.height;
        var exportDiv = document.getElementById('exportDiv');
        exportDiv.innerHTML = '<canvas id="exportCanvas" width="' + imgWidth + '" height="' + imgHeigth + '"></canvas>';

        var canvas = document.querySelector("canvas"),
            context = canvas.getContext("2d");

         canvas.innerHTML = image;

        image.onload = function () {
            context.drawImage(image, 0, 0);
        };
    });

So what I do is the following: When the page loads I draw a circle using D3.js. If the "toPngBtn" button is clicked, then I will get the svg element, serialize it, create a new Image() object and append the blob to the source. I get the dimensions of the SVG and create a new CANVAS of the same size and append it to a div. I set the innerHTML of the canvas to be the newly created image and when the image is loaded, I tell the context to draw the image.

The good part is that the image appears on the page. The bad part is that in Internet Explorer I cannot right click on the image and save it. Works fine in Chrome and Firefox.

The question: Is there a workaround for that? I tried to use the

...    
image.onload = function () {
                context.drawImage(image, 0, 0);
                var a = document.createElement("a");
                a.download = "svg-graph.png";
                a.href = canvas.toDataURL("image/png");
                a.click();
            };
...

to prompt the file for download, but again Internet Explorer doesn't allow CORS so it doesn't work... Any ideas on how to make an image from SVG downloadable in IE? Thank you.

John
  • 475
  • 1
  • 8
  • 23

2 Answers2

3

Drawing an svg image onto a canvas did taint the canvas in IE < Edge ( and in latest Safari if a <foreignObject> is in the svg being drawn), for security reasons.

Hence, when you right click the drawn canvas, you can't anymore access the save image as... functionality.

However, in these browsers, you can just right click the original svg element and choose save image as... => yourFile.png.

So the solution is either to first try to render the svg on the canvas, then check if it was tainted by calling its toDataURL() method in a try-catch block, or to do some UA-string spoofing and directly send some notice to the user to right click the image and do it by himself...

Note that even if the canvas is tainted, it has nothing to do with cross-origin-resources in your case.

Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Do you know of any reason why an IE 11 user would report not having the option to "save picture as" by right clicking an svg element? The option seems to be there for one user, but not another, even though both have identical IE versions. – Dave Sep 12 '16 at 21:08
  • @Dave, no I have no idea, trully sorry and if you find out I'd be glad to hear the why. Maybe some plugin or antivirus? – Kaiido Sep 12 '16 at 23:02
1

Internet Explorer does not support download attribute on anchor tags. So for Internet Explorer, you can try the following code

window.navigator.msSaveBlob(canvas.msToBlob(), "svg-graph.png");

Completed code:

function isIE() {
  var userAgent = window.navigator.userAgent;
  return userAgent.indexOf("MSIE ") > -1 || userAgent.indexOf("Trident/") > -1;
}
image.onload = function () {
   context.drawImage(image, 0, 0);
   if(isIE()){ 
      window.navigator.msSaveBlob(canvas.msToBlob(), "svg-graph.png");
   } else{
      var a = document.createElement("a");
      a.download = "svg-graph.png";
      a.href = canvas.toDataURL("image/png");
      a.click();
   }
};
Gilsha
  • 14,431
  • 3
  • 32
  • 47
  • 1
    I am tempted to upvote it because I didn't know IE's `navigator.msSaveBlob` method, but if the canvas is tainted (which occurs when you draw an svg onto it in IE – Kaiido Jan 07 '16 at 06:07
  • Thank you very much. This is the solution to the problem we had all along. This is actually the solution for saving the D3.js Graph to PNG. – John Jan 07 '16 at 14:23