canvas实现粒子时钟效果


Posted in Javascript onFebruary 06, 2017

前面的话

本文将使用canvas实现粒子时钟效果

效果展示

点阵数字

digit.js是一个三维数组,包含的是0到9以及冒号(digit[10])的二维点阵。每个数字的点阵表示是7*10大小的二维数组

通过遍历数字点阵的二维数组,当该位置的值为1时,则绘制一个粒子,否则不绘制

canvas实现粒子时钟效果

将绘制数字的函数命名为renderDigit()。在该函数中,将粒子绘制为一个小圆。小圆的半径为R,小圆所占据的矩形宽(高)为2(R+1)。由于数字点阵是10*7的二维数组,所以一个数字的宽度为14(R+1),高度为20(R+1)

假设数字的高度为100px,则小圆的半径R=4

<div id="test">
 <button>1</button>
 <button>2</button>
 <button>3</button>
 <button>4</button>
 <button>5</button>
 <button>6</button>
 <button>7</button>
 <button>8</button>
 <button>9</button>
 <button>10</button>
</div>
<canvas id="canvas">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
<script src="http://files.cnblogs.com/files/xiaohuochai/digit.js"></script> 
<script>var canvas = document.getElementById('canvas');
 if(canvas.getContext){
  var cxt = canvas.getContext('2d');
 }
 function renderDigit(num){
  //重置画布宽度,达到清空画布的效果
  canvas.height = 100;
  var R = canvas.height/20-1;
  for(var i = 0; i < digit[num].length; i++){
   for(var j = 0; j < digit[num][i].length; j++){
    if(digit[num][i][j] == 1){
     cxt.beginPath();
     cxt.arc(j*2*(R+1)+(R+1),i*2*(R+1)+(R+1),R,0,2*Math.PI);
     cxt.closePath();
     cxt.fill();
    }
   }
  }  
 }
 var test = document.getElementById('test');
 test.onclick = function(e){
  e = e || event;
  var target = e.target || e.srcElement;
  if(!isNaN(target.innerHTML)){
   renderDigit(target.innerHTML);
  } 
 }
</script>
 

时钟实现

在上一步的点阵数字的基础上,实现一个粒子时钟。将时钟实现的函数命名为digitTime(),时钟实现由获取时间数据和渲染时钟两部分组成

【时间数据】

 最简单的时钟形式由两位的小时、两位的分钟和两位的秒钟组成,中间用冒号隔开。通过日期对象Date来获取当前时间,以及当前的小时、分钟和秒钟。但是,最终需要得到的是数字表示的时钟

 比如12:02:36的时间数据的表示形式为data[1,2,10,0,2,10,3,6]

【渲染时钟】

 获取到时间数据后,通过循环使用renderDigit()来渲染时钟中的每一个数字。此时,有一个需要改变的地方是arc()函数中的x坐标,否则它们将叠加在一起

 为了将时钟数字表示更加清晰在每个数字之间增加一定的间距。每个数字的宽度是14(R+1),假设data数组中7个数字的索引为index,则每个数字的起始X坐标可以等于14(R+2)*index

 最后通过定时器每间隔一段时间后更新时间

<canvas id="canvas" style="width:400px;">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
<script src="http://files.cnblogs.com/files/xiaohuochai/digit.js"></script> 
<script>
 var canvas = document.getElementById('canvas');
 if(canvas.getContext){
  var cxt = canvas.getContext('2d');
 }
 canvas.height = 100;
 canvas.width = 700;
 function renderDigit(index,num){
  var R = canvas.height/20-1;
  for(var i = 0; i < digit[num].length; i++){
   for(var j = 0; j < digit[num][i].length; j++){
    if(digit[num][i][j] == 1){
     cxt.beginPath();
     cxt.arc(14*(R+2)*index + j*2*(R+1)+(R+1),i*2*(R+1)+(R+1),R,0,2*Math.PI);
     cxt.closePath();
     cxt.fill();
    }
   }
  }  
 }
 function digitTime(){
  /*获取时间数据*/
  var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
  //存储时间数字,由十位小时、个位小时、冒号、十位分钟、个位分钟、冒号、十位秒钟、个位秒钟这7个数字组成
  var data = [];
  data.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
  /*渲染时钟*/
  //重置画布宽度,达到清空画布的效果
  canvas.height = 100;
  for(var i = 0; i < data.length; i++){
   renderDigit(i,data[i]);
  }
 }
 digitTime();
 clearInterval(oTimer);
 var oTimer = setInterval(function(){
  digitTime();
 },500);
</script>

随机抛物线

这节的随机抛物线运动是下节粒子动画的预备节。以DOM节点的投掷碰壁为基础,利用canvas实现一个小球的随机抛物线运动

将小球的运动拆分为x轴和y轴运动。x轴做匀速运动,y轴先做向上的减速运动,再做向下的加速运动。当小球离开画布区域时,停止定时器

<button id="btn">按钮</button>
<canvas id="canvas" style="border:1px solid black">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
<script>
 var canvas = document.getElementById('canvas');
 if(canvas.getContext){
  var cxt = canvas.getContext('2d');
 }
 //声明canvas的宽高
 var H = 100,W = 200;
 canvas.height = H;
 canvas.width = W; 
 var R = canvas.height/20-1;
 var numArray = [1,2,3,4];
 var colorArray = ["#3BE","#09C","#A6C","#93C","#9C0","#690","#FB3","#F80","#F44","#C00"];
 btn.onclick = function(){
  //声明x、y轴坐标
  var x=Math.floor(Math.random() * 60 + 10);
  var y=Math.floor(Math.random() * 60 + 10);
  //声明x、y轴的步长值
  var stepY = -3*numArray[Math.floor(Math.random()*numArray.length)];
  var stepX = Math.floor(Math.random() * 10 -5);
  //声明y轴变化值
  var disY = numArray[Math.floor(Math.random()*numArray.length)];
  var color =colorArray[Math.floor(Math.random()*colorArray.length)];
  clearInterval(oTimer);
  var oTimer = setInterval(function(){
   stepY += disY;
   x += stepX;
   y += stepY;
   canvas.height = 100;
   cxt.beginPath();
   cxt.arc(x,y,R,0,2*Math.PI);
   cxt.fillStyle = color;
   cxt.closePath();
   cxt.fill(); 
   if(x > W + R || y > H + R){
    clearInterval(oTimer);
   } 
  },50);
 }
</script>

粒子动画

下面来实现粒子动画。在时间数字变化的瞬间,由众多的粒子组成的新数字上重复生成相同的粒子,并且新生成的粒子做随机的抛物线运动

所以,第一步是先要判断是哪个或哪些数字在时间更新时发生了变化。然后,通过这些变化信息,生成要运动的小球。在定时器的运行间隔内,对运动小球的状态进行更新。最后,对时钟和运行的小球进行统一渲染

<canvas id="canvas" style="width:500px;">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
<script src="http://files.cnblogs.com/files/xiaohuochai/digit.js"></script> 
<script>
 var canvas = document.getElementById('canvas');
 if(canvas.getContext){
  var cxt = canvas.getContext('2d');
 }
 //声明canvas的宽高
 var H = 100,W = 700;
 canvas.height = H;
 canvas.width = W;
 //存储时间数据
 var data = [];
 //存储运动的小球
 var balls = [];
 //设置粒子半径
 var R = canvas.height/20-1;
 (function(){
  var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
  //存储时间数字,由十位小时、个位小时、冒号、十位分钟、个位分钟、冒号、十位秒钟、个位秒钟这7个数字组成
  data.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]); 
 })();
 /*生成点阵数字*/
 function renderDigit(index,num){
  for(var i = 0; i < digit[num].length; i++){
   for(var j = 0; j < digit[num][i].length; j++){
    if(digit[num][i][j] == 1){
     cxt.beginPath();
     cxt.arc(14*(R+2)*index + j*2*(R+1)+(R+1),i*2*(R+1)+(R+1),R,0,2*Math.PI);
     cxt.closePath();
     cxt.fill();
    }
   }
  }  
 }
 /*更新时钟*/
 function updateDigitTime(){
  var changeNumArray = [];
  var temp = /(\d)(\d):(\d)(\d):(\d)(\d)/.exec(new Date());
  var NewData = [];
  NewData.push(temp[1],temp[2],10,temp[3],temp[4],10,temp[5],temp[6]);
  for(var i = data.length-1; i >=0 ; i--){
   //时间发生变化 
   if(NewData[i] !== data[i]){
    //将变化的数字值和在data数组中的索引存储在changeNumArray数组中
    changeNumArray.push(i+'_'+(Number(data[i])+1)%10);
   }
  }
  //增加小球
  for(var i = 0; i< changeNumArray.length; i++){
   addBalls.apply(this,changeNumArray[i].split('_'));
  } 
  data = NewData.concat();
 }
 /*更新小球状态*/
 function updateBalls(){
  for(var i = 0; i < balls.length; i++){
   balls[i].stepY += balls[i].disY;
   balls[i].x += balls[i].stepX;
   balls[i].y += balls[i].stepY; 
   if(balls[i].x > W + R || balls[i].y > H + R){
    balls.splice(i,1);
    i--;
   }    
  }
 }
 /*增加要运动的小球*/
 function addBalls(index,num){
  var numArray = [1,2,3];
  var colorArray = ["#3BE","#09C","#A6C","#93C","#9C0","#690","#FB3","#F80","#F44","#C00"];
  for(var i = 0; i < digit[num].length; i++){
   for(var j = 0; j < digit[num][i].length; j++){
    if(digit[num][i][j] == 1){
     var ball = {
      x:14*(R+2)*index + j*2*(R+1)+(R+1),
      y:i*2*(R+1)+(R+1),
      stepX:Math.floor(Math.random() * 4 -2),
      stepY:-2*numArray[Math.floor(Math.random()*numArray.length)],
      color:colorArray[Math.floor(Math.random()*colorArray.length)],
      disY:1
     };
     balls.push(ball);   
    }
   }
  } 
 }
 /*渲染*/
 function render(){
  //重置画布宽度,达到清空画布的效果
  canvas.height = 100;
  //渲染时钟
  for(var i = 0; i < data.length; i++){
   renderDigit(i,data[i]);
  }  
  //渲染小球
  for(var i = 0; i < balls.length; i++){
   cxt.beginPath();
   cxt.arc(balls[i].x,balls[i].y,R,0,2*Math.PI);
   cxt.fillStyle = balls[i].color;
   cxt.closePath();
   cxt.fill();    
  }
 }
 clearInterval(oTimer);
 var oTimer = setInterval(function(){
  //更新时钟
  updateDigitTime();
  //更新小球状态
  updateBalls();
  //渲染
  render();
 },50);
</script>

源码查看

公告栏扩展

将canvas粒子时钟js部分封装为canvasTime.js,在公告栏添加如下代码,即可以实现在公告栏插入时钟的效果

<canvas id="canvas" style="width:100%;">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
<script src="http://files.cnblogs.com/files/xiaohuochai/canvasTime.js"></script>

canvas实现粒子时钟效果

canvas实现粒子时钟效果

好的代码像粥一样,都是用时间熬出来的

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
LazyLoad 延迟加载(按需加载)
May 31 Javascript
location.href语句与火狐不兼容的问题
Jul 04 Javascript
jquery监控数据是否变化(修正版)
Apr 12 Javascript
JS文本获得焦点清除文本文字的示例代码
Jan 13 Javascript
jquery实现两个图片渐变切换效果的方法
Jun 25 Javascript
D3.js实现散点图和气泡图的方法详解
Sep 21 Javascript
扩展jquery easyui tree的搜索树节点方法(推荐)
Oct 28 Javascript
Angular2自定义分页组件
Apr 19 Javascript
xmlplus组件设计系列之树(Tree)(9)
May 02 Javascript
详解webpack提取第三方库的正确姿势
Dec 22 Javascript
解决iView中时间控件选择的时间总是少一天的问题
Mar 15 Javascript
vue-cli配置flexible过程详解
Jul 04 Javascript
javascript笔记之匿名函数和闭包
Feb 06 #Javascript
如何用JS/HTML将时间戳转换为“xx天前”的形式
Feb 06 #Javascript
D3.js中强制异步文件读取同步的几种方法
Feb 06 #Javascript
浅谈Javascript事件对象
Feb 05 #Javascript
js中创建对象的几种方式
Feb 05 #Javascript
js实现增加数字显示的环形进度条效果
Feb 05 #Javascript
JS实现复制内容到剪贴板功能
Feb 05 #Javascript
You might like
在JavaScript中调用php程序
2009/03/09 PHP
使用php显示搜索引擎来的关键词
2014/02/13 PHP
微信支付开发教程(一)微信支付URL配置
2014/05/28 PHP
ExtJS GTGrid 简单用户管理
2009/07/01 Javascript
js简易namespace管理器 实例代码
2013/06/21 Javascript
javascript获取ckeditor编辑器的值(实现代码)
2013/11/18 Javascript
js和jquery中循环的退出和继续下一个循环
2014/09/03 Javascript
浅谈重写window对象的方法
2014/12/29 Javascript
深入浅出分析javaScript中this用法
2015/05/09 Javascript
jQuery实现强制cookie过期方法汇总
2015/05/22 Javascript
JavaScript+CSS实现仿Mootools竖排弹性动画菜单效果
2015/10/14 Javascript
如何解决ligerUI布局时Center中的Tab高度大小
2015/11/24 Javascript
详解JavaScript中的自定义事件编写
2016/05/10 Javascript
js定时器+简单的动画效果实例
2017/11/10 Javascript
React Native react-navigation 导航使用详解
2017/12/01 Javascript
js序列化和反序列化的使用讲解
2019/01/19 Javascript
浅谈layui数据表格判断问题(加入表单元素),设置单元格样式
2019/10/26 Javascript
JS深入学习之数组对象排序操作示例
2020/05/01 Javascript
解决vant title-active-color与title-inactive-color不生效问题
2020/11/03 Javascript
vue自定义插件封装,实现简易的elementUi的Message和MessageBox的示例
2020/11/20 Vue.js
python之pandas用法大全
2018/03/13 Python
Django框架首页和登录页分离操作示例
2019/05/28 Python
python字典和json.dumps()的遇到的坑分析
2020/03/11 Python
使用Python Tkinter实现剪刀石头布小游戏功能
2020/10/23 Python
CSS3实现简易版的刮刮乐效果
2016/09/27 HTML / CSS
基于css3实现漂亮便签样式
2013/03/18 HTML / CSS
欧洲最大的笔和书写专家:The Pen Shop
2017/03/19 全球购物
美国电子产品购物网站:BuyDig.com
2020/06/17 全球购物
党员公开承诺书
2014/03/25 职场文书
平安工地建设方案
2014/05/06 职场文书
小学生环保倡议书
2014/05/15 职场文书
初中生庆国庆演讲稿范文2014
2014/09/25 职场文书
2014年售票员工作总结
2014/11/19 职场文书
2015年银行员工工作总结
2015/04/24 职场文书
表扬信格式模板
2015/05/05 职场文书
战马观后感
2015/06/08 职场文书