简单酷炫的Canvas数字时钟
声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢!
我记得很早之前就看过这个DEMO,是岑安大大博客里看到的:
就是这个数字时钟,当时觉得这个创意不错,但是也没去折腾。直到昨天同事又在网上看到这个案例,他觉得很酷炫,就跑过来问我,这个是怎么实现的,然后我大概想了一下实现方法后也来了点兴趣,就花了一点时间模仿做出来了一个。不同的是,岑安用的是div来做的。而我就是用canvas来实现的。用canvas来做性能方面会更好,因为就单单操控每个点的运动,用js控制dom的style属性跟用js控制canvas绘图相比性能方面肯定是有所欠缺的。
先上个我做的DEMO吧,然后再简述一下做这个的方法: 看DEMO请戳我 。
做这个思路很简单,就是通过字符串保存各个数字的位置:
var numData = [
"1111/1001/1001/1001/1001/1001/1111", //
"0001/0001/0001/0001/0001/0001/0001", //
"1111/0001/0001/1111/1000/1000/1111", //
"1111/0001/0001/1111/0001/0001/1111", //
"1010/1010/1010/1111/0010/0010/0010", //
"1111/1000/1000/1111/0001/0001/1111", //
"1111/1000/1000/1111/1001/1001/1111", //
"1111/0001/0001/0001/0001/0001/0001", //
"1111/1001/1001/1111/1001/1001/1111", //
"1111/1001/1001/1111/0001/0001/1111", //
"0000/0000/0010/0000/0010/0000/0000", //:
]
0代表没像素,1代表有像素,/是为了更好看些,就是分行嘛,简单说起来:比如0就是:
1 1 1 1
1 0 0 1
1 0 0 1
1 0 0 1
1 0 0 1
1 0 0 1
1 1 1 1 这样就很清楚了吧。从0到9还有一个:号都用字符串表示好。
然后就写个粒子对象,也就是像素点:
var P_radius = 8,Gravity = 9.8;
var Particle = function(){
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.color = "";
this.visible = false;
this.drop = false;
}
Particle.prototype = {
constructors:Particle,
paint:function(){ //绘制自身
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x,this.y,P_radius,0,2*Math.PI);
ctx.fill();
},
reset:function(x,y,color){ //重置
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;
this.color = color;
this.visible = true;
this.drop = false;
},
isDrop:function(){ //落下
this.drop = true;
var vx = Math.random()*20+15
this.vx = Math.random()>=0.5?-vx : vx;
},
update:function(time){ //每一帧的动作
if(this.drop){
this.x += this.vx*time;
this.y += this.vy*time; var vy = this.vy+Gravity*time; if(this.y>=canvas.height-P_radius){
this.y = canvas.height-P_radius
vy = -vy*0.7;
} this.vy = vy; if(this.x<-P_radius||this.x>canvas.width+P_radius||this.y<-P_radius||this.y>canvas.height+P_radius){
this.visible = false;
}
}
}
}
粒子对象的属性比较简单,就位置,速度,以及是否可视化。方法的话,paint是绘制方法,reset是重置(因为粒子要循环利用的,提升性能),isDrop是粒子落下方法,update就是每一帧更新粒子的动作,update中当粒子运动超出canvas的绘制区域时,就把它的可视化置为false,在粒子容器中保存起来等待下一次调用。
写好粒子对象后,就要考虑如何让粒子按照位置画上去,同时当粒子不需要用时能够让他做自由落体的动画了。
先画背景(也就是那没有像素的白点):
function drawBg(){
var tx = (canvas.width-((P_radius*2+X_J)*4*8+7*xjg))/2;
for(var i=0;i<8;i++){
var ty = (canvas.height-((P_radius+yjg)*6))/2;
for(var j=0;j<numData[0].length;j++){
var tt = numData[0].charAt(j);
if(tt==="/"){
ty+=yjg;
}else {
var x = tx+j%5*(P_radius*2+X_J),
y = ty;
bgctx.fillStyle = "#FFF";
bgctx.beginPath();
bgctx.arc(x,y,P_radius,0,2*Math.PI);
bgctx.fill();
}
}
tx+=xjg+4*(P_radius*2+X_J);
}
}
先把背景画到一个离屏canvas中缓存起来,接下来每一帧重画的时候就不需要逻辑计算了,直接把那个离屏canvas画上去就行了。上面的逻辑应该不难理解,就是通过两个循环,循环8个数字,然后再对每个数字一个点一个点进行绘制,当遇到“/”时,就说明要换行了,把绘制的ty加个换行间隔,再把tx重置,再进行绘制。就这样,点就可以都画出来了。效果图如下:
背景画好了,就开始根据每一秒的时间,画数字像素吧。方法主要是这个:
function setTime(time){
var h = time.getHours()+"",
m = time.getMinutes()+"",
s = time.getSeconds()+"";
h = h.length===1?"0"+h:h;
m = m.length===1?"0"+m:m;
s = s.length===1?"0"+s:s; var nowdate = h+":"+m+":"+s;
var tx = (canvas.width-((P_radius*2+X_J)*4*8+7*xjg))/2,color = "";
for(var i=0;i<nowdate.length;i++){
var n = nowdate.charAt(i)===":"?10:parseInt(nowdate.charAt(i)),
text = numData[n]; var ty = (canvas.height-((P_radius+yjg)*6))/2; switch(i){
case 0:color = "#4DCB74";break;
case 2:color = "#4062E0";break;
case 3:color = "#D65050";break;
case 5:color = "#4062E0";break;
case 6:color = "#797C17";break;
} for(var j=0;j<text.length;j++){
var tt = text.charAt(j);
if(tt==="/"){
ty+=yjg;
}else{
var x = tx+j%5*(P_radius*2+X_J),
y = ty,
pp = null,
usefullp = null;
particles.forEach(function(p){
if(p.visible&&p.x===x&&p.y===y){
pp = p;
}else if(!p.visible&&usefullp===null){
usefullp = p;
}
});
if(pp!==null&&tt==="0"){
pp.isDrop();
}else if(pp===null&&tt==="1"){
usefullp.reset(x , y , color);
}
}
}
tx+=xjg+4*(P_radius*2+X_J);
}
}
原理也不难,也是跟上面画背景差不多,遍历所有点,然后根据当前时间的数字转换成的字符串来判断,当前点是否应该有像素,如果有像素就再判断当前这个点是否已经有粒子对象在了,如果已经有粒子对象在了,就直接跳出不处理,如果没有粒子对象在,就再粒子容器中找一个没有被使用的粒子reset到这个位置。还有一种情况,就是当前这个点是不应该有像素的,但是却有粒子,那就获取这个粒子,让这个粒子进行自由落体。
时间设置也写好了,就可以写舞台更新的代码了:
var timeCount_0 = 0,timeCount_1 = 0,particles = [];
function initAnimate(){
for(var i=0;i<200;i++){
var p = new Particle();
particles.push(p);
} timeCount_0 = new Date();
timeCount_1 = new Date();
drawBg();
setTime(timeCount_0)
animate();
} function animate(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(bgcanvas,0,0); var timeCount_2 = new Date(); if(timeCount_1-timeCount_0>=1000){
setTime(timeCount_1);
timeCount_0 = timeCount_1;
} particles.forEach(function(p){
if(p.visible){
p.update((timeCount_2-timeCount_1)/70);
p.paint();
}
}); timeCount_1 = timeCount_2; RAF(animate)
}
在initAnimate进行动画初始化,初始化也就是先实例化两百个粒子对象放到粒子容器中保存起来,再更新时间戳,缓存背景,设置当前时间,然后调用animate动画循环主体开始动画。
animate中的逻辑也很简单了,获取时间戳,如果两个时间戳之间的时间差大于或等于1秒,就进行setTime。而再下面的就是对粒子容器里的所有可视化的粒子进行遍历循环重绘了。
然后就做好啦:。当然这个效果还是有很多可以优化的地方的,因为时钟和分钟都是动的比较少的,所以可以把这两个缓存起来,当没有动作的时候就直接将缓存数据画上去就行了,这样就可以减少舞台每一帧的绘图API调用量,肯定是能提高性能的。不过现在毕竟粒子不多,两三百个粒子对象也就够用了,如果不去做优化,动画也还是能很流畅的运行的。所以楼主就偷个小懒啦。
源码地址:https://github.com/whxaxes/canvas-test/blob/gh-pages/src/Funny-demo/coolClock/index.html
简单酷炫的Canvas数字时钟的更多相关文章
- 简单酷炫的canvas动画
作为一个新人怀着激动而紧张的心情写了第一篇帖子还请大家多多支持,小弟在次拜谢. 驯鹿拉圣诞老人动画效果图如下 html如下: <div style="width:400px;heigh ...
- 仿智能社官网:原生JS实现简单又酷炫的3D立方体时钟
先放一下我做的效果:https://linrunzheng.github.io/3Dclock/3Dclock/new.html 至于3D立方体怎么做这里就不在阐述了,可以看一下我之前的博客. 这里默 ...
- 酷炫放大镜canvas实现
主要采用了canvas内渲染canvas的技术,还有利用比例来放大图片 比例:放大镜宽度/画布宽度=原图宽度/渲染图宽度 <!DOCTYPE html><html lang=&quo ...
- HTML5 Canvas玩转酷炫大波浪进度图
如上图所见,本文就是要实现上面那种效果. 由于最近AlloyTouch要写一个下拉刷新的酷炫loading效果.所以首选大波浪进度图. 首先要封装一下大波浪图片进度组件.基本的原理是利用Canvas绘 ...
- html5+Canvas实现酷炫的小游戏
最近除了做业务,也在尝试学习h5和移动端,在这个过程中,学到了很多,利用h5和canvas做了一个爱心鱼的小游戏.点这里去玩一下 PS: 貌似有点闪屏,亲测多刷新两下就好了==.代码在本地跑都不会闪, ...
- 8个经典炫酷的HTML5 Canvas动画欣赏
HTML5非常强大,尤其是Canvas技术的应用,让HTML5几乎可以完成所有Flash能完成的效果.本文精选了8个经典炫酷的HTML5 Canvas动画欣赏,每一个都提供全部的源代码,希望对你有所帮 ...
- canvas实现酷炫气泡效果
canvas实现动画主要是靠设置定时器(setinterval())和定时清除画布里的元素实现,canvas动画上手很简单,今天可以自己动手来实现一个酷炫气泡效果. 气泡炸裂效果(类似水面波纹) 代码 ...
- 【Android】Anroid5.0+新控件---酷炫标题栏的简单学习
Android5.0+推出的新控件感觉特别酷,最近想模仿大神做个看图App出来,所以先把这些新控件用熟悉了. 新控件的介绍.使用等等网上相应的文章已经特别多了,题主也没那能力去写篇详解出来,本篇随笔记 ...
- Canvas+Video打造酷炫播放体验
一.简介 直到现在,仍然不存在一项旨在网页上显示视频的标准. 今天,大多数视频是通过插件(比如 Flash)来显示的.然而,并非所有浏览器都拥有同样的插件. HTML5 规定了一种通过 video 元 ...
随机推荐
- python 垃圾回收
# 垃圾回收 # 小整数对象池 # a = 100# python对小整数的定义是[-5,257],这些证书对象是提前创建好的,不会被垃圾回收,再一个python的程序中,所有位于这个范围内的正式使用 ...
- android app使用微信登录接口回调没有被执行的问题研究
本人开发的一个app使用了sharesdk集成微信登录功能,在测试的过程中微信授权登录界面有调用,但是授权后原应用的回调没有被执行 应用的包名是com.kimi.searcher 首先,确认微信点击授 ...
- [转] 谈谈JS中的函数节流
函数节流的目的 从字面上就可以理解,函数节流就是用来节流函数从而一定程度上优化性能的.例如,DOM 操作比起非DOM 交互需要更多的内存和CPU 时间.连续尝试进行过多的DOM 相关操作可能会导致浏览 ...
- 长短时记忆网络LSTM和条件随机场crf
LSTM 原理 CRF 原理 给定一组输入随机变量条件下另一组输出随机变量的条件概率分布模型.假设输出随机变量构成马尔科夫随机场(概率无向图模型)在标注问题应用中,简化成线性链条件随机场,对数线性判别 ...
- alpha冲刺1/10
目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:来自双十一的爱 团队部分 后敬甲(组长) 过去两天完成了哪些任务 文字描述 Alpha版本的任务细分安排 leangoo ...
- 1个汉字在UTF-8编码占3个字节
http://blog.csdn.net/ns_code/article/details/14162087 http://www.ruanyifeng.com/blog/2007/10/ascii_u ...
- python全栈开发day59-Django基础
一.今日内容总结 1.HTTP协议: 请求:浏览器发给服务端的消息 格式: 请求方法 URL 协议版本\r\n k1: v1\r\n k2: v2\r\n \r\n 请求体(请求数据) 响应:服务端返 ...
- Docker技术底层架构剖析
[Docker 底层技术] docker底层的 2 个核心技术分别是 Namespaces 和 Control groups 在操作系统中,网络配置,进程,用户,IPC(进程之间的调用)等信息之间的 ...
- zabbix邮箱报警设置&问题汇总
zabbix邮件报警部署! Zabbix监控服务端.客户端都已经部署完成,被监控主机已经添加,Zabiix监控运行正常,通过查看Zabbix监控服务器,可以了解服务器的运行状态是否正常,运维人员不会时 ...
- Python中元类
元类(metaclass) 简单地说,元类就是一个能创建类的类,而类class 是由type创建的,class可以创建对象 type与object的关系详见:python中type和object 1. ...