This project is a video on the Mucho Internet. This article summarizes its own learning.
lattice
To draw numbers in canvas, you can use dot matrix.
Below is the lattice layout of 5. 1 represents to draw and 0 represents not to draw. Here the number is 10*7 grid system, colon is 10*4 grid system.
[ [1, 1, 1, 1, 1, 1, 1], [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1], [1, 1, 0, 0, 0, 1, 1], [0, 1, 1, 1, 1, 1, 0] ]
With this grid system, we can draw the numbers.
Digital Drawing
In canvas, how to draw numbers with circles? How to determine the xaxis coordinates and yaxis coordinates of the center of a circle?
ctx.arc( x + j * 2 * (radius + 1) + (radius + 1), y + i * 2 * (radius + 1) + (radius + 1), radius, 0, 2 * Math.PI )
Suppose the radius of a circle is R.
 The radius of the circle is R, and the box of the bounding box is R+1, so the length of each box is 2*(R+1).
 Assuming that the vertex of the lattice is (x,y), i represents the row and j represents the column.

So the coordinates of position (i,j) are:
 Xaxis coordinates: x + j*2*(R+1)+(R+1)
 Y axis coordinates: y + i*2*(R+1)+(R+1)
Here x + j*2*(R+1) is drawn to the front of the bounding box, plus (R+1), so that the drawn point is at the center of the circle.
How to locate the second number
How to determine the starting position of the second number?
Margin Left plus the position of the first number. Our digital lattice is seven columns, and the space occupied by one number is 14*(R+1). In order to make the distance between two digits free, we use 15.
Note that the third position is a colon, and we use a 10 * 4 lattice system for colons, so when drawing the fourth number, add 9 instead of 15.
renderDigit(marginLeft, marginTop, parseInt(hour / 10), ctx); renderDigit(marginLeft + 15 * (radius + 1), marginTop, parseInt(hour % 10), ctx); renderDigit(marginLeft + 30 * (radius + 1), marginTop, 10, ctx); renderDigit(marginLeft + 39 * (radius + 1), marginTop, parseInt(minutes / 10), ctx); renderDigit(marginLeft + 54 * (radius + 1), marginTop, parseInt(minutes % 10), ctx); renderDigit(marginLeft + 69 * (radius + 1), marginTop, 10, ctx); renderDigit(marginLeft + 78 * (radius + 1), marginTop, parseInt(seconds / 10), ctx); renderDigit(marginLeft + 93 * (radius + 1), marginTop, parseInt(seconds % 10), ctx);
Update figures
How to display the effect of time moving on the screen?
 Display the countdown on the screen to get the next time next next Show Time Seconds
 Compare the current time with the next time (just compare seconds)
 If nextSeconds is not curSeconds, it means that time has changed and the current time needs to be updated.
let nextShowTimeSeconds = getCurrentShowTimeSeconds(); let nextHour = parseInt(nextShowTimeSeconds / 3600); let nextMinutes = parseInt((nextShowTimeSeconds  nextHour * 3600) / 60); let nextSeconds = nextShowTimeSeconds % 60; let curHour = parseInt(curShowTimeSeconds / 3600); let curMinutes = parseInt((curShowTimeSeconds  curHour * 3600) / 60); let curSeconds = curShowTimeSeconds % 60; if (nextSeconds !== curSeconds) { curShowTimeSeconds = nextShowTimeSeconds; }
Drawing Colorful Balls
Time has moved. When time changes, how can we make a colorful ball appear in the position of time?
When the time changes, let the colorful ball appear on the page.
Here we need to judge every time, call the addBall function when the time changes.
if (parseInt(curHour / 10) !== parseInt(nextHour / 10)) { addBall(marginLeft, marginTop, parseInt(curHour / 10)); } if (parseInt(curHour % 10) !== parseInt(nextHour % 10)) { addBall(marginLeft + 15 * (radius + 1), marginTop, parseInt(curHour % 10)); } if (parseInt(curMinutes / 10) !== parseInt(nextMinutes / 10)) { addBall(marginLeft + 39 * (radius + 1), marginTop, parseInt(curMinutes / 10)); } if (parseInt(curMinutes % 10) !== parseInt(nextMinutes % 10)) { addBall(marginLeft + 54 * (radius + 1), marginTop,parseInt(curMinutes % 10)); } if (parseInt(curSeconds / 10) !== parseInt(nextSeconds / 10)) { addBall(marginLeft + 78 * (radius + 1), marginTop, parseInt(curSeconds / 10)); } if (parseInt(curSeconds % 10) !== parseInt(nextSeconds % 10)) { addBall(marginLeft + 93 * (radius + 1), marginTop, parseInt(curSeconds % 10)); }
addBall
The addBall function renders a sphere at a specified position.
The addBall function takes three parameters, the x coordinate of the sphere, the y coordinate and the number.
Traversing through all the numbers here, if the ball is 1, it needs to be drawn at that location and added to the balls.
function addBall(x, y, num) { digit[num].forEach((element, i) => { element.forEach((item, j) => { let aBall = {}; if (item === 1) { aBall = { x: x + j * 2 * (radius + 1) + (radius + 1), y: y + i * 2 * (radius + 1) + (radius + 1), g: 1.5 + Math.random(), //acceleration vx: Math.pow(1, Math.ceil(Math.random() * 1000)) * 4, //Is the preceding paragraph  1 or 1? vy: 5, color: colors[Math.floor(Math.random() * colors.length)] }; } balls.push(aBall); }); }); }
aball is a small ball to be drawn on the screen. It receives seven parameters:
 x: x coordinates
 y: Y coordinates
 r: Radius
 g: Acceleration
 vx: xaxis velocity
 vy: yaxis velocity
 color:
Here we focus on the role of the three attributes of g, vx and vy. What we use here is junior high school physics knowledge  speed and acceleration.
ball = {x:512, y:100, r:20, g:1.5, vx:4, vy:0, color:'#058'}
Update Ball
After the ball has been drawn, it needs to be landed.
Comparing and traversing the array balls of small balls, let the x and y coordinates of each ball add the velocity on its own axis, and the y axis velocity vy add the acceleration of the ball. So there's a small ball landing effect.
balls.forEach(ball => { ball.x += ball.vx; ball.y += ball.vy; ball.vy += ball.g; });
Ground Detection
Or in an array traversed by balls.
How do you know if the ball has landed?
If the yaxis coordinates of the sphere are greater than or equal to the height of the screen minus the radius of the sphere, then the sphere has touched the bottom. There needs to be a rebound effect.
When rebounding, there are resistance coefficients affected by air resistance.
Updating the y coordinates of the ball and the velocity of the y axis will give the ball a rebound effect.
if (ball.y >= windowHeight  radius) { ball.y = windowHeight  radius; ball.vy = ball.vy * 0.6; }
After running this program line for a period of time, you will find a special carton. This is because we have been adding balls and not deleting them.
console.log(balls.length)
When updating the balls, printing the length of balls will find that it keeps increasing, no matter how much memory your computer has, it will eventually be occupied, so you have to limit the length of the balls array.
optimization
The optimization technique here is to detect whether the ball is on the screen or not, and delete it if it is not on the screen.
let cnt = 0; balls.forEach(ball => { if (ball.x + radius > 0 && ball.x  radius < windowWidth) { balls[cnt++] = ball; } });
How to detect whether the ball is detected on the screen?
Or use the above method to detect landing.
The x coordinates of the sphere + the radius of the sphere > 0 and the X coordinates of the sphere  the radius of the sphere < the radius of the canvas, indicating that the sphere is inside the canvas.
Use cnt to count and place the required balls in front of balls
So the former CNT balls are also in the canvas, just delete the ball after cnt.
while (balls.length > Math.min(300, cnt)) { balls.pop(); }
Math.min (300, cnt) means that if cnt > 300, take 300, otherwise take cnt.
Its function is to control the number of effects on the screen.
summary
The greatest benefit of doing this animation is:
 Drawing Numbers Using Lattice System
 The ball landing is a simple original physical knowledge.
 Ball landing detection method