Back in our d3.interval loop, update() has run and we have the positions of all our raindrops. Next, we will deal with drawing them. If we had a DOM, we would interact with our omnipresent 200 SVG circles and ask them kindly to move down a little. But we produce a static image and we can only draw and not change. So, we draw. Like in a flip book we dispose of the old image and draw a new one. Let's repeat this. Each time we want to move something on the canvas we remove the old image and draw a new image with changed positions.
It's straightforward:
function animate() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawScene();
rain.items.forEach(function(el) {
circle(context, el.x, el.y, 1.5, 'blue');
});
}
animate() uses the context's own clearRect() function, which does what it says on the tin. You pass it the area you want to clear – in our case the entire canvas – and it will clear it. You can also fill a white rectangle or change the canvas.width and canvas.height values, but clearRect() is faster than the first and clearer than the second method.
Next, you run the drawScene() function, which draws our scene: the house and the tree. It's what you built in the previous section, just wrapped up in an aptly-named function.
Finally, we draw each drop to the canvas. What is circle() you ask? It's a helper function to build visual primitives – in our case a circle. It has been added at the top of the code:
function circle(ctx, x, y, r, color) {
ctx.beginPath();
ctx.fillStyle = color;
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
}
The two main functions update() and animate() are being run repeatedly until the end of your browser tab's session; which could mean bad weather for some time.