Reputation: 6353
I have 25 images I want to show really quickly, kinda like a slideshow without effects. My images are named 0 to 26.
I've tried setting a for loop and a setTimeout for the delay but the setTimeout runs only at the end of the for loop showing i = 25 at my Checkpoint.
JS:
function startAnimation(){
for(var i=0; i<25; i++){
setTimeout(function(){
img = new Image();
img.src = 'images/canvas/'+[i]+'.jpg';
img.onload = function(){ctx.drawImage(img,0,0, 850,194)}
alert('CP. In setTimeout. i= '+i);
},1000);
ctx.clearRect(0,0,canvas.width, canvas.height); //clear image after 1 sec, loop to show next.
alert('CP outside. i = '+i);
}
}
I followed this solution How do I add a delay in a JavaScript loop?:
function startAnimation(){
setTimeout(function(){
img = new Image();
img.src = 'images/canvas/'+[counter]+'.jpg';
img.onload = function(){ctx.drawImage(img,0,0, canvas.width,canvas.height)};
counter++;
if(counter<26){
startAnimation();
}
},150)
}
It seems to be working like I want it to.
Upvotes: 0
Views: 2625
Reputation: 1734
Instead of using setTimeOut and for loop, it would be better if you use setInterval Like so...
var i = 0,
img;
function startAnimation() {
if (i >= 24) {
clearInterval(timer); // or i = 0;
}
i++;
img = new Image();
img.src = 'images/canvas/' + [i] + '.jpg';
img.onload = function () {
ctx.drawImage(img, 0, 0, 850, 194);
};
alert('CP. In setTimeout. i= ' + i);
ctx.clearRect(0, 0, canvas.width, canvas.height); //clear image after 1 sec, loop to show next.
alert('CP outside. i = ' + i);
}
var timer = setInterval(startAnimation, 1000);
Upvotes: 2
Reputation: 119837
//preload your images into an array first for smoother animation
function getImages(callback) {
var imgs = [],
loaded = 0,
length = 25,
i;
for (i = 0; i < length; i++) {
(function (i) {
//create image
var img = new Image();
//set a callbacl
img.onload = function () {
//add to array
imgs[i] = img;
//increment loaded count
loaded++;
//if we loaded all of them, call the callback passing in the images
if (loaded === length) callback(imgs);
}
//load
img.src = 'images/canvas/' + [i] + '.jpg';
}(i));
}
}
function startAnimation(i) {
//get all images
getImages(function (imgs) {
var i = 0;
//run through ueach in an interval
var animationInterval = setInterval(function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (i < imgs.length) {
ctx.drawImage(img[i++], 0, 0, 850, 194)
} else {
clearInterval(animationInterval);
}
}, 1000);
});
}
//call
startAnimation();
Upvotes: 4
Reputation: 113866
Based on the following snippet of code:
//clear image after 1 sec, loop to show next.
It appears that you have misunderstood how setTimeout
works. The setTimeout
function does not wait before returning. It returns immediately and schedules the code/function passed to it to execute at a later time (1 second in your case). So what your loop does is to create 25 setTimeouts that all simultaneously execute one second after the loop is executed.
There are two solutions around this. One, to create 25 setTimeouts each one second later than the other:
for(var i=0; i<25; i++){
setTimeout(function(){/* ... */}, 1000 * i);
}
Alternatively to call setTimeout recursively to process your image list:
function foo (i) {
/* ... */
if (i >= 0) {
setTimeout(foo(i-1),1000);
}
}
foo(24);
The second form is more common.
In addition to the setTimeout issue. You also need to read up on how closures work inside loops because in your loop all the setTimeouts will execute with the value of i = 24
instead of i
being the values 1 to 24.
See: Please explain the use of JavaScript closures in loops
Upvotes: 3