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 相关文章推荐
JS在IE和FF下attachEvent,addEventListener学习笔记
Nov 26 Javascript
jquery通过a标签删除table中的一行的代码
Dec 02 Javascript
jQuery插件pagination实现分页特效
Apr 12 Javascript
JavaScript获取并更改input标签name属性的方法
Jul 02 Javascript
微信小程序 解决请求服务器手机预览请求不到数据的方法
Jan 04 Javascript
node.js发送邮件email的方法详解
Jan 06 Javascript
Vue.js学习笔记之常用模板语法详解
Jul 25 Javascript
Vue组件和Route的生命周期实例详解
Feb 10 Javascript
在vue中实现点击选择框阻止弹出层消失的方法
Sep 15 Javascript
微信小程序实现日历功能
Nov 27 Javascript
vue拖拽组件 vuedraggable API options实现盒子之间相互拖拽排序
Jul 08 Javascript
如何vue使用el-table遍历循环表头和表体数据
Apr 26 Vue.js
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
PHP insert语法详解
2008/06/07 PHP
php更新修改excel中的内容实例代码
2014/02/26 PHP
PHP四舍五入、取整、round函数使用示例
2015/02/06 PHP
[原创]php token使用与验证示例【测试可用】
2017/08/30 PHP
Yii2框架操作数据库的方法分析【以mysql为例】
2019/05/27 PHP
php文件后缀不强制为.php的实操方法
2019/09/18 PHP
JavaScript事件列表解说
2006/12/22 Javascript
javascript时区函数介绍
2012/09/14 Javascript
分析Node.js connect ECONNREFUSED错误
2013/04/09 Javascript
前台js调用后台方法示例
2013/12/02 Javascript
jquery的ajax异步请求接收返回json数据实例
2014/06/16 Javascript
jQuery动画特效实例教程
2014/08/29 Javascript
DOM中事件处理概览与原理的全面解析
2016/08/16 Javascript
JS解决iframe之间通信和自适应高度的问题
2016/08/24 Javascript
Node.js Sequelize如何实现数据库的读写分离
2016/10/23 Javascript
扩展jquery easyui tree的搜索树节点方法(推荐)
2016/10/28 Javascript
jQuery和JavaScript节点插入元素的方法对比
2016/11/18 Javascript
Javascript实现base64的加密解密方法示例
2017/06/27 Javascript
vue中实现Monaco Editor自定义提示功能
2019/07/05 Javascript
基于JavaScript实现控制下拉列表
2020/05/08 Javascript
React实现类似淘宝tab居中切换效果的示例代码
2020/06/02 Javascript
解决Vue 移动端点击出现300毫秒延迟的问题
2020/07/21 Javascript
[11:57]《一刀刀一天》第十七期:TI中国军团加油!
2014/05/26 DOTA
浅析Python多线程下的变量问题
2015/04/28 Python
在Python操作时间和日期之asctime()方法的使用
2015/05/22 Python
Python正则替换字符串函数re.sub用法示例
2017/01/19 Python
python实现字符串和字典的转换
2018/09/29 Python
python网络编程 使用UDP、TCP协议收发信息详解
2019/08/29 Python
基于DOM+CSS3实现OrgChart组织结构图插件
2016/03/02 HTML / CSS
出纳的岗位职责
2013/11/09 职场文书
爱岗敬业演讲稿范文
2014/01/14 职场文书
电气自动化专业职业规划范文
2014/02/16 职场文书
办公室主任竞聘演讲稿
2014/05/15 职场文书
茶楼服务员岗位职责
2015/02/09 职场文书
加班费申请报告
2015/05/15 职场文书
CSS中float高度塌陷问题的四种解决方案
2022/04/18 HTML / CSS