上周开始利用闲暇时间看html5 canvas技术。觉得非常好玩。就利用 canvas 做了一个简陋的钟表。源码非常简单,但是在制作的过程中,进入的误区却不少,浪费了很多时间。先上源码,然后在说说我走的岔路。
源码是基于 require.js 去写的,可以去 官网 了解 require.js 的详细资料。
1 define(function(){ 2 function T_clock(options){ 3 this.container = options.container || document.body; 4 if(!document.createElement('canvas').getContext){ 5 alert('当前浏览器不支持canvas!'); 6 return; 7 } 8 this.init(); 9 }; 10 var cfg = { 11 bg:'#ffaa77', 12 bg_rbga:'rgba(255,170,119,1)', 13 outCircleLen:99, 14 innerCircleLen:94, 15 minLen:65, 16 secLen:75, 17 hourLen:55, 18 ctx:undefined 19 }; 20 T_clock.prototype.init = function(){ 21 var cv = document.createElement('canvas'); 22 this.container.appendChild(cv); 23 cv.height = 600; 24 cv.width = 800; 25 cv.style.backgroundColor = cfg.bg; 26 if(cv.getContext){ 27 cfg.ctx = cv.getContext('2d'); 28 } 29 setInterval(function(){ 30 cfg.ctx.clearRect(0,0,800,600); 31 cfg.ctx.beginPath(); 32 cfg.ctx.lineWidth = 1; 33 cfg.ctx.arc(100,100,cfg.outCircleLen,0,2*Math.PI,false); 34 cfg.ctx.moveTo(100 + cfg.innerCircleLen,100); 35 cfg.ctx.arc(100,100,94,0,2*Math.PI,false); 36 37 cfg.ctx.font = 'bold 14px 宋体'; 38 cfg.ctx.textAlign = 'center'; 39 cfg.ctx.textBaseline = 'middle'; 40 var numR = 76,x,y,arc; 41 for(var i=1,arc=-Math.PI/3;i<13;i++,arc+= Math.PI/6){ 42 x = 100 + numR * Math.cos(arc); 43 y = 100 + numR * Math.sin(arc); 44 cfg.ctx.fillText(i,x,y); 45 } 46 for(i=0,arc=-Math.PI/2; i<60; i++,arc+=Math.PI/30){ 47 x = 100 + 94 * Math.cos(arc); 48 y = 100 + 94 * Math.sin(arc); 49 cfg.ctx.moveTo(x,y); 50 if(i % 5 == 0){ 51 x = 100 + (94 - 10) * Math.cos(arc); 52 y = 100 + (94 - 10) * Math.sin(arc); 53 } 54 else{ 55 x = 100 + (94 - 5) * Math.cos(arc); 56 y = 100 + (94 - 5) * Math.sin(arc); 57 } 58 cfg.ctx.lineTo(x,y); 59 } 60 cfg.ctx.closePath(); 61 cfg.ctx.stroke(); 62 63 var d = new Date(); 64 var sec = d.getSeconds(); 65 var min = d.getMinutes(); 66 var hour = d.getHours(); 67 var sec_angle = - Math.PI * sec / 30 + Math.PI; 68 69 cfg.ctx.beginPath(); 70 cfg.ctx.strokeStyle = '#F00'; 71 cfg.ctx.lineWidth = 1; 72 cfg.ctx.moveTo(100,100); 73 cfg.ctx.lineTo(100 + cfg.secLen * Math.sin(sec_angle),100 + cfg.secLen * Math.cos(sec_angle)); 74 cfg.ctx.closePath(); 75 cfg.ctx.stroke(); 76 77 cfg.ctx.beginPath(); 78 cfg.ctx.strokeStyle = '#555'; 79 cfg.ctx.lineWidth = 2; 80 cfg.ctx.moveTo(100,100); 81 var min_angle = - Math.PI * min / 30 + Math.PI - Math.PI * sec / 1800; 82 cfg.ctx.lineTo(100 + cfg.minLen * Math.sin(min_angle),100 + cfg.minLen * Math.cos(min_angle)); 83 cfg.ctx.closePath(); 84 cfg.ctx.stroke(); 85 86 cfg.ctx.beginPath(); 87 cfg.ctx.strokeStyle = '#000'; 88 cfg.ctx.lineWidth = 2; 89 cfg.ctx.moveTo(100,100); 90 var hour_angle = - Math.PI * hour / 6 + Math.PI - Math.PI * min / 360; 91 cfg.ctx.lineTo(100 + cfg.hourLen * Math.sin(hour_angle),100 + cfg.hourLen * Math.cos(hour_angle)); 92 cfg.ctx.closePath(); 93 cfg.ctx.stroke(); 94 },1000); 95 }; 96 97 return T_clock; 98 })
1 require(['../../js/require/config.js'],function(cfg){ 2 require(['h5/L_canvas'],function(Canvas){ 3 new Canvas({}); 4 }); 5 })
上效果图;
误区一:错误的理解 canvas 中的每一个图(画的每一个元素)都是一个单独的对象,可以自己销毁(擦除)自己。其实不是这样的,canvas 的 context 对象只提供了一个 clearRect 方法去清空指定区域的内容。
误区二:在一个钟表里,只有指针是动的,钟表的圆盘及数字是不动的。于是我就想在做指针动画的时候,不清除钟表的圆盘和数字,只是清除指针重画指针来实现这样的效果。期间我试了很多办法都不行。最典型的就是用了 canvas 的这个属性 globalCompositeOperation, 通过用背景色重画动画的上一个动作,用于擦除上一个动画,效果非常的莫名其妙,推测应该是 Math 对象的一些运算结果都不是精确值导致的。最后我只能在每次心跳时,清空画布重画钟表的圆盘和数字来实现动画效果;
误区三:每画一个元素,如果样式和下一个原色的样式不一样,都要单独设置元素的样式,并且要嵌在context.beginPah,context.closePath()内部,每调用closePath方法,都要调用Stroke或者fill方法把元素画出来。否则画布不会显示的。参看上传的第一块代码。
A pure heart will go far.