使用<canvas>元素不是非常难,但需要一些基本的HTML和JavaScript知识。
今天我们来利用canvas API绘制一个时钟,先上图:
画图之前,先把思路捋一遍:首先分解一下这个时钟的图形,它是由表盘(圆形)和指针(直线)组成。
canvas中圆形与矩形差距很大,canvas并没有提供专门绘制圆形的方法,但可以绘制圆弧,将圆弧首尾相连得到圆形
arc( x , y , radius , 起始弧度 , 结束弧度 , 旋转方向)
x,y --- 圆心坐标
radius --- 半径
弧度和角度的关系 --- 弧度 = 角度*Math.PI/180
例:2π是360°(完整的圆形)
旋转方向 --- true:逆时针;false:顺时针(默认)
掌握画圆大法后,就可以着手施工了:
首先准备好画布
<canvas id="myClock" width="500" height="500"></canvas>
接着获取上下文对象
var canvas = document.getElementById('myClock'); var con = canvas.getContext('2d');
分解功能:
1.表盘上的刻度(60个表示秒的刻度,12个表示小时的刻度)
1.1 60个秒刻度-->360°/60-->6°一个小格
//定义原点和半径 var x = 250; var y = 250; var r = 150; con.moveTo(x,y); con.arc(x,y,r,0,6*Math.PI/180); con.moveTo(x,y); con.arc(x,y,r,6*Math.PI/180,12*Math.PI/180); con.stroke(); ……
先来做个小实验,以上代码片段将会得到这个图形
利用循环,将以上代码完善
//定义原点和半径 var x = 250; var y = 250; var r = 150; //绘制秒刻度开始 con.beginPath();//为了不影响其他绘图,加上起始路径 for (var i = 0; i < 60; i++) { con.moveTo(x, y); //以圆心为起点 con.arc(x, y, r, 6 * i * Math.PI / 180, 6 * (i + 1) * Math.PI / 180);//绘制一段6°的圆弧 } con.closePath(); //为了不影响其他绘图,加上起始路径 con.stroke();
此刻,得到如下图形
怎么看怎么不像表盘咧?!为了达到秒刻度的效果,只需在上面覆盖一个较小的白色实心圆形即可
//较小的白色圆盘 con.beginPath(); con.moveTo(x,y); con.arc(x,y,0.95*r,0,2*Math.PI); con.closePath(); con.fillStyle = '#fff';//填充图形背景色 con.fill(); //实心圆
现在看上去,表盘的雏形算是出来了。
同样的步骤,将小时刻度也画出来,为了区分小时刻度和秒刻度,可以加粗小时刻度的线条
1.2 12个小时刻度-->360°/12-->30°一个大格
con.beginPath();//为了不影响其他绘图,加上起始路径 con.lineWidth = 4; //加粗小时刻度 for(var i = 0;i<12;i++){ con.moveTo(x,y); con.arc(x,y,r,30*i*Math.PI/180,30*(i+1)*Math.PI/180); } con.closePath(); //为了不影响其他绘图,加上起始路径 con.stroke();
最后,再叠加一个较小的白色实心圆心,表盘就画完了(最难的部分也搞定了)
con.fillStyle = '#fff'; con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.85 * r, 0, 2 * Math.PI); con.closePath(); con.fill();
总得来说,画表盘就和化妆一样,需要层层叠加
2.时、分、秒针
//注意:考虑到针要以圆心为中心旋转 con.lineWidth = 5; //定义时针线条的宽度 con.beginPath(); con.moveTo(x,y); //还是以圆心为起点 con.arc(x,y,0.5*r,0,0);//此处半径即时针的长度 con.closePath(); con.stroke();
分针和秒针就不做赘述,修改lineWidth的值和圆弧的半径即可
3.让时钟走起来
如何让秒针隔一秒动一下呢?是不是很快想到这个方法--->setInterval()
…… //获取当前系统时间 var today = new Date(); var hh = today.getHours(); var mm = today.getMinutes(); var ss = today.getSeconds(); //时针对应的弧度 var hhVal = (-90 + hh * 30 + mm / 2)*Math.PI/180; //-90:canvas画圆的起始点在表盘的3个字,而时钟的起始点应在12个字。+mm/2:时针不会一直只在整点的位置,分针走30分钟,时针多走15° var mmVal = (-90 + mm * 6) * Math.PI / 180; var ssVal = (-90 + ss * 6) * Math.PI / 180; …… con.arc(x, y, 0.5 * r, hhVal, hhVal); …… //调用函数 setInterval(toDraw, 1000);
组合好代码后,时钟就能走起来了:(^-^)V
奉上完整代码:
HTML部分
<canvas id="myClock" width="500" height="500"></canvas> <p id="showDate"></p>
JavaScript部分
window.onload = function () { //获取上下文对象 var canvas = document.getElementById('myClock'); var con = canvas.getContext('2d'); //自定义函数---画表盘,针 function toDraw() { //定义原点和半径 var x = 250; var y = 250; var r = 150; //绘制秒刻度开始 con.beginPath(); for (var i = 0; i < 60; i++) { con.moveTo(x, y);//以圆心为起点 con.arc(x, y, r, 6 * i * Math.PI / 180, 6 * (i + 1) * Math.PI / 180);//绘制一段6°的圆弧 } con.closePath(); //为了不影响其他绘图,加上起始路径 con.stroke(); //较小的白色圆盘 con.fillStyle = '#fff'; con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.95 * r, 0, 2 * Math.PI); con.closePath(); con.fill(); //实心圆 //绘制秒刻度结束 //同理绘制小时刻度 con.beginPath(); con.lineWidth = 4; //加粗小时刻度 for (var i = 0; i < 12; i++) { con.moveTo(x, y); con.arc(x, y, r, 30 * i * Math.PI / 180, 30 * (i + 1) * Math.PI / 180); } con.closePath(); //为了不影响其他绘图,加上起始路径 con.stroke(); //较小的白色圆盘 con.fillStyle = '#fff'; con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.85 * r, 0, 2 * Math.PI); con.closePath(); con.fill(); //绘制小时刻度结束 //获取当前系统时间 var today = new Date(); var hh = today.getHours(); var mm = today.getMinutes(); var ss = today.getSeconds(); document.getElementById('showDate').innerHTML = hh+':'+mm+':'+ss; //时针对应的弧度 var hhVal = (-90 + hh * 30 + mm / 2) * Math.PI / 180; var mmVal = (-90 + mm * 6) * Math.PI / 180; var ssVal = (-90 + ss * 6) * Math.PI / 180; //开始绘制时、分、秒针(注意:考虑到针要以原点为中心旋转) con.lineWidth = 5; //时针 con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.5 * r, hhVal, hhVal); con.closePath(); con.stroke(); con.lineWidth = 3; //分针 con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.65 * r, mmVal, mmVal); con.closePath(); con.stroke(); con.lineWidth = 1; //秒针 con.beginPath(); con.moveTo(x, y); con.arc(x, y, 0.8 * r, ssVal, ssVal); con.closePath(); con.stroke(); } //每隔1秒调用一次函数 setInterval(toDraw, 1000); }