HTML5 Canvas教程(12)

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,然后申请下一帧动画。

译者注:在这里,动画的帧率跟你的机器硬件、浏览器软件的具体情况有一定关系,一般来说流畅

的动画帧率在40FPS60FPS之间。那么,对于程序员来说,很难判断应该针对每一个具体的用户使用多大的帧率,因此,各大浏览器都为我们提供了一个 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); };