
一、前期准备
1. HTML中准备一个容器存放画布,并为其设置width,height。
1 | < div > |
2 | < canvas id = "clock" height = "200px" width = "200px" ></ canvas > |
3 | </ div > |
1 | let dom = document.getElementById( 'clock' ); //获取画布 |
2 | let ctx = dom.getContext( '2d' ); //获取canvas上下文 |
3 | let width = ctx.canvas.width; //获取预先设置的canvas画布宽度 |
4 | let height = ctx.canvas.height; //获取预先设置的canvas画布高度 |
5 | let r = width / 2; //定义半径,为后续绘制圆形图案做准备 |
1 | function drawBackground() { |
2 | ctx.save(); //每次开始前都要保存当前画布状态,以免移动画布影响后续绘制 |
3 | ctx.translate(r, r); //将起始点位置移动至圆心 |
4 | ctx.beginPath(); //每次开始绘制前必须开始一条路径 |
5 | ctx.lineWidth = 10 ; //设置绘制线的宽度 |
6 | ctx.arc(0, 0, r - ctx.lineWidth / 2, 0, 2 * Math.PI, false ); //画一个整圆 |
7 | ctx.stroke(); //对圆进行描边 |
8 | } |
绘制前,首先看一下每个小时刻度(1,2,3,...12)在所在容器的坐标确定



所以,每一刻度点的
X = r*cos(角度)====>X = Math.cos(rad) * r
Y = r*sin(角度)====>Y = Math.sin(rad) * r
但是 Math.cos(rad)与 Math.sin(rad) 中的角度都要求是弧度,弧度与角度的转换见上图,即圆周360度 = 弧度 2*Math.PI
所以,时钟一圈共有12个小时,那个每小时所占的弧度为:rad = 2 * Math.PI / 12
时钟一圈共有60的分钟,那么每分钟所占的弧度为:rad = 2 * Math.PI / 60
01 | var hourNumbers = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]; //定义标记小时的数组 |
02 | hourNumbers.map( function (number, i) { //遍历 取出各刻度及所在索引 |
03 | //每个刻度所占弧度为索引乘以一小时的弧度,即 1点钟30度,2点钟60度,以此类推.. |
04 | var rad = 2 * Math.PI / 12 * i; |
05 | var x = Math.cos(rad) * (r - 30 * rem); |
06 | var y = Math.sin(rad) * (r - 30 * rem); //确定各刻度点 X、Y坐标 |
07 | ctx.textAlign = 'center' ; //绘制的刻度在整个画布左右居中 |
08 | ctx.textBaseline = 'middle' ; //同理,上下居中 |
09 | ctx.font = 18 * rem + "px Arial" ; //设置显示刻度的数字 1,2,3.. 的字体及字号 |
10 | ctx.fillText(number, x, y) //绘制文字 |
11 | }); |
绘制后的效果图如下:

四、绘制时针、分针、秒针及圆心点
绘制时针与分针原理为 绘制直线
主要用到的方法为:ctx.rotate()、ctx.moveTo()、ctx.lineTo()、ctx.lineCap
01 | function drawHour(hour, minute) { |
02 | ctx.save(); //存储画布状态,前面提到过 |
03 | ctx.beginPath(); //开始一条路径 |
04 | var rad = 2 * Math.PI / 12 * hour; //每小时旋转的弧度 |
05 | var mrad = 2 * Math.PI / 12 / 60 * minute; //每分钟旋转的弧度 |
06 | ctx.rotate(rad + mrad); //旋转 |
07 | ctx.lineWidth = 6; //设置宽度 |
08 | ctx.moveTo(0, 10); //移动起始点至(0,10) |
09 | ctx.lineTo(0, -r / 2); //从起始点绘制到(0,r/2)点,负号表示方向向上 |
10 | ctx.lineCap = 'round' ; //设置结束线帽 |
11 | ctx.stroke(); //描边 |
12 | ctx.restore(); //将画布恢复到旋转之前状态 |
13 | } |

五、使时钟指针动起来
原理为获取当前时间 new Date(),设置定时器 setInterval(draw, 1000) 每隔一段时间更新绘制画布
01 | function draw() { |
02 | ctx.clearRect(0, 0, width, height); //重新绘制之前清除画布,否则状态叠加,页面显示如下图 |
03 | var now = new Date(); //获取当前时间 |
04 | var hour = now.getHours(); //当前小时 |
05 | var minute = now.getMinutes(); //当前分钟 |
06 | var second = now.getSeconds(); //当前秒数 |
07 | drawBackground(); //绘制圆盘背景 |
08 | drawHour(hour, minute); //绘制时针 |
09 | drawMinute(minute); //绘制分针 |
10 | drawSecond(second); //绘制秒针 |
11 | drawDot(); //绘制原点 |
12 | ctx.restore(); //回复画布状态 |
13 | } |
14 | setInterval(draw, 1000); //定时器执行整个绘画方法 |

上图为没有清除画布ctx.clearRect() 的效果,所以切记 一定要在绘制之前清除画布,重新画。
六、时钟出现了,且会自定更新。
