Karish Karish
Karish Karish

Reputation: 269

JavaScript animation with multiple setTimeout

i am trying to animate 3 different shapes with setTimeout , my question is how can i use multiple setTimeout to animate 3 different shapes also is there a better way to do this maybe using setInterval

window.onload = draw;
var x = 5;
var y = 5;

radius = 50;

var x2 = 50;
var y2 = 120;

var x3 = 53;
var y3 = 230;
var context;

var loopTimer;

function draw(){
var canvas = document.getElementById('canvas');
 context = canvas.getContext('2d');
context.save();
context.clearRect(0,0,720,550);

rectangle(x,y);
circle(x2,y2);
circle2(x3,y3);

}

function rectangle(x,y){
//drawing a rectangle 
context.fillStyle = "rgba(93,119,188,237)";
context.clearRect(0,0,720,550);
context.rect(x, y, 50, 50);
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'yellow';
context.stroke();
x += 1;
loopTimer = setTimeout('rectangle('+x+','+y+')',50);
}

function circle(x2,y2){
//darwong a circle
context.beginPath();
context.clearRect(0,0,720,550);
context.fillStyle = "#0000ff";  
//Draw a circle of radius 20 at the current coordinates on the canvas. 
context.arc(x2, y2, radius, 0, Math.PI*2, true); 
context.closePath();
context.fill();
x2 += 1;
loopTimer = setTimeout('circle('+x2+','+y2+')',20);
}

function circle2(x3,y3){
//drawing a second circle 
context.beginPath();
context.clearRect(0,0,720,550);
context.fillStyle = 'green';
context.arc(x3, y3, radius, 0, Math.PI*2, true); 
context.closePath();
context.fill();
context.lineWidth = 5;//border around the circle 
context.strokeStyle = 'red';
context.stroke();
x3 += 1;
loopTimer = setTimeout('circle2('+x3+','+y3+')',20);
}

Upvotes: 0

Views: 1940

Answers (2)

user1693593
user1693593

Reputation:

Animating objects

When doing digital animation there is never need for more than one single timer.

The key is to bind properties to the objects being animation such as its position, speed (or steps), color, shape and so forth.

The logic step therefor is to create custom objects that we can collect this information and use an update function to do all the updates for us in a single step within the loop.

Example

ONLINE DEMO HERE

Lets create an object collection where we store all our objects:

var animObjects = [];

Nothing fancy about that - just an array.

A single loop

To show how simple this can get I will show the loop itself first, then dissect the object. The loop simply iterates through our collection and calls the update method on each object:

function loop() {
 
    /// clear canvas before redrawing all objects   
    ctx.clearRect(0, 0, demo.width, demo.height);
    
    /// loop through the object collection and update each object
    for(var i = 0, animObject; animObject = animObjects[i]; i++) {
        animObject.update();
    }

    /// use this instead of setTimeout/setInterval (!)
    requestAnimationFrame(loop);
}

Now, you noticed probably that we used requestAnimationFrame (rAF) here instead of setTimeout or setInterval. rAF allows us to synchronize to the monitor's update frequency whereas setTimout/setInterval cannot. In addition rAF works more efficient than the other two which will benefit us if we need to animate a lot of stuff.

The animation object

Now lets take a look at the object, how come we only need to call update and things animate?

As we saw earlier we create a animated circle object simply by calling:

var animObject = new animCircle(context, x, y, radius, color, stepX, stepY);

This allows us to set which context we want to use (in case we use several layers of canvas), the start position, color and number of steps per frame. Note that these properties can be changed during the animation (e.g. change radius and color).

The object itself looks like this -

function animCircle(ctx, x, y, r, color, stepX, stepY) {

    /// keep a reference to 'this' context for external calls
    var me = this;
    
    /// make the parameters public so we can alter them
    this.x = x;
    this.y = y;
    this.radius = r;
    this.color = color;
    this.stepX = stepX;
    this.stepY = stepY;
    
    /// this will update the object by incrementing x and y
    this.update = function() {

        me.x += me.stepX;
        me.y += me.stepY;

        /// additional updates can be inserted here

        render();
    }
    
    /// and this takes care of drawing the object with current settings
    function render() {
        ctx.beginPath();
        ctx.arc(me.x, me.y, me.radius, 0, 2 * Math.PI);
        ctx.closePath();
        ctx.fillStyle = me.color;
        ctx.fill();
    }
    return this;
}

That's all there is to it!

The objects update() method will do all the calculations for us as well as call the internal render() method.

You can create many of these objects at various positions and speeds and animate all of them from a single loop.

I only created an object for the circle to keep things simple. You should be able to create an object for rectangle and what have you by using this as a base. You can of course extent the object to keep track of other things as well such as stroke color, angles and so forth.

I also made the objects bounce off the canvas' edges for the sake of demo. Please adjust as needed.

Upvotes: 6

Lukas Lukac
Lukas Lukac

Reputation: 8346

If i get the question right... why you just dont create three different functions like drawCircle? drawWhatever and create three setTimeouts? or something like that... ?

  • why you use so manny ' ? there is no reason to do that in:

    var loopTimer = setTimeout('draw('+x+','+y+')',20);

Upvotes: 1

Related Questions