长期以来,为 Web 构建的基于触控笔的绘图应用一直存在延迟问题,因为网页必须将图形更新与 DOM 同步。在任何绘图应用中,延迟时间超过 50 毫秒都可能会干扰用户的手眼协调,使应用难以使用。
canvas.getContext()
的 desynchronized
提示会调用绕过常规 DOM 更新机制的其他代码路径。相反,该提示会告知底层系统尽可能跳过尽可能多的合成,在某些情况下,画布的底层缓冲区会直接发送到屏幕的显示控制器。这样可以消除使用渲染程序合成器队列所造成的延迟。
此产品有多好?
如果您想查看代码,请向下滚动。如需查看其运作方式,您需要使用带触摸屏的设备,最好还要使用触控笔。(手指也可以。)如果您有,请尝试使用 2d 或 webgl 示例。其他用户可以观看由 Miguel Casas 演示此功能的视频,Miguel Casas 是实现此功能的工程师之一。打开演示,按下“播放”按钮,然后快速随机来回移动滑块。
此示例使用了 Blender 开源电影项目 Durian 制作的短片 Sintel 中的一个时长为一分二十一秒的剪辑。在此示例中,电影在 <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' 上下文。