I have tried to make two squares move at the same time... I know the first animation is repeating to infinite but what should i do?
3 Answers
Both of the other solutions are correct, but please, PLEASE don't make your code a list of if else conditions with a massive inside block. Consider, instead the following solution:
$(document).ready(function(){ animateTheBox('block1',0); animateTheBox('block2',2); }); function animateTheBox(block,i) { var animation = {}; var duration = 3000; var easing = 'linear'; var done = function(){ animateTheBox(block, (i+1)%4); }; switch(i){ case 0: animation = {'left' : "-=100px"} break; case 1: animation = {'top' : "-=100px"} break; case 2: animation = {'left' : "+=100px"} break; case 3: animation = {'top' : "+=100px"} break; default: return; //This is so you can't call the function in weird ways, as before. } $('.' + block).animate(animation, duration, easing, done); } Use a switch statement to determine what kind of animation to do, then only write the actual animation call once. This kind of abstraction is easier to read, and has the added benefit of being way more maintainable. You can be sure that your animation will be done the same way every single time.
EDIT:
Though the above design pattern is probably better in the long run, you could easily do this with an array instead:
$(document).ready(function(){ animateTheBox('block1',0); animateTheBox('block2',2); }); function animateTheBox(block,i) { var animations = [ {'left' : "-=100px"} , {'top' : "-=100px"} , {'left' : "+=100px"} , {'top' : "+=100px"} ]; var duration = 3000; var easing = 'linear'; var done = function(){ animateTheBox(block, (i+1)%4); }; if ( i < 0 || i >= animations.length) return; //Don't deal with out of bound numbers. $('.' + block).animate(animations[i], duration, easing, done); } And actually, this could make multi step animation abstraction really easy:
$(document).ready(function(){ var block1Steps = [ {'left' : "-=100px"} , {'top' : "-=100px"} , {'left' : "+=100px"} , {'top' : "+=100px"} ]; var block2Steps = [ {'left' : "+=100px"} , {'top' : "+=100px"} , {'left' : "-=100px"} , {'top' : "-=100px"} ]; multiAnimate($('.block1'), block1Steps, 3000, 'linear', true); multiAnimate($('.block2'), block2Steps, 3000, 'linear', true); }); function multiAnimate(item, animations, duration, easing, infinite){ var i = -1; var step = function(){ i++; if (infinite) i %= animations.length; if (i >= animations.length) return; item.animate(animations[i], duration, easing, step); }; step(); } Then, if you wanted to get REALLY Apeshit, you could give each animation its own duration and easing, and BAM! You've basically created for yourself a little arbitrary multistep animation library.
function multiAnimate(item, animations, duration, easing, infinite){ var defaultDuration = 1000; var defaultEasing = 'linear'; var i = -1; var step = function(){ i++; if (infinite) i %= animations.length; if (i >= animations.length) return; item.animate(animations[i].animation , (animations[i].duration)? animations[i].duration: defaultDuration , (animations[i].easing)? animations[i].easing: defaultEasing , step ); }; step(); } $(document).ready(function(){ var block1Steps = [ { animation: {'left' : "-=100px"} , duration: 3000 , easing: 'linear' } , { animation: {'top' : "-=100px"} , duration: 1000 , easing: 'swing' } , { animation: {'left' : "+=100px"} , duration: 5000 , easing: 'swing' } , { animation: {'top' : "+=100px"} , duration: 2000 , easing: 'linear' } ]; var block2Steps = [ { animation: {'left' : "+=100px"} , duration: 5000 , easing: 'swing' } , { animation: {'top' : "+=100px"} , duration: 2000 , easing: 'linear' } , { animation: {'left' : "-=100px"} , duration: 3000 , easing: 'linear' } , { animation: {'top' : "-=100px"} , duration: 1000 , easing: 'swing' } ]; multiAnimate($('.block1'), block1Steps, 3000, 'linear', true); multiAnimate($('.block2'), block2Steps, 3000, 'linear', true); }); 3 Comments
The reason is you need to wait for the first animation to complete before telling the box to begin the next set of animation. In your code, you're not giving the red box a chance to begin animating because the yellow one is constantly doing it (there is a closure created by the animateTheBox and both boxes are calling it) :)
So I added the complete function handler to your .animate() and moved the animateTheBox() call into there.
1 Comment
You need to use the completion function of each animation to start the next animation like this:
$(document).ready(function(){ animateTheBox('block1',0); animateTheBox('block2',2); }); function animateTheBox(block,i) { if (i==0) { $('.'+block).animate({'left' : "-=100px"}, 3000, 'linear', function() { animateTheBox(block,1); }); } else if (i==1) { $('.'+block).animate({'top' : "-=100px"}, 3000, 'linear', function() { animateTheBox(block,2); }); } else if (i==2) { $('.'+block).animate({'left' : "+=100px"}, 3000, 'linear', function() { animateTheBox(block,3); }); } else if (i==3) { $('.'+block).animate({'top' : "+=100px"}, 3000, 'linear', function() { animateTheBox(block,0); }); } } Working demo: http://jsfiddle.net/jfriend00/39SUN/
In the spirit of DRY, here's a much shorter way of doing it:
$(document).ready(function(){ animateTheBox('.block1',0); animateTheBox('.block2',2); }); function animateTheBox(block,i) { var anims = [ {left: "-=100px"}, {top: "-=100px"}, {left: "+=100px"}, {top: "+=100px"}, ]; $(block).animate(anims[i], 3000, 'linear', function() { animateTheBox(block,(i+1) % 4); }); } Working demo: http://jsfiddle.net/jfriend00/nKuGs/