2010-01-22 43 views
2

我正在使用带有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); 

再次,Windows上的浏览器会闪烁一下。它看起来像画布实现尝试在下一个绘制操作发生之前将画布清除为白色(这在mac上不会发生)。我想知道是否有一个设置可以在Canvas对象中修改该值(双缓冲,在绘制之前清除等)?

这是我使用作为参考的文章: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/

感谢

回答

0

问题是与浏览器使用本地图形API在不同的操作系统的方式。即使在同一个操作系统上,使用不同的API(例如Windows中的GDI与Direct2D)也会产生不同的结果。

+1

是的,我猜这是没有什么可以做的 - 没有办法告诉Canvas改变浏览器实现重绘的方式,对吗?像canvas.pleaseDoubleBuffer =“true”标志? – user246114

+0

或者我的意思是 - 看起来好像某些实现上的画布在每次画画之后都被擦除为白色 - 如果可以关闭,则全部都是完美的。不要以为有这样的事情可以这样做。 – user246114

+0

不幸的是,我不知道如何控制画布使用底层操作系统API。 –

1

我认为很明显,实现Canvas对象的浏览器使用DIBS(设备无关位图)。您无需首先锁定手柄即可访问像素缓冲区的事实证明了这一点。而Direct2D与JS在浏览器中无关。由于GDI使用DDB(依赖于设备的位图,即从视频存储器分配而不是传统的RAM),GDI是不同的。所有这些与最佳JS渲染速度无关。我认为像你这样写RGBA值可能是最好的方法。

上面代码中的关键因素是对putImageData()的调用。这是浏览器在实现上可能不同的地方。你实际上是直接写入DIB,并且putImageData只是一个InvalidateRect的包装?或者你实际上正在写入内存中的副本,然后将其复制到画布设备上下文中?如果你使用linux或mac,那么这仍然是一个有效的问题。尽管设备上下文等通常是“窗口”术语,但大多数操作系统都以几乎相同的方式处理句柄或结构。但是,我们再次受到浏览器供应商的支配。

我认为有以下可以说:

如果您正在绘制在一气呵成许多像素,那么你做直接写入pixelbuffer可能是最好的。在X操作之后,一次性“复制”(复制)pixelbuffer会更快。原因在于像FillRect这样的本地图形函数也会调用“invalidate rectangle”,它告诉系统一部分屏幕是否需要重新绘制(刷新)。因此,如果您调用100行命令,那么会发布100个更新 - 减慢过程。除非(和这是捕获),你应该使用beginPath/EndPath方法。那么这是一个完全不同的球赛。

在这里,开始/结束路径“系统”开始起作用,并且还有Stroke/Outline命令。它们允许您在一次更新中执行X次绘图操作。但是很多人都弄错了,并且每次调用line/fillrect时都会重绘。

另外,你有没有尝试过创建一个不可见的画布对象,绘制到,然后复制到可见的画布?这可能会更快(适当的双缓冲)。