首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >炫丽的倒计时效果Canvas绘图与动画基础

炫丽的倒计时效果Canvas绘图与动画基础

作者头像
玩蛇的胖纸
发布2018-06-08 13:05:42
6160
发布2018-06-08 13:05:42
举报

前言

想要在自己做的网页中,加入canvas动画效果,但是发现模板各种调整不好,觉得还是要对canvas有所了解,才可以让自己的网页变得狂拽炫酷吊炸天!

一、绘制基础

1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;">
 9     </canvas>
10 
11     <script>
12         window.onload=function (ev) {
13             var canvas=document.getElementById('canvas');
14         //画布的长宽,没有单位的
15             canvas.width=1024;
16             canvas.height=600;
17             var context=canvas.getContext('2d');
18             //使用context绘制,画图之前的配置
19 
20            
21             //1.绘制折线图形
22             context.beginPath();
23             context.moveTo(100,100);
24             context.lineTo(500,500);
25             context.lineTo(100,500);
26             context.lineTo(100,100);
27             context.closePath();
28 //图线的状态,如果用context.beginPath();.... context.closePath();包住,才只对下面最近的一个 context.stroke();(画线)命令起作用,不然就对所有 context.stroke();起作用
29 
30             context.lineWidth=5;//画线的粗细
31             context.strokeStyle='#005588';
32             context.stroke();
33 
34             context.beginPath();
35             context.moveTo(200,100);
36             context.lineTo(600,500);
37             context.closePath();
38 
39             context.strokeStyle='black'; //画线的颜色
40             context.stroke();
41 
42 
43         }
44     </script>
45 </body>
46 </html>
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;">
 9     </canvas>
10 
11     <script>
12         window.onload=function (ev) {
13             var canvas=document.getElementById('canvas');
14             canvas.width=1024;
15             canvas.height=600;
16             var context=canvas.getContext('2d');
17             //使用context绘制
18 
19             context.lineWidth=5;
20             context.strokeStyle="#005588";
21 
22             for(var i=0;i<10;i++){
23                 context.beginPath();
24                 context.arc(50+i*100,60,40,0,2*Math.PI*(i+1)/10);
25                 context.closePath();
26 
27                 context.stroke()
28             }
29 
30             for(var i=0;i<10;i++){
31                 context.beginPath();
32                 context.arc(50+i*100,180,40,0,2*Math.PI*(i+1)/10);
33                 // context.closePath();
34 
35                 context.stroke()
36             }
37 
38 
39             for(var i=0;i<10;i++){
40                 context.beginPath();
41                 context.arc(50+i*100,300,40,0,2*Math.PI*(i+1)/10,true);
42                 context.closePath();
43 
44                 context.stroke()
45             }
46 
47             for(var i=0;i<10;i++){
48                 context.beginPath();
49                 context.arc(50+i*100,420,40,0,2*Math.PI*(i+1)/10,true);
50                 // context.closePath();
51 
52                 context.stroke()
53             }
54 
55             context.fillStyle="#005588";
56             for(var i=0;i<10;i++){
57                 context.beginPath();
58                 context.arc(50+i*100,540,40,0,2*Math.PI*(i+1)/10);
59                 context.closePath();
60 
61                 context.fill()
62             }
63             
64         }
65     </script>
66 </body>
67 </html>

二、倒计时电子钟的实现

新建两个js文件:digit.js 存放一个三维数组,countdown.js实现时钟效果

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;">
 9     </canvas>
10 
11     <script src="digit.js"></script>
12     <script src="countdown.js"></script>
13 
14 </body>
15 </html>
  1 digit =
  2     [
  3         [
  4             [0,0,1,1,1,0,0],
  5             [0,1,1,0,1,1,0],
  6             [1,1,0,0,0,1,1],
  7             [1,1,0,0,0,1,1],
  8             [1,1,0,0,0,1,1],
  9             [1,1,0,0,0,1,1],
 10             [1,1,0,0,0,1,1],
 11             [1,1,0,0,0,1,1],
 12             [0,1,1,0,1,1,0],
 13             [0,0,1,1,1,0,0]
 14         ],//0
 15         [
 16             [0,0,0,1,1,0,0],
 17             [0,1,1,1,1,0,0],
 18             [0,0,0,1,1,0,0],
 19             [0,0,0,1,1,0,0],
 20             [0,0,0,1,1,0,0],
 21             [0,0,0,1,1,0,0],
 22             [0,0,0,1,1,0,0],
 23             [0,0,0,1,1,0,0],
 24             [0,0,0,1,1,0,0],
 25             [1,1,1,1,1,1,1]
 26         ],//1
 27         [
 28             [0,1,1,1,1,1,0],
 29             [1,1,0,0,0,1,1],
 30             [0,0,0,0,0,1,1],
 31             [0,0,0,0,1,1,0],
 32             [0,0,0,1,1,0,0],
 33             [0,0,1,1,0,0,0],
 34             [0,1,1,0,0,0,0],
 35             [1,1,0,0,0,0,0],
 36             [1,1,0,0,0,1,1],
 37             [1,1,1,1,1,1,1]
 38         ],//2
 39         [
 40             [1,1,1,1,1,1,1],
 41             [0,0,0,0,0,1,1],
 42             [0,0,0,0,1,1,0],
 43             [0,0,0,1,1,0,0],
 44             [0,0,1,1,1,0,0],
 45             [0,0,0,0,1,1,0],
 46             [0,0,0,0,0,1,1],
 47             [0,0,0,0,0,1,1],
 48             [1,1,0,0,0,1,1],
 49             [0,1,1,1,1,1,0]
 50         ],//3
 51         [
 52             [0,0,0,0,1,1,0],
 53             [0,0,0,1,1,1,0],
 54             [0,0,1,1,1,1,0],
 55             [0,1,1,0,1,1,0],
 56             [1,1,0,0,1,1,0],
 57             [1,1,1,1,1,1,1],
 58             [0,0,0,0,1,1,0],
 59             [0,0,0,0,1,1,0],
 60             [0,0,0,0,1,1,0],
 61             [0,0,0,1,1,1,1]
 62         ],//4
 63         [
 64             [1,1,1,1,1,1,1],
 65             [1,1,0,0,0,0,0],
 66             [1,1,0,0,0,0,0],
 67             [1,1,1,1,1,1,0],
 68             [0,0,0,0,0,1,1],
 69             [0,0,0,0,0,1,1],
 70             [0,0,0,0,0,1,1],
 71             [0,0,0,0,0,1,1],
 72             [1,1,0,0,0,1,1],
 73             [0,1,1,1,1,1,0]
 74         ],//5
 75         [
 76             [0,0,0,0,1,1,0],
 77             [0,0,1,1,0,0,0],
 78             [0,1,1,0,0,0,0],
 79             [1,1,0,0,0,0,0],
 80             [1,1,0,1,1,1,0],
 81             [1,1,0,0,0,1,1],
 82             [1,1,0,0,0,1,1],
 83             [1,1,0,0,0,1,1],
 84             [1,1,0,0,0,1,1],
 85             [0,1,1,1,1,1,0]
 86         ],//6
 87         [
 88             [1,1,1,1,1,1,1],
 89             [1,1,0,0,0,1,1],
 90             [0,0,0,0,1,1,0],
 91             [0,0,0,0,1,1,0],
 92             [0,0,0,1,1,0,0],
 93             [0,0,0,1,1,0,0],
 94             [0,0,1,1,0,0,0],
 95             [0,0,1,1,0,0,0],
 96             [0,0,1,1,0,0,0],
 97             [0,0,1,1,0,0,0]
 98         ],//7
 99         [
100             [0,1,1,1,1,1,0],
101             [1,1,0,0,0,1,1],
102             [1,1,0,0,0,1,1],
103             [1,1,0,0,0,1,1],
104             [0,1,1,1,1,1,0],
105             [1,1,0,0,0,1,1],
106             [1,1,0,0,0,1,1],
107             [1,1,0,0,0,1,1],
108             [1,1,0,0,0,1,1],
109             [0,1,1,1,1,1,0]
110         ],//8
111         [
112             [0,1,1,1,1,1,0],
113             [1,1,0,0,0,1,1],
114             [1,1,0,0,0,1,1],
115             [1,1,0,0,0,1,1],
116             [0,1,1,1,0,1,1],
117             [0,0,0,0,0,1,1],
118             [0,0,0,0,0,1,1],
119             [0,0,0,0,1,1,0],
120             [0,0,0,1,1,0,0],
121             [0,1,1,0,0,0,0]
122         ],//9
123         [
124             [0,0,0,0],
125             [0,0,0,0],
126             [0,1,1,0],
127             [0,1,1,0],
128             [0,0,0,0],
129             [0,0,0,0],
130             [0,1,1,0],
131             [0,1,1,0],
132             [0,0,0,0],
133             [0,0,0,0]
134         ]//:
135     ];
 1 var WINDOW_WIDTH=1024;
 2 var WINDOW_HEIGHT=600;
 3 var RADIUS=8;
 4 var MARGIN_TOP=60;
 5 var MARGIN_LIFT=30;
 6 const endTime=new Date("2018/3/20,18:47:52");//js中的月份是从0-11,如果要表示7月,则用6表示,const代表常量
 7 var curShowTimeSeconds=0;
 8 
 9 
10 window.onload=function () {
11 
12     var canvas=document.getElementById('canvas');
13     var context=canvas.getContext('2d');
14 
15     canvas.width=WINDOW_WIDTH;
16     canvas.height=WINDOW_HEIGHT;
17 
18     curShowTimeSeconds=getCurrentShowTimeSeconds();
19     render(context);
20 };
21 
22 function getCurrentShowTimeSeconds() {
23     var curTime=new Date();
24     var ret=endTime.getTime()-curTime.getTime();
25     ret=Math.round(ret/1000);
26     return ret>=0?ret:0;
27 }
28 
29 
30 function render(cxt) {
31     var hours=parseInt(curShowTimeSeconds/3600);
32     var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
33     var seconds=curShowTimeSeconds%60;
34 
35     renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
36     renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
37     renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
38     renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
39     renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
40     renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
41     renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
42     renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt);
43 
44 }
45 
46 function renderDigit(x,y,num,cxt) {
47     cxt.fillStyle="rgb(0,102,153)";
48 
49     for(var i=0;i<digit[num].length;i++)
50         for(var j=0;j<digit[num][i].length;j++)
51             if(digit[num][i][j]==1){
52             cxt.beginPath();
53             cxt.arc(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
54             cxt.closePath();
55 
56             cxt.fill()
57             }
58 }

注意:数组阵列中,只能从0-9,如果超过10,就会报错,换言之,定义的到期时间距离程序当前时间不能超过100个小时,也就是四天。

三、倒计时电子钟的实现

1.实现倒计时效果,修改countdown.js

 1 var WINDOW_WIDTH=1024;
 2 var WINDOW_HEIGHT=600;
 3 var RADIUS=8;
 4 var MARGIN_TOP=60;
 5 var MARGIN_LIFT=30;
 6 const endTime=new Date("2018/3/20,18:47:52");//js中的月份是从0-11,如果要表示7月,则用6表示,const代表常量
 7 var curShowTimeSeconds=0;
 8 
 9 
10 window.onload=function () {
11 
12     var canvas=document.getElementById('canvas');
13     var context=canvas.getContext('2d');
14 
15     canvas.width=WINDOW_WIDTH;
16     canvas.height=WINDOW_HEIGHT;
17 
18     curShowTimeSeconds=getCurrentShowTimeSeconds();
19     // render(context);
20     setInterval(function () {
21         render(context);
22         updata();
23 
24     },
25         50)
26 };
27 
28 function updata() {
29     var nextShowTimeSeconds=getCurrentShowTimeSeconds();
30 
31     var nextHours=parseInt(nextShowTimeSeconds/3600);
32     var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
33     var nextSeconds=nextShowTimeSeconds%60;
34 
35     var curHours=parseInt(curShowTimeSeconds/3600);
36     var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
37     var curSeconds=curShowTimeSeconds%60;
38 
39     if(nextSeconds!=curSeconds){
40         curShowTimeSeconds=nextShowTimeSeconds;
41     }
42 
43 
44 }
45 
46 function getCurrentShowTimeSeconds() {
47     var curTime=new Date();
48     var ret=endTime.getTime()-curTime.getTime();
49     ret=Math.round(ret/1000);
50     return ret>=0?ret:0;
51 }
52 
53 function render(cxt) {
54 
55     cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
56     var hours=parseInt(curShowTimeSeconds/3600);
57     var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
58     var seconds=curShowTimeSeconds%60;
59 
60     renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
61     renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
62     renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
63     renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
64     renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
65     renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
66     renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
67     renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt);
68 
69 }
70 
71 function renderDigit(x,y,num,cxt) {
72     cxt.fillStyle="rgb(0,102,153)";
73 
74     for(var i=0;i<digit[num].length;i++)
75         for(var j=0;j<digit[num][i].length;j++)
76             if(digit[num][i][j]==1){
77             cxt.beginPath();
78             cxt.arc(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
79             cxt.closePath();
80 
81             cxt.fill()
82             }
83 }

各一秒变化一次:

2.使用canvas做一个物理小球

新建一个physical.html

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;"></canvas>
 9 </body>
10 
11 <script>
12     var ball={x:512,y:100,r:20,g:2,vx:-4,vy:0,color:"#005588"};
13     window.onload=function (ev) {
14         var canvas=document.getElementById("canvas");
15         canvas.width=1024;
16         canvas.height=600;
17         var context=canvas.getContext("2d");
18         //每隔50毫秒,生成一次小球,并更新下一次小球出现的位置和速度
19         setInterval(function () {
20             render(context);
21             update();
22         },50)
23     };
24     function render(cxt) {
25         cxt.clearRect(0,0,cxt.canvas.width,cxt.canvas.height);
26 
27         cxt.fillStyle=ball.color;
28         cxt.beginPath();
29         cxt.arc(ball.x,ball.y,ball.r,0,2*Math.PI)
30         cxt.closePath();
31 
32         cxt.fill();
33     }
34     function update() {
35         ball.x+=ball.vx;
36         ball.y+=ball.vy;
37         ball.vy+=ball.g;
38         if(ball.y>canvas.height-ball.r){
39             ball.y=canvas.height-ball.r;
40             ball.vy=-ball.vy*0.5;
41         }
42     }
43 
44 </script>
45 </html>

3.根据物理小球的例子,对countdown.js进行改写:

1.声明一个数组存放所有产生的小球,声明另一个数组存放几种颜色,用于随机取出赋给小球,以达到多种颜色小球的效果:

 1 //小球
 2 var balls = [];
 3 const colors = ["#33B5E5",
 4                 "#0099CC",
 5                 "#AA66CC",
 6                 "#9933CC",
 7                 "#99CC00",
 8                 "#669900",
 9                 "#FFBB33",
10                 "#FF8800",
11                 "#FF4444",
12                 "#CC0000"]

2.在update()函数中增加判断生成物理小球的条件,以及调用更新小球所在位置和速度的函数updateBalls():

 1 if(nextSeconds!=curSeconds){
 2         //小球
 3         if( parseInt(curHours/10) != parseInt(nextHours/10) ){
 4             addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
 5         }
 6         if( parseInt(curHours%10) != parseInt(nextHours%10) ){
 7             addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
 8         }
 9 
10         if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
11             addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
12         }
13         if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
14             addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
15         }
16 
17         if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
18             addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
19         }
20         if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
21             addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
22         }
23 
24         //更新时间
25         curShowTimeSeconds=nextShowTimeSeconds;
26     }
27     //更新小球的速度
28     updateBalls();

3.定义设置要生成的小球的各种参数的函数addBalls():

 1 function addBalls( x , y , num ){
 2     console.log("addBalls");
 3     for( var i=0;i<digit[num].length;i++)
 4         for(var j=0;j<digit[num][i].length;j++)
 5             if( digit[num][i][j] == 1 ){
 6                 var aBall = {
 7                     x:x+j*2*(RADIUS+1)+(RADIUS+1),
 8                     y:y+i*2*(RADIUS+1)+(RADIUS+1),
 9                     g:1.5+Math.random(),
10                     vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
11                     vy:-5,
12                     color: colors[ Math.floor( Math.random()*colors.length ) ]
13                 };
14                 balls.push(aBall);
15             }
16 }

4.定义更新小球位置和速度的函数updateBalls():

 1 function updateBalls(){
 2     for( var i = 0 ; i < balls.length ; i ++ ){
 3         balls[i].x += balls[i].vx;
 4         balls[i].y += balls[i].vy;
 5         balls[i].vy += balls[i].g;
 6         if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
 7             balls[i].y = WINDOW_HEIGHT-RADIUS;
 8             balls[i].vy = - balls[i].vy*0.75;
 9         }
10     }
11 }

5.在render函数中增加画物理小球的代码:

1 for(var i=0;i<balls.length;i++){
2         cxt.fillStyle=balls[i].color;
3 
4         cxt.beginPath();
5         cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
6         cxt.closePath();
7 
8         cxt.fill();
9     }

修改后的countdown.js为:

  1 var WINDOW_WIDTH=1024;
  2 var WINDOW_HEIGHT=600;
  3 var RADIUS=8;
  4 var MARGIN_TOP=60;
  5 var MARGIN_LIFT=30;
  6 const endTime=new Date("2018/3/20,18:47:52");//const代表常量
  7 var curShowTimeSeconds=0;
  8 
  9 //小球
 10 var balls = [];
 11 const colors = ["#33B5E5",
 12                 "#0099CC",
 13                 "#AA66CC",
 14                 "#9933CC",
 15                 "#99CC00",
 16                 "#669900",
 17                 "#FFBB33",
 18                 "#FF8800",
 19                 "#FF4444",
 20                 "#CC0000"]
 21 
 22 window.onload=function () {
 23 
 24     var canvas=document.getElementById('canvas');
 25     var context=canvas.getContext('2d');
 26 
 27     canvas.width=WINDOW_WIDTH;
 28     canvas.height=WINDOW_HEIGHT;
 29 
 30     curShowTimeSeconds=getCurrentShowTimeSeconds();
 31     // render(context);
 32     setInterval(function () {
 33         render(context);
 34         update();
 35     },
 36         50)
 37 };
 38 
 39 function update() {
 40     var nextShowTimeSeconds=getCurrentShowTimeSeconds();
 41 
 42     var nextHours=parseInt(nextShowTimeSeconds/3600);
 43     var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
 44     var nextSeconds=nextShowTimeSeconds%60;
 45 
 46     var curHours=parseInt(curShowTimeSeconds/3600);
 47     var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
 48     var curSeconds=curShowTimeSeconds%60;
 49 
 50     if(nextSeconds!=curSeconds){
 51         //小球
 52         if( parseInt(curHours/10) != parseInt(nextHours/10) ){
 53             addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
 54         }
 55         if( parseInt(curHours%10) != parseInt(nextHours%10) ){
 56             addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
 57         }
 58 
 59         if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
 60             addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
 61         }
 62         if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
 63             addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
 64         }
 65 
 66         if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
 67             addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
 68         }
 69         if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
 70             addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
 71         }
 72 
 73         //更新时间
 74         curShowTimeSeconds=nextShowTimeSeconds;
 75     }
 76     //更新小球的速度
 77     updateBalls();
 78 
 79 }
 80 
 81 function updateBalls(){
 82     for( var i = 0 ; i < balls.length ; i ++ ){
 83         balls[i].x += balls[i].vx;
 84         balls[i].y += balls[i].vy;
 85         balls[i].vy += balls[i].g;
 86         if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
 87             balls[i].y = WINDOW_HEIGHT-RADIUS;
 88             balls[i].vy = - balls[i].vy*0.75;
 89         }
 90     }
 91 }
 92 
 93 function addBalls( x , y , num ){
 94     console.log("addBalls");
 95     for( var i=0;i<digit[num].length;i++)
 96         for(var j=0;j<digit[num][i].length;j++)
 97             if( digit[num][i][j] == 1 ){
 98                 var aBall = {
 99                     x:x+j*2*(RADIUS+1)+(RADIUS+1),
100                     y:y+i*2*(RADIUS+1)+(RADIUS+1),
101                     g:1.5+Math.random(),
102                     vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
103                     vy:-5,
104                     color: colors[ Math.floor( Math.random()*colors.length ) ]
105                 };
106                 balls.push(aBall);
107             }
108 }
109 
110 function getCurrentShowTimeSeconds() {
111     var curTime=new Date();
112     var ret=endTime.getTime()-curTime.getTime();
113     ret=Math.round(ret/1000);
114     return ret>=0?ret:0;
115 }
116 
117 function render(cxt) {
118 
119     cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
120     var hours=parseInt(curShowTimeSeconds/3600);
121     var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
122     var seconds=curShowTimeSeconds%60;
123 
124     renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
125     renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
126     renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
127     renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
128     renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
129     renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
130     renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
131     renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt);
132 
133     for(var i=0;i<balls.length;i++){
134         cxt.fillStyle=balls[i].color;
135 
136         cxt.beginPath();
137         cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
138         cxt.closePath();
139 
140         cxt.fill();
141     }
142 
143 }
144 
145 function renderDigit(x,y,num,cxt) {
146     cxt.fillStyle="rgb(0,102,153)";
147 
148     for(var i=0;i<digit[num].length;i++)
149         for(var j=0;j<digit[num][i].length;j++)
150             if(digit[num][i][j]==1){
151             cxt.beginPath();
152             cxt.arc(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
153             cxt.closePath();
154 
155             cxt.fill()
156             }
157 }

效果达到了,不过小球会越来越多,最后弄得网页很卡很卡,对于代码的性能优化,是具有必要性的!

四、性能优化、扩展

1.优化:

改写countdown.js给updateBalls增加代码,让物理小球离开画布的,全都消失解放内存。(原视频教程中bug,我用另外的方法实现的,效果不错)

1     var cnt=[];
2     for(var i=0;i<balls.length;i++){
3         if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
4             cnt.push(balls[i]);
5         }
6     }
7     balls=cnt;

修改以后的countdown.js代码:

  1 var WINDOW_WIDTH=1024;
  2 var WINDOW_HEIGHT=600;
  3 var RADIUS=8;
  4 var MARGIN_TOP=60;
  5 var MARGIN_LIFT=30;
  6 const endTime=new Date("2018/3/20,18:47:52");//const代表常量
  7 var curShowTimeSeconds=0;
  8 
  9 //小球
 10 var balls = [];
 11 const colors = ["#33B5E5",
 12                 "#0099CC",
 13                 "#AA66CC",
 14                 "#9933CC",
 15                 "#99CC00",
 16                 "#669900",
 17                 "#FFBB33",
 18                 "#FF8800",
 19                 "#FF4444",
 20                 "#CC0000"]
 21 
 22 window.onload=function () {
 23 
 24     var canvas=document.getElementById('canvas');
 25     var context=canvas.getContext('2d');
 26 
 27     canvas.width=WINDOW_WIDTH;
 28     canvas.height=WINDOW_HEIGHT;
 29 
 30     curShowTimeSeconds=getCurrentShowTimeSeconds();
 31     // render(context);
 32     setInterval(function () {
 33         render(context);
 34         update();
 35         //打印物理小球个数
 36         console.log(balls.length);
 37     },
 38         50)
 39 };
 40 
 41 function update() {
 42     var nextShowTimeSeconds=getCurrentShowTimeSeconds();
 43 
 44     var nextHours=parseInt(nextShowTimeSeconds/3600);
 45     var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
 46     var nextSeconds=nextShowTimeSeconds%60;
 47 
 48     var curHours=parseInt(curShowTimeSeconds/3600);
 49     var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
 50     var curSeconds=curShowTimeSeconds%60;
 51 
 52     if(nextSeconds!=curSeconds){
 53         //小球
 54         if( parseInt(curHours/10) != parseInt(nextHours/10) ){
 55             addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
 56         }
 57         if( parseInt(curHours%10) != parseInt(nextHours%10) ){
 58             addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
 59         }
 60 
 61         if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
 62             addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
 63         }
 64         if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
 65             addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
 66         }
 67 
 68         if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
 69             addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
 70         }
 71         if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
 72             addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
 73         }
 74 
 75         //更新时间
 76         curShowTimeSeconds=nextShowTimeSeconds;
 77     }
 78     //更新小球的速度
 79     updateBalls();
 80 
 81 }
 82 
 83 function updateBalls(){
 84     for( var i = 0 ; i < balls.length ; i ++ ){
 85         balls[i].x += balls[i].vx;
 86         balls[i].y += balls[i].vy;
 87         balls[i].vy += balls[i].g;
 88         if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
 89             balls[i].y = WINDOW_HEIGHT-RADIUS;
 90             balls[i].vy = - balls[i].vy*0.75;
 91         }
 92     }
 93 
 94     var cnt=[];
 95     for(var i=0;i<balls.length;i++){
 96         if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
 97             cnt.push(balls[i]);
 98         }
 99     }
100     balls=cnt;
101 
102 }
103 
104 function addBalls( x , y , num ){
105     for( var i=0;i<digit[num].length;i++)
106         for(var j=0;j<digit[num][i].length;j++)
107             if( digit[num][i][j] == 1 ){
108                 var aBall = {
109                     x:x+j*2*(RADIUS+1)+(RADIUS+1),
110                     y:y+i*2*(RADIUS+1)+(RADIUS+1),
111                     g:1.5+Math.random(),
112                     vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
113                     vy:-5,
114                     color: colors[ Math.floor( Math.random()*colors.length ) ]
115                 };
116                 balls.push(aBall);
117             }
118 }
119 
120 function getCurrentShowTimeSeconds() {
121     var curTime=new Date();
122     var ret=endTime.getTime()-curTime.getTime();
123     ret=Math.round(ret/1000);
124     return ret>=0?ret:0;
125 }
126 
127 function render(cxt) {
128 
129     cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
130     var hours=parseInt(curShowTimeSeconds/3600);
131     var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
132     var seconds=curShowTimeSeconds%60;
133 
134     renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
135     renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
136     renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
137     renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
138     renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
139     renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
140     renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
141     renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt);
142 
143     for(var i=0;i<balls.length;i++){
144         cxt.fillStyle=balls[i].color;
145 
146         cxt.beginPath();
147         cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
148         cxt.closePath();
149 
150         cxt.fill();
151     }
152 
153 }
154 
155 function renderDigit(x,y,num,cxt) {
156     cxt.fillStyle="rgb(0,102,153)";
157 
158     for(var i=0;i<digit[num].length;i++)
159         for(var j=0;j<digit[num][i].length;j++)
160             if(digit[num][i][j]==1){
161             cxt.beginPath();
162             cxt.arc(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
163             cxt.closePath();
164 
165             cxt.fill()
166             }
167 }

效果图:

2.扩展改写为时钟

改写countdown.js中的getCurrentShowTimeSeconds函数:

1 function getCurrentShowTimeSeconds() {
2     var curTime=new Date();
3     var ret=curTime.getHours()*3600+curTime.getMinutes()*60+curTime.getSeconds();
4     return ret;
5 }

countdown.js时钟代码:

  1 var WINDOW_WIDTH=1024;
  2 var WINDOW_HEIGHT=600;
  3 var RADIUS=8;
  4 var MARGIN_TOP=60;
  5 var MARGIN_LIFT=30;
  6 //const endTime=new Date("2018/3/20,18:47:52");//const代表常量
  7 var curShowTimeSeconds=0;
  8 
  9 //小球
 10 var balls = [];
 11 const colors = ["#33B5E5",
 12                 "#0099CC",
 13                 "#AA66CC",
 14                 "#9933CC",
 15                 "#99CC00",
 16                 "#669900",
 17                 "#FFBB33",
 18                 "#FF8800",
 19                 "#FF4444",
 20                 "#CC0000"]
 21 
 22 window.onload=function () {
 23 
 24     var canvas=document.getElementById('canvas');
 25     var context=canvas.getContext('2d');
 26 
 27     canvas.width=WINDOW_WIDTH;
 28     canvas.height=WINDOW_HEIGHT;
 29 
 30     curShowTimeSeconds=getCurrentShowTimeSeconds();
 31     // render(context);
 32     setInterval(function () {
 33         render(context);
 34         update();
 35         //打印物理小球个数
 36         console.log(balls.length);
 37     },
 38         50)
 39 };
 40 
 41 function update() {
 42     var nextShowTimeSeconds=getCurrentShowTimeSeconds();
 43 
 44     var nextHours=parseInt(nextShowTimeSeconds/3600);
 45     var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
 46     var nextSeconds=nextShowTimeSeconds%60;
 47 
 48     var curHours=parseInt(curShowTimeSeconds/3600);
 49     var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
 50     var curSeconds=curShowTimeSeconds%60;
 51 
 52     if(nextSeconds!=curSeconds){
 53         //小球
 54         if( parseInt(curHours/10) != parseInt(nextHours/10) ){
 55             addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
 56         }
 57         if( parseInt(curHours%10) != parseInt(nextHours%10) ){
 58             addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
 59         }
 60 
 61         if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
 62             addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
 63         }
 64         if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
 65             addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
 66         }
 67 
 68         if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
 69             addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
 70         }
 71         if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
 72             addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
 73         }
 74 
 75         //更新时间
 76         curShowTimeSeconds=nextShowTimeSeconds;
 77     }
 78     //更新小球的速度
 79     updateBalls();
 80 
 81 }
 82 
 83 function updateBalls(){
 84     for( var i = 0 ; i < balls.length ; i ++ ){
 85         balls[i].x += balls[i].vx;
 86         balls[i].y += balls[i].vy;
 87         balls[i].vy += balls[i].g;
 88         if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
 89             balls[i].y = WINDOW_HEIGHT-RADIUS;
 90             balls[i].vy = - balls[i].vy*0.75;
 91         }
 92     }
 93 
 94     var cnt=[];
 95     for(var i=0;i<balls.length;i++){
 96         if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
 97             cnt.push(balls[i]);
 98         }
 99     }
100     balls=cnt;
101 
102 }
103 
104 function addBalls( x , y , num ){
105     for( var i=0;i<digit[num].length;i++)
106         for(var j=0;j<digit[num][i].length;j++)
107             if( digit[num][i][j] == 1 ){
108                 var aBall = {
109                     x:x+j*2*(RADIUS+1)+(RADIUS+1),
110                     y:y+i*2*(RADIUS+1)+(RADIUS+1),
111                     g:1.5+Math.random(),
112                     vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
113                     vy:-5,
114                     color: colors[ Math.floor( Math.random()*colors.length ) ]
115                 };
116                 balls.push(aBall);
117             }
118 }
119 
120 function getCurrentShowTimeSeconds() {
121     var curTime=new Date();
122     var ret=curTime.getHours()*3600+curTime.getMinutes()*60+curTime.getSeconds();
123     return ret;
124 }
125 
126 function render(cxt) {
127 
128     cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
129     var hours=parseInt(curShowTimeSeconds/3600);
130     var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
131     var seconds=curShowTimeSeconds%60;
132 
133     renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
134     renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
135     renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
136     renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
137     renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
138     renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
139     renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
140     renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt);
141 
142     for(var i=0;i<balls.length;i++){
143         cxt.fillStyle=balls[i].color;
144 
145         cxt.beginPath();
146         cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
147         cxt.closePath();
148 
149         cxt.fill();
150     }
151 
152 }
153 
154 function renderDigit(x,y,num,cxt) {
155     cxt.fillStyle="rgb(0,102,153)";
156 
157     for(var i=0;i<digit[num].length;i++)
158         for(var j=0;j<digit[num][i].length;j++)
159             if(digit[num][i][j]==1){
160             cxt.beginPath();
161             cxt.arc(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
162             cxt.closePath();
163 
164             cxt.fill()
165             }
166 }

现在的时间,效果图。

至此,完成了canvas的动画基础!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-03-19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、绘制基础
  • 二、倒计时电子钟的实现
  • 三、倒计时电子钟的实现
    • 1.实现倒计时效果,修改countdown.js
      • 2.使用canvas做一个物理小球
        • 3.根据物理小球的例子,对countdown.js进行改写:
        • 四、性能优化、扩展
          • 1.优化:
            • 2.扩展改写为时钟
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档