说说今天学习的用JS绘制绚丽的时钟效果

今天又是一天的html5的Canvas属性的学习,然后自己做了一个小demo,绘制了一个绚丽的带有动画效果的时钟。

废话不多说,先贴图,大家感受下:


上面分别是时分秒,时间走动,只有某个数字改变了,组成数字的小圆球们就会变成随机的彩色小球以自由落体运动下落,然后随机朝两边滚动,然后滚到画面外。效果很简单,但实现起来还要结合已学的物理和数学知识。


下面贴上代码。大家可以自己试试

index.html:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="utf-8">
    <title></title>
</head>
<body style="height:100%">
    <canvas id="canvas" style="border:1px solid #aaa;display:block;margin:50px auto;">
        当前浏览器不支持canvas
    </canvas>


<script type="text/javascript" src="digit.js"></script>
<script type="text/javascript" src="canvas.js"></script>
</body>
</html>

digit.js:  这里面定义了数字的二维矩阵,1表示小圆球显示位置,通过多个小圆球组成数字。最后一个是冒号的矩阵

var 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,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]
		],  //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]
		]  //:
	];

canvas.js:这里面是具体的逻辑实现代码,关键地方我都有写注释,大家有什么不懂的可以在评论上问我。

var WINDOW_WIDTH = 1024;
var WINDOW_HEIGHT = 600;

// 小圆半径
var RADIUS = 8;

// 绘制小圆的起点
var MARGIN_TOP = 60;
var MARGIN_LEFT = 30;

// 截止时间
// const endTime = new Date();
// 设置截止时间为当前时间1小时后
// endTime.setTime( endTime.getTime()+3600*1000);

// 倒计时时间
var curShowTimeSeconds = 0;

// 用于存储彩色小圆球的数组
var balls = [];

// 彩色小圆球的颜色
const colors = ["#33B5E5","#0099CC","#AA66CC","#9933CC","#99CC00","#669900","#FFBB33","#FF8800","#FF4444","#CC0000"];

window.onload = function() {

	//屏幕自适应
	WINDOW_WIDTH = document.body.clientWidth;
	//WINDOW_HEIGHT = document.body.clientHeight;

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

	// 获取canvas标签
	var canvas = document.getElementById("canvas");
	// 获取canvas上下文
	var context = canvas.getContext("2d");

	canvas.width = WINDOW_WIDTH;
	canvas.height = WINDOW_HEIGHT;

	// 得到当前时间
	curShowTimeSeconds = getCurrentShowTimeSeconds();
	
	// 执行动画效果经常会使用的函数,表示每隔50毫秒执行一次function()
	setInterval(
		function() {
			render(context);	// 渲染画面	
			update();			// 更新数据
		},
		50
	);


}

function getCurrentShowTimeSeconds() {
	// 获取当前时间
	var curTime = new Date();

	// 返回今天已经经过的时间秒数
	var ret = curTime.getHours()*3600 + curTime.getMinutes()*60
	+curTime.getSeconds();

	return ret;
}

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)) {
			 //改变 curHours%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)) {
			//改变 curSeconds%10
			addBalls(MARGIN_LEFT+93*(RADIUS+1),MARGIN_TOP,parseInt(nextSeconds%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.5;
		}
	}

	//以下为改善性能,防止balls数组太大,所以删掉出了画面的小球
	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];
		}
	}
	// 删掉后面已经出界面的小球
	while(balls.length > 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]){
				var aBall = {
					x:x+j*2*(RADIUS+1)+(RADIUS+1),		// 小球圆心的横坐标
					y:y+i*2*(RADIUS+1)+(RADIUS+1),		// 小球圆心的纵坐标
					g:1.5+Math.random(),				// 小球下坠的加速度
					// Math.ceil表示取整, Math.pow表示开方:第一个参数是底数,第二个是参数是次方数
					vx:Math.pow(-1,Math.ceil(Math.random()*1000))*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);								// 个位

	// updateBalls函数中已经定义好了彩色小圆球的属性和状态,并放在balls数组里,下面只需循环遍历绘制彩色的小圆球
	for (var i = 0; i < balls.length; i++) {
		cxt.fillStyle = balls[i].color;
		cxt.beginPath();
		// 具体绘制小球,属性分别是小球圆心的横坐标,小球圆心的纵坐标,小球半径,小球绘制的起点0,小球绘制的终点2π,顺时针或逆时针绘制
		// 因为是2π,画成的一个正圆,所以顺时针逆时针都可以
		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();
			}
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值