绘制大量线条时的HTML画布性能

时间:2012-06-16 01:06:08

标签: javascript html html5 canvas

我目前正在编写一个显示很多的应用程序,我的意思是,在HTML5画布上有很多2D路径(由数百个,数千个小段组成)。通常,几百万点。这些点从服务器下载到二进制ArrayBuffer

我可能不会在现实世界中使用那么多点,但我对如何提高性能感兴趣。如果你愿意,你可以称之为好奇心;)

无论如何,我已经测试了以下解决方案:

  1. gl.LINESgl.LINE_STRIP WebGL 一起使用,并计算GPU上着色器中的所有内容。目前最快的,可以显示 1000万个细分,而不会在我的Macbook Air上退缩。但是如果你想避免在JavaScript中处理事情,那么对于二进制格式有非常严格的限制,这很慢。

  2. 使用 Canvas2D ,在一次stroke()调用中绘制一条包含所有细分的巨大路径。当我超过 100k点时,页面会在画布更新前冻结几秒钟。所以,不在这里工作。

  3. 使用 Canvas2D ,但使用自己的stroke()调用绘制每个路径。尽管其他人一直在互联网上说,这比在一次调用中绘制所有内容要快得多,但仍然比WebGL慢很多。当我达到 500k段时,情况开始恶化。

  4. 两个Canvas2D解决方案需要循环遍历JavaScript中所有路径的所有点,因此这非常慢。 您是否知道可以提高JavaScript在ArrayBuffer中的迭代速度或一般处理速度的方法?

    但是,奇怪的是,在所有画布绘制调用完成后,屏幕不会立即更新。当我开始达到性能限制时,绘制调用结束和画布更新之间存在明显的延迟你知道它来自哪里,有没有办法减少它?

1 个答案:

答案 0 :(得分:7)

首先,WebGL是一个很好的炒作理念,但是解码和显示二进制数据所需的处理量在着色器中不起作用,因此我将其排除在外。

以下是我遇到的主要瓶颈。其中一些在一般编程中很常见,但记住它们是个好主意:

  • 最好使用多个小for循环
  • 尽可能在最高级别创建变量和闭包,不要在for循环中创建它们
  • 以数据块的形式呈现数据,并使用setTimeout在几毫秒后安排下一个块:这样,用户仍然可以使用UI
  • JavaScript对象和数组快速而便宜,使用它们。最好按顺序从头到尾读/写它们。
  • 如果您不在数组中按顺序写入数据,使用对象 (因为非顺序读写对对象来说很便宜)并将索引推送到索引数组。我使用SortedList实现来保持索引的排序,我发现here。开销很小(大约是渲染时间的10-20%),最后它非常值得。

这就是我记得的一切。如果我找到别的东西,我会更新这个答案!