AL-zami
AL-zami

Reputation: 9076

rain drop animation on html canvas

I am trying to create water drop falling effect on canvas.I created some sample drops using array.to animate it i mean to change their positions i introduced a setTimeout function.it worked for single water drop.since there are multiple drops on my canvas it is not working anymore.drops remain still.how the setTimeout function can be used to animate all the individual drops?

here is the fiddle jsfiddle

animate effect for an individual drop single drop animation

<html>
<head>
</head>
<body>
<script>
function makeit(){
var canvas=document.getElementById("mycanvas");
var ctx=canvas.getContext('2d');
canvas.width=600;
canvas.height=600;
canvas.style.border="1px solid black";

var drop=function (x,y){
ctx.save();

ctx.fillStyle="orange";
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fill();

ctx.fillStyle="red";
ctx.moveTo(x-5,y);
ctx.lineTo(x,y-7);
ctx.lineTo(x+5,y);
ctx.arc(x,y,5,0,Math.PI);

ctx.closePath();

ctx.fill();
ctx.restore();
y=y+3;
if(y==canvas.height){
y=0;
}

var m=setTimeout('drop('+x+','+y+')',20);

}

var xpos=[10,20,30,40,50,60,70,70,76];
var ypos=[30,20,60,80,76,90,30,40,79];
for(i=0;i<xpos.length;i++){
drop(xpos[i],ypos[i]);

}

}
 window.onload=makeit;
</script>
<canvas id="mycanvas" ></canvas>



</body>
</html>

Upvotes: 3

Views: 6332

Answers (2)

markE
markE

Reputation: 105035

Here's another option using window.requestAnimationFrame to animate your drops:

  • Define a Drop pseudo-class which knows its x,y position and the speed at which it falls

  • Add Drop methods to redraw the drop on the canvas and increment its Y value to make it fall.

  • Create an animation loop with window.requestAnimationFrame to (1) clear the canvas by filling it with an orange background, (2) make each drop fall and (3) redraw each drop on the canvas.

Annotated code and a Demo: http://jsfiddle.net/m1erickson/m8UPC/

<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
    body{ background-color: ivory; }
    canvas{border:1px solid red;}
</style>
<script>
$(function(){

    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");

    // a flag to let you stop the animation
    var ok2animate=true;


    // a Drop pseudo-class
    // Properties: current x,y & the speed at which this drop falls
    function Drop(){
        this.x=Math.random()*(canvas.width-20);
        this.y=-Math.random()*20;
        this.fallRate=1;
    }
    // draw this drop on the canvas
    Drop.prototype.draw=function(){
        ctx.beginPath();
        ctx.moveTo(this.x-5,this.y);
        ctx.lineTo(this.x,this.y-7);
        ctx.lineTo(this.x+5,this.y);
        ctx.arc(this.x,this.y,5,0,Math.PI);
        ctx.closePath();
        ctx.fill();
        return(this);    
    }
    // make this drop "fall" 
    Drop.prototype.fall=function(){
        this.y+=this.fallRate;
        return(this);
    }

    // an animation loop to make some test drops fall 
    function animate(){

        // request another animation frame
        if(ok2animate){
            requestAnimationFrame(animate);
        }

        // fill the canvas with the orange background
        ctx.fillStyle="orange";
        ctx.fillRect(0,0,canvas.width,canvas.height)

        // make all drops fall and then redraw them
        ctx.fillStyle="red";
        for(var i=0;i<drops.length;i++){
            drops[i].fall().draw();
        }

    }

    // let the user stop the animation
    $("#stop").click(function(){
        ok2animate=false;
    });



    // an array of objects each representing 1 drop
    var drops=[];

    // add some test drops
    for(var i=0;i<10;i++){
        drops.push(new Drop());    
    }

    // start the animation
    requestAnimationFrame(animate);


}); // end $(function(){});
</script>
</head>
<body>
    <button id="stop">Stop</button><br>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Upvotes: 2

Oliboy50
Oliboy50

Reputation: 2721

Here is how I would do what you're trying to :

function makeit() {
    // These variables can be used in the drawing functions
    var canvas = document.getElementById("mycanvas");
    var ctx = canvas.getContext('2d');
    var drops = [];

    // Init canvas & drops
    init();

    // Make the 3rd drop falls
    var fall = setInterval(function () {
        updateDrop(3);
    }, 200);

    // Make the 7th drop falls
    var fall2 = setInterval(function () {
        updateDrop(7);
    }, 400);

    // Stop the 3rd drop at anytime with this code :
    // clearInterval(fall);


    // Functions
    function init() {
        canvas.width = 600;
        canvas.height = 600;
        canvas.style.border = "1px solid black";
        // Draw background
        drawBackground();
        // Draw drops
        var xpos = [10, 20, 30, 40, 50, 60, 70, 70, 76];
        var ypos = [30, 20, 60, 80, 76, 90, 30, 40, 79];
        for (i = 0; i < xpos.length; i++) {
            drops.push(drawDrop(xpos[i], ypos[i]));
        }
    }

    function drawBackground() {
        ctx.fillStyle = "orange";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fill();
    }

    function drawDrop(x, y) {
        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.moveTo(x - 5, y);
        ctx.lineTo(x, y - 7);
        ctx.lineTo(x + 5, y);
        ctx.arc(x, y, 5, 0, Math.PI);
        ctx.closePath();
        ctx.fill();

        return {
            'x': x,
                'y': y
        };
    }

    function updateDrop(dropNumber) {
        var dropNumber = dropNumber - 1; //Because 0 is first
        // Update position        
        if (drops[dropNumber].y >= canvas.height) {
            drops[dropNumber].y = 0;
        } else {
            drops[dropNumber].y += 3;
        }
        //Draw background
        drawBackground();
        //Draw drops
        for (i = 0; i < drops.length; i++) {
            drawDrop(drops[i].x, drops[i].y);
        }
    }

}
window.onload = makeit;

Then, if you want to stop the 3rd drop from falling, you can execute this line :

clearInterval(fall);

Just look at the JSFiddle : http://jsfiddle.net/Oliboy50/QHRaS/5/

Don't forget ctx.beginPath() before drawing lines, else you won't be able to clear them.

Upvotes: 2

Related Questions