图像

计算机图形学领域经常将矢量图形和位图图形分开来讨论。本章一直在讨论第一种图形,即通过对图形的逻辑描述来绘图。而位图则相反,不需要设置实际图形,而是通过处理像素数据来绘制图像(光栅化的着色点)。

我们可以使用drawImage方法在画布上绘制像素值。此处的像素数值可以来自<img>元素,或者来自其他的画布。下例创建了一个独立的<img>元素,并且加载了一张图像文件。但我们无法马上使用该图片进行绘制,因为浏览器可能还没有完成图片的获取操作。为了处理这个问题,我们在图像元素上注册一个"load"事件处理程序并且在图片加载完之后开始绘制。

  1. <canvas></canvas>
  2. <script>
  3. let cx = document.querySelector("canvas").getContext("2d");
  4. let img = document.createElement("img");
  5. img.src = "img/hat.png";
  6. img.addEventListener("load", () => {
  7. for (let x = 10; x < 200; x += 30) {
  8. cx.drawImage(img, x, 10);
  9. }
  10. });
  11. </script>

默认情况下,drawImage会根据原图的尺寸绘制图像。你也可以增加两个参数来设置不同的宽度和高度。

如果我们向drawImage函数传入 9 个参数,我们可以用其绘制出一张图片的某一部分。第二个到第五个参数表示需要拷贝的源图片中的矩形区域(xy坐标,宽度和高度),同时第六个到第九个参数给出了需要拷贝到的目标矩形的位置(在画布上)。

图像 - 图1

该方法可以用于在单个图像文件中放入多个精灵(图像单元)并画出你需要的部分。

我们可以改变绘制的人物造型,来展现一段看似人物在走动的动画。

clearRect方法可以帮助我们在画布上绘制动画。该方法类似于fillRect方法,但是不同的是clearRect方法会将目标矩形透明化,并移除掉之前绘制的像素值,而不是着色。

我们知道每个精灵和每个子画面的宽度都是 24 像素,高度都是 30 像素。下面的代码装载了一幅图片并设置定时器(会重复触发的定时器)来定时绘制下一帧。

  1. <canvas></canvas>
  2. <script>
  3. let cx = document.querySelector("canvas").getContext("2d");
  4. let img = document.createElement("img");
  5. img.src = "img/player.png";
  6. let spriteW = 24, spriteH = 30;
  7. img.addEventListener("load", () => {
  8. let cycle = 0;
  9. setInterval(() => {
  10. cx.clearRect(0, 0, spriteW, spriteH);
  11. cx.drawImage(img,
  12. // source rectangle
  13. cycle * spriteW, 0, spriteW, spriteH,
  14. // destination rectangle
  15. 0, 0, spriteW, spriteH);
  16. cycle = (cycle + 1) % 8;
  17. }, 120);
  18. });
  19. </script>

cycle绑定用于记录角色在动画图像中的位置。每显示一帧,我们都要将cycle加 1,并通过取余数确保cycle的值在 0~7 这个范围内。我们随后使用该绑定计算精灵当前形象在图片中的x坐标。