HTML5/Canvas 支持双缓冲吗?
我想做的是将图形绘制在缓冲区上,然后能够将其按原样复制到画布上,这样我就可以制作动画并避免闪烁。但我找不到这个选项。有人知道我该怎么做吗?
What I'd like to do is draw my graphics on a buffer and then be able to copy it as is to the canvas so I can do animation and avoid flickering. But I couldn't find this option. Anyone know how I can go about this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
一个非常简单的方法是在同一屏幕位置放置两个画布元素,并设置需要显示的缓冲区的可见性。完成后,在隐藏部分上绘制并翻转。
一些代码:
CSS:
JS 中的翻转:
在此代码中,数组“Buffers[]”保存两个画布对象。所以当你想开始绘图时,你仍然需要获取上下文:
A very simple method is to have two canvas-elements at the same screen location and set visibility for the buffer that you need to show. Draw on the hidden and flip when you are done.
Some code:
CSS:
Flipping in JS:
In this code the array 'Buffers[]' holds both canvas-objects. So when you want to start drawing you still need to get the context:
以下有用的链接除了显示使用双缓冲的示例和优点之外,还显示了使用 html5 canvas 元素的其他几个性能技巧。它包含 jsPerf 测试的链接,该测试将跨浏览器的测试结果聚合到 Browserscope 数据库中。这确保了性能提示得到验证。
https://web.dev/canvas-performance/
为了您的方便,我提供了一个最小的文章中描述的有效双缓冲示例。
The following helpful link, in addition to showing examples and advantages of using double buffering, shows several other performance tips for using the html5 canvas element. It includes links to jsPerf tests, which aggregate test results across browsers into a Browserscope database. This ensures that the performance tips are verified.
https://web.dev/canvas-performance/
For your convenience, I have included a minimal example of effective double buffering as described in the article.
我测试过的浏览器都通过在绘制框架的代码完成之前不重新绘制画布来为您处理这种缓冲。另请参阅 WHATWG 邮件列表:http://www.mail- archive.com/[电子邮件受保护]/msg19969.html
Browsers I've tested all handle this buffering for you by not repainting the canvas until the code that draws your frame has completed. See also the WHATWG mailing list: http://www.mail-archive.com/[email protected]/msg19969.html
你总是可以做
var canvas2 = document.createElement("canvas");
并且根本不将其附加到 DOM 中。
只是说,因为你们似乎如此痴迷于
display:none;
对我来说,它看起来更干净,并且比仅仅拥有一个尴尬的隐形画布更准确地模仿了双缓冲的想法。
You could always do
var canvas2 = document.createElement("canvas");
and not append it to the DOM at all.
Just saying since you guys seem so obsessed with
display:none;
it just seems cleaner to me and mimicks the idea of double buffering way more accurately than just having an awkwardly invisible canvas.
两年多后:
不需要“手动”实现双缓冲。 Geary 先生在他的书“HTML5 Canvas”中对此进行了描述。
要有效减少闪烁,请使用
requestAnimationFrame()
< /a>!More than two years later:
There is no need for 'manually' implement double buffering. Mr. Geary wrote about this in his book "HTML5 Canvas".
To effectively reduce flicker use
requestAnimationFrame()
!对于不相信的人,这里有一些闪烁的代码。请注意,我明确清除了之前的圆圈。
For the unbelievers, here's some flickering code. Note that I'm explicitly clearing to erase the previous circle.
乔什(不久前)询问浏览器如何知道“绘图过程何时结束”以避免闪烁。我会直接对他的帖子发表评论,但我的代表不够高。这也只是我的意见。我没有事实支持它,但我对此相当有信心,这可能对将来阅读本文的其他人有所帮助。
我猜浏览器不“知道”你何时完成绘图。但就像大多数 JavaScript 一样,只要您的代码在不放弃对浏览器的控制的情况下运行,浏览器基本上就会被锁定,并且不会/无法更新/响应其 UI。我猜测,如果您清除画布并绘制整个框架而不放弃对浏览器的控制,那么在完成之前它实际上不会绘制画布。
如果您设置了一种情况,其中渲染跨越多个 setTimeout/setInterval/requestAnimationFrame 调用,您在一次调用中清除画布,并在接下来的几次调用中在画布上绘制元素,每 5 次调用重复一次循环(例如),我我敢打赌您会看到闪烁,因为每次调用后画布都会更新。
也就是说,我不确定我会相信这一点。我们已经到了 javascript 在执行之前被编译为本机机器代码的阶段(至少据我了解,Chrome 的 V8 引擎是这样做的)。如果不久之后浏览器开始在与 UI 不同的线程中运行 JavaScript 并同步对 UI 元素的任何访问,从而允许 UI 在不访问 UI 的 JavaScript 执行期间更新/响应,我不会感到惊讶。当/如果发生这种情况(我知道有许多障碍需要克服,例如事件处理程序在您仍在运行其他代码时启动),我们可能会在未使用的画布动画上看到闪烁某种双缓冲。
就我个人而言,我喜欢将两个画布元素放置在彼此之上并交替在每个框架上显示/绘制的想法。相当不具有干扰性,并且可能很容易通过几行代码添加到现有应用程序中。
Josh asked (a while back) about how the browser knows "when the drawing process ends" so as to avoid flicker. I would have commented directly to his post but my rep isn't high enough. Also this is just my opinion. I don't have facts to back it up, but I feel fairly confident about it and it may be helpful to others reading this in the future.
I'm guessing the browser doesn't "know" when you're done drawing. But just like most javascript, as long as your code runs without relinquishing control to the browser, the browser is essentially locked up and won't/can't update/respond to its UI. I'm guessing that if you clear the canvas and draw your entire frame without relinquishing control to the browser, it won't actually draw your canvas until you're done.
If you set up a situation where your rendering spans multiple setTimeout/setInterval/requestAnimationFrame calls, where you clear the canvas in one call and draw elements on your canvas in the next several calls, repeating the cycle (for example) every 5 calls, I'd be willing to bet you'd see flicker since the canvas would be updated after each call.
That said, I'm not sure I'd trust that. We're already at the point that javascript is compiled down to native machine code before execution (at least that's what Chrome's V8 engine does from what I understand). I wouldn't be surprised if it wasn't too long before browsers started running their javascript in a separate thread from the UI and synchronizing any access to UI elements allowing the UI to update/respond during javascript execution that wasn't accessing UI. When/if that happens (and I understand there are many hurdles that would have to be overcome, such as event handlers kicking off while you're still running other code), we'll probably see flicker on canvas animation that aren't using some kind of double-buffering.
Personally, I love the idea of two canvas elements positioned over top of each other and alternating which is shown/drawn on each frame. Fairly unintrusive and probably pretty easily added to an existing application with a few lines of code.
网络浏览器中没有闪烁!他们已经使用 dbl 缓冲进行渲染。 Js引擎将在显示之前完成所有渲染。此外,上下文保存和恢复仅堆栈变换矩阵数据等,而不是画布内容本身。
因此,您不需要也不想要 dbl 缓冲!
There is no flickering in web browsers! They already use dbl buffering for their rendering. Js engine will make all your rendering before showing it. Also, context save and restore only stack transformational matrix data and such, not the canvas content itself.
So, you do not need or want dbl buffering!
您可能不需要自己动手,而是通过使用现有的库来创建干净且无闪烁的 JavaScript 动画来获得最佳效果:
这是一个流行的动画:http://processingjs.org
Rather than rolling your own, you're probably going to get the best mileage by using an existing library for creating clean and flicker-free JavaScript animation:
Here's a popular one: http://processingjs.org
你需要 2 个画布:(注意 css z-index 和位置:绝对)
你可以注意到第一个画布是可见的,第二个画布是隐藏的,这个想法是在隐藏的画布上绘制,之后我们将隐藏可见的画布并使其隐藏画布可见。当它隐藏时'清除隐藏的画布
you need 2 canvas: (notice the css z-index and position:absolute)
you can notice that the first canvas is visible and the second it's hidden the idea it's to draw on the hidden after that we will hide the visible and make the hidden canvas visible. when it's hidden 'clear hidden canvas
在大多数情况下,您不需要这样做,浏览器会为您实现这一点。 但并不总是有用!
当你的绘图非常复杂时,你仍然必须实现这个。
大多数屏幕更新率约为60Hz,这意味着屏幕每16ms更新一次。浏览器的更新率可能接近这个数字。如果您的形状需要 100 毫秒才能完成,您将看到一个未完成的形状。所以在这种情况下可以实现双缓冲。
我做了一个测试:
清除一个矩形,等待一段时间,然后填充一些颜色。
如果我将时间设置为10ms,我就不会看到闪烁。但如果我把它设置为20ms,就会发生闪烁。In most situations, you don't need to do this, the browser implements this for you. But not always useful!
You still have to implement this when your drawing is very complicated.
Most of the screen update rate is about 60Hz, it means the screen updates per 16ms. The browser's update rate may near this number. If your shape need 100ms to be completed, you'll see a uncompleted shape. So you can implement double buffering in this situation.
I have made a test:
Clear a rect, wait for some time, then fill with some color.
If I set the time to 10ms, I won't see flickering. But if I set it to 20ms, the flickering happens.Opera 9.10 非常慢并且显示绘图过程。如果您想看到不使用双缓冲的浏览器,请尝试 Opera 9.10。
有些人建议浏览器以某种方式确定绘图过程何时结束,但你能解释一下它是如何工作的吗?即使绘图速度很慢,我也没有注意到 Firefox、Chrome 或 IE9 中有任何明显的闪烁,所以看起来这就是他们正在做的事情,但如何实现这一点对我来说是个谜。浏览器如何知道在执行更多绘图指令之前正在刷新显示?您是否认为他们只是计时,以便如果超过 5 毫秒左右的时间间隔没有执行画布绘制指令,它就假设它可以安全地交换缓冲区?
Opera 9.10 is very slow and shows the drawing process. If you want to see a browser not use double buffering, try Opera 9.10 out.
Some people suggested that browsers are somehow determining when the drawing process ends but can you explain how that can work? I haven't noticed any obvious flicker in Firefox, Chrome, or IE9 even when the drawing is slow so it seems like that is what they are doing but how that is accomplished is a mystery to me. How would the browser ever know that it is refreshing the display just before more drawing instructions are to be executed? Do you think they just time it so if an interval of more than 5ms or so goes by without executing a canvas drawing instruction, it assumes it can safely swap buffers?
这是图像数据双缓冲的示例。
This is an example of double buffering with image data.