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

时间:2024-12-08 16:36:26

前言

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

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;">
</canvas> <script>
window.onload=function (ev) {
var canvas=document.getElementById('canvas');
canvas.width=1024;
canvas.height=600;
var context=canvas.getContext('2d');
//使用context绘制 context.lineWidth=5;
context.strokeStyle="#005588"; for(var i=0;i<10;i++){
context.beginPath();
context.arc(50+i*100,60,40,0,2*Math.PI*(i+1)/10);
context.closePath(); context.stroke()
} for(var i=0;i<10;i++){
context.beginPath();
context.arc(50+i*100,180,40,0,2*Math.PI*(i+1)/10);
// context.closePath(); context.stroke()
} for(var i=0;i<10;i++){
context.beginPath();
context.arc(50+i*100,300,40,0,2*Math.PI*(i+1)/10,true);
context.closePath(); context.stroke()
} for(var i=0;i<10;i++){
context.beginPath();
context.arc(50+i*100,420,40,0,2*Math.PI*(i+1)/10,true);
// context.closePath(); context.stroke()
} context.fillStyle="#005588";
for(var i=0;i<10;i++){
context.beginPath();
context.arc(50+i*100,540,40,0,2*Math.PI*(i+1)/10);
context.closePath(); context.fill()
} }
</script>
</body>
</html>

圆弧Code

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

二、倒计时电子钟的实现

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

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;">
</canvas> <script src="digit.js"></script>
<script src="countdown.js"></script> </body>
</html>
 digit =
[
[
[0,0,1,1,1,0,0],
[0,1,1,0,1,1,0],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,0,1,1,0],
[0,0,1,1,1,0,0]
],//0
[
[0,0,0,1,1,0,0],
[0,1,1,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[1,1,1,1,1,1,1]
],//1
[
[0,1,1,1,1,1,0],
[1,1,0,0,0,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,1,1,0],
[0,0,0,1,1,0,0],
[0,0,1,1,0,0,0],
[0,1,1,0,0,0,0],
[1,1,0,0,0,0,0],
[1,1,0,0,0,1,1],
[1,1,1,1,1,1,1]
],//2
[
[1,1,1,1,1,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,1,1,0],
[0,0,0,1,1,0,0],
[0,0,1,1,1,0,0],
[0,0,0,0,1,1,0],
[0,0,0,0,0,1,1],
[0,0,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,1,1,0]
],//3
[
[0,0,0,0,1,1,0],
[0,0,0,1,1,1,0],
[0,0,1,1,1,1,0],
[0,1,1,0,1,1,0],
[1,1,0,0,1,1,0],
[1,1,1,1,1,1,1],
[0,0,0,0,1,1,0],
[0,0,0,0,1,1,0],
[0,0,0,0,1,1,0],
[0,0,0,1,1,1,1]
],//4
[
[1,1,1,1,1,1,1],
[1,1,0,0,0,0,0],
[1,1,0,0,0,0,0],
[1,1,1,1,1,1,0],
[0,0,0,0,0,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,1,1,0]
],//5
[
[0,0,0,0,1,1,0],
[0,0,1,1,0,0,0],
[0,1,1,0,0,0,0],
[1,1,0,0,0,0,0],
[1,1,0,1,1,1,0],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,1,1,0]
],//6
[
[1,1,1,1,1,1,1],
[1,1,0,0,0,1,1],
[0,0,0,0,1,1,0],
[0,0,0,0,1,1,0],
[0,0,0,1,1,0,0],
[0,0,0,1,1,0,0],
[0,0,1,1,0,0,0],
[0,0,1,1,0,0,0],
[0,0,1,1,0,0,0],
[0,0,1,1,0,0,0]
],//7
[
[0,1,1,1,1,1,0],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,1,1,0],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,1,1,0]
],//8
[
[0,1,1,1,1,1,0],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[1,1,0,0,0,1,1],
[0,1,1,1,0,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,0,1,1],
[0,0,0,0,1,1,0],
[0,0,0,1,1,0,0],
[0,1,1,0,0,0,0]
],//9
[
[0,0,0,0],
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0],
[0,0,0,0],
[0,1,1,0],
[0,1,1,0],
[0,0,0,0],
[0,0,0,0]
]//:
];

digit.js

 var WINDOW_WIDTH=1024;
var WINDOW_HEIGHT=600;
var RADIUS=8;
var MARGIN_TOP=60;
var MARGIN_LIFT=30;
const endTime=new Date("2018/3/20,18:47:52");//js中的月份是从0-11,如果要表示7月,则用6表示,const代表常量
var curShowTimeSeconds=0; window.onload=function () { var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d'); canvas.width=WINDOW_WIDTH;
canvas.height=WINDOW_HEIGHT; curShowTimeSeconds=getCurrentShowTimeSeconds();
render(context);
}; function getCurrentShowTimeSeconds() {
var curTime=new Date();
var ret=endTime.getTime()-curTime.getTime();
ret=Math.round(ret/1000);
return ret>=0?ret:0;
} function render(cxt) {
var hours=parseInt(curShowTimeSeconds/3600);
var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
var seconds=curShowTimeSeconds%60; renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt); } function renderDigit(x,y,num,cxt) {
cxt.fillStyle="rgb(0,102,153)"; 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(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
cxt.closePath(); cxt.fill()
}
}

countdown.js

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

三、倒计时电子钟的实现

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

 var WINDOW_WIDTH=1024;
var WINDOW_HEIGHT=600;
var RADIUS=8;
var MARGIN_TOP=60;
var MARGIN_LIFT=30;
const endTime=new Date("2018/3/20,18:47:52");//js中的月份是从0-11,如果要表示7月,则用6表示,const代表常量
var curShowTimeSeconds=0; window.onload=function () { var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d'); canvas.width=WINDOW_WIDTH;
canvas.height=WINDOW_HEIGHT; curShowTimeSeconds=getCurrentShowTimeSeconds();
// render(context);
setInterval(function () {
render(context);
updata(); },
50)
}; function updata() {
var nextShowTimeSeconds=getCurrentShowTimeSeconds(); var nextHours=parseInt(nextShowTimeSeconds/3600);
var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
var nextSeconds=nextShowTimeSeconds%60; var curHours=parseInt(curShowTimeSeconds/3600);
var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
var curSeconds=curShowTimeSeconds%60; if(nextSeconds!=curSeconds){
curShowTimeSeconds=nextShowTimeSeconds;
} } function getCurrentShowTimeSeconds() {
var curTime=new Date();
var ret=endTime.getTime()-curTime.getTime();
ret=Math.round(ret/1000);
return ret>=0?ret:0;
} function render(cxt) { cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
var hours=parseInt(curShowTimeSeconds/3600);
var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
var seconds=curShowTimeSeconds%60; renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt); } function renderDigit(x,y,num,cxt) {
cxt.fillStyle="rgb(0,102,153)"; 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(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
cxt.closePath(); cxt.fill()
}
}

countdown

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

各一秒变化一次:

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

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

新建一个physical.html

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<canvas id="canvas" style="border:1px solid #aaa;display: block;margin: 50px auto;"></canvas>
</body> <script>
var ball={x:512,y:100,r:20,g:2,vx:-4,vy:0,color:"#005588"};
window.onload=function (ev) {
var canvas=document.getElementById("canvas");
canvas.width=1024;
canvas.height=600;
var context=canvas.getContext("2d");
//每隔50毫秒,生成一次小球,并更新下一次小球出现的位置和速度
setInterval(function () {
render(context);
update();
},50)
};
function render(cxt) {
cxt.clearRect(0,0,cxt.canvas.width,cxt.canvas.height); cxt.fillStyle=ball.color;
cxt.beginPath();
cxt.arc(ball.x,ball.y,ball.r,0,2*Math.PI)
cxt.closePath(); cxt.fill();
}
function update() {
ball.x+=ball.vx;
ball.y+=ball.vy;
ball.vy+=ball.g;
if(ball.y>canvas.height-ball.r){
ball.y=canvas.height-ball.r;
ball.vy=-ball.vy*0.5;
}
} </script>
</html>

physical.html

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

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

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

 //小球
var balls = [];
const colors = ["#33B5E5",
"#0099CC",
"#AA66CC",
"#9933CC",
"#99CC00",
"#669900",
"#FFBB33",
"#FF8800",
"#FF4444",
"#CC0000"]

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

 if(nextSeconds!=curSeconds){
//小球
if( parseInt(curHours/10) != parseInt(nextHours/10) ){
addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
}
if( parseInt(curHours%10) != parseInt(nextHours%10) ){
addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
} if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
}
if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
} if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
}
if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
} //更新时间
curShowTimeSeconds=nextShowTimeSeconds;
}
//更新小球的速度
updateBalls();

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

 function addBalls( x , y , num ){
console.log("addBalls");
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 aBall = {
x:x+j*2*(RADIUS+1)+(RADIUS+1),
y:y+i*2*(RADIUS+1)+(RADIUS+1),
g:1.5+Math.random(),
vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
vy:-5,
color: colors[ Math.floor( Math.random()*colors.length ) ]
};
balls.push(aBall);
}
}

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

 function updateBalls(){
for( var i = 0 ; i < balls.length ; i ++ ){
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
balls[i].y = WINDOW_HEIGHT-RADIUS;
balls[i].vy = - balls[i].vy*0.75;
}
}
}

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

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

修改后的countdown.js为:

 var WINDOW_WIDTH=1024;
var WINDOW_HEIGHT=600;
var RADIUS=8;
var MARGIN_TOP=60;
var MARGIN_LIFT=30;
const endTime=new Date("2018/3/20,18:47:52");//const代表常量
var curShowTimeSeconds=0; //小球
var balls = [];
const colors = ["#33B5E5",
"#0099CC",
"#AA66CC",
"#9933CC",
"#99CC00",
"#669900",
"#FFBB33",
"#FF8800",
"#FF4444",
"#CC0000"] window.onload=function () { var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d'); canvas.width=WINDOW_WIDTH;
canvas.height=WINDOW_HEIGHT; curShowTimeSeconds=getCurrentShowTimeSeconds();
// render(context);
setInterval(function () {
render(context);
update();
},
50)
}; function update() {
var nextShowTimeSeconds=getCurrentShowTimeSeconds(); var nextHours=parseInt(nextShowTimeSeconds/3600);
var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
var nextSeconds=nextShowTimeSeconds%60; var curHours=parseInt(curShowTimeSeconds/3600);
var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
var curSeconds=curShowTimeSeconds%60; if(nextSeconds!=curSeconds){
//小球
if( parseInt(curHours/10) != parseInt(nextHours/10) ){
addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
}
if( parseInt(curHours%10) != parseInt(nextHours%10) ){
addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
} if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
}
if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
} if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
}
if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
} //更新时间
curShowTimeSeconds=nextShowTimeSeconds;
}
//更新小球的速度
updateBalls(); } function updateBalls(){
for( var i = 0 ; i < balls.length ; i ++ ){
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
balls[i].y = WINDOW_HEIGHT-RADIUS;
balls[i].vy = - balls[i].vy*0.75;
}
}
} function addBalls( x , y , num ){
console.log("addBalls");
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 aBall = {
x:x+j*2*(RADIUS+1)+(RADIUS+1),
y:y+i*2*(RADIUS+1)+(RADIUS+1),
g:1.5+Math.random(),
vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
vy:-5,
color: colors[ Math.floor( Math.random()*colors.length ) ]
};
balls.push(aBall);
}
} function getCurrentShowTimeSeconds() {
var curTime=new Date();
var ret=endTime.getTime()-curTime.getTime();
ret=Math.round(ret/1000);
return ret>=0?ret:0;
} function render(cxt) { cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
var hours=parseInt(curShowTimeSeconds/3600);
var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
var seconds=curShowTimeSeconds%60; renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt); for(var i=0;i<balls.length;i++){
cxt.fillStyle=balls[i].color; cxt.beginPath();
cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
cxt.closePath(); cxt.fill();
} } function renderDigit(x,y,num,cxt) {
cxt.fillStyle="rgb(0,102,153)"; 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(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
cxt.closePath(); cxt.fill()
}
}

countdown

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

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

四、性能优化、扩展

1.优化:

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

     var cnt=[];
for(var i=0;i<balls.length;i++){
if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
cnt.push(balls[i]);
}
}
balls=cnt;

修改以后的countdown.js代码:

 var WINDOW_WIDTH=1024;
var WINDOW_HEIGHT=600;
var RADIUS=8;
var MARGIN_TOP=60;
var MARGIN_LIFT=30;
const endTime=new Date("2018/3/20,18:47:52");//const代表常量
var curShowTimeSeconds=0; //小球
var balls = [];
const colors = ["#33B5E5",
"#0099CC",
"#AA66CC",
"#9933CC",
"#99CC00",
"#669900",
"#FFBB33",
"#FF8800",
"#FF4444",
"#CC0000"] window.onload=function () { var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d'); canvas.width=WINDOW_WIDTH;
canvas.height=WINDOW_HEIGHT; curShowTimeSeconds=getCurrentShowTimeSeconds();
// render(context);
setInterval(function () {
render(context);
update();
//打印物理小球个数
console.log(balls.length);
},
50)
}; function update() {
var nextShowTimeSeconds=getCurrentShowTimeSeconds(); var nextHours=parseInt(nextShowTimeSeconds/3600);
var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
var nextSeconds=nextShowTimeSeconds%60; var curHours=parseInt(curShowTimeSeconds/3600);
var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
var curSeconds=curShowTimeSeconds%60; if(nextSeconds!=curSeconds){
//小球
if( parseInt(curHours/10) != parseInt(nextHours/10) ){
addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
}
if( parseInt(curHours%10) != parseInt(nextHours%10) ){
addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
} if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
}
if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
} if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
}
if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
} //更新时间
curShowTimeSeconds=nextShowTimeSeconds;
}
//更新小球的速度
updateBalls(); } function updateBalls(){
for( var i = 0 ; i < balls.length ; i ++ ){
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
balls[i].y = WINDOW_HEIGHT-RADIUS;
balls[i].vy = - balls[i].vy*0.75;
}
} var cnt=[];
for(var i=0;i<balls.length;i++){
if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
cnt.push(balls[i]);
}
}
balls=cnt; } function addBalls( x , y , 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 ){
var aBall = {
x:x+j*2*(RADIUS+1)+(RADIUS+1),
y:y+i*2*(RADIUS+1)+(RADIUS+1),
g:1.5+Math.random(),
vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
vy:-5,
color: colors[ Math.floor( Math.random()*colors.length ) ]
};
balls.push(aBall);
}
} function getCurrentShowTimeSeconds() {
var curTime=new Date();
var ret=endTime.getTime()-curTime.getTime();
ret=Math.round(ret/1000);
return ret>=0?ret:0;
} function render(cxt) { cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
var hours=parseInt(curShowTimeSeconds/3600);
var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
var seconds=curShowTimeSeconds%60; renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt); for(var i=0;i<balls.length;i++){
cxt.fillStyle=balls[i].color; cxt.beginPath();
cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
cxt.closePath(); cxt.fill();
} } function renderDigit(x,y,num,cxt) {
cxt.fillStyle="rgb(0,102,153)"; 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(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
cxt.closePath(); cxt.fill()
}
}

countdown.js

效果图:

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

2.扩展改写为时钟

改写countdown.js中的getCurrentShowTimeSeconds函数:

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

countdown.js时钟代码:

 var WINDOW_WIDTH=1024;
var WINDOW_HEIGHT=600;
var RADIUS=8;
var MARGIN_TOP=60;
var MARGIN_LIFT=30;
//const endTime=new Date("2018/3/20,18:47:52");//const代表常量
var curShowTimeSeconds=0; //小球
var balls = [];
const colors = ["#33B5E5",
"#0099CC",
"#AA66CC",
"#9933CC",
"#99CC00",
"#669900",
"#FFBB33",
"#FF8800",
"#FF4444",
"#CC0000"] window.onload=function () { var canvas=document.getElementById('canvas');
var context=canvas.getContext('2d'); canvas.width=WINDOW_WIDTH;
canvas.height=WINDOW_HEIGHT; curShowTimeSeconds=getCurrentShowTimeSeconds();
// render(context);
setInterval(function () {
render(context);
update();
//打印物理小球个数
console.log(balls.length);
},
50)
}; function update() {
var nextShowTimeSeconds=getCurrentShowTimeSeconds(); var nextHours=parseInt(nextShowTimeSeconds/3600);
var nextMinutes=parseInt((nextShowTimeSeconds-nextHours*3600)/60);
var nextSeconds=nextShowTimeSeconds%60; var curHours=parseInt(curShowTimeSeconds/3600);
var curMinutes=parseInt((curShowTimeSeconds-curHours * 3600)/60);
var curSeconds=curShowTimeSeconds%60; if(nextSeconds!=curSeconds){
//小球
if( parseInt(curHours/10) != parseInt(nextHours/10) ){
addBalls( MARGIN_LIFT + 0 , MARGIN_TOP , parseInt(curHours/10) );
}
if( parseInt(curHours%10) != parseInt(nextHours%10) ){
addBalls( MARGIN_LIFT + 15*(RADIUS+1) , MARGIN_TOP , parseInt(curHours/10) );
} if( parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
addBalls( MARGIN_LIFT + 39*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes/10) );
}
if( parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
addBalls( MARGIN_LIFT + 54*(RADIUS+1) , MARGIN_TOP , parseInt(curMinutes%10) );
} if( parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
addBalls( MARGIN_LIFT + 78*(RADIUS+1) , MARGIN_TOP , parseInt(curSeconds/10) );
}
if( parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
addBalls( MARGIN_LIFT + 93*(RADIUS+1) , MARGIN_TOP , parseInt(nextSeconds%10) );
} //更新时间
curShowTimeSeconds=nextShowTimeSeconds;
}
//更新小球的速度
updateBalls(); } function updateBalls(){
for( var i = 0 ; i < balls.length ; i ++ ){
balls[i].x += balls[i].vx;
balls[i].y += balls[i].vy;
balls[i].vy += balls[i].g;
if( balls[i].y >= WINDOW_HEIGHT-RADIUS ){
balls[i].y = WINDOW_HEIGHT-RADIUS;
balls[i].vy = - balls[i].vy*0.75;
}
} var cnt=[];
for(var i=0;i<balls.length;i++){
if(balls[i].x-RADIUS>0&&balls[i].x+RADIUS<WINDOW_WIDTH){
cnt.push(balls[i]);
}
}
balls=cnt; } function addBalls( x , y , 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 ){
var aBall = {
x:x+j*2*(RADIUS+1)+(RADIUS+1),
y:y+i*2*(RADIUS+1)+(RADIUS+1),
g:1.5+Math.random(),
vx:Math.pow( -1 , Math.ceil( Math.random()*1000 ) ) * 4,
vy:-5,
color: colors[ Math.floor( Math.random()*colors.length ) ]
};
balls.push(aBall);
}
} function getCurrentShowTimeSeconds() {
var curTime=new Date();
var ret=curTime.getHours()*3600+curTime.getMinutes()*60+curTime.getSeconds();
return ret;
} function render(cxt) { cxt.clearRect(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);//对整个画布进行刷新,防止新画的跟以前画的叠加
var hours=parseInt(curShowTimeSeconds/3600);
var minutes=parseInt((curShowTimeSeconds-hours * 3600)/60);
var seconds=curShowTimeSeconds%60; renderDigit(MARGIN_LIFT,MARGIN_TOP,parseInt(hours/10),cxt);
renderDigit(MARGIN_LIFT+15*(RADIUS+1),MARGIN_TOP,parseInt(hours%10),cxt);
renderDigit(MARGIN_LIFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
renderDigit(MARGIN_LIFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
renderDigit(MARGIN_LIFT+54*(RADIUS+1),MARGIN_TOP,parseInt(minutes%10),cxt);
renderDigit(MARGIN_LIFT+69*(RADIUS+1),MARGIN_TOP,parseInt(10),cxt);
renderDigit(MARGIN_LIFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
renderDigit(MARGIN_LIFT+93*(RADIUS+1),MARGIN_TOP,parseInt(seconds%10),cxt); for(var i=0;i<balls.length;i++){
cxt.fillStyle=balls[i].color; cxt.beginPath();
cxt.arc(balls[i].x,balls[i].y,RADIUS,0,2*Math.PI,true);
cxt.closePath(); cxt.fill();
} } function renderDigit(x,y,num,cxt) {
cxt.fillStyle="rgb(0,102,153)"; 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(x+j*2*(RADIUS+1)+(RADIUS+1),y+i*2*(RADIUS+1)+(RADIUS+1),RADIUS,0,2*Math.PI);
cxt.closePath(); cxt.fill()
}
}

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

现在的时间,效果图。

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