我想要做的是在缓冲区上绘制图形,然后将其原样复制到画布上,这样我就可以进行动画并避免闪烁。但我找不到这个选项。任何人都知道我可以如何去做这件事?HTML5/Canvas支持双缓冲吗?
回答
下有用的链接,除了展示的例子,并使用双缓冲的优势,展示了使用HTML5的Canvas元素其他一些性能提示。它包含jsPerf测试的链接,它将浏览器的测试结果汇总到一个Browserscope数据库中。这可确保性能提示得到验证。
http://www.html5rocks.com/en/tutorials/canvas/performance/
为方便起见,我已包括在文章中描述的有效的双缓冲的最小例子。
// canvas element in DOM
var canvas1 = document.getElementById('canvas1');
var context1 = canvas1.getContext('2d');
// buffer canvas
var canvas2 = document.createElement('canvas');
canvas2.width = 150;
canvas2.height = 150;
var context2 = canvas2.getContext('2d');
// create something on the canvas
context2.beginPath();
context2.moveTo(10,10);
context2.lineTo(10,30);
context2.stroke();
//render the buffered canvas onto the original canvas element
context1.drawImage(canvas2, 0, 0);
而不是滚动您自己,你可能会使用现有的库,以获得最佳里程为创造清洁,无闪烁的JavaScript动画:
这里有一个流行的一种:http://processingjs.org
一非常简单的方法是在同一屏幕位置放置两个画布元素,并为您需要显示的缓冲区设置可见性。当你完成后,在隐藏处画画并翻转。
某些代码:
CSS:
canvas { border: 2px solid #000; position:absolute; top:0;left:0;
visibility: hidden; }
翻转在JS:
Buffers[1-DrawingBuffer].style.visibility='hidden';
Buffers[DrawingBuffer].style.visibility='visible';
DrawingBuffer=1-DrawingBuffer;
在此代码阵列 '缓冲器[]' 同时拥有画布对象。所以,当你要开始绘制你仍然需要获得上下文:
var context = Buffers[DrawingBuffer].getContext('2d');
不错的解决方案:D – 2011-07-05 13:36:21
偏题:我个人喜欢用'
浏览器我测试过的所有,直到吸引你的框架代码完成时不重画在画布上处理这个缓冲你。请参阅WHATWG邮件列表:http://www.mail-archive.com/[email protected]/msg19969.html
好吧,我注意到闪烁或屏幕撕裂。不知道如何描述它。在Linux上使用最新的Chrome。 – grom 2012-07-27 04:45:17
Opera 9.10非常慢并显示绘图过程。如果你想看到浏览器不使用双缓冲,请尝试Opera 9.10。
有些人建议浏览器以某种方式确定绘图过程何时结束,但您能否解释这可以如何工作?即使画图很慢,我也没有注意到Firefox,Chrome或IE9中有任何明显的闪烁,所以看起来这就是他们正在做的事情,但是如何实现这一点对我来说是个谜。在更多的绘图指令被执行之前,浏览器如何知道它正在刷新显示?你认为他们只是计时吗?如果超过5毫秒的时间间隔没有执行画布绘图指令,它会认为它可以安全地交换缓冲区?
需要2个帆布:(注意CSS的z-index和位置:绝对)
<canvas id="layer1" width="760" height="600" style=" position:absolute; top:0;left:0;
visibility: visible; z-index: 0; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<canvas id="layer2" width="760" height="600" style="position:absolute; top:0;left:0;
visibility: visible; z-index: 1; solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
,你可以看到,第一画布上是可见的,它是隐藏它借鉴隐藏的想法第二之后,我们将隐藏可见并使隐藏的画布可见。当它是隐藏的“清除隐藏的帆布
<script type="text/javascript">
var buff=new Array(2);
buff[0]=document.getElementById("layer1");
buff[1]=document.getElementById("layer2");
ctx[0]=buff[0].getContext("2d");
ctx[1]=buff[1].getContext("2d");
var current=0;
// draw the canvas (ctx[ current ]);
buff[1- current ].style.visibility='hidden';
buff[ current ].style.visibility='visible';
ctx[1-current].clearRect(0,0,760,600);
current =1-current;
对于不信的人,这里有一些闪烁的代码。请注意,我明确地清除了以前的圈子。
http://coderextreme.net/basketball2.html(http://jsfiddle.net/GzSWJ/)
<!DOCTYPE html>
<html>
<head><title>Basketball</title></head>
<body>
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function draw_ball(ball) {
ctx.clearRect(0, 0, 400, 400);
ctx.fillStyle = "#FF0000";
ctx.beginPath();
ctx.arc(ball.x, ball.y, 30, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
var deltat = 1;
var ball = {};
ball.y = 0;
ball.x = 200;
ball.vy = 0;
ball.vx = 10;
ball.ay = 9.8;
ball.ax = 0.1;
function compute_position() {
if (ball.y > 370 && ball.vy > 0) {
ball.vy = -ball.vy * 84/86;
}
if (ball.x < 30) {
ball.vx = -ball.vx;
ball.ax = -ball.ax;
} else if (ball.x > 370) {
ball.vx = -ball.vx;
ball.ax = -ball.ax;
}
ball.ax = ball.ax/2;
ball.vx = ball.vx * 185/186;
ball.y = ball.y + ball.vy * deltat + ball.ay * deltat * deltat/2
ball.x = ball.x + ball.vx * deltat + ball.ax * deltat * deltat/2
ball.vy = ball.vy + ball.ay * deltat
ball.vx = ball.vx + ball.ax * deltat
draw_ball(ball);
}
setInterval(compute_position, 40);
</script></body></html>
乔什问(而回)关于浏览器如何知道“什么时候绘制过程结束”,以避免闪烁。我会直接评论他的帖子,但我的代表不够高。这也只是我的看法。我没有支持它的事实,但我对此相当有信心,未来读者可能会对此有所帮助。
我猜测你完成绘图时浏览器并不知道。但是就像大多数JavaScript一样,只要代码在不放弃对浏览器的控制权的情况下运行,浏览器就会被锁定,并且不会更新/响应其UI。我在猜测,如果你清除画布并画出整个画面而不放弃对浏览器的控制,那么在完成之前它不会实际绘制画布。
如果您设置了一种情况,即您的渲染跨越多个setTimeout/setInterval/requestAnimationFrame调用,您可以在一次调用中清除画布,并在接下来的几次调用中在画布上绘制元素,每次重复循环5次电话,我愿意打赌你会看到闪烁,因为每次通话后画布都会更新。
这就是说,我不确定我会相信这一点。我们已经认识到,JavaScript在执行之前会被编译为本地机器代码(至少这是Chrome的V8引擎根据我的理解所做的)。如果浏览器在与用户界面不同的线程中开始运行它们的javascript并同步对UI元素的任何访问,以允许UI在不访问UI的JavaScript执行期间更新/响应,我不会感到惊讶。当/如果发生这种情况(并且我知道有许多障碍需要克服,例如事件处理程序在您仍在运行其他代码时开始运行),我们可能会看到未使用的画布动画闪烁某种双缓冲。
就我个人而言,我喜欢将两个画布元素放置在彼此顶部并交替显示/在每个画面上绘制的想法。相当不引人注意,可能很容易通过几行代码添加到现有应用程序中。
正确。例如,查看JSFiddle http://stackoverflow.com/questions/11777483/do-we-need-to-implement-double-buffering-ourselves-with-canvas。 – Eric 2013-08-01 03:51:27
在大多数情况下,您不需要执行此操作,浏览器会为您执行此操作。 但并不总是有用!
当你的绘图非常复杂时,你仍然需要实现这一点。 大部分的屏幕更新率大约是60Hz,这意味着屏幕每16ms更新一次。浏览器的更新率可能接近这个数字。如果你的形状需要100ms完成,你会看到一个未完成的形状。所以你可以在这种情况下实现双缓冲。
我做了一个测试:Clear a rect, wait for some time, then fill with some color.
如果我把时间设置为10ms,我就不会看到闪烁。但是如果我将其设置为20ms,闪烁就会发生。
您如何解释使用双缓冲技术所见证的性能改进? http://www.html5rocks.com/en/tutorials/canvas/performance/ – ricksuggs 2013-10-11 13:58:52
@ricksuggs那么,html5rocks上提到的“双缓冲”或“离屏渲染”与我想的有点不同。我认为DB是交换屏幕页面(在vram中),这实际上只是一个指针操作,而不是复制内存块。 OP要求使用DB来避免闪烁,这是通过requestAnimationFrame()真正解决的。也许这个[文章](http://tinyurl.com/lpnkfnj)关于屏外渲染可能很有趣。在那里,我回答了关于使用Sprite Buffer – ohager 2014-06-04 17:21:55
你总是可以做 var canvas2 = document.createElement("canvas");
而不是将它追加到DOM。
只是说,因为你们似乎很迷恋display:none;
它只是看起来更清洁,模仿双缓冲方式的想法比只是一个笨拙的无形画布更准确。
le在4岁面包上烤面包的方法将缓冲图像数据复制并粘贴到屏幕上的问题:-DD – DeadlyBacon 2016-01-16 12:23:46
答案仍然帮助我:D – AME 2017-06-09 07:59:44
- 1. iOS支持双模BLE吗?
- 2. C#双缓冲?
- 3. Java双缓冲
- 4. GDI +双缓冲
- 5. WinAPI双缓冲
- 6. Android双缓冲
- 7. VB.NET双缓冲
- 8. 双缓冲swt
- 9. Jython双缓冲
- 10. 双缓冲
- 11. TypeError:str不支持缓冲区接口
- 12. Python3.4'str'dons不支持缓冲区接口
- 13. sscanf()是否支持“递归”缓冲区?
- 14. TypeError:'str'不支持缓冲接口
- 15. 画布:双缓冲
- 16. 双缓冲? Win32 C++
- 17. WM_EX_COMPOSITED无双缓冲
- 18. 的WinForms双缓冲
- 19. Java - 双缓冲NullPointerException
- 20. 启用双缓冲
- 21. JWindow的双缓冲
- 22. Silverlight MediaElement双缓冲
- 23. 双缓冲和libgdx
- 24. 双缓冲帮助
- 25. DrawReversibleLine()和双缓冲
- 26. 在c#双缓冲
- 27. Android上支持双向SSL握手吗?
- 28. Redis支持文件缓存吗?
- 29. WPF中的双缓冲?
- 30. GDI + C++中的双缓冲
我的经验是,帆布画是由浏览器合并,使动画顺利。你能分享一些闪烁的代码吗? – eyelidlessness 2010-05-08 19:10:42
我注意到IE在使用'explorercanvas'时可能会闪烁,但这当然不是HTML5,并且是仅由VML模拟的'canvas'元素。我从来没有见过其他浏览器这样做。 – cryo 2010-05-19 10:16:54
相关http://stackoverflow.com/questions/11777483/ – julien 2012-11-29 14:48:12