HTML5 Canvas 教程:十二、動畫

十二、動畫 Animation

 

12.1清除畫布內容 Clear Canvas

 

爲了清除HTML5畫布,可以使用clearRect()方法來清除畫布位圖。該方法的性能比清除畫布的其他技術要好得多,比如重置畫布的寬度和高度,或者銷燬畫布元素然後重新創建它。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

      #buttons {

        position: absolute;

        top: 5px;

        left: 10px;

      }

      #buttons > input {

        padding: 10px;

        display: block;

        margin-top: 5px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <div id="buttons">

      <input type="button" id="clear" value="Clear">

    </div>

    <script>

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      // begin custom shape

      context.beginPath();

      context.moveTo(17080);

      context.bezierCurveTo(130100130150230150);

      context.bezierCurveTo(250180320180340150);

      context.bezierCurveTo(420150420120390100);

      context.bezierCurveTo(430403703034050);

      context.bezierCurveTo(32052502025050);

      context.bezierCurveTo(20051502017080);

 

      // complete custom shape

      context.closePath();

      context.lineWidth = 5;

      context.strokeStyle = 'blue';

      context.stroke();

 

      // bind event handler to clear button

      document.getElementById('clear').addEventListener('click'function() {

        context.clearRect(00, canvas.width, canvas.height);

      }, false);

 

    </script>

  </body>

</html>

 

代碼說明:點擊清除按鈕清除畫布。

 

以上代碼演示了點擊清除按鈕,清除畫布上的所有內容。

 

 

12.2動畫幀 Animation Frame

 

要使用HTML5 Canvas創建動畫,可以使用requestAnimFrame shim,它使瀏覽器能夠確定動畫的最佳FPS。對於每個動畫幀,我們可以更新畫布上的元素,清除畫布,重新繪製畫布,然後繼續請求另一個動畫幀。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <script>

      window.requestAnimFrame = (function(callback) {

        return window.requestAnimationFrame || 

               window.webkitRequestAnimationFrame || 

               window.mozRequestAnimationFrame || 

               window.oRequestAnimationFrame || 

               window.msRequestAnimationFrame ||

        function(callback) {

          window.setTimeout(callback1000 / 60);

        };

      })();

 

      function drawRectangle(myRectanglecontext) {

        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(myRectanglecanvascontextstartTime) {

        // update

        var time = (new Date()).getTime() - startTime;

 

        var linearSpeed = 100;

        // pixels / second

        var newX = linearSpeed * time / 1000;

 

        if(newX < canvas.width-myRectangle.width-myRectangle.borderWidth/2) {

          myRectangle.x = newX;

        }

 

        // clear

        context.clearRect(00canvas.width, canvas.height);

 

        drawRectangle(myRectanglecontext);

 

        // request new frame

        requestAnimFrame(function() {

          animate(myRectanglecanvascontextstartTime);

        });

      }

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      var myRectangle = {

        x: 0,

        y: 75,

        width: 100,

        height: 50,

        borderWidth: 5

      };

 

      drawRectangle(myRectangle, context);

 

      // wait one second before starting animation

      setTimeout(function() {

        var startTime = (new Date()).getTime();

        animate(myRectangle, canvas, context, startTime);

      }, 1000);

    </script>

  </body>

</html>

 

以上代碼演示了在畫布上繪製一個矩形,並使矩形向右移動的動畫。注意代碼中的animate方法,該方法不斷更新矩形的位置,並清除畫布,將新的矩形繪製出來以實現矩形的移動。

 

12.3線性運動 Linear Motion

 

爲了用HTML5畫布創建線性運動動畫,我們可以根據速度方程增加每個幀對象的x、y值以改變對象的位置,計算方式爲:距離=速度*時間(distance = velocity * time)。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <script>

      window.requestAnimFrame = (function(callback) {

        return window.requestAnimationFrame || 

               window.webkitRequestAnimationFrame || 

               window.mozRequestAnimationFrame || 

               window.oRequestAnimationFrame || 

               window.msRequestAnimationFrame ||

        function(callback) {

          window.setTimeout(callback1000 / 60);

        };

      })();

 

      function drawRectangle(myRectanglecontext) {

        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(myRectanglecanvascontextstartTime) {

        // update

        var time = (new Date()).getTime() - startTime;

 

        var linearSpeed = 100;

        // pixels / second

        var newX = linearSpeed * time / 1000;

 

        if(newX < canvas.width-myRectangle.width-myRectangle.borderWidth/2) {

          myRectangle.x = newX;

        }

 

        // clear

        context.clearRect(00canvas.width, canvas.height);

 

        drawRectangle(myRectanglecontext);

 

        // request new frame

        requestAnimFrame(function() {

          animate(myRectanglecanvascontextstartTime);

        });

      }

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      var myRectangle = {

        x: 0,

        y: 75,

        width: 100,

        height: 50,

        borderWidth: 5

      };

 

      drawRectangle(myRectangle, context);

 

      // wait one second before starting animation

      setTimeout(function() {

        var startTime = (new Date()).getTime();

        animate(myRectangle, canvas, context, startTime);

      }, 1000);

    </script>

  </body>

</html>

 

這段代碼的演示內容與上一段基本一致,不在贅述。

 

 

12.4加速度 Acceleration

 

爲了用HTML5畫布創建二次運動動畫,我們可以爲每幀增加對象的vx(水平速度)、vy(垂直速度)或vx和vy兩者同時增加,然後根據加速度方程更新對象的位置,計算方法爲:距離=速度*時間+ 1/2 *加速度*時間^2(distance = velocity * time + 1/2 * acceleration * time^2)。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <script>

      window.requestAnimFrame = (function(callback) {

        return window.requestAnimationFrame || 

               window.webkitRequestAnimationFrame || 

               window.mozRequestAnimationFrame || 

               window.oRequestAnimationFrame || 

               window.msRequestAnimationFrame ||

        function(callback) {

          window.setTimeout(callback1000 / 60);

        };

      })();

 

      function drawRectangle(myRectanglecontext) {

        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(myRectanglecanvascontextstartTime) {

        // update

        var time = (new Date()).getTime() - startTime;

 

        // pixels / second^2

        var gravity = 200;

 

        myRectangle.y = 0.5 * gravity * Math.pow(time / 10002);

 

        if(myRectangle.y > canvas.height - 

                myRectangle.height - myRectangle.borderWidth / 2) {

          myRectangle.y = canvas.height - 

                myRectangle.height - myRectangle.borderWidth / 2;

        }

        lastTime = time;

 

        // clear

        context.clearRect(00canvas.width, canvas.height);

 

        // draw

        drawRectangle(myRectanglecontext);

 

        // request new frame

        requestAnimFrame(function() {

          animate(myRectanglecanvascontextstartTime);

        });

      }

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      var myRectangle = {

        x: 239,

        y: 0,

        width: 100,

        height: 50,

        borderWidth: 5

      };

 

      drawRectangle(myRectangle, context);

 

      // wait one second before dropping rectangle

      setTimeout(function() {

        var startTime = (new Date()).getTime();

        animate(myRectangle, canvas, context, startTime);

      }, 2000);

 

    </script>

  </body>

</html>

 

以上代碼演示了在畫布上創建一個垂直降落的矩形,並且在降落過程中有一定的加速度,請注意代碼中與加速度有關的幾項常量,可以試着將其改爲更符合實際的重力加速度。

 

 

12.5振盪(往復)動畫 Oscillation Animation

 

爲了使用HTML5畫布創建振盪往復動畫,我們可以使用簡單的諧波振盪方程來設置圖形在每個幀的位置:

x(t) = 幅值*sin(t * 2PI/週期) + x0,(x(t) = amplitude * sin(t * 2PI / period) + x0)。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <script>

      window.requestAnimFrame = (function(callback) {

        return window.requestAnimationFrame || 

               window.webkitRequestAnimationFrame || 

               window.mozRequestAnimationFrame || 

               window.oRequestAnimationFrame || 

               window.msRequestAnimationFrame ||

        function(callback) {

          window.setTimeout(callback1000 / 60);

        };

      })();

 

      function drawRectangle(myRectanglecontext) {

        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(myRectanglecanvascontextstartTime) {

        // update

        var time = (new Date()).getTime() - startTime;

        var amplitude = 150;

 

        // in ms

        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;

 

        // clear

        context.clearRect(00canvas.width, canvas.height);

 

        // draw

        drawRectangle(myRectanglecontext);

 

        // request new frame

        requestAnimFrame(function() {

          animate(myRectanglecanvascontextstartTime);

        });

      }

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      var myRectangle = {

        x: 250,

        y: 70,

        width: 100,

        height: 50,

        borderWidth: 5

      };

 

      drawRectangle(myRectangle, context);

 

      // wait one second before starting animation

      setTimeout(function() {

        var startTime = (new Date()).getTime();

        animate(myRectangle, canvas, context, startTime);

      }, 1000);

    </script>

  </body>

</html>

 

以上代碼演示了在畫布上繪製一個矩形,並使矩形進行振盪往復運動。

 

 

12.6動畫的啓動與停止 Start and Stop an Animation

 

要啓動HTML5畫布動畫,可以不斷地請求新的動畫幀;要停止HTML5畫布動畫,則停止請求新的動畫幀。

 

<!DOCTYPE HTML>

<html>

  <head>

    <style>

      body {

        margin: 0px;

        padding: 0px;

      }

    </style>

  </head>

  <body>

    <canvas id="myCanvas" width="578" height="200"></canvas>

    <script>

      window.requestAnimFrame = (function(callback) {

        return window.requestAnimationFrame || 

               window.webkitRequestAnimationFrame || 

               window.mozRequestAnimationFrame || 

               window.oRequestAnimationFrame || 

               window.msRequestAnimationFrame ||

        function(callback) {

          window.setTimeout(callback1000 / 60);

        };

      })();

 

      function drawRect(myRectanglecontext) {

        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(lastTimemyRectanglerunAnimationcanvascontext) {

        if(runAnimation.value) {

          // update

          var time = (new Date()).getTime();

          var timeDiff = time - lastTime;

 

          // pixels / second

          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;

          }

 

          // clear

          context.clearRect(00canvas.width, canvas.height);

 

          // draw

          drawRect(myRectanglecontext);

 

          // request new frame

          requestAnimFrame(function() {

            animate(timemyRectanglerunAnimationcanvascontext);

          });

        }

      }

      var canvas = document.getElementById('myCanvas');

      var context = canvas.getContext('2d');

 

      var myRectangle = {

        x: 0,

        y: 75,

        width: 100,

        height: 50,

        borderWidth: 5

      };

 

      /*

       * define the runAnimation boolean as an obect

       * so that it can be modified by reference

       */

      var runAnimation = {

        value: false

      };

 

      // add click listener to canvas

      document.getElementById('myCanvas')

                .addEventListener('click'function() {

        // flip flag

        runAnimation.value = !runAnimation.value;

 

        if(runAnimation.value) {

          var date = new Date();

          var time = date.getTime();

          animate(time, myRectangle, runAnimation, canvas, context);

        }

      });

      drawRect(myRectangle, context);

    </script>

  </body>

</html>

 

說明:點擊畫布啓動動畫並停止動畫。

 

以上代碼演示了通過點擊鼠標啓動和停止動畫,而不是像以上的代碼範例停止1秒後啓動動畫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章