如何对画布图形进行动画处理 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

canvas 元素是 HTML 文档的可绘制区域,可以使用 JavaScript 收集图形(如动画、图表和游戏)。 本主题首先介绍使用 canvas 元素对基本图形进行动画处理所需的步骤。

先决条件

本主题假设你:

  • 可以创建使用 JavaScript 的基本 Windows 应用商店应用,该应用使用 Windows JavaScript 库模板。
  • 对 HTML 和 JavaScript 有基本的了解。

有关创建第一个采用 JavaScript 的 Windows 应用商店应用的说明,请参阅创建第一个采用 JavaScript 的 Windows 应用商店应用。有关使用 WinJS 模板的说明,请参阅“如何获取和使用 WinJS 工具包”。

说明

步骤 1: 对动画进行计时

使用 requestAnimationFrame 方法,通过指定要在需要更新动画以进行下一次重画时调用(回调)的函数来开始动画:

requestAnimationFrame(animationFunction);

requestAnimationFrame 会考虑页面可见性和显示器的刷新率,以确定每秒向动画分配多少帧(即调用 animationFunction)。

我们的 JavaScript 示例绘制一个在较大的圆周围沿着螺旋方向移动的动画圆。

requestAnimationFrame(draw);

下面是我们的动画(结果可能会有所不同,较快的硬件会导致动画圆的步调更紧密):

由画布动画绘制的螺旋圆的示例。

步骤 2: 绘制图像

  1. 清除画布

    在绘制每个帧之前,你将需要清除画布。

    可通过多种方法清除画布或图像的某些部分,例如,使用 globalCompositOperation 属性清除某些区域,或者使用 clip 方法对路径进行剪辑。 清除画布最简单的方式是使用 clearRect 方法。

    在我们的示例中,clearRect 方法用于清除整个画布,但是,为了更便于查看图像的绘制效果,已将 clearRect 方法注释掉。 如果此代码行未注释掉,你将在较大的圆形轨道周围看到一个沿着螺旋方向移动的圆形,而且在绘制每一帧之前,它的痕迹将被清除。

    // The clearRect method clears the entire canvas.
    context.clearRect(0, 0, 160, 160);
    
  2. 保存画布状态

    在绘制图像时,可以更改某些设置(如样式或转换)。 如果你希望在每次开始重绘图像时都使用原始设置,则可以使用 save 方法。

    save 方法用于将画布状态保存到堆栈上,restore 方法用于取回画布状态。 画布状态包含已经应用的所有样式和转换。每次调用 save 方法时,当前的画布状态都会保存到堆栈上。 restore 方法会返回堆栈中已保存的最新状态。

    在我们的示例中,我们在开始设置某些转换以绘制和移动动画圆之前使用 save 方法。

    // Save the canvas state.
    context.save();
    
  3. 绘制图像

    在将图像绘制到画布上时,可以使用两种转换来对图像进行更改:translate 和 rotate 方法。

    translate 方法用于将画布及其原点移动到画布网格中的另一点:

    translate(x, y)
    

    此方法采用两个参数:x 是画布的左移或右移量,y 是画布的上移或下移量。

    在执行任何转换之前,最好保存画布状态,因为与为了使画布返回到其原始状态而必须执行反向转换相比,调用 restore 方法会更方便。 translate 方法允许你将图像放置在画布上的任何位置,而不必手动调整坐标。

    rotate 方法用于围绕当前的原点旋转画布。 此方法只有一个参数:画布的旋转角度(以弧度作为度量单位)。

    rotate(angle)
    

    旋转是顺时针移动,旋转中心始终为画布的原点(左上角)。 若要移动中心,需要使用 translate 方法移动画布。

    在我们的示例中,我们将对 translaterotate 方法交替调用几次。对 translate 方法的第一次调用会将动画放在画布中央。

    接着,我们将对 rotatetranslate 方法进行两组调用。 对于 rotatetranslate 方法的第一组调用将生成一个在画布周围沿着一个大环绘制的小圆。第二组调用将生成一个沿小得多的轨道绘制的小圆。

    画布的高度和宽度都设置为 160 像素,因此,我们会将 translate 方法的 x 和 y 坐标设置为等于 80,以便整个动画将位于画布的中央。

    // centers the image on the canvas             
    context.translate(80, 80);
    

    我们通过使用 date 对象计算 rotate 方法的参数,以开始对 rotate 方法进行首次调用。此参数是画布将要旋转的角度。

    var time = new Date();
    context.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
    

    请注意,用于计算 getSeconds 的值为 60,用于计算 getMilliseconds 的值为 60,000。

    translate 方法会移动 x 坐标,从而在画布周围沿着较大的轨道移动旋转圆。

    // Translate determines the size of the circle's orbit.
    context.translate(50, 0);
    

    下面是第一次调用 rotatetranslate 方法的效果:

    没有循环的大圆。

    rotatetranslate 方法的两个后续调用会创建一个较小的循环轨道。

    // Rotate causes the circle to move in a small orbit.
    context.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
    
    // Translate determines the size of the orbit.
    context.translate(0, 5);
    

    请注意,在为第二个 rotate 调用计算角度时,用于计算 getSeconds 的值为 6,用于计算 getMilliseconds 的值为 6,000。

    下面展示了在将第一组 rotatetranslate 方法注释掉后,第二组 rotatetranslate 方法将绘制的内容:

    循环圆。

    在所有重新定位之后,将在画布上绘制圆。

    // This draws the repositioned circle
    context.beginPath();
    context.arc(5, 5, 4, 0, Math.PI*2, true); 
    context.stroke();
    
  4. 还原画布状态

    我们在前面的步骤 b 中保存了画布状态,因此,现在我们将重置画布状态,以便绘制下一个帧。

    // Restores the canvas to the previous state
    context.restore();
    

完整示例

动画图形

此 JavaScript 示例绘制一个在较大的圆周围沿着螺旋方向移动的动画圆。

window.onload = init;
  
// As an optimization, make "context" a global variable that is only set once.
var context;
  
function init(){
  context = document.getElementById('canvas').getContext('2d');    
  window.requestAnimationFrame(draw);
} // init

function draw() {
  // Save the canvas state.
  context.save();         
  
  // context.clearRect(0, 0, 160, 160);

  // centers the image on the canvas             
  context.translate(80, 80); 
  
  // Rotate moves the spiraling circle around the canvas in a large orbit.
  var time = new Date();
  context.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
  
  // Translate determines the location of the small circle.
  context.translate(50, 0);  
  
  // Rotate causes the circle to spiral as it circles around the canvas.
  context.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
  
  // determines the size of the loop
  context.translate(0, 5);  
  
  // This draws the circle
  context.beginPath();
  context.arc(5, 5, 4, 0, Math.PI*2, true); 
  context.stroke();
  
  // Restores the canvas to the previous state
  context.restore();
  window.requestAnimationFrame(draw);
}  // draw

这是在 canvas 元素周围创建黑色边框的级联样式表 (CSS) 的示例。

/* style the canvas element with a black border. */
canvas { border: 1px solid black; }

此 HTML 文件创建一个 canvas 元素并使用外部 JavaScript 和 CSS 文件。

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="myJavascript.js"></script>
        <link Rel="stylesheet" Href="myStyle.css" Type="text/css">
    </head>
    <body>
        <canvas id="canvas" width="160" height="160" />
    </body>
</html>

相关主题

快速入门:绘制到画布