How do I handle many images in my HTML5 canvas?

html, html5-canvas, javascript

Solution

Update: Based on new information in the question, your problem (restated) is that you want to either

- wait for all images to load first, and then start animating with them, or

- start animating and only use an image if it is available.

Both are described below.

1. Loading many images and proceeding only when they are finished

With this technique we load all images immediately and when the last has loaded we run a custom callback.

Demo: http://jsfiddle.net/3MPrT/1/

// Load images and run the whenLoaded callback when all have loaded;
// The callback is passed an array of loaded Image objects.
function loadImages(paths,whenLoaded){
  var imgs=[];
  paths.forEach(function(path){
    var img = new Image;
    img.onload = function(){
      imgs.push(img);
      if (imgs.length==paths.length) whenLoaded(imgs);
    }
    img.src = path;
  });
}

var imagePaths = [...]; // array of strings
loadImages(imagePaths,function(loadedImages){
  setInterval(function(){ animateInCircle(loadedImages) }, 30);
});

2. Keeping track of all images loaded so far

With this technique we start animating immediately, but only draw images once they are loaded. Our circle dynamically changes dimension based on how many images are loaded so far.

Demo: http://jsfiddle.net/3MPrT/2/

var imagePaths = [...]; // array of strings
var loadedImages = [];  // array of Image objects loaded so far

imagePaths.forEach(function(path){
  // When an image has loaded, add it to the array of loaded images
  var img = new Image;
  img.onload = function(){ loadedImages.push(img); }
  img.src = path;
});

setInterval(function(){
  // Only animate the images loaded so far
  animateInCircle(loadedImages);
}, 100);

And, if you wanted the images to rotate in a circle instead of just move in a circle:

Rotating images: http://jsfiddle.net/3MPrT/7/

ctx.save();
ctx.translate(cx,cy); // Center of circle
ctx.rotate( (angleOffset+(new Date)/3000) % Math.TAU );
ctx.translate(radius-img.width/2,-img.height/2);
ctx.drawImage(img,0,0);
ctx.restore();

Original answer follows.

In general, you must wait for each image loading to complete:

function animate(){
  var img1 = new Image;
  img1.onload = function(){
    context.drawImage(img1,x1,y1);
  };
  img1.src = "/path";

  var img2 = new Image;
  img2.onload = function(){
    context.drawImage(img2,x2,y2);
  };
  img2.src = "/path";
}

You may want to make this code more DRY by using an object:

var imgLocs = {
  "/path1" : { x:17, y:42  },
  "/path2" : { x:99, y:131 },
  // as many as you want
};

function animate(){
  for (var path in imgLocs){
    (function(imgPath){
      var xy = imgLocs[imgPath];
      var img = new Image;
      img.onload = function(){
        context.drawImage( img, xy.x, xy.y );
      }
      img.src = imgPath;
    })(path);
  }
}

Problem

I'm very new to Html5 canvas and Javascript. I'm trying this : ``` function animate() { var image1 = new Image(); image.src = /path var image2 = new Image(); image2.src = /path for(;;) { //change value of x and y so that it looks like moving context.beginPath(); context.drawImage(<image>, x, y ); context.closePath(); context.fill(); } } ``` EDIT: And I call the `animate` function each 33ms : ``` if (playAnimation) { // Run the animation loop again in 33 milliseconds setTimeout(animate, 33); }; ``` If I follow the answer given here, I get the image struck and its not moving any further.

Original source