用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 相关文章推荐
CSS实现圆形放大镜狙击镜效果 只有圆圈里的放大
Dec 10 HTML / CSS
纯HTML5+CSS3制作图片旋转
Jan 12 HTML / CSS
CSS3中设置3D变形的transform-style属性详解
May 23 HTML / CSS
用CSS3实现无限循环的无缝滚动的示例代码
Nov 01 HTML / CSS
css3 伪类选择器快速复习小结
Sep 10 HTML / CSS
详解Canvas事件绑定
Jun 27 HTML / CSS
html5基础教程常用技巧整理
Aug 20 HTML / CSS
HTML5 video 事件应用示例
Sep 11 HTML / CSS
使用HTML5 Canvas API控制字体的显示与渲染的方法
Mar 24 HTML / CSS
HTML5 新表单类型示例代码
Mar 20 HTML / CSS
HTML5高仿微信聊天、微信聊天表情|对话框|编辑器功能
Apr 23 HTML / CSS
Html5踩坑记之mandMobile使用小记
Apr 02 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
PHP执行速率优化技巧小结
2008/03/15 PHP
PHP 透明水印生成代码
2012/08/27 PHP
php设计模式之中介者模式分析【星际争霸游戏案例】
2020/03/23 PHP
PHP7修改的函数
2021/03/09 PHP
jQuery 使用手册(五)
2009/09/23 Javascript
js 利用className得到对象的实现代码
2011/11/15 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
10个很棒的jQuery代码片段
2015/09/24 Javascript
jquery实现仿新浪微博带动画效果弹出层代码(可关闭、可拖动)
2015/10/12 Javascript
WordPress中利用AJAX异步获取评论用户头像的方法
2016/01/08 Javascript
JS实现把鼠标放到链接上出现滚动文字的方法
2016/04/06 Javascript
ionic实现滑动的三种方式
2016/08/27 Javascript
详解JavaScript模块化开发
2016/12/04 Javascript
Jquery实时监听input value的实例
2017/01/26 Javascript
基于jquery实现九宫格拼图小游戏
2018/11/30 jQuery
nodejs实现用户登录路由功能
2019/05/22 NodeJs
Vue 数据响应式相关总结
2021/01/28 Vue.js
利用Python自动监控网站并发送邮件告警的方法
2016/08/24 Python
Django学习笔记之Class-Based-View
2017/02/15 Python
python 读取文件并把矩阵转成numpy的两种方法
2019/02/12 Python
python实现ip代理池功能示例
2019/07/05 Python
pytorch 可视化feature map的示例代码
2019/08/20 Python
在Python中字符串、列表、元组、字典之间的相互转换
2019/11/15 Python
python调用jenkinsAPI构建jenkins,并传递参数的示例
2020/12/09 Python
canvas学习和滤镜实现代码
2018/08/22 HTML / CSS
Html5与App的通讯方式详解
2019/10/24 HTML / CSS
Lampegiganten丹麦:欧洲领先的照明网上商店
2018/04/25 全球购物
牦牛毛户外探险服装:Kora
2019/02/08 全球购物
公司年会搞笑主持词
2014/03/24 职场文书
不尊敬老师的检讨书
2014/12/21 职场文书
责任书范本大全
2015/05/11 职场文书
大学运动会加油稿
2015/07/22 职场文书
公司新员工欢迎词
2015/09/30 职场文书
《唯一的听众》教学反思
2016/02/18 职场文书
使用pycharm运行flask应用程序的详细教程
2021/06/07 Python
SQL解决未能删除约束问题drop constraint
2022/05/30 SQL Server