user4305497
user4305497

Reputation:

Issue using setTimeout to animate in canvas

I'm trying to animate vertical rows of circles that are recurring, one row at a time. Each row of circles starts at the bottom of the browser and goes to the top. But I'm having trouble using setTimeout to keep it recurring with only one new line of circles at a time. My current code has recurring lines of circles, but it adds an extra line of circles each time and speeds up the animation each time as well. How can I avoid the speeding up and adding extra rows of circles?

here's the fiddle

var newLine = function(){
        var posX = Math.random() * canvas.width;
            posY = canvas.height;

        setInterval(function() {
            posY -= 40;

            c.fillStyle = "rgba(23, 23, 23, 0.05)";
            c.fillRect(0, 0, canvas.width, canvas.height);

            c.fillStyle = "white";
            c.beginPath();
            c.arc(posX, posY, Math.random() * 20, 0, twoPi, false);
            c.fill();

        }, 30);
        setTimeout(newLine, 2000);
    };  
    newLine();

Upvotes: 2

Views: 144

Answers (1)

Michael Geary
Michael Geary

Reputation: 28850

The problem is that every time you call newLine() it creates a new interval timer. So after calling the function several times you have several interval timers all running at once.

The fix is simply to clear the interval timer before starting a new one:

    var timer;

    var newLine = function(){
        clearInterval( timer );
        var posX = Math.random() * canvas.width;
            posY = canvas.height;

        timer = setInterval(function() {
            posY -= 40;

            c.fillStyle = "rgba(23, 23, 23, 0.05)";
            c.fillRect(0, 0, canvas.width, canvas.height);

            c.fillStyle = "white";
            c.beginPath();
            c.arc(posX, posY, Math.random() * 20, 0, twoPi, false);
            c.fill();

        }, 30);
        setTimeout(newLine, 2000);
    };  
    newLine();

Updated fiddle

About your question in the comments... One problem you're running to is a very subtle JavaScript trap. I didn't notice it either until doing some debugging.

Take a close look at these lines:

        var posX = Math.random() * canvas.width;
            posY = canvas.height;

Now ask yourself these questions: Is posX a local variable? Is posY a local variable? Are you sure they're both local variables?

If you saw some results in your tests where two or or more of the line animations move up in lockstep, this will explain why.

The other part of your question is easy. Disregard my previous advice about moving the timer variable outside the newLine() function so you can cancel it! Instead, make timer a local variable inside newLine(), and make each instance of newLine() cancel its own timer when done.

Once you do that, the rest of your code works fine:

    var newLine = function(){
        var posX = Math.random() * canvas.width;
        var posY = canvas.height;

        var timer = setInterval(function() {
            posY -= 10;
            if( posY <= 0 ) {
                clearInterval( timer );
                return;
            }

            c.fillStyle = "rgba(23, 23, 23, 0.05)";
            c.fillRect(0, 0, canvas.width, canvas.height);

            c.fillStyle = "white";
            c.beginPath();
            c.arc(posX, posY, Math.random() * 5, 0, twoPi, false);
            c.fill();

        }, 30);

        setTimeout( newLine, Math.random() * 2000 );
    };

    newLine();

New fiddle

Upvotes: 2

Related Questions