为 Web 构建的基于触控笔的绘图应用长期以来一直存在延迟问题,因为网页必须与 DOM 同步图形更新。在任何绘图应用中,超过 50 毫秒的延迟都会干扰用户的手眼协调,导致应用难以使用。
针对 canvas.getContext()
的 desynchronized
提示会调用一个绕过常规 DOM 更新机制的不同代码路径。相反,该提示会告知底层系统尽可能多地跳过合成,在某些情况下,画布的底层缓冲区会直接发送到屏幕的显示控制器。这样可以消除因使用渲染程序合成器队列而导致的延迟。
此产品有多好?
如果您想查看代码,请向前滚动。如需查看实际应用,您需要带触摸屏的设备,最好是触控笔。(手指也可以)。如果您有 2d 或 webgl 示例,不妨查看一下。对于其他开发者,请查看实现此功能的工程师 Miguel Casas 提供的演示。打开演示版,按下“播放”,然后随机快速地来回移动滑块。
此示例使用了 Blender 开放式电影项目 Durian 的短片 Sintel 中的片段,时长为 1 分 21 秒。在此示例中,电影在 <video>
元素中播放,该元素的内容同时渲染到 <canvas>
元素中。许多设备无需撕裂即可做到这一点,但采用前端缓冲区渲染的设备(例如 ChromeOS)可能会出现撕裂的情况。(这部电影很棒,但也很伤心。
我看到它后一个小时就毫无用处了。您就要受到警告了。)
使用提示
与将 desynchronized
添加到 canvas.getContext()
相比,使用低延迟具有更多作用。我将逐一介绍这些问题。
创建画布
在另一个 API 上,我会先讨论特征检测。对于 desynchronized
提示,您必须先创建画布。调用 canvas.getContext()
并向其传递值为 true
的新 desynchronized
提示。
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
desynchronized: true,
// Other options. See below.
});
功能检测
接下来,调用 getContextAttributes()
。如果返回的属性对象具有 desynchronized
属性,请对其进行测试。
if (ctx.getContextAttributes().desynchronized) {
console.log('Low latency canvas supported. Yay!');
} else {
console.log('Low latency canvas not supported. Boo!');
}
避免闪烁
在以下两种情况下,如果编码不正确,可能会导致闪烁。
部分浏览器(包括 Chrome)会在帧之间清除 WebGL 画布。显示控制器可能会在缓冲区为空时读取缓冲区,从而导致绘制图像闪烁。为避免出现这种情况,请将 preserveDrawingBuffer
设置为 true
。
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('webgl', {
desynchronized: true,
preserveDrawingBuffer: true
});
当您在自己的绘图代码中清除屏幕上下文时,也可能会发生闪烁。如果需要,请绘制到屏幕外帧缓冲区,然后将其复制到屏幕。
Alpha 渠道
alpha 设置为 true 的半透明画布元素仍然可以不同步,但其上方不得有任何其他 DOM 元素。
只能有一个
首次调用 canvas.getContext()
后,您将无法更改上下文属性。始终都是如此,但如果您不了解或忘记了这一点,那么重复一遍这样的说法可能会让您感到不快。
例如,假设我获取了一个上下文并将 alpha 指定为 false,然后在稍后在代码中的某个位置再次调用 canvas.getContext()
,将 alpha 设置为 true,如下所示。
const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
alpha: false,
desynchronized: true,
});
//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
alpha: true,
desynchronized: true,
});
ctx1
和 ctx2
不是同一个对象,这一点并不明显。Alpha 仍为 false,且始终不会创建 alpha 为 true 的上下文。
支持的画布类型
传递给 getContext()
的第一个参数是 contextType
。如果您已熟悉 getContext()
,则毫无疑问想知道是否支持除“2d”上下文类型之外的任何其他上下文类型。下表显示了支持 desynchronized
的上下文类型。
contextType | 上下文类型对象 |
---|---|
|
|
|
|
|
|
总结
如果您想详细了解此类内容,请查看示例。除了已经介绍的视频示例之外,我们还提供同时显示 '2d' 和 'webgl' 上下文的示例。