geeky_monster
geeky_monster

Reputation: 8792

javascript Uncaught TypeError while drawing on HTML5 Canvas

I am trying to draw a series of images on an HTML5 Canvas . For eg - For the word APPLE , I am trying to put 5 pictures - A.png, B.png, C.png etc in series to display the word . My code is as below:

var x = 100; 
var word = "APPLE";
var imageArray = new Array();

for (var i = 0; i < word.length; i++) {
  imageArray[i] = new Image();
  imageArray[i].onload = function() {
    context.drawImage(imageArray[i], x, 25, 70, 70); // canvas context
    x += 80;
  };
  imageArray[i].src = "images/"+word.charAt(i)+".png";
}

I get an Error -

javascript Uncaught TypeError: Type error

Can someone please explain me why is occuring and what is the best way to achieve this ?

Upvotes: 1

Views: 1350

Answers (2)

Dennis
Dennis

Reputation: 32598

After your loop exits, imageArray and i are kept inside the onload functions you created. i incremented again after your last iteration so it is now pointing to an undefined element in your array. You can use a function to create a new scope:

for (var i = 0; i < word.length; i++) {
  imageArray[i] = new Image();
  imageArray[i].onload = (function(i){
    return function() {
      // i in here is now the outer function parameter instead
      // of the i in the function that creates the images
      context.drawImage(this, x+i*80, 25, 70, 70);
    }
  })(i);
  imageArray[i].src = "images/"+word.charAt(i)+".png";
}

Tharabas answer is generally nicer, however forEach won't work in IE < 9

Upvotes: 2

Tharabas
Tharabas

Reputation: 3422

There are several possible error sources in you code:

  1. if you want to iterate over every letter in your word, you should stop at the end of the word and not at index 10:

    var word = "APPLE"; // has 5 letters
    for (var i = 0; i < word.length; i++) {
      // ... do your code
    }
    
  2. Within the callback onload = function() ... you access the imageArray[i] which is not what you intend to, as the value of i modifies and at the time it is called, you access the first element behind your desired array. Additionally, you can not rely on each letter being loaded in the correct sequence. You can avoid both of these error, by using forEach:

    var word = "APPLE"; // again, the 5 letter word
    // transform the word to an array ['A', 'P', 'P', 'L', 'E']
    var letters = word.split('');
    letters.forEach(function(letter, index) {
      var image = new Image();
      image.onload = function() {
        context.drawImage(image, x + index * 80, 25, 70, 80);
      }
      image.src = "images/" + letter + ".png";
    })
    

Upvotes: 3

Related Questions