Front words
As mentioned earlier canvas particle clock In this paper, canvas adaptive circular clock rendering is introduced in detail.
Effect demonstration
The effect of the final adaptive circular clock is as follows
functional analysis
Next, we will analyze the function of the circular clock.
Static Background
For clocks, the background remains the same, including the outer clock frame, the inner dots and numbers, and the fixed buttons at the center.
Dynamic Clock
The dynamic state of tense is reflected in the change of seconds, minutes and clocks with the current time. Turn on a timer that changes once a second. The second hand is consistent with the number of seconds in the current time. The change of the minute hand is related to the number of seconds and minutes in the current time. The change of the hour hand is related to the number of minutes and hours in the current time.
[3] Adaptation
In order to achieve clock adaptation, it is necessary to correlate the dimension drawing inside the clock with the overall width of the clock, instead of setting it to a fixed value.
Here's a simple analysis of the clock

Static clock
To achieve a static clock background, including the outer clock frame, the inner circle and digital, and the fixed button of the center point, the radius is 100 based on the clock size of 200*200, and the center point is adjusted to (0,0) by translat ().
[Initial settings]
Because R and cxt.lineWidth are often used outside, they are saved as variables.
var cxt = drawing.getContext('2d'); var W = drawing.width = 400; var H = drawing.height = 400; var R = W / 2; var cw = cxt.lineWidth = 0.1*R;
[outer clock frame]
In order to keep the outer clock frame from exceeding the canvas area, the radius is set to R-cw/2, and the width of the line is proportional to the radius.
cxt.translate(R,R); cxt.beginPath(); cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke();
[Inner Number]
Draw 12 digits at 0.8R-cw/2 from the center of the circle to indicate the current number of minutes. The font size of the digits is proportional to the radius.
cxt.beginPath(); cxt.font = 0.2 * R + 'px Song style'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); }
[Inner Origin]
At 0.9R-cw/2 from the center of the circle, 60 circles are drawn to represent the current number of seconds. When the current number of seconds is at the same angle as the number of minutes, it is expressed as a large circle (radius is cx/5), otherwise it is a small circle (radius is cx/8).
cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); }
Fixed Button for Drawing Center Point
cxt.beginPath();
cxt.arc(0,0,cw/3,0,2*Math.PI,false);
cxt.fill();
Finally, the static background is encapsulated as the function drawStatics(), which is coded as follows
<canvas id="drawing" style="border:1px solid black"></canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var cxt = drawing.getContext('2d'); var W = drawing.width = 200; var H = drawing.height = 200; var R = W / 2; var cw = cxt.lineWidth = 0.1*R; function drawStatics(){ cxt.translate(R,R); cxt.beginPath(); cxt.lineWidth = 0.1*R; cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke(); cxt.beginPath(); cxt.font = 0.2 * R + 'px Song style'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); } cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); } cxt.beginPath(); cxt.arc(0,0,cw/3,0,2*Math.PI,false); cxt.fill(); } function draw(){ cxt.clearRect(0,0,W,H); drawStatics(); } draw(); } </script>
The static effect is as follows
Dynamic effect
Next, we will divide it into hour hand, minute hand and second hand for dynamic effect.
[second hand]
Turn on a timer that changes once a second and keep the second hand in line with the number of seconds in the current time.
function drawSecond(second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * second; cxt.rotate(radius); cxt.lineWidth = 2; cxt.moveTo(0,cw*2); cxt.lineTo(0,-0.8*R); cxt.strokeStyle = 'red'; cxt.stroke(); cxt.restore(); }
[minute hand]
The change of minute hand is related to the current number of seconds and minutes.
function drawMinute(minute,second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * minute; var sRaiuds = 2*Math.PI/60/60 * second; cxt.rotate(radius + sRaiuds); cxt.lineWidth = 4; cxt.lineCap = 'round'; cxt.moveTo(0,cw); cxt.lineTo(0,-(0.8*R - cw/2)); cxt.stroke(); cxt.restore(); }
[hour hand]
The change of clockwise is related to the current number of minutes and hours.
function drawHour(hour,minute){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/12 * hour; var mRaiuds = 2*Math.PI/12/60 * minute; cxt.rotate(radius + mRaiuds); cxt.lineWidth = 6; cxt.lineCap = 'round'; cxt.moveTo(0,cw/2); cxt.lineTo(0,-(0.8*R - cw*2)); cxt.stroke(); cxt.restore(); }
Complete code
Now, the code needs to be adjusted because canvas is drawn in code order, so the code order should be static background (clock frame, dots and numbers) - > dynamic effect (seconds, minutes, clocks) - > Central button.
Therefore, it is necessary to separate the center-buttoned code from the static background function drawStatics() and rearrange the code order.
Because of the error of the browser's timer, it is not appropriate to set the timer to 1000ms. Because of system carton and other reasons, it may skip a certain effect. Therefore, it is necessary to set the timer to 500ms.
The final complete code is as follows
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <canvas id="drawing"></canvas> <script> var drawing = document.getElementById('drawing'); if(drawing.getContext){ var cxt = drawing.getContext('2d'); var W = drawing.width = 200; var H = drawing.height = 200; var R = W / 2; var cw = cxt.lineWidth = 0.1*R; function drawStatics(){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); cxt.lineWidth = 0.1*R; cxt.arc(0,0,R-cw/2,0,2*Math.PI,false); cxt.stroke(); cxt.beginPath(); cxt.font = 0.2 * R + 'px Song style'; cxt.textAlign = 'center'; cxt.textBaseline = 'middle'; var r1 = 0.8*R - cw/2; for(var i = 12; i > 0; i--){ var radius = 2*Math.PI/12 * i + 1.5*Math.PI; var x = Math.cos(radius) * r1; var y = Math.sin(radius) * r1; cxt.fillText(i,x,y); } cxt.beginPath(); var r2 = 0.9*R - cw/2; for(var i = 0; i < 60; i++){ var radius = 2*Math.PI/60*i + 1.5*Math.PI; var x = Math.cos(radius) * r2; var y = Math.sin(radius) * r2; cxt.beginPath(); if(i%5 === 0){ cxt.arc(x,y,cw/5,0,2*Math.PI,false); }else{ cxt.arc(x,y,cw/8,0,2*Math.PI,false); } cxt.fill(); } cxt.restore(); } function drawDot(){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); cxt.arc(0,0,cw/3,0,2*Math.PI,false);
cxt.fillStyle = '#fff';
cxt.fill(); cxt.restore(); } function drawSecond(second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * second; cxt.rotate(radius); cxt.lineWidth = 2; cxt.moveTo(0,cw*2); cxt.lineTo(0,-0.8*R); cxt.strokeStyle = 'red'; cxt.stroke(); cxt.restore(); } function drawMinute(minute,second){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/60 * minute; var sRaiuds = 2*Math.PI/60/60 * second; cxt.rotate(radius + sRaiuds); cxt.lineWidth = 4; cxt.lineCap = 'round'; cxt.moveTo(0,cw); cxt.lineTo(0,-(0.8*R - cw/2)); cxt.stroke(); cxt.restore(); } function drawHour(hour,minute){ cxt.save(); cxt.translate(R,R); cxt.beginPath(); var radius = 2*Math.PI/12 * hour; var mRaiuds = 2*Math.PI/12/60 * minute; cxt.rotate(radius + mRaiuds); cxt.lineWidth = 6; cxt.lineCap = 'round'; cxt.moveTo(0,cw/2); cxt.lineTo(0,-(0.8*R - cw*2)); cxt.stroke(); cxt.restore(); } function draw(){ cxt.clearRect(0,0,W,H); drawStatics(); var now = new Date(); drawHour(now.getHours(),now.getMinutes()); drawMinute(now.getMinutes(),now.getSeconds()); drawSecond(now.getSeconds()); drawDot(); } draw(); setInterval(draw,500); } </script> </body> </html>