今天又是一天的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();
}
}
}
}