1. 8.10 图像
    2. 8.11 动画帧

8.10 图像

一个 ImageBitmap 对象表示一个位图图像,它可以绘制到画布上,而不会出现过长的延迟。

对什么是过长延迟的具体判断留给实现者,但一般来说,如果使用位图需要网络 I/O 甚至本地磁盘 I/O,那么延迟可能过长;而如果它只需要从 GPU 或系统 RAM 中进行阻塞读取,那么延迟可能是可以接受的。

promise = self.createImageBitmap(image [, options ])
promise = self.createImageBitmap(image, sx, sy, sw, sh [, options ])

接收 image,它可以是 img 元素、SVG image 元素、video 元素、canvas 元素、Blob 对象、ImageData 对象或另一个 ImageBitmap 对象,并返回一个承诺,该承诺在创建新的 ImageBitmap 时解析。

如果无法构建 ImageBitmap 对象,例如提供的 image 数据实际上不是图像,则承诺将被拒绝。

如果提供了 sxsyswsh 参数,则源图像将被裁剪到给定的像素,原始图像中丢失的任何像素都将被替换为 透明黑色。这些坐标位于源图像的像素坐标空间中,CSS 像素 中。

如果提供了 options,则 ImageBitmap 对象的位图数据将根据 options 进行修改。例如,如果 premultiplyAlpha 选项设置为“premultiply”,则位图数据的颜色通道将 乘以其 alpha 通道

如果源图像处于无效状态(例如,未成功加载的 img 元素、其[[Detached]] 内部插槽值为 true 的 ImageBitmap 对象、其 data 属性值的 [[ViewedArrayBuffer]] 内部插槽已分离的 ImageData 对象或其数据无法解释为位图图像的 Blob),则承诺将使用 "InvalidStateError" DOMException 拒绝。

如果脚本不允许访问源图像的图像数据(例如,CORS-跨域video 或工作进程中来自另一个 来源 的脚本绘制的 canvas),则承诺将使用 "SecurityError" DOMException 拒绝。

imageBitmap.close()

释放 imageBitmap 的基础位图数据

imageBitmap.width

返回图像的 自然宽度,以 CSS 像素 为单位。

imageBitmap.height

返回图像的 自然高度,以 CSS 像素 为单位。

使用此 API,可以预先切割和准备精灵图。

var sprites = {};
function loadMySprites() {
  var image = new Image();
  image.src = 'mysprites.png';
  var resolver;
  var promise = new Promise(function (arg) { resolver = arg });
  image.onload = function () {
    resolver(Promise.all([
      createImageBitmap(image,  0,  0, 40, 40).then(function (image) { sprites.person = image }),
      createImageBitmap(image, 40,  0, 40, 40).then(function (image) { sprites.grass  = image }),
      createImageBitmap(image, 80,  0, 40, 40).then(function (image) { sprites.tree   = image }),
      createImageBitmap(image,  0, 40, 40, 40).then(function (image) { sprites.hut    = image }),
      createImageBitmap(image, 40, 40, 40, 40).then(function (image) { sprites.apple  = image }),
      createImageBitmap(image, 80, 40, 40, 40).then(function (image) { sprites.snake  = image })
    ]));
  };
  return promise;
}

function runDemo() {
  var canvas = document.querySelector('canvas#demo');
  var context = canvas.getContext('2d');
  context.drawImage(sprites.tree, 30, 10);
  context.drawImage(sprites.snake, 70, 10);
}

loadMySprites().then(runDemo);

8.11 动画帧

某些对象包含 AnimationFrameProvider 接口混合。

每个 AnimationFrameProvider 对象还具有一个 目标对象,它存储提供程序的内部状态。定义如下

如果 AnimationFrameProviderWindow
Window关联 Document
如果 AnimationFrameProviderDedicatedWorkerGlobalScope
DedicatedWorkerGlobalScope

每个 目标对象 都具有一个 动画帧回调映射,它是一个 有序映射,必须最初为空,以及一个 动画帧回调标识符,它是一个必须最初为零的数字。

如果以下任何一项为真,则 AnimationFrameProvider provider 被认为是 支持的


Window/requestAnimationFrame

在所有当前引擎中都受支持。

Firefox23+Safari7+Chrome24+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android23+Safari iOS?Chrome Android?WebView Android4.4+Samsung Internet?Opera Android?

requestAnimationFrame(callback) 方法的步骤是

  1. 如果 this支持,则抛出 "NotSupportedError" DOMException

  2. targetthis目标对象

  3. target动画帧回调标识符 加一,设 handle 为结果。

  4. callbackstarget动画帧回调映射

  5. 设置 callbacks[handle] 为 callback

  6. 返回 handle

Window/cancelAnimationFrame

在所有当前引擎中都受支持。

Firefox23+Safari7+Chrome24+
Opera?Edge79+
Edge (Legacy)12+Internet Explorer10+
Firefox Android?Safari iOS?Chrome Android?WebView Android?Samsung Internet?Opera Android?

cancelAnimationFrame(handle) 方法的步骤是

  1. 如果 this支持,则抛出 "NotSupportedError" DOMException

  2. callbacksthis目标对象动画帧回调映射

  3. 移除 callbacks[handle]。

运行动画帧回调,针对具有时间戳 now目标对象 target

  1. callbackstarget动画帧回调映射

  2. callbackHandles获取 callbacks 的键的结果。

  3. 对于 callbackHandles 中的每个 handle,如果 handle 存在callbacks

    1. callbackcallbacks[handle]。

    2. 移除 callbacks[handle]。

    3. 调用 callback,传递 « now » 和 "report"。

在工作进程中,requestAnimationFrame() 可以与从 canvas 元素传输的 OffscreenCanvas 一起使用。首先,在文档中,将控制权传输到工作进程

const offscreenCanvas = document.getElementById("c").transferControlToOffscreen();
worker.postMessage(offscreenCanvas, [offscreenCanvas]);

然后,在工作进程中,以下代码将绘制一个从左到右移动的矩形

let ctx, pos = 0;
function draw(dt) {
  ctx.clearRect(0, 0, 100, 100);
  ctx.fillRect(pos, 0, 10, 10);
  pos += 10 * dt;
  requestAnimationFrame(draw);
}

self.onmessage = function(ev) {
  const transferredCanvas = ev.data;
  ctx = transferredCanvas.getContext("2d");
  draw();
};