4

I am having trouble getting the onLoad handler to fire when the src of imgGraph is loaded with a generated dataURI. The dataURI is generated from a d3.js visualization (svg) using canvas.

var canvas = document.getElementById(visual + '-canvas');
if(visual == "graph"){
     console.log('graph logic n stuff')
     canvas.width = 558;
     canvas.height = 558;
     var graph = d3.select('#graph-svg').node();
     var svg_xml = (new XMLSerializer()).serializeToString(graph);
     var imgGraph = new Image();
     var context = canvas.getContext('2d');
     var imageData;
     imgGraph.onload = function(){
         console.log('img loaded')
         context.drawImage(imgGraph, 0, 0);
         imageData = getImgData(canvas);
         console.log(imageData)
         def.resolve(imageData)
     }
     console.log('setting src')
     imgGraph.src = "data:image/svg+xml;base64,"+btoa(svg_xml);
}

The img src is being set, but the img.onload is never fired. When logging and surfing to the datauri, the image is being displayed however. Other images seem to fire the onload event correctly.

DataURI - PasteBin

Brent Nys
  • 55
  • 1
  • 7

2 Answers2

4

Don't base64 encode your svg.
Instead one should prefer an percent encoded version, or for huge svg, a blobURI :

img.src = 'data:image/svg+xml;charset=utf8,' + encodeURIComponent(yourSVGMarkup);

or

img.src = URL.createObjectURL(
  new Blob([yourSVGMarkup], {
    type: 'image/svg+xml;charset=utf8'
    })
  );

JSfiddle to demonstrate the difference.

But you should note that SVGs loaded inside an <img> element can't load any external resources. So you'll have to base64 encode all the images linked in your svg prior to extract the markup if you want to draw them on your canvas too.
When this will be done, your svg markup will indeed be long, and maybe too long for a dataURI version.

That's when the blobURI is useful.

PS: if you need help for appending your raster images inside your svg, check this Q/A

Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Thanks, this worked! The implementation with blob even yields a better quality than my previous method! – Brent Nys Apr 19 '17 at 12:45
0

Try:

imgGraph.complete = function(){

TJS101
  • 490
  • 1
  • 7
  • 19
  • Doesn't this only work on img-tags that are appended to the DOM? If I try this I get the following error: _Cannot assign to read only property 'complete' of object '#_ – Brent Nys Apr 19 '17 at 09:32
  • Yes, it does, and I am not sure why this does not have the same result. For an image created in the way you describe you might want to create a loop check for non-zero width / height for the image object. Or loop to see if the imgGraph.complete property is true. – TJS101 Apr 19 '17 at 09:39
  • See my previous Q&A: http://stackoverflow.com/questions/16648546/how-to-monitor-an-image-source-for-fully-loaded-status – TJS101 Apr 19 '17 at 09:45