参考博客:https://www.cnblogs.com/liugang-vip/p/3557983.html
基于此博客自己实现的效果如下:修改了部分细节。
总结:
1. canvas的使用方法见 http://www.w3school.com.cn/tags/html_ref_canvas.asp
2. 特别需要注意的是画出指针以后如果要设置其样式,需要在restore()方法执行之前,因为在restore之后前面translate方法设置的圆心已经不起作用了。即:
代码语言:javascript复制//画秒针 最长
context.save();
context.lineWidth = 3;
context.strokeStyle = "#f00";
context.translate(250,250); //--------注意这里-----------
context.rotate(second*6*Math.PI/180);
context.beginPath();
context.moveTo(0,-185);
context.lineTo(0,20); //从右往左画
context.stroke();
context.closePath();
// context.restore(); //不能写在这里
//秒针装饰
context.beginPath();
context.strokeStyle="#f00";
context.arc(0,-130,3,0,360,false);//这里可以用0,-130的前提是上面以250,250为圆心
context.fillStyle="#fff"; //填充颜色
context.fill(); //填充
context.stroke();
context.closePath();
context.restore();
如上面代码所示,当画出秒针后如果执行了context.restore()方法,translate()方法就不起作用了,即原点不再是(250,250)。进行秒针装饰时在arc()方法中用(0,-130)坐标就不会得到效果,因为原点已经恢复为屏幕本来的原点(左上角)。
解决办法有两个:
① 注释context.restore()方法,装饰完成后再执行;
② 改arc()方法的坐标,以坐标原点在左上角来计算要画的装饰圆圈的坐标位置。这里将0,-130替换为250,120。
建议用第一种。 (时针、分针同理)
3. 需要特别理解的方法:restore、beginpath、closepath
每进行一次绘制都要以beginpath开始,以closepath结束。 一次完整的绘制可以看成是一条路径path,比如一个圆,一条线段。
在设置好圆心,进行旋转操作时用到了context.translate(250,250); context.rotate(second*6*Math.PI/180); 两个方法,但是在restore方法执行后会失去作用。
表示并不太明白w3school给出的解释,如下图:
完整代码:
代码语言:javascript复制<doctype html>
<head>
<meta charset="utf-8">
<title>lmz 时钟</title>
<style type="text/css">
</style>
</head>
<body>
<canvas width="500" height="500" style="background:yellow; display:block;" id="clock">
您的浏览器当前版本不支持canvas表签</canvas>
<script>
//获取画布DOM
var canvas = document.getElementById('clock');
//设置绘图环境
var context = canvas.getContext('2d');
function drawClock(hour, minute, second){
//-------画表盘------------------------------------------------
context.beginPath(); //画笔开始,开始绘制一条路径
context.lineWidth = 5; //设置画笔的线宽
context.strokeStyle = "blue";//设置画笔的颜色
context.arc(250,250,200,0,360,false);//绘制圆:坐标250,250 半径200 整个圆360度 false表示顺时针
context.stroke(); //执行绘图,绘制已定义的确切的路径
context.closePath(); //结束画布,该路径绘制结束
//-------画刻度:分为小时刻度、分针刻度-------------------------
//先画小时刻度,共12个
for (var i = 1; i <= 12; i ) {
context.save(); //设置旋转环境 保存当前环境的状态
//设置绘制时针刻度时画笔的样式
context.lineWidth=7;
context.strokeStyle="#000";
context.translate(250,250); //重新映射画布上的 (0,0) 位置,用于旋转
context.rotate(i*30*Math.PI/180); //设置旋转角度:每次旋转30度,但要转换成弧度。(因为每次旋转画完一个刻度后,执行restore方法,又回到了原来的地方,所以这里每次旋转要乘以i)
context.beginPath();
context.moveTo(0,-170); //画线,从(0,-170)开始
context.lineTo(0,-190); //画线,画到终点(0,-190)————长度20,宽7的小矩形
context.stroke(); //绘图
context.closePath();
//----------------绘制文字-------------------
context.font="30px Georgia";
context.fillStyle="#f00";//红色字体
context.fillText(i.toString(),-10,-150);
context.restore(); //将旋转之后的元素放回原画布 / 返回之前保存过的路径状态和属性
};
//画分钟刻度,共60个
for (var i = 0; i < 60; i ) {
context.save();
context.lineWidth = 5; //绘制分针刻度时小一些
context.strokeStyle="#000";
context.translate(250,250);
context.rotate(i*6*Math.PI/180); //每小格是6度
context.beginPath();
context.moveTo(0,-180);
context.lineTo(0,-170); //从右往左画
context.stroke();
context.closePath();
context.restore();
};
//画时针 最短
context.save();
context.lineWidth = 7;
context.strokeStyle = "#000";
context.translate(250,250);
context.rotate(hour*30*Math.PI/180);
context.beginPath();
context.moveTo(0,-140);
context.lineTo(0,10); //从右往左画
context.stroke();
context.closePath();
//时针装饰
context.beginPath();
context.lineWidth = 4;
context.strokeStyle="#000";
context.arc(0,-120,6,0,360,false);
context.fillStyle="#fff"; //填充颜色
context.fill(); //填充
context.stroke();
context.closePath();
context.restore(); //----------
//画分针 稍微长
context.save();
context.lineWidth = 5;
context.strokeStyle = "#090";
context.translate(250,250);
context.rotate(minute*6*Math.PI/180);
context.beginPath();
context.moveTo(0,-160);
context.lineTo(0,15); //从右往左画
context.stroke();
context.closePath();
//分针装饰
context.beginPath();
context.lineWidth = 3;
context.strokeStyle="#090";
context.arc(0,-140,5,0,360,false);
context.fillStyle="#fff"; //填充颜色
context.fill(); //填充
context.stroke();
context.closePath();
context.restore();
//画秒针 最长
context.save();
context.lineWidth = 3;
context.strokeStyle = "#f00";
context.translate(250,250); //--------注意这里-----------
context.rotate(second*6*Math.PI/180);
context.beginPath();
context.moveTo(0,-185);
context.lineTo(0,20); //从右往左画
context.stroke();
context.closePath();
// context.restore(); //必须注释掉
//秒针装饰
context.beginPath();
context.strokeStyle="#f00";
context.arc(0,-130,4,0,360,false);
context.fillStyle="#fff"; //填充颜色
context.fill(); //填充
context.stroke();
context.closePath();
// context.restore(); //必须注释掉------因为后面还要装饰
//-----------指针美化-------------应该在绘制完就进行装饰,而不是最后统一装饰
//画出时针、分针、秒针的交叉点
context.beginPath();
context.strokeStyle="#f00";
context.arc(0,0,5,0,360,false); //交叉点为什么仍然是(0,0),因为上面的translate仍然起作用
context.fillStyle="#fff"; //填充颜色
context.fill(); //填充,相当于画一个实心圆
context.stroke();
context.closePath();
context.restore(); //装饰完才执行,否则translate就不起效果,这里arc就不能用(0,0)作为原点
}
//还要让指针动起来:
function startClock(){
var now = new Date(); //定义时间
var second = now.getSeconds(); //获取秒
var minute = now.getMinutes(); //
var hour = now.getHours();
//解决指针偏移问题,更加逼真————所谓的偏移其实就是把已经走过的秒换算成分、分换算成时,给加上去
hour = hour minute/60; //小时必须获取浮点类型,产生偏移(小时 分钟比)
minute = minute second/60;
//将24小时转换成12小时
hour = hour > 12 ? hour-12 : hour;
drawClock(hour,minute,second);
context.clearRect(0,0,500,500); //清除画布
this.drawClock(hour,minute,second); //通过参数,把获取的时间加到指针绘制上,指针就动起来了
}
setInterval(startClock, 1000);
</script>
</body>
</html>