zoukankan      html  css  js  c++  java
  • 炫丽的倒计时效果Canvas绘图与动画基础

    前言

    想要在自己做的网页中,加入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>
    图线 Code
     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>
    圆弧Code

    二、倒计时电子钟的实现

    新建两个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     ];
    digit.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 };
    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 }
    countdown.js

    注意:数组阵列中,只能从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 }
    countdown

    各一秒变化一次:

    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>
    physical.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 }
    countdown

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

    四、性能优化、扩展

    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 }
    countdown.js

    效果图:

    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 }
    View Code

    现在的时间,效果图。

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

  • 相关阅读:
    Spring MVC 框架搭建及详解
    设计模式应用案例(上)
    UAC权限
    General Structure of Quartz.NET and How To Implement It
    求比指定数大且最小的“不重复数”问题
    Getting Started with Core Data
    HDU 2034 人见人爱A-B
    第九届蓝桥杯JavaC组决(国)赛真题
    第九届蓝桥杯JavaC组决(国)赛真题
    第九届蓝桥杯JavaC组决(国)赛真题
  • 原文地址:https://www.cnblogs.com/xuepangzi/p/8605584.html
Copyright © 2011-2022 走看看