2.4.1 清除canvas上的内容
要清除canvas上的内容,只需使用 clearRect() 方法清除整个 canvas 区域就行了。
如:
<script>
context.clearRect(0,0,canvas.width,canvas.height); </script>
代码
function clearCanvas(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height); }
2.4.2 使用 requestAnimationFrame 方法创建动画
如果要用 HTML5 的 canvas 创建动画,那么就需要用到 requestAnimationFrame 方法,这个
方法能够使浏览器智能的判断帧率 FPS ,而且对于动画的每一帧我们都可以进行更新、清除 canvas 、重画 canvas,然后申请下一帧动画。
译者注:在这里,动画的帧率跟你的机器硬件、浏览器软件的具体情况有一定关系,一般来说流畅
的动画帧率在40FPS到60FPS之间。那么,对于程序员来说,很难判断应该针对每一个具体的用户使用多大的帧率,因此,各大浏览器都为我们提供了一个 windows.requestAnimationFrame 方法来自动的判断具体的帧率,这就给程序员省去了很多麻烦。
这个 requestAnimationFrame 方法接受一个由用户自定义的回调函数对象作为参数,
requestAnimationFrame 将在当前帧完成后自动调用这个回调函数,而我们要做的就是在这个回调
函数中进行我们的下一帧图像绘制操作,并在此回调函数最后再次调用 requestAnimationFrame 方法,使动画一帧帧的连续绘制下去。
比如说,我们的绘图方法叫做 animate,将此方法注册为windows.onload方法,每次页面调用
就启动此方法,每次调用 animate 就在 canvas 绘制当前时间应该显示的那一帧图像,并在
animate 结尾返回之前,以其自身,也就是以 animate 为回调函数参数调用
requestAnimationFrame, 由 requestAnimationFrame 自动再次调用 animate 绘制下一帧图像。这个基本的流程可以参见下图:
不过,由于不同的浏览器对 requestAnimationFrame 的支持程度不同,所以,是使用的时候一般要稍作调整,通过对requestAnimationFrame 的再封装提高程序对不同浏览器的兼容度。具体可以声明一个如下的 requestAnimFrame 方法来替代requestAnimationFrame(注意名字不同):
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback){
window.setTimeout(callback, 1000 / 60); };
})();
上面代码中的 webkitRequestAnimationFrame、 mozRequestAnimationFrame、
oRequestAnimationFrame 和 msRequestAnimationFrame 分别是兼容 Chrome、 Firefox、 Opera 和 IE。
这样,在animate 的最后只要添加如下一行就可以了。
requestAnimFrame(function() { animate(); });
比较完整的实现方法参见下面的代码。至于animate中如何确定当前具体应该是哪一帧图像,可以
参见下一节的内容。
代码
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(){
var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d");
// 更新图像
// 清屏
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘制当前帧
// 请求绘制下一帧
requestAnimFrame(function(){
animate();
});
}
window.onload = function(){
// 初始化
animate(); };
2.4.3 线性运动
创建线性运动的动画,我们需要在每一帧里根据运动速度和方向调整运动对象的 (x, y) 坐标的值。其中的速度就是来自等式“距离=速度×时间”。
效果动画
http://www.html5canvastutorials.com/advanced/html5-canvas-linear-motion-
animation/
译者注:本例中的 animate 带有两个参数,其中的 lastTime 指的是上一帧调用的时间,通过
与当前时间的比较来确定当前帧中运动物体的位置。
代码
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(lastTime, myRectangle){ var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d");
// 更新图像
var date = new Date(); var time = date.getTime(); var timeDiff = time - lastTime; var linearSpeed = 100; // 像素 / 秒
var linearDistEachFrame = linearSpeed * timeDiff / 1000; var currentX = myRectangle.x;
if (currentX < canvas.width - myRectangle.width -
myRectangle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myRectangle.x = newX;
}
lastTime = time;
// 清屏
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘图 context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width,
myRectangle.height);
context.fillStyle = "#8ED6FF"; context.fill();
context.lineWidth = myRectangle.borderWidth; context.strokeStyle = "black";
context.stroke();
// 请求绘制下一帧
requestAnimFrame(function(){ animate(lastTime, myRectangle);
});
}
window.onload = function(){ var myRectangle = { x: 0, y: 50, width: 100, height: 50, borderWidth: 5
};
var date = new Date(); var time = date.getTime(); animate(time, myRectangle); };
2.4.4 加速运动加速运动可以通过修改水平 vx 和垂直方向上 vy 的加速度来实现。
效果图
http://www.html5canvastutorials.com/advanced/html5-canvas-quadraticmotion-animation/
代码
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRectangle(myRectangle){
var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d");
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width, myRectangle.height);
context.fillStyle = "#8ED6FF";
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = "black"; context.stroke();
}
function animate(lastTime, myRectangle){ var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// 更新图像
var date = new Date(); var time = date.getTime(); var timeDiff = time - lastTime; var gravity = 2; // 像素 / 秒^2
var speedIncrementEachFrame = gravity * timeDiff / 1000; // 像素 / 秒 myRectangle.vy += speedIncrementEachFrame; myRectangle.y += (myRectangle.vy * timeDiff);
if (myRectangle.y > canvas.height - myRectangle.height -
myRectangle.borderWidth / 2) {
myRectangle.y = canvas.height - myRectangle.height -
myRectangle.borderWidth / 2;
}
lastTime = time;
// 清屏
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘图
drawRectangle(myRectangle);
// 请求绘制下一帧
requestAnimFrame(function(){ animate(lastTime, myRectangle);
});
}
window.onload = function(){ var myRectangle = { x: 239, y: 0, vx: 0, vy: 0, width: 100, height: 50, borderWidth: 5
};
drawRectangle(myRectangle);
// 矩形下坠前等待一分钟
setTimeout(function(){ var date = new Date(); var time = date.getTime(); animate(time, myRectangle);
}, 1000);
};
2.4.5 震荡
震荡效果我们用这样一个公式来计算像素的坐标位置:x(时间) = 振幅 * sin(时间 * 2PI / 周
期) + x0。(x0为像素点的原始位置)效果图
http://www.html5canvastutorials.com/advanced/html5-canvas-oscillation-
animation/
代码
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function animate(myRectangle){
var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d");
// 更新图像
var date = new Date(); var time = date.getTime(); var amplitude = 150; var period = 2000; // 单位是毫秒
var centerX = canvas.width / 2 - myRectangle.width / 2; var nextX = amplitude *
Math.sin(time * 2 * Math.PI / period) + centerX;
myRectangle.x = nextX;
// 清屏
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘图
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width,
myRectangle.height);
context.fillStyle = "#8ED6FF";
context.fill();
context.lineWidth = myRectangle.borderWidth;
context.strokeStyle = "black"; context.stroke();
// 请求绘制下一帧
requestAnimFrame(function(){ animate(myRectangle);
});
}
window.onload = function(){ var myRectangle = { x: 250, y: 70, width: 100, height: 50, borderWidth: 5
};
animate(myRectangle); };
2.4.6 开始和停止动画
要开始动画,我们只需要调用一个不断请求下一帧的方法就可以了,而要停止已启动的动画,那么就只要不再继续请求下一帧就行了。
效果 http://www.html5canvastutorials.com/advanced/html5-canvas-start-and-stop-
an-animation/
代码
window.requestAnimFrame = (function(callback){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
function drawRect(myRectangle){
var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d");
context.beginPath();
context.rect(myRectangle.x, myRectangle.y, myRectangle.width,
myRectangle.height);
context.fillStyle = "#8ED6FF"; context.fill();
context.lineWidth = myRectangle.borderWidth; context.strokeStyle = "black";
context.stroke();
}
function animate(lastTime, myRectangle, animProp){
if (animProp.animate) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
// 更新
var date = new Date(); var time = date.getTime(); var timeDiff = time - lastTime; var linearSpeed = 100;
// 像素 / 秒
var linearDistEachFrame = linearSpeed * timeDiff / 1000; var currentX = myRectangle.x;
if (currentX < canvas.width - myRectangle.width -
myRectangle.borderWidth / 2) {
var newX = currentX + linearDistEachFrame;
myRectangle.x = newX;
}
lastTime = time;
// 清屏
context.clearRect(0, 0, canvas.width, canvas.height);
// 绘图
drawRect(myRectangle);
// 请求绘制下一帧
requestAnimFrame(function(){
animate(lastTime, myRectangle, animProp);
});
}
}
window.onload = function(){ var myRectangle = { x: 0, y: 50, width: 100, height: 50, borderWidth: 5
};
/*
* 这里用于判断是否停止的属性 animProp 需要被声明为一个对象
* 如此才可以在被作为参数传递的时候是以引用传递
* 这样其值才能被修改
*/ var animProp = { animate: false
};
// 向canvas添加鼠标 click 事件的监听方法
document.getElementById("myCanvas").addEventListener("click", function(){
if (animProp.animate) { animProp.animate = false;
} else {
animProp.animate = true; var date = new Date(); var time = date.getTime();
animate(time, myRectangle, animProp);
}
});
drawRect(myRectangle); };