canvas初学之倒计时动画

                                   制作一个倒计时的动画

        我们来看这个动画,在时间变化的同时,会有小球动画从原时间上炸开,落到地上。因此我们主要的工作首先是要显示出由点构成的时间,其次需要每秒变化时间,最后就是小球的动画了。先来看一下效果图:

这是一个简单的1个小时倒计时的动画,接下来我们来看如何制作这段代码:

1. 时间点阵

时间点阵的显示可以通过二维数组点阵来显示,这里我们建立一个digit.js的文件专门用于时间点阵,代码如下:

//0-9为:10行7列(10*7),而冒号:(10*4)
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]
        ]//:
    ];

这个点阵包含了0-9的数字以及一个冒号,我们在显示时间的时候只需要调用点阵相对的数字即可。 

2.时间动画

    我们如何能制作时间这个动画呢?要制作倒计时,首先需要知道当前时间与规定时间的差值,因此,我们为此封装一个函数getCurrentShowTimeSeconds()

//获取当前时间与规定时间之差,返回值为秒
function getCurrentShowTimeSeconds(){
	var curTime = new Date()
	var ret = endTime.getTime()-curTime.getTime()//此处获得为毫秒数
	ret = Math.round(ret/1000)//转化为秒
	return ret>=0?ret:0;
}

在这个函数中,首先我们通过js的date()函数与getTime()函数求出规定时间与当前时间的差值(单位为毫秒),然后换算为秒数,如果这个秒数大于0,则返回秒数,如果小于0 ,即当前时间已经超过了规定时间,那么返回0;

找到时间差值后,我们需要绘制出当前的时间,首先,我们需要想到,如何绘制单个数字,在这里我们建立了一个renderDigit(x,y,num,cxt)函数:

function renderDigit(x,y,num,cxt){
	cxt.fillStyle = '#e89abe';
	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();
			}
		}
	}
}

renderDigit(x,y,num,cxt)函数 主要是为了绘制每个具体的数字,其中x,y是绘制出的数字的坐标,num表示需要绘制的数字是多少,在renderDigit函数中,引入digit.js并遍历所需要绘制的数字的那个数组,完整绘制出想要的数字。

当我们可以绘制每个数字后,就需要绘制出需要显示的时间的所有数字,我们将这个功能封装在render函数中:

//绘制时间
	var hours = parseInt(curShowTimeSeconds/3600);
	var minutes = parseInt(curShowTimeSeconds-hours*3600)/60;
	var seconds = curShowTimeSeconds%60;

	renderDigit(MARGIN_LEFT,MARGIN_TOP,parseInt(hours/10),cxt);
	renderDigit(MARGIN_LEFT+15*(RADIUS+1), MARGIN_TOP,parseInt(hours%10),cxt);
	renderDigit(MARGIN_LEFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
	renderDigit(MARGIN_LEFT+54*(RADIUS+1), MARGIN_TOP,parseInt(minutes%10),cxt);
	renderDigit(MARGIN_LEFT+69*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
	renderDigit(MARGIN_LEFT+93*(RADIUS+1), MARGIN_TOP,parseInt(seconds%10),cxt);

其中,curShowTimeSeconds为我们最初设定的一个变量,初始值为0:

 var curShowTimeSeconds = 0//表示现在距离倒计时需要多少秒

curShowTimeSeconds = getCurrentShowTimeSeconds();

通过换算,就可以获得所需要的时,分,秒的具体数值,然后我们就需要开始绘制时间:

在renderDigit函数中,x为绘制的左边距,y为绘制的右边距,num为数字

其中x如何获得是一个难点:

我们需要观察我们的digit.js中的二维数组,通过观察,可以发现0-9的数字是10*7的数组,而冒号是10*4的数组,因此每个数字的宽度应该是14*R,R为绘制出的点阵中每个点的半径,我们可以通过画格子的方式来绘制点

                               (图片转自慕课网liuyubobobo讲师课程炫丽的倒计时效果canvas绘图与动画基础) 

这样我们就可以画出每个数字了

接下来,我们需要将时间动起来,我们将这个功能写在一个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) {
		
	curShowTimeSeconds = nextShowTimeSeconds
}

建立一个新的变量nextShowTimeSeconds,用于存储下一次调用函数的时间,计算下一次的时间 与本次是否相同,如果相同,则不变,不同,则用新秒数替换原来的秒数,重新绘制时间

3.最后,我们需要添加小球的动画

首先,依旧是要绘制小球,绘制的功能我们都放在render函数中,我们首先设置一个balls[]数组,数组中存放着所有的小球,通过addBalls(x,y,num)函数为这个数组中增加小球:

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(),//随机一个g,即g取值在1.5-2.5之间
					vx:Math.pow(-1,Math.ceil(Math.random()*1000))*4,//ceil,向上取整;-1的多少次方
					//vx即为随机取值在-4或4,如果随机为偶数,则为4,否则为-4
					vy:-5,
					//小球颜色,随机一个索引
					color:colors[Math.floor(Math.random()*colors.length)]
				}

				balls.push(aBall)
			}
		}
	}

}

首先遍历digit二维数组中的digit[num]数组,如果digit[num][i][j]==1,即这个点阵[i][j]处位置需要画上小球,那么我们在这里加上一个小球,用于计时的时候让这些小球滚落。

 因为我们的小球颜色,运动轨迹都是随机的,因此,我们使用随机函数来随机小球的颜色和运动轨迹,小球的颜色我们设置一个数组,在随机小球颜色中随机的即为数组中的颜色

const colors = ["#33B5E5","#0099CC","#AA66CC","#9933CC","#99CC00","#669900","#FFBB33","#FF8800","#FF4444","#CC0000"]

这样我们就可以在balls[]数组中加上小球了,接下来就可以绘制了,我们来看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();
	}

小球绘制比较简单,只需要遍历balls数组即可。

如何做出小球滚动的动画呢?我们应该发现了,对于时间和小球的绘制,我都将其放在render函数中,而同理,对于动画功能,我们也应该将其放在一个函数中,应该都将其放在update函数中,然而每一个小球动画的具体细节,还是应该封装为另一个函数,然后我们再在update中调用即可,新封住的函数为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 = 0
	for (var i = 0; i < balls.length; i++) {
		if (balls[i].x + RADIUS>0&&balls[i].x- RADIUS<WINDOW_WIDTH) {
			balls[cnt++] = balls[i]//一旦小球符和条件在画布里,则将符和的小球挤在balls数组前面

		}
	}
	while(balls.length>Math.min(300,cnt)){
		balls.pop();
	}
}

首先遍历balls数组,设置小球轨迹与碰撞检测,如果碰到下边距,则令小球反弹回来,只是反弹的速度为原速度的0.75倍,这是为了更加贴合实际中的空气阻力。同时,我们需要将一些已经跑出屏幕外的小球从balls数组中删除,这样,每次更新的小球动画就完成了,我们接下来需要看的就是每次更新时,怎样调用这个动画,在update函数中:

我们在之前的写好的update函数中新添加了这些内容用于更新小球:

	if (nextSeconds != curSeconds) {
		if(parseInt(curHours/10) != parseInt(nextHours/10) ){
			addBalls(MARGIN_LEFT+0,MARGIN_TOP,parseInt(curHours/10));
		}
		if(parseInt(curHours%10) != parseInt(nextHours%10) ){
			addBalls(MARGIN_LEFT+15*(RADIUS+1),MARGIN_TOP,parseInt(curHours%10));
		}

		if(parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
			addBalls(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes/10));
		}
		if(parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
			addBalls(MARGIN_LEFT+54*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes%10));
		}

		if(parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
			addBalls(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds/10));
		}
		if(parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
			addBalls(MARGIN_LEFT+93*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds%10));
		}

		curShowTimeSeconds = nextShowTimeSeconds
	}
	updateBalls();

现在,我们大部分的内容都已经写好了,我们来看一下这个程序最主要的两个函数render函数和update函数的所有代码:

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_LEFT+0,MARGIN_TOP,parseInt(curHours/10));
		}
		if(parseInt(curHours%10) != parseInt(nextHours%10) ){
			addBalls(MARGIN_LEFT+15*(RADIUS+1),MARGIN_TOP,parseInt(curHours%10));
		}

		if(parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
			addBalls(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes/10));
		}
		if(parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
			addBalls(MARGIN_LEFT+54*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes%10));
		}

		if(parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
			addBalls(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds/10));
		}
		if(parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
			addBalls(MARGIN_LEFT+93*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds%10));
		}

		curShowTimeSeconds = nextShowTimeSeconds
	}
	updateBalls();
	console.log(balls.length)
}
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_LEFT,MARGIN_TOP,parseInt(hours/10),cxt);
	renderDigit(MARGIN_LEFT+15*(RADIUS+1), MARGIN_TOP,parseInt(hours%10),cxt);
	renderDigit(MARGIN_LEFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
	renderDigit(MARGIN_LEFT+54*(RADIUS+1), MARGIN_TOP,parseInt(minutes%10),cxt);
	renderDigit(MARGIN_LEFT+69*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
	renderDigit(MARGIN_LEFT+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();
	}
}

为了做到每秒都会和真实时间一样改变,我们用js中的计时器setInterval来将render函数与update函数包围

	setInterval(function(){
			render(context);
			update();
		},50
	);

设定的是每50ms更新一次,可能有人会问,为什么不是1s更新一次,因为我们的倒计时就是每秒会跳动的啊?后来通过验证发现,当设置为1s更新时,会有运行延迟,每次刷新都会超过1s,我们能明显感觉到刷新,而当设置为50ms时,就是1s内页面会多次刷新,这样会让动画效果更流畅。

现在,我们的工作基本都完成了,上源码:

html:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>倒计时</title>
	<script type="text/javascript" src="js/digit.js"></script>
	<script type="text/javascript" src="js/countdown.js"></script>
</head>
<body style="height: 100%">
	<h1 class="tishi">一小时倒计时:</h1>
	<canvas id="canvas" style="height: 100%">当前浏览器不支持canvas,请更换浏览器后再试</canvas>
</body>
</html>

countdown.js:

var WINDOW_WIDTH = 1024
var WINDOW_HEIGHT = 600
var RADIUS = 8
var MARGIN_TOP = 60//每个数字距离上边距的距离
var MARGIN_LEFT = 30//第一个数字距离左边距的距离
var endTime = new Date()
endTime.setTime(endTime.getTime()+3600*1000)
var curShowTimeSeconds = 0//表示现在倒计时需要多少秒

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

window.onload = function(){


	WINDOW_WIDTH = document.documentElement.clientWidth
	WINDOW_HEIGHT = document.documentElement.clientHeight

	MARGIN_LEFT = Math.round(WINDOW_WIDTH/10)
	RADIUS = Math.round(WINDOW_WIDTH*4/5/108)-1

	MARGIN_TOP = Math.round(WINDOW_HEIGHT/5)


	var canvas = document.getElementById('canvas')
	var context = canvas.getContext('2d')

	canvas.width = WINDOW_WIDTH
	canvas.height = WINDOW_HEIGHT

	curShowTimeSeconds = getCurrentShowTimeSeconds();
	setInterval(function(){
			render(context);
			update();
		},50
	);
}
//获取当前时间与规定时间之差,返回值为秒
function getCurrentShowTimeSeconds(){
	var curTime = new Date()
	var ret = endTime.getTime()-curTime.getTime()//此处获得为毫秒数
	ret = Math.round(ret/1000)//转化为秒
	return ret>=0?ret:0;
}

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_LEFT+0,MARGIN_TOP,parseInt(curHours/10));
		}
		if(parseInt(curHours%10) != parseInt(nextHours%10) ){
			addBalls(MARGIN_LEFT+15*(RADIUS+1),MARGIN_TOP,parseInt(curHours%10));
		}

		if(parseInt(curMinutes/10) != parseInt(nextMinutes/10) ){
			addBalls(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes/10));
		}
		if(parseInt(curMinutes%10) != parseInt(nextMinutes%10) ){
			addBalls(MARGIN_LEFT+54*(RADIUS+1),MARGIN_TOP,parseInt(curMinutes%10));
		}

		if(parseInt(curSeconds/10) != parseInt(nextSeconds/10) ){
			addBalls(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds/10));
		}
		if(parseInt(curSeconds%10) != parseInt(nextSeconds%10) ){
			addBalls(MARGIN_LEFT+93*(RADIUS+1),MARGIN_TOP,parseInt(curSeconds%10));
		}

		curShowTimeSeconds = nextShowTimeSeconds
	}
	updateBalls();
	console.log(balls.length)
}


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 = 0
	for (var i = 0; i < balls.length; i++) {
		if (balls[i].x + RADIUS>0&&balls[i].x- RADIUS<WINDOW_WIDTH) {
			balls[cnt++] = balls[i]//一旦小球符和条件在画布里,则将符和的小球挤在balls数组前面

		}
	}
	while(balls.length>Math.min(300,cnt)){
		balls.pop();
	}
}


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(),//随机一个g,即g取值在1.5-2.5之间
					vx:Math.pow(-1,Math.ceil(Math.random()*1000))*4,//ceil,向上取整;-1的多少次方
					//vx即为随机取值在-4或4,如果随机为偶数,则为4,否则为-4
					vy:-5,
					//小球颜色,随机一个索引
					color:colors[Math.floor(Math.random()*colors.length)]
				}

				balls.push(aBall)
			}
		}
	}

}


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_LEFT,MARGIN_TOP,parseInt(hours/10),cxt);
	renderDigit(MARGIN_LEFT+15*(RADIUS+1), MARGIN_TOP,parseInt(hours%10),cxt);
	renderDigit(MARGIN_LEFT+30*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+39*(RADIUS+1),MARGIN_TOP,parseInt(minutes/10),cxt);
	renderDigit(MARGIN_LEFT+54*(RADIUS+1), MARGIN_TOP,parseInt(minutes%10),cxt);
	renderDigit(MARGIN_LEFT+69*(RADIUS+1),MARGIN_TOP,10,cxt);
	renderDigit(MARGIN_LEFT+78*(RADIUS+1),MARGIN_TOP,parseInt(seconds/10),cxt);
	renderDigit(MARGIN_LEFT+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 = '#e89abe';
	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();
			}
		}
	}
}

这样,我们炫丽的倒计时效果就做出来啦~

当然,我们也可以将其改造成时钟:

·倒计时扩展的时钟效果:
首先,不需要endTime这个变量(这个变量本身代替的是结束的时间)
除此之外,修改的焦点应当主要放在getCurrentShowTimeSeconds()中,倒计时效果中,该函数
表示现在距离倒计时结束的时间还有多少秒。而如果改成时钟,即将这个函数改为今天已经走了
多少秒即可

猜你喜欢

转载自blog.csdn.net/Yvonne_Lu7/article/details/81231255