joep
joep

Reputation: 258

drawImage on a canvas with setTimeout

I have built an image up on a canvas with drawImage using several pieces.

I now want to try either load them in 1 by 1, or, attempt animate them or modify the size of the pieces used to make up the full image after they have initially loaded.

I am having trouble getting them to work with a setTimeout function, is this even a suitable method? or is there a better way?

Here is my original working canvas built with several image pieces: https://codepen.io/anon/pen/MyaMOK

Here is my attempt loading them in 1 by 1 and the setTimeout:

setTimeout(function(){
    ctx.drawImage(img, piece.sx, piece.sy, piece.sWidth, piece.sHeight, piece.x, piece.y, piece.w, piece.h);
},100*tileCount);

https://codepen.io/anon/pen/RaWzgJ

It seems to just load 1 "piece" in the bottom right corner, and none of the others, though this method seems to work fine outside the setTimeout.

Can anyone suggest a workable solution?

Upvotes: 0

Views: 900

Answers (2)

Soubhik Mondal
Soubhik Mondal

Reputation: 2666

I took your code and modified it by adding console.log before the setTimeout function and within the callback of the setTimeout function.

The result was that the loops were working as expected. The piece object was getting updated for every iteration.

However, the setTimeout functions were called only after the entire loop was exhausted, and to my surprise, taken the same values for piece object.

The reason why it behaved like this, according to me, is thus:

  1. setTimeout function only registers the callback function (to be executed later) but does not block the loop (it is asynchronous).

  2. Therefore, the loop continues without executing any of the callbacks within setTimeout and piece gets updated through out.

  3. When the loop is exhausted, the callback functions start executing. However, all the callbacks are referring to the same piece object (due to hoisting and because javascipt is not block-scoped), hence they all get the same value.

  4. Conclusion: all the image pieces get correctly outputted, but they get outputted at the same place, one on-top of another.

Why putting setTimeout in another function works:

Putting setTimeout in another function works because calling the new function creates a new scope with its own piece object, i.e., it is no longer sharing from the same global piece object.

Upvotes: 0

joep
joep

Reputation: 258

Figured it out.

making function within a function = bad. moved the setTimeout function outside of the for loop and passed the variables to it from within, updated working codepen is here:

https://codepen.io/anon/pen/RaWzgJ

Upvotes: 2

Related Questions