angelHank angelHank - 1 year ago 46
Javascript Question

Stopping animated rain in Canvas smmoothly

Rain Picture HereSo my issue isn't stopping the rain its stopping the making of the rain so the already rendered rain completes its animation off the screen.

I tried setInterval and setTimeout in JS but it just freezes.

And using JQuery to remove canvas tag takes off all drops at once.

Any ideas or direction would be great!



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

var canvasW = window.innerWidth;
var canvasH = window.innerHeight;
canvas.height = canvasH;
canvas.width = canvasW;


var mf = 70;
var drops = [];



for(var i = 0; i < mf; i++){
drops.push({
x: Math.random()*canvasW,
y: Math.random()*canvasH,
r: Math.random()*5+2,
d: Math.random() + 1
})

}

function fill() {
ctx.fill();
}



function drawRain(){
ctx.clearRect(0, 0, canvasW, canvasH);
ctx.fillStyle = "rgba(255, 255, 255, .5)";
ctx.beginPath();
for(var i = 0; i < mf; i++){
var f = drops[i];
ctx.moveTo(f.x-5, f.y);
ctx.lineTo(f.x, f.y-15);
ctx.lineTo(f.x+5, f.y);
ctx.arc(f.x, f.y + f.r*.7,5, 0, Math.PI, false);
}
fill();

moveRain();

}

function moveRain(){
for(var i = 0; i < mf; i++){
var f = drops[i];
f.y += Math.pow(f.d, 2) + 1;

if(f.y > canvasH){
drops[i] = {x: Math.random()*canvasW, y: 0, r: f.r, d: f.d};
}
}
}


var i = setInterval(drawRain, 20);


setTimeout(function( ) { clearInterval(); }, 2000);

canvas{ background-color: black }

<canvas id="rainCanvas"></canvas>




Answer Source

What you want to do is set a flag to stop the rain from wrapping back to the top in your function to stop raining:

var stopRain = false;

...

setTimeout(function( ) { stopRain = true; }, 2000);

Now inside moveRain when that variable is true instead of moving it back to the top remove it from the array. Once we removed all the drops we can then clear the interval as it's no longer needed:

function moveRain(){
    for(var i = 0; i < mf; i++){
        var f = drops[i];
        f.y += Math.pow(f.d, 2) + 1;

        if(f.y > canvasH){
            if(stopRain) {              // When we stop raining 
            drops.splice(i, 1);        // Remove drop from array
            mf--;                      // Make sure to update the "length"
            if(mf<1) clearInterval(i); // If there are not more drops clear the interval
          } else drops[i] = {x: Math.random()*canvasW, y: 0, r: f.r, d: f.d};
        }
    }
}

Fiddle Example

You could also use drops.length instead of using mf, this way you don't need to do mf--.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download