博客简介
之前的一篇博客中介绍了几个基础的动画。我们可以设置监听,通过鼠标控制实现更为高级的动画,在这里将绘制一个简单的桌面,桌面上再绘制一个刚体小球,我们可以给这个小球加上初速度,加速度,长尾效果…这是一个很经典的样例,在许多地方你都有可能见到它,并且应用到。
展示:
canvas绘制的刚体小球
首先创建一个对象
var ball=
{
x:100,
y:100,
vx:5,
vy:3,
r:20,
color:"#8A2BE2",//紫色小球
draw:function()
{
ctx.save();
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.fillStyle=this.color;
ctx.fill();
ctx.restore();
}
};
绘制函数
function draw()
{
ctx.clearRect(0,0,canvas.width,canvas.height);
//绘制背景
ctx.save();
ctx.fillStyle=" #2F4F4F";
ctx.strokeStyle=getColor();
ctx.lineWidth=40;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.strokeRect(0,0,canvas.width,canvas.height);
ctx.restore();
//计算速度
ball.vx*=(ball.x+ball.r+20>canvas.width||ball.x-ball.r-20<0)?-1:1;
ball.vy*=(ball.y+ball.r+20>canvas.height||ball.y-ball.r-20<0)?-1:1;
//计算位置
ball.x+=ball.vx;
ball.y+=ball.vy;
//画出图形
ball.color="rgb("+200+","+color1+","+color2+")";
ball.draw();
//递归调用
raf=window.requestAnimationFrame(draw);
}
这个时候我们可以得到这样的小球:
并且随着时间的推移,小球的位置发生变化,遇到墙壁反弹会反方向。
添加变化的颜色getColor
想不想要小球随着时间变化?那将会更加吸引人。为了得到变换的颜色,我设置了这样一个函数:
function getColor()//产生颜色
{
color1+=(t1==1)?2:-2;
color2+=(t2==1)?1:-1;
t1*=(color1>=255||color1<=0)?-1:1;
t2*=(color2>=255||color2<=0)?-1:1;
return "rgb("+color1+","+color2+","+20+")";
}
这样一来我们就能给小球和边框添加随时间变化的颜色了.
长尾效果
如何实现长尾效果?我们的绘制函数每当绘制一个新的图形时会清除整个画布,但是如果我们不清除画布而是用一个白色的半透明色fillRect函数取代它,这样每一帧就会越来越淡,直到消失。
ctx.save();
ctx.fillStyle='rgba(255,255,255,0.2)';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.restore();
这个时候就能看见长尾效果了。
添加加速度
为了让小球的行为更加真实,我们可以给速度添加一个线性的变换函数:
ball.vy *= .99;
ball.vy += .25;
这个时候竖直方向的速度将会逐渐减小,最后稳定在某个值,一直在地板上弹跳。
设置监听
如果想要与鼠标互动,那么可以用canvas.addEventListener来设置监听
- canvas.addEventListener(‘mousemove’, func)
关于鼠标的互动:
- mouseout:鼠标远离canvas触发
- click:鼠标点击canvas触发
- mousemove:鼠标移动触发
- mouseover:鼠标悬停触发
鼠标移动到画布上创建小球,移开鼠标动画停止
这个操作实现要结合mouseover和mouseout:
- mouseover:鼠标悬停触发,创建动画,调用draw函数
- mouseout:鼠标远离canvas触发,清除计时器,停止计时
- raf = window.requestAnimationFrame(draw);创建并且获取计时器对象
- window.cancelAnimationFrame(raf):清除定时器
window.onload=function()
{
canvas=document.getElementById("canvas");
ctx=canvas.getContext('2d');
//draw();
canvas.addEventListener("mouseover",function(e)
{
raf=requestAnimationFrame(draw);//创建动画
})
canvas.addEventListener("mouseout",function(e)
{
window.cancelAnimationFrame(raf);
})
}
鼠标点击画布创建小球,移开鼠标动画停止,重新放上画布又能按以上触发
这个操作实现要结合mousemove,click和mouseout:
- mousemove:鼠标移动触发。鼠标移动时,我们不能立即创建动画,而是只要画出小球,但是随着鼠标的移动,小球的移动轨迹将会练成一条涂鸦线,所以我们要在没有放上小球时清除整个画面再画上为触发的小球,调用draw函数。
- click:当屏幕上没有小球的时候,点击将会创建动画
- mouseout:鼠标远离canvas触发,清除计时器,停止计时
- 如何判断屏幕上有没有小球?我们可以设置一个全局变量用于判断,如果click后将变量改为1,表示有小球。如果鼠标离开了canvas,修改为0
canvas.addEventListener("mousemove",function(e)
{
if(!running)//没有小球
{
clear();
ball.x=e.clientX;
ball.y=e.clientY;
ball.draw();//只画出小球
}
})
canvas.addEventListener("click",function(e)
{
if(!running)//没有小球
{
raf=window.requestAnimationFrame(draw);
running=true;
}
})
canvas.addEventListener("mouseout",function()
{
window.cancelAnimationFrame(raf);//清除定时器
running=false;
})
最后是所有的代码:
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
<link rel="stylesheet" type="text/css" href="test.css">
<script src="test.js"></script>
</head>
<body>
<canvas id="canvas" width="600" height="300"></canvas>
</canvas>
</body>
</html>
JScript
var canvas,ctx,raf,color1=0,color2=0,t1=1,t2=1;
var running = false;
window.onload=function()
{
canvas=document.getElementById("canvas");
ctx=canvas.getContext('2d');
//绘制背景
ctx.save();
//ctx.fillStyle="#F0F8FF";
ctx.strokeStyle=getColor();
ctx.lineWidth=40;
//ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.strokeRect(0,0,canvas.width,canvas.height);
ctx.restore();
canvas.addEventListener("mousemove",function(e)
{
if(!running)//没有小球
{
clear();
ball.x=e.clientX;
ball.y=e.clientY;
ball.draw();//只画出小球
}
})
canvas.addEventListener("click",function(e)
{
if(!running)//没有小球
{
raf=window.requestAnimationFrame(draw);
running=true;
}
})
canvas.addEventListener("mouseout",function()
{
window.cancelAnimationFrame(raf);//清除定时器
running=false;
})
}
function clear() {
ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.fillRect(20,20,canvas.width-40,canvas.height-40);
}
var ball=
{
x:100,
y:100,
vx:5,
vy:3,
r:20,
color:"#8A2BE2",//紫色小球
draw:function()
{
ctx.save();
ctx.beginPath();
ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);
ctx.fillStyle=this.color;
ctx.fill();
ctx.restore();
}
};
function getColor()//产生颜色
{
color1+=(t1==1)?2:-2;
color2+=(t2==1)?1:-1;
t1*=(color1>=255||color1<=0)?-1:1;
t2*=(color2>=255||color2<=0)?-1:1;
return "rgb("+color1+","+color2+","+20+")";
}
function draw()
{
ctx.save();
ctx.fillStyle='rgba(255,255,255,0.2)';
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.restore();
//绘制背景
ctx.save();
ctx.strokeStyle=getColor();
ctx.lineWidth=40;
ctx.strokeRect(0,0,canvas.width,canvas.height);
ctx.restore();
//计算速度
ball.vy *= 0.99;
ball.vy += 0.25;
ball.vx*=(ball.x+ball.r+20>canvas.width||ball.x-ball.r-20<0)?-1:1;
ball.vy*=(ball.y+ball.r+20>canvas.height||ball.y-ball.r-20<0)?-1:1;
//计算位置
ball.x+=ball.vx;
ball.y+=ball.vy;
//画出图形
ball.color="rgb("+138+","+color1+","+226+")";
ball.draw();
//递归调用
raf=window.requestAnimationFrame(draw);
}