Reputation: 75
var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
var imgArray = [];
for (var i=0;i<data.length;i++){
var drawRepeat = Math.floor((data[i]/divider));
imgArray[i] = [];
for (var j=0;j<drawRepeat;j++){
//alert(j);
var xPos = ((i*30)+10);
var yPos = 250-((j*30)+30);
imgArray[i][j] = new Image();
imgArray[i][j].src="assets/orange.png";
imgArray[i][j].onload = function(){
ctx.drawImage(imgArray[i][j],xPos,yPos);
};
}
}
I want to draw multiple images with a for loop. weirdly when i place an alert() with the for loop it works? but if i comment it away it will only display 1 of the image.
Is there any solution to this?
Upvotes: 1
Views: 4005
Reputation: 75
var c=document.getElementById("cvs");
var ctx=c.getContext("2d");
var img = new Image();
img.src="assets/orange.png";
img.onload = function(){
for (var i=0;i<data.length;i++){
var drawRepeat = Math.floor((data[i]/divider));
for (var j=0;j<drawRepeat;j++){
//alert(j);
var xPos = ((i*30)+10);
var yPos = 250-((j*30)+30);
ctx.drawImage(img,xPos,yPos);
}
}
}
I managed to solved the problem with onload by placing the onload outside the for loops and putting drawImage command inside the onload function and in the for loops. Works as well.
Upvotes: 0
Reputation: 5475
That's the problem related to closures. I'll explain after giving the code.
var c = document.getElementById("cvs");
var ctx = c.getContext("2d");
var imgArray = [];
for (var i = 0; i < data.length; i++) {
var drawRepeat = Math.floor((data[i] / divider));
imgArray[i] = [];
for (var j = 0; j < drawRepeat; j++) {
//alert(j);
(function (_i, _j) {
var xPos = ((_i * 30) + 10);
var yPos = 250 - ((_j * 30) + 30);
imgArray[_i][_j] = new Image();
imgArray[_i][_j].src = "assets/orange.png";
imgArray[_i][_j].onload = function () {
ctx.drawImage(imgArray[_i][_j], xPos, yPos);
};
})(i, j);
}
}
UPDATE:
The reason I am doing this weird stuff is that the function registered to onload
event will be called asynchronously - that is the loop will continue and the function will be called when the image loads, and not at that very moment. So what happens is that this loop continues, and once it's completed (note that this may occur even before completion), i
's value will be data.length - 1
. Now, some image is loaded, and then the function is called. This function refers to i
(in the code you gave), which by now is data.length - 1
. And so, only the last image gets drawn. I know this is confusing - even I felt it confusing when I first stumbled upon closures. I recommend you read some good article on them and you'll see what the problem is.
What we did was to create a scope (experts might find a problem with this expression) by creating an anonymous function which is called immediately, and is passed the values of i
and j
as it's parameters - _i
and _j
(Note that we could've used the same names, but to avoid confusion, I didn't use the same names). Now, these are local to the function and aren't altered. So, when i
th image is loaded, it's onload function is called which draws the _i
th image in the array.
I have failed to explain it well, so as I said, please read some article on closures.
Upvotes: 3