Toby Toby - 1 month ago 10
Javascript Question

Showing hundreds of tiny images in HTML5 Canvas only after load

I have a canvas and 100 tiny images that I want to add to my canvas in a grid-like formation.

I have already achieved this, but the images are being draw on the canvas one by one and sometimes the image at the 40th position might be drawn before the image at the 10th position.

It takes a couple of seconds and then I get my desired result, but I was wondering how I could show images only after they're loaded?

I know there are other questions with a similar problem but I have read all of them and tried their solutions but have not succeeded yet.

I have this piece of code that draws the images one by one on the canvas at the right position using nested for loops:

for(...) {
for(..) {
add_image(source, row, column, width, height);
}
}


Now
add_image
actually creates an image object and draws it
onload


function add_image(...) {
let image = new Image();
image.src = source;

image.onload = function() {
context.drawImage(img, row, col, width, height);
}
}


In this exact situation, what is the best way to load all the images first and the "draw" them? I tried creating an array and populating it with all the image objects, then when all the images were loaded I would run the for loop to draw the images, but it wouldn't work and I didn't see a console error so I was left clueless.

Thank you in advance!

Answer

Add the images to an array and count each image as you do. In the image onload event decrease the counter. When the count is zero all the images have been loaded and can be drawn.

Example:

var images = [];
var loading = 0;
function add_image(url,xpos,ypos) {
  var image = new Image();
  image.src = url;
  images.push({
     image : image,
     xpos : xpos,
     ypos : ypos,
  });
  loading += 1;
  image.onload = function() {
      loading -= 1;
      if(loading === 0){
         drawImages(); // call function to draw all the images.
      }
  }
}
function drawImages(){
   for(var i = 0; i < images.length; i ++){
       // draw the image
       ctx.drawImage(images[i].image,images[i].xpos,images[i].ypos);
   }
}