Daniel Bengtsson
Daniel Bengtsson

Reputation: 113

javascript canvas - check if images created with toDataURL() are loaded

I'm loading an image into my albImg array.

in my loop i then do this:

    for(var j = 1; j < albImg.length; j++){
        if(albImg[j].complete == true && albImg[j].width > 0){
            loadedimages++;
        }
    }

to make sure all my images are loaded. I then call my flipImg() function like this:

    if(loadedimages == albImg.length-1){
         flipImg();
    }

I then flip an image and

ctx2.save();
ctx2.scale(-1, 1);
for (var i = RszSpriteCount; i < sprites.length; i++) {
    ctx2.drawImage(albImg[sprites[i][0]], sprites[i][1], sprites[i][2], sprites[i][3], sprites[i][4], 0 - (sprites[i][1] + sprites[i][3]), sprites[i][2], sprites[i][3], sprites[i][4]);
}
ctx2.restore();
var flipSz = albImg.length;
albImg[flipSz] = new Image();
albImg[flipSz].src = cnv2.toDataURL();

Here's where my problem begins.

The new image I created - albImg[5] - can't be displayed until it is loaded. But it is created as if it already is loaded.

That is to say that:

albImg[5].width is already set (to 750) before I can display it. albImg[5].complete is set to true, before I can display it. albImg[5].onload = ctx.drawImage(albImg[5], 0, 0); will try to draw the image before it is loaded.

How can I check if my flipped image really is loaded before I display it? in Javascript?

(due to circumstances I'm not using jQuery for this)

Please help.

Upvotes: 0

Views: 2837

Answers (1)

Kaiido
Kaiido

Reputation: 136678

Your main error is in how you do set the onload event handler :

albImg[5].onload = ctx.drawImage(albImg[5], 0, 0)  

will set the return value of drawImage() (undefined) to the onload listener.

What you want is

albImg[5].onload = e => ctx.drawImage(albImg[5], 0, 0);  

or

albImg[5].onload = function(){ ctx.drawImage(this, 0, 0) };

For the complete and width properties set to true, it's because while the loading of an Image is always async, in your case, the image is probably already HTTP cached.
Since the HTTP loading and the javascript execution are not executed on the same thread, it is possible that the Image actually loaded before the browser returns its properties.

But even then, the onload event will fire (best to set it before the src though).

var cacher = new Image();
cacher.onload = function(){
  var img = new Image();
  img.onload = function(){
    console.log('"onload" fires asynchronously even when cached');
    };
  img.src = c.toDataURL();
  console.log('cached : ', img.complete, img.naturalWidth);
  }
cacher.src = c.toDataURL();
console.log('before cache :', cacher.complete, cacher.naturalWidth);
<canvas id="c"></canvas>

So when dealing with an new Image (not one in the html markup), always simply listen to its onload event.


Now, with the few information you gave in your question, it would seem that you don't even need these images, nor to deal with any of their loadings (except for the sprites of course), since you can directly and synchronously call ctx.drawImage(CanvasElement, x, y).

const ctx = c.getContext('2d');
ctx.moveTo(0, 0);
ctx.lineTo(300, 75);
ctx.lineTo(0, 150);
ctx.fillStyle = 'rgba(120,120,30, .35)';
ctx.fill();

const flipped = c.cloneNode(); // create an offscreen canvas
const f_ctx = flipped.getContext('2d');
f_ctx.setTransform(-1, 0,0,1, c.width, 0);// flip it
f_ctx.drawImage(c,0,0);// draw the original image

// now draw this flipped version on the original one just like an Image.
ctx.drawImage(flipped, 0,0);
// again in 3s
setTimeout(()=>ctx.drawImage(flipped, 150,0), 3000);
<canvas id="c"></canvas>

Upvotes: 2

Related Questions