canvas 实现自定义钟表

2019-01-17 11:02:30 浏览数 (3)

参考博客: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>

0 人点赞