用HTML5制作数字时钟的教程


Posted in HTML / CSS onMay 11, 2015

用HTML5制作数字时钟的教程

就是这个数字时钟,当时觉得这个创意不错,但是也没去折腾。直到昨天同事又在网上看到这个案例,他觉得很酷炫,就跑过来问我,这个是怎么实现的,然后我大概想了一下实现方法后也来了点兴趣,就花了一点时间模仿做出来了一个。不同的是,岑安用的是div来做的。而我就是用canvas来实现的。用canvas来做性能方面会更好,因为就单单操控每个点的运动,用js控制dom的style属性跟用js控制canvas绘图相比性能方面肯定是有所欠缺的。

先上个我做的DEMO吧,然后再简述一下做这个的方法:   看DEMO请戳我 。

做这个思路很简单,就是通过字符串保存各个数字的位置: 
复制代码

XML/HTML Code复制内容到剪贴板
  1. var numData = [   
  2.             "1111/1001/1001/1001/1001/1001/1111", //0   
  3.             "0001/0001/0001/0001/0001/0001/0001", //1   
  4.             "1111/0001/0001/1111/1000/1000/1111", //2   
  5.             "1111/0001/0001/1111/0001/0001/1111", //3   
  6.             "1010/1010/1010/1111/0010/0010/0010", //4   
  7.             "1111/1000/1000/1111/0001/0001/1111", //5   
  8.             "1111/1000/1000/1111/1001/1001/1111", //6   
  9.             "1111/0001/0001/0001/0001/0001/0001", //7   
  10.             "1111/1001/1001/1111/1001/1001/1111", //8   
  11.             "1111/1001/1001/1111/0001/0001/1111", //9   
  12.             "0000/0000/0010/0000/0010/0000/0000", //:   
  13.         ]  

0代表没像素,1代表有像素,/是为了更好看些,就是分行嘛,简单说起来:比如0就是:

XML/HTML Code复制内容到剪贴板
  1.         1  1  1  1   
  2.   
  3. 1  0  0  1   

  4.   
  5. 1  0  0  1   

  6.   
  7. 1  0  0  1   

  8.   
  9. 1  0  0  1   

  10.   
  11. 1  0  0  1   

  12.   
  13. 1  1  1  1

       

这样就很清楚了吧。从0到9还有一个:号都用字符串表示好。

然后就写个粒子对象,也就是像素点:

XML/HTML Code复制内容到剪贴板
  1. var P_radius = 8,Gravity = 9.8;   
  2.         var Particle = function(){   
  3.             this.x = 0;   
  4.             this.y = 0;   
  5.             this.vx = 0;   
  6.             this.vy = 0;   
  7.             this.color = "";   
  8.             this.visible = false;   
  9.             this.drop = false;   
  10.         }   
  11.         Particle.prototype = {   
  12.             constructors:Particle,   
  13.             paint:function(){        //绘制自身   
  14.                 ctx.fillStyle = this.color;   
  15.                 ctx.beginPath();   
  16.                 ctx.arc(this.x,this.y,P_radius,0,2*Math.PI);   
  17.                 ctx.fill();   
  18.             },   
  19.             reset:function(x,y,color){        //重置   
  20.                 this.x = x;   
  21.                 this.y = y;   
  22.                 this.vx = 0;   
  23.                 this.vy = 0;   
  24.                 this.color = color;   
  25.                 this.visible = true;   
  26.                 this.drop = false;   
  27.             },   
  28.             isDrop:function(){        //落下   
  29.                 this.drop = true;   
  30.                 var vx = Math.random()*20+15   
  31.                 this.vx = Math.random()>=0.5?-vx : vx;   
  32.             },   
  33.             update:function(time){        //每一帧的动作   
  34.                 if(this.drop){   
  35.                     this.x += this.vx*time;   
  36.                     this.y += this.vy*time;   
  37.   
  38.                     var vy = this.vy+Gravity*time;   
  39.   
  40.                     if(this.y>=canvas.height-P_radius){   
  41.                         this.y = canvas.height-P_radius   
  42.                         vy = -vy*0.7;   
  43.                     }   
  44.   
  45.                     this.vy = vy;   
  46.   
  47.                     if(this.x<-P_radius||this.x>canvas.width+P_radius||this.y<-P_radius||this.y>canvas.height+P_radius){   
  48.                         this.visible = false;   
  49.                     }   
  50.                 }   
  51.             }   
  52.         }

      

  53.   

粒子对象的属性比较简单,就位置,速度,以及是否可视化。方法的话,paint是绘制方法,reset是重置(因为粒子要循环利用的,提升性能),isDrop是粒子落下方法,update就是每一帧更新粒子的动作,update中当粒子运动超出canvas的绘制区域时,就把它的可视化置为false,在粒子容器中保存起来等待下一次调用。

写好粒子对象后,就要考虑如何让粒子按照位置画上去,同时当粒子不需要用时能够让他做自由落体的动画了。

先画背景(也就是那没有像素的白点):

XML/HTML Code复制内容到剪贴板
  1. function drawBg(){   
  2.             var tx = (canvas.width-((P_radius*2+X_J)*4*8+7*xjg))/2;   
  3.             for(var i=0;i<8;i++){   
  4.                 var ty = (canvas.height-((P_radius+yjg)*6))/2;   
  5.                 for(var j=0;j<numData[0].length;j++){   
  6.                     var tt = numData[0].charAt(j);   
  7.                     if(tt==="/"){   
  8.                         ty+=yjg;   
  9.                     }else {   
  10.                         var x = tx+j%5*(P_radius*2+X_J),   
  11.                             y = ty;   
  12.                         bgctx.fillStyle = "#FFF";   
  13.                         bgctx.beginPath();   
  14.                         bgctx.arc(x,y,P_radius,0,2*Math.PI);   
  15.                         bgctx.fill();   
  16.                     }   
  17.                 }   
  18.                 tx+=xjg+4*(P_radius*2+X_J);   
  19.             }   
  20.         }   

先把背景画到一个离屏canvas中缓存起来,接下来每一帧重画的时候就不需要逻辑计算了,直接把那个离屏canvas画上去就行了。上面的逻辑应该不难理解,就是通过两个循环,循环8个数字,然后再对每个数字一个点一个点进行绘制,当遇到“/”时,就说明要换行了,把绘制的ty加个换行间隔,再把tx重置,再进行绘制。就这样,点就可以都画出来了。效果图如下:
用HTML5制作数字时钟的教程

背景画好了,就开始根据每一秒的时间,画数字像素吧。方法主要是这个:

XML/HTML Code复制内容到剪贴板
  1. function setTime(time){   
  2.             var h = time.getHours()+"",   
  3.                 m = time.getMinutes()+"",   
  4.                 s = time.getSeconds()+"";   
  5.             hh = h.length===1?"0"+h:h;   
  6.             mm = m.length===1?"0"+m:m;   
  7.             ss = s.length===1?"0"+s:s;   
  8.   
  9.             var nowdate = h+":"+m+":"+s;   
  10.             var tx = (canvas.width-((P_radius*2+X_J)*4*8+7*xjg))/2,color = "";   
  11.             for(var i=0;i<nowdate.length;i++){   
  12.                 var n = nowdate.charAt(i)===":"?10:parseInt(nowdate.charAt(i)),   
  13.                     text = numData[n];   
  14.   
  15.                 var ty = (canvas.height-((P_radius+yjg)*6))/2;   
  16.   
  17.                 switch(i){   
  18.                     case 0:color = "#4DCB74";break;   
  19.                     case 2:color = "#4062E0";break;   
  20.                     case 3:color = "#D65050";break;   
  21.                     case 5:color = "#4062E0";break;   
  22.                     case 6:color = "#797C17";break;   
  23.                 }   
  24.   
  25.                 for(var j=0;j<text.length;j++){   
  26.                     var tt = text.charAt(j);   
  27.                     if(tt==="/"){   
  28.                         ty+=yjg;   
  29.                     }else{   
  30.                         var x = tx+j%5*(P_radius*2+X_J),   
  31.                             y = ty,   
  32.                             pp = null,   
  33.                             usefullp = null;   
  34.                         particles.forEach(function(p){   
  35.                             if(p.visible&p.x===x&p.y===y){   
  36.                                 ppp = p;   
  37.                             }else if(!p.visible&usefullp===null){   
  38.                                 usefullp = p;   
  39.                             }   
  40.                         });   
  41.                         if(pp!==null&tt==="0"){   
  42.                             pp.isDrop();   
  43.                         }else if(pp===null&tt==="1"){   
  44.                             usefullp.reset(x , y , color);   
  45.                         }   
  46.                     }   
  47.                 }   
  48.                 tx+=xjg+4*(P_radius*2+X_J);   
  49.             }   
  50.         }  

原理也不难,也是跟上面画背景差不多,遍历所有点,然后根据当前时间的数字转换成的字符串来判断,当前点是否应该有像素,如果有像素就再判断当前这个点是否已经有粒子对象在了,如果已经有粒子对象在了,就直接跳出不处理,如果没有粒子对象在,就再粒子容器中找一个没有被使用的粒子reset到这个位置。还有一种情况,就是当前这个点是不应该有像素的,但是却有粒子,那就获取这个粒子,让这个粒子进行自由落体。

时间设置也写好了,就可以写舞台更新的代码了:

XML/HTML Code复制内容到剪贴板
  1. var timeCount_0 = 0,timeCount_1 = 0,particles = [];   
  2.         function initAnimate(){   
  3.             for(var i=0;i<200;i++){   
  4.                 var p = new Particle();   
  5.                 particles.push(p);   
  6.             }   
  7.   
  8.             timeCount_0 = new Date();   
  9.             timeCount_1 = new Date();   
  10.             drawBg();   
  11.             setTime(timeCount_0)   
  12.             animate();   
  13.         }   
  14.   
  15.         function animate(){   
  16.             ctx.clearRect(0,0,canvas.width,canvas.height);   
  17.             ctx.drawImage(bgcanvas,0,0);   
  18.   
  19.             var timeCount_2 = new Date();   
  20.   
  21.             if(timeCount_1-timeCount_0>=1000){   
  22.                 setTime(timeCount_1);   
  23.                 timeCount_0 = timeCount_1;   
  24.             }   
  25.   
  26.             particles.forEach(function(p){   
  27.                 if(p.visible){   
  28.                     p.update((timeCount_2-timeCount_1)/70);   
  29.                     p.paint();   
  30.                 }   
  31.             });   
  32.   
  33.             timeCount_1 = timeCount_2;   
  34.   
  35.             RAF(animate)   
  36.         }  

在initAnimate进行动画初始化,初始化也就是先实例化两百个粒子对象放到粒子容器中保存起来,再更新时间戳,缓存背景,设置当前时间,然后调用animate动画循环主体开始动画。

animate中的逻辑也很简单了,获取时间戳,如果两个时间戳之间的时间差大于或等于1秒,就进行setTime。而再下面的就是对粒子容器里的所有可视化的粒子进行遍历循环重绘了。
然后就做好啦:
用HTML5制作数字时钟的教程

个效果还是有很多可以优化的地方的,因为时钟和分钟都是动的比较少的,所以可以把这两个缓存起来,当没有动作的时候就直接将缓存数据画上去就行了,这样就可以减少舞台每一帧的绘图API调用量,肯定是能提高性能的。不过现在毕竟粒子不多,两三百个粒子对象也就够用了,如果不去做优化,动画也还是能很流畅的运行的。所以楼主就偷个小懒啦。

源码地址:https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/coolClock/index.html

HTML / CSS 相关文章推荐
关于box-sizing的全面理解
Jul 28 HTML / CSS
利用纯CSS3实现tab选项卡切换示例代码
Sep 21 HTML / CSS
css3 仿写阿里云水纹效果的示例代码
Feb 10 HTML / CSS
HTML5实现经典坦克大战坦克乱走还能发出一个子弹
Sep 02 HTML / CSS
HTML块级标签汇总(小篇)
Jul 13 HTML / CSS
使用html2canvas.js实现页面截图并显示或上传的示例代码
Dec 18 HTML / CSS
移动端Html5中百度地图的点击事件
Jan 31 HTML / CSS
Canvas图片分割效果的实现
Jul 29 HTML / CSS
html2canvas截图空白问题的解决
Mar 24 HTML / CSS
HTML中meta标签及Keywords
Apr 15 HTML / CSS
html5拖拽应用记录及注意点
May 27 HTML / CSS
HTML基础详解(下)
Oct 16 HTML / CSS
用HTML5 实现橡皮擦的涂抹效果的教程
May 11 #HTML / CSS
用HTML5中的Canvas结合公式绘制粒子运动的教程
May 08 #HTML / CSS
使用分层画布来优化HTML5渲染的教程
May 08 #HTML / CSS
简单介绍HTML5中的文件导入
May 08 #HTML / CSS
使用HTML5的Notification API制作web通知的教程
May 08 #HTML / CSS
利用HTML5中的Canvas绘制一张笑脸的教程
May 07 #HTML / CSS
HTML5实现获取地理位置信息并定位功能
Apr 25 #HTML / CSS
You might like
文章推荐系统(三)
2006/10/09 PHP
php REMOTE_ADDR之获取访客IP的代码
2008/04/22 PHP
PHP中将ip地址转成十进制数的两种实用方法
2013/08/15 PHP
php实现excel中rank函数功能的方法
2015/01/20 PHP
PHP中使用file_get_contents post数据代码例子
2015/02/13 PHP
php查询mysql大量数据造成内存不足的解决方法
2015/03/04 PHP
PHP实现的多维数组排序算法分析
2018/02/10 PHP
PHP预定义接口――Iterator用法示例
2020/06/05 PHP
基于Unit PNG Fix.js有时候在ie6下不正常的解决办法
2013/06/26 Javascript
什么是Node.js?Node.js详细介绍
2014/06/01 Javascript
jquery实现仿JqueryUi可拖动的DIV实例
2015/07/31 Javascript
JS实现跟随鼠标的链接文字提示框效果
2015/08/06 Javascript
JavaScript实现的Tween算法及缓冲特效实例代码
2015/11/03 Javascript
基于JavaScript代码实现自动生成表格
2016/06/15 Javascript
javascript 定时器工作原理分析
2016/12/03 Javascript
整理一些最近经常遇到的前端面试题
2017/04/25 Javascript
Node.js中的http请求客户端示例(request client)
2017/05/04 Javascript
详解vue.js的devtools安装
2017/05/26 Javascript
bootstrap daterangepicker双日历时间段选择控件详解
2017/06/15 Javascript
Angular4学习教程之HTML属性绑定的方法
2018/01/04 Javascript
Vue通过ref父子组件拿值方法
2018/09/12 Javascript
[02:49]2018DOTA2亚洲邀请赛主赛事决赛日战况回顾 Mineski鏖战5局夺得辉耀
2018/04/10 DOTA
[49:31]TFT vs Mski Supermajor小组赛C组 BO3 第一场 6.3
2018/06/04 DOTA
Python设置默认编码为utf8的方法
2016/07/01 Python
python 调用pyautogui 实时获取鼠标的位置、移动鼠标的方法
2019/08/27 Python
使用Python给头像加上圣诞帽或圣诞老人小图标附源码
2019/12/25 Python
python中实现栈的三种方法
2020/12/19 Python
使用postMessage让 iframe自适应高度的方法示例
2019/10/08 HTML / CSS
博士毕业生自我鉴定范文
2014/04/13 职场文书
乌镇导游词
2015/02/02 职场文书
2015年国庆节新闻稿
2015/07/18 职场文书
Java新手教程之ArrayList的基本使用
2021/06/20 Java/Android
mongodb数据库迁移变更的解决方案
2021/09/04 MongoDB
MySQL读取JSON转换的方式
2022/03/18 MySQL
漫画《尖帽子的魔法工坊》宣布动画化
2022/04/06 日漫
Python线程池与GIL全局锁实现抽奖小案例
2022/04/13 Python