我正在使用带有javascript的Canvas对象。只是做一些测试,看看我在绘制循环中设置像素的速度有多快。
在Mac上,它在FF,safari,chrome中运行良好。在Windows上,我对FF和chrome有一个闪烁的效果。看起来在某种程度上,Windows上的画布实现与不同浏览器的Mac上的不同? (不确定这是不是真的)。
这是我用来绘图的基本代码(摘自下面的文章 - 我已经对下面的内容进行了优化以拉紧绘制循环,它现在运行得非常流畅):
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (var x = 0; x < canvasData.width; x++) {
for (var y = 0; y < canvasData.height; y++) {
// Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
canvasData.data[idx + 0] = 0;
canvasData.data[idx + 1] = 255;
canvasData.data[idx + 2] = 0;
canvasData.data[idx + 3] = 255;
}
}
ctx.putImageData(canvasData, 0, 0);
再次,窗户上的浏览器会闪烁一下。看起来画布实现试图在下一个绘图操作发生之前将画布清除为白色(这不会发生在mac上)。我想知道是否有一个设置我可以在Canvas对象中更改以修改该值(双缓冲,在绘制前清除等)?
这是我用作参考的文章: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/
由于
答案 0 :(得分:1)
我认为实现Canvas对象的浏览器使用DIBS(设备无关位图)是相当清楚的。您可以在不必先锁定句柄的情况下访问pixelbuffer这一事实证明了这一点。并且Direct2D在浏览器中与JS无关。 GDI是不同的,因为它使用DDB(设备相关的位图,即从视频存储器而不是传统的RAM分配)。然而,所有这些都与最佳JS渲染速度无关。我认为像你一样编写RGBA值可能是最好的方法。
上面代码中的关键因素是对putImageData()的调用。这是浏览器实现方式不同的地方。你实际上是直接写入DIB,而putImageData只是InvalidateRect的一个包装器吗?或者你实际上是在写入内存中的副本,然后将其复制到canvas设备上下文中?如果你使用linux或mac,那么这仍然是一个有效的问题。虽然设备上下文等通常是“窗口”术语,但大多数操作系统以几乎相同的方式处理句柄或结构。但是,我们再次受到浏览器供应商的支配。
我认为可以这样说:
如果您一次性绘制多个像素,那么直接写入像素缓冲区可能是最好的。在X次操作之后,一次性“bitblt”(复制)pixelbuffer会更快。这样做的原因是像FillRect这样的原生图形函数也会调用“invalidate rectangle”,它告诉系统屏幕需要重新绘制(刷新)的部分。因此,如果您调用100行命令,则将发出100次更新 - 减慢该过程。除非(这是捕获)你使用beginPath / EndPath方法,因为它们应该被使用。然后,这是一个完全不同的球赛。
这里是开始/结束路径“系统”发挥作用,以及Stroke / Outline命令。它们允许您在单个更新中执行X个绘图操作。但是很多人都错了,每次调用line / fillrect等都会重新绘制。
另外,您是否尝试过创建一个不可见的画布对象,绘制到该对象,然后复制到可见的画布?这可能更快(适当的双缓冲)。
答案 1 :(得分:0)
问题在于浏览器在不同操作系统上使用本机图形API的方式。即使在相同的操作系统上,使用不同的API(例如Windows中的GDI与Direct2D)也会产生不同的结果。