HTML5 Canvas笔记 -- 1

     闲话少叙,今天准备把HTML5 Canvas相关学习笔记记录下来。

     开题第一篇,这里讲讲如何用JS在Canvas上绘制一个钟表。

     如今大部分浏览器都支持Canvas元素,如果不确定,可以用语句 document.createElement("canvas").getContext("2d"); 检测一下,不支持的话会抛出异常。

     

     HTML代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="canvasClock.js" defer="defer"></script>
</head>
<body>
<canvas id="canvasClock" width="600" height="300">Canvas not supported!</canvas>
</body>
</html>

     HTML代码不做介绍。Canvas元素尺寸我们设置为600*300。(关于Canvas的尺寸,分为"Canvas元素尺寸"和"绘制表面的尺寸",在Canvas标签中指明尺寸,是同时对这两个尺寸都生效的。若在CSS中指明宽高,其对绘制表面尺寸是无效的。)

     绘制钟表过程中,首先,我们定义一个Clock对象,包含一些属性和方法,使用setTimeout或setInterval调用绘制钟表函数。流程比较简单。

     JS代码在这里:

     

/**
 * js for canvasClock
 */
 
 
 var canvasClock = document.getElementById("canvasClock");
 var canvasContext = canvasClock.getContext("2d");
 canvasClock.style.background="#98FB98";
 
 function Clock(splitNums,context){
 	this.splitNums = splitNums;
 	this.context = context;
 	this.marginTopBottom = 20; 
 	this.centerPosX = this.context.canvas.width/2;
 	this.centerPosY = this.context.canvas.height/2;
 	this.surfaceRadius = Math.floor((this.context.canvas.height-2*this.marginTopBottom)/2);
 	this.innerCircieRadius = Math.floor(this.surfaceRadius/15);
 	this.handCircleRadius = Math.floor(this.surfaceRadius/30);
 	this.noValue;
 }
 
 Clock.prototype={
 	constructor:Clock,
 	drawSurface:function(){
 		this.context.beginPath();
        this.context.strokeStyle = "black";
 		this.context.arc(this.centerPosX,this.centerPosY,
 		this.surfaceRadius,0,Math.PI*2,true);
 		this.context.stroke();
 	},
 	drawInnerCircle:function(){
 		this.context.beginPath();
 		this.context.fillStyle = "red";
 		this.context.arc(this.centerPosX,this.centerPosY,
 		this.innerCircieRadius,0,Math.PI*2,true);
 		this.context.fill();
 	},
 	drawIndexLine:function(){
 		this.context.beginPath();
        this.context.strokeStyle = "black";
 		var totalIndex = this.splitNums*5;
 		var angleInterval = Math.PI*2/totalIndex;
 		var shotIndexL = this.surfaceRadius/16;
 		var longIndexL = this.surfaceRadius/9;
 		for(var i=0;i<totalIndex;i++){
 			if(i%5==0){
 				this.context.moveTo(
 				this.centerPosX+this.surfaceRadius*Math.cos(angleInterval*i),
 				this.centerPosY-this.surfaceRadius*Math.sin(angleInterval*i));
 				this.context.lineTo(
 				this.centerPosX+(this.surfaceRadius-longIndexL)*Math.cos(angleInterval*i),
 				this.centerPosY-(this.surfaceRadius-longIndexL)*Math.sin(angleInterval*i)
 				);
 			}else{
 				this.context.moveTo(
 				this.centerPosX+this.surfaceRadius*Math.cos(angleInterval*i),
 				this.centerPosY-this.surfaceRadius*Math.sin(angleInterval*i));
 				this.context.lineTo(
 				this.centerPosX+(this.surfaceRadius-shotIndexL)*Math.cos(angleInterval*i),
 				this.centerPosY-(this.surfaceRadius-shotIndexL)*Math.sin(angleInterval*i)
 				)
 			}
 		}
 		this.context.stroke();
 	},
 	drawHands:function(){
 		var date = new Date();
 		var hour = date.getHours(),
 		    min = date.getMinutes(),
 		    sec = date.getSeconds();
        this.drawHand(hour,min,sec,0);
        this.drawHand(0,min,sec,1);
        this.drawHand(0,0,sec,2);
 	},
 	drawHand:function(hour,minute,second,timeMark){
 		//time: hour or minute or second
 		//timeMark: 0-hour, 1-minute, 2-second
 		var handLength = 10,
 		    longIndexL = this.surfaceRadius/9;
 		var totalIndex = this.splitNums*5;
 		var angleInterval = Math.PI*2/totalIndex;
 		var endPosX=0,endPosY=0;
 		
 		this.context.beginPath();
 		this.context.strokeStyle="#8B1A1A";
 		this.context.fillStyle="#8B1A1A";
 		this.context.moveTo(this.centerPosX,this.centerPosY);
 		
 		switch(timeMark){
 			case 0: handLength=this.surfaceRadius-longIndexL*3-3;
 			        endPosX = this.centerPosX+handLength*Math.sin(
 		            hour*(angleInterval*5)+
 		            minute*(Math.PI*2/this.splitNums)/60+
 		            second*(Math.PI*2/this.splitNums)/3600);
 		            endPosY = this.centerPosY-handLength*Math.cos(
 		            hour*(angleInterval*5)+
 		            minute*(Math.PI*2/this.splitNums)/60+
 		            second*(Math.PI*2/this.splitNums)/3600);
 			break;
 			case 1: handLength=this.surfaceRadius-longIndexL*2-3;
 			        endPosX=this.centerPosX+handLength*Math.sin(
 		            minute*angleInterval+
 		            second*angleInterval/60);
 	          	    endPosY=this.centerPosY-handLength*Math.cos(
 		            minute*angleInterval+
 		            second*angleInterval/60);
 			break;
 			case 2: handLength=this.surfaceRadius-longIndexL-3;
 	    	        endPosX=this.centerPosX+handLength*Math.sin(
 		            second*angleInterval);
 		            endPosY=this.centerPosY-handLength*Math.cos(
 		            second*angleInterval);
 			break;
 			default: break;
 		}
 		this.context.lineTo(endPosX,endPosY);
 		this.context.stroke();
 		this.context.beginPath();
 		this.context.arc(endPosX,endPosY,
 		            this.handCircleRadius,0,Math.PI*2,true);
 		this.context.fill();
 		
 	},
 	drawNumbers:function() {
    
 		var totalIndex = this.splitNums*5;
 		var angleInterval = Math.PI*2/totalIndex;
 		var longIndexL = this.surfaceRadius/5;
 		var numWidth = 0, numHeight=0;
 	    
 		this.context.fillStyle = "black";
 		for(var i=0;i<this.splitNums;i++){
 			numWidth = this.context.measureText(String(i)).width;
 			this.context.fillText(String(i),
 			this.centerPosX+(this.surfaceRadius-longIndexL)*Math.sin(angleInterval*5*i)
 			-numWidth/2,
 			this.centerPosY-(this.surfaceRadius-longIndexL)*Math.cos(angleInterval*5*i)
 			+15/3);
 		}
 	}
 }
 
 var clock = new Clock(12,canvasContext);
 canvasContext.font = "15px Arial";
 function drawClock() {
 	canvasContext.clearRect(0,0,canvasContext.canvas.width,canvasContext.canvas.height);
	clock.drawSurface();
	clock.drawIndexLine();
	clock.drawNumbers();
	clock.drawHands();
	clock.drawInnerCircle();
	loop = setTimeout(drawClock, 1000);
}
 loop = setTimeout(drawClock, 0);
 
     个人倾向使用setTimeout方法,保证执行完一个canvas绘制流程再进行下一个。

      另外使用fillText()方法绘制文字时,注意是把文字的左下角放在绘制点,所以在绘制钟表数字时,要把数字向左下移动(文字宽度/2,文字高度/2),保证数字中心在绘制点上,看起来比较美观。

      Clock对象中,splitNums意为表盘显示12小时或24个小时,显示24个小时时,由于秒数、分数都从Date()获取,范围都是0-59,也就只能走表盘的一半,但计时是对的。想改善的同学可以自行优化(使秒数、分数范围在0-119即可)。

      效果图:

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值