instructions

This article explains how to use canvas to draw beautiful rain effect, let’s have a look at the final effect. rendering

explain

Look at the picture and see what we need to achieve. 1, raindrops falling effect, moving the mouse to control the direction of falling 2, raindrops falling scattered into small droplets, small droplets of movement direction and the direction of mouse movement in the same 3, raindrops falling to the mouse coordinates within a certain range, scattered into small droplets of water, the same, small droplets of movement direction and the direction of mouse movement in the same

Ok, we split the whole effect roughly into three effects, and then we’re done. Let’s do it step by step.

1, rain falling effect, move the mouse to control the direction of falling

The idea is to start with an array of raindrop objects. A raindrop object with each attribute is used to mean, raindrops x coordinate and y coordinate, length, falling speed, color, determine whether delete logo When the update animation Add a certain amount of rain in the array object, and then through the array and modify each raindrop object coordinates x and y coordinates, with canvas according to the rain of the coordinates of the object, draw two dots, It’s a raindrop.

So the focus of the implementation is on the coordinates of the raindrop x when initializing a raindrop: a random number of raindrop Y: -100. This is to make the raindrop X when updating the animation from outside the viewable area: Speedx = speedx + (Maxspeedx-speedx) / 50. Speedx = speedx + (maxspeedx-speedx) / 50

Maxspeedx = (e.clientx-canvasel.clientWidth / 2)/(canvasel.clientWidth / 2), e.clientx: Mouse distance to the left of the visible area value canvasel.clientWidth: The width of the entire viewable area means that speedx is a value that gets progressively closer to MaxSpeedx and maxSpeedx is in the range of -1 to 1, and the closer it gets to -1, the further it goes to the left, and the closer it gets to 1, the further it goes to the right. Why not just use MaxSpeedx? This is to make the speed of raindrop change direction not so fast, do not follow the mouse change direction immediately change, to have a little delay, look better. If you use maxspeedx, this is what it looks like

With Speedx, this is what it looks like

Y coordinate: the original y coordinate value + speed Speed is a fixed value as mentioned in the x coordinate above, indicating the falling speed of the raindrop.

Ok, finally, draw two points with canvas according to the coordinates of the raindrop object, and then connect them together, and the raindrop is drawn. The coordinates of the first point are relatively simple, and directly obtain the x and y coordinates of the raindrop object, which are the coordinates of this point and the coordinates of the second point: The x-coordinate is equal to the value of the x-coordinate of the raindrop plus the length of the raindrop times speedx the y-coordinate is equal to the value of the y-coordinate of the raindrop plus the length of the raindrop and when you connect these two points, you have a line, and you have a raindrop

When you set the x coordinate, you use speedx again, so that the drop direction is the same as the drop direction, when speedx is not used

When using Speedx, yes

2, rain drops fall into small droplets, small droplets of water and the direction of the mouse movement in the same direction

And the idea here is actually a little bit similar to what we did up here where we started off with an array of water droplets. A small drop of water, in fact, is to draw an arc. A drop object has various attributes to represent the coordinates of the drop, the X-axis moving speed, the Y-axis moving speed, the radius of the circle, the flag bit to determine whether to delete. When updating the animation, add a certain number of droplets to the array, then go through the number group, modify the X and Y coordinates of each droplets object, and draw an arc with canvas according to the coordinates and radius attributes of droplets object.

So the focus of the implementation effect and initialize a small water droplets on coordinates Small water droplets are rain disappear, so the coordinates of small water droplets is according to the coordinates of raindrops, delete a raindrop, will appear a few small water droplets, and the movement of the small water droplets direction is also and raindrops falling direction, the direction of the mouse, Therefore, speedx, the variable mentioned above, will still be required: x coordinates of the deleted raindrop + length of the deleted raindrop * speedx y coordinates: When updating the animation, two properties of the small drop object are used: vx (the change rate of the value of the x axis) and VY (the change rate of the value of the y axis). The x-coordinate of the droplets is vx + speedx / 2 the x-coordinate of the droplets is the original x-coordinate + vx,

Speedx: the variable mentioned above is related to the direction of mouse movement. The function here is to control the movement of the small drop in the same direction as the other directions. Speedx / 2, divided by 2 is to make the small drop in the X-axis movement distance shorter, more realistic

Gravity = gravity + gravity; gravity = gravity + gravity Vy: a negative number gravity: a positive number The whole code is set to 0.5 because the original y coordinate is a positive number, so the value of the y coordinate of the drop will decrease first and then increase. This is to realize the effect that the drop will rise first and then fall. Look at the picture

Finally, the canvas can be used to draw an arc according to the coordinate properties and radius properties of the small water drop, and the radian is random

3, raindrops fall to the mouse coordinates within a certain range, scattered into small droplets, similarly, small droplets of water and the direction of movement of the mouse in the same direction








Because the raindrop is a line connecting two points, to see whether the raindrop falls into this range, is to look at the coordinates of the point below the raindrop, the straight line distance to the mouse, is the length of the AB line segment in the figure.

Pythagorean theorem: The sum of squares of two sides of a right triangle is equal to the square of the hypotenuse.

AB = Math.sqrt(BC*BC + AC * AC)

BC = raindrop x – mouse x AC = raindrop Y – mouse y The math.sqrt () method is used to calculate the square root of a number

We know that the linear distance between the raindrop and the mouse, compared with the radius of the circle, is greater than the radius is not within the range, otherwise it is in. If it’s in range, delete raindrops and draw small drops.

conclusion

To achieve this effect, the trouble lies in the direction, the direction of raindrops, the direction of raindrops falling, and the direction of small water drops moving, which are all related to the direction of mouse movement. After determining various directions, draw lines and arcs with canvas continuously according to the distance.

The complete code

<! doctype html> <html lang="en">
<head>
  <meta charset="UTF-8">
  <style>
    * {
      margin: 0;
      padding: 0;
    }
  </style>
</head>
<body>
  <canvas id="canvas" style="position: absolute; height: 100%; width:100%;"></canvas>
  <script>
    window.onload = main;
    function mainVar canvasEl = document.getelementById ('canvas');
      var ctx = canvasEl.getContext('2d'); // canvas backgroundColor var backgroundColor ='# 000'; // canvas The width of the canvas is equal to the width of the viewable area canvasel.width = canvasel.clientWidth; Canvasel. height = canvasel. clientHeight; Var dropList = []; var dropList = []; Gravity = 0; gravity = 0; gravity = 0; gravity = 0; gravity = 0; Var linelist = []; var linelist = []; Var mousePos = [0, 0]; var mousePos = [0, 0]; // With mousePos as the center of the circle and mouseDis as the radius, the raindrops within this range will scatter to form many small water droplets. Var lineNum = 3; var lineNum = 3; Var speedx = 0; var speedx = 0; var speedx = 0; Var maxspeedx = 0; var maxspeedx = 0; // Resets canvas canvas size window.onresize = when the page size changesfunction() { canvasEl.width = canvasEl.clientWidth; canvasEl.height = canvasEl.clientHeight; } // Moving the mouse triggers the event window.onmousemove =functionMousePos [0] = e.clientx; mousePos[0] = e.clientx; mousePos[0] = e.clientx; mousePos[0] = e.clientx; mousePos[1] = e.clientY; // Set the value of maxspeedx by mouse position. The value ranges from -1 to 1. // 1, the direction of raindrops // 2, the direction of raindrops falling // 3, the speed of raindrops falling direction changes with the direction of mouse movement // 4, the direction of small water droplets moving // the closer the value is to 1, the closer the direction is to the right // the closer the value is to -1, Maxspeedx = (e.clientx-canvasel.clientWidth / 2)/(canvasel.clientWidth / 2); } // According to the argument, return an RGB color, which is used to set the color of the raindropfunction getRgb(r, g, b) {
        return "rgb(" + r + "," + g + "," + b + ")"; } // Draw a drop of rain (a line)functionCreateLine (e) {var temp = 0.25 * (50 + math.random () * 100); Var line = {// Raindrop drop speed: 5.5 * (math.random () * 6 + 3), // Determine whether to delete, the value istrueTo delete a die:false, // raindrop x posx: e, // raindrop y posy: -50, // raindrop length h: temp, // raindrop color color: getRgb(Math.floor(temp * 255 / 75), Math.floor(temp * 255 / 75), Math.floor(temp * 255 / 75)) }; // Add the line (raindrop) object to the array linelist.push(line); } // Draw a small drop of water (the small drops of water after the raindrop is a circle)functionCreateDrop (x, y) {var drop = {createDrop(x, y) {createDrop(x, y)trueTo delete a die:false// Posx: x, // posy: y, // vx indicates the speed of the change of the value of the x axis vx: (math.random () -0.5) * 8, // vy indicates the speed at which the Y-axis value changes. Values range: -3 to -9 vy: math.random () * (-6) -3, // Radius of the arc: Math.random() * 1.5 + 1};returndrop; } // Draw a certain number of dropletsfunctionMaxi = math.floor (math.random () * 5 + 5); math.floor (math.random () * 5 + 5);for(var i = 0; i < maxi; i++) { dropList.push(createDrop(x, y)); }} / / call the update function, update the animation window. RequestAnimationFrame (update); // Update the animationfunction update() {// If the array holding the droplets has contentsif(droplist.length > 0) {// Walk through the array of small droplets droplist.foreach (function(e) {// set e.vx, vx indicates the speed of x coordinate change // (speedx)/2 to make the distance of the small drop of water moving in the x axis shorter, more realistic // Also make the direction of the small drop of water moving and the direction of the rain drop, the direction of the rain drop falling, Mouse moves in the same direction e.vx = e.vx + (speedx / 2); e.posx = e.posx + e.vx; // Set e.py, vy is the speed of change in y coordinate // E.py is between -3 and -9, and e.py (y coordinate) must be positive, so the value of E.py will decrease first and then increase. E.y = e.y + gravity; e.posy = e.posy + e.vy; // If the drop's y-coordinate is greater than the height of the viewable area, set the die property totrue// Remove small droplets if they are outside the viewable areaif (e.posy > canvasEl.clientHeight) {
              e.die = true; }}); } // Delete the member whose die attribute is true // remove the droplets outside the viewable areafor (var i = dropList.length - 1; i >= 0; i--) {
          if(dropList[i].die) { dropList.splice(i, 1); }} // Set the rain direction change speed, value range: Speedx = speedx + (maxspeedx-speedx) / 50; // Draw a certain number of raindrops according to lineNumfor(var i = 0; i < lineNum; CreateLine (math.random () * 2 * canvasel.width - (0.5 * canvasel.width)); } var endLine = canvasel.clientheight - math.random () * canvasel.clientheight / 5; // loop through the array linelist.foreach (function(e) {// Use Pythagorean theorem to determine a range, Var dis = math.sqrt (((e.posx + speedx * e.h) -) mousePos[0]) * ((e.posx + speedx * e.h) - mousePos[0]) + (e.posy + e.h - mousePos[1]) * (e.posy + e.h - mousePos[1])); // If the mouse is in the mouseDis area, delete the raindrops and draw some small water droplets (arcs) // Achieve the effect of raindrops scattered into small water droplets when the mouse touches the raindropsif(dis < mouseDis) {// Delete raindrop e.dee =true; // Make madedrops(e.bose + speedx * e.h, e.bose + e.h); } // If the raindrop exceeds the end line, delete the raindrop and draw some small drops (arc).if ((e.posy + e.h) > endLine) {
            e.die = true; madedrops(e.posx + speedx * e.h, e.posy + e.h); } // If the y coordinate of the raindrop is greater than the height of the viewable area, set the die property totrue// If the raindrop is outside the viewable area, delete itif (e.posy >= canvasEl.clientHeight) {
            e.die = true;
          } else{// Gradually increase the y coordinate value of the raindrop e.posy = e.posy + e.spade; E.posx = e.posx + e.state * speedx; e.posx = e.posx + e.state * speedx; }}); // Remove the drop in the mouse area, beyond the end line, outside the viewable areafor (var i = linelist.length - 1; i >= 0; i--) {
          if(linelist[i].die) { linelist.splice(i, 1); } // render(); / / recursive calls the update, the realization of animation window. RequestAnimationFrame (update); } / / renderingfunction renderCtx. fillStyle = backgroundColor; ctx.fillRect(0, 0, canvasEl.width, canvasEl.height); CTX. LineWidth = 5; linelist.forEach(function(line) { ctx.strokeStyle = line.color; ctx.beginPath(); ctx.moveTo(line.posx, line.posy); Ctx. lineTo(line.posx + line.h * speedx, line.posy + line.h); ctx.lineTo(line.posx + line.h); ctx.stroke(); }); LineWidth = 1; CTX. LineWidth = 1; ctx.strokeStyle ="#fff";
        dropList.forEach(function(e) { ctx.beginPath(); ctx.arc(e.posx, e.posy, e.radius, Math.random() * Math.PI * 2, 1 * Math.PI); ctx.stroke(); }); /* ctx.beginPath(); ctx.arc(mousePos[0], mousePos[1], mouseDis, 0, 2 * Math.PI); ctx.stroke(); */ } } </script> </body> </html>Copy the code

Finally, this special effect is learned from SXQ111. You can also give him a small star on Github.