加速在HTML5画布元素上绘制许多点的过程

12

我需要在HTML5画布上绘制许多点,但是这需要相当长的时间。我的代码看起来像这样:

var points = getPoints() // Array of {x,y,color}
var ctx = canvas.getContext("2d");

for (var i = 0; i < points.length; i++) {
   ctx.fillStyle = points[i].color
   ctx.beginPath()
   ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2, true)
   ctx.fill() }

我想知道有哪些性能调整可以加快速度。我只使用了5种不同的颜色。例如,是否可以实时对点列表进行排序,仅更改 ctx.fillStyle 5次而不是每个点都更改一次?


我认为这是一条相当慢的线路:ctx.arc(points[i].x, points[i].y, radius, 0, Math.PI * 2, true)。尝试绘制简单的矩形,看看是否可以加快速度。(在我看来,应该可以...) - ppeterka
1
我试过了,确实加快了速度。然而我不明白那如何有所帮助。 - Nicolas
1
我认为如果您设置一个fiddle,人们就可以更轻松地进行调整,以下是我能想到的一些修改,以使其更快(也许)-> [FIDDLE](http://jsfiddle.net/4WTaQ/)... - adeneo
@ Alnitak 在每个画布上大约有3k个点。在大约8x6个画布的瓦片配置上。总共需要几秒钟的时间。 - Nicolas
@ppeterka 实际上,我认为首选解决方案(考虑到颜色数量较少)不需要改变.fillStyle,因此无需创建排序数组。 - Alnitak
显示剩余5条评论
1个回答

17
例如,在绘制点列表时,是否在运行时对其进行排序以仅更改ctx.fillStyle 5次而不是每个点更改1次,会对性能有所裨益吗?
根据我的经验,是的 - 经常更改.fillStyle会非常昂贵。
我编写了一个在画布中绘制大量矩形的代码,使用只有两种颜色的方块来绘制矩形的时间明显优于使用许多频繁更改颜色的方块来绘制矩形。
总之,由于您只有五种不同的颜色:
  1. 创建一个屏幕外画布,可以在其中绘制五个圆圈
  2. 使用.drawImage()将正确的颜色圆圈快速复制到目标画布中,而无需重新计算圆弧坐标
  3. 在循环内部将points[i]分配给一个局部变量,以避免反复引用它。
在我的笔记本电脑上,此代码在400x400画布上绘制3000个圆形需要7毫秒。
var colours = ['red', 'green', 'blue', 'yellow', 'magenta'];
var n = colours.length;
var r = 10;
var d = r * 2;

var off = document.createElement('canvas');
off.width = n * d;
off.height = d;
var ctx = off.getContext('2d');  

for (var i = 0; i < n; ++i) {
    ctx.fillStyle = colours[i];
    ctx.beginPath();
    ctx.arc(i * d + r, r, r, 0, 2 * Math.PI);
    ctx.closePath();
    ctx.fill();
}

var canvas = document.getElementById('canvas');
var ctx2 = canvas.getContext('2d');
var t0 = Date.now();
for (var i = 0; i < 3000; ++i) {
    var c = Math.floor(n * Math.random());
    var x = Math.floor(canvas.width * Math.random());
    var y = Math.floor(canvas.height * Math.random());
    ctx2.drawImage(off, c * d, d, d, x - r, y - r, d, d);
}
var t1 = Date.now();
alert((t1 - t0) + "ms");

请查看http://jsfiddle.net/alnitak/Dpgts/


哇,我的只用了3毫秒。令人印象深刻。非常感谢! - Nicolas
顺便说一句,如果你的圆不重叠,你可以使用.putImageData来大大加快速度。 - Alnitak
他们不这样做。你的意思是用.drawImage()代替吗? - Nicolas
@Stewie 我试了,但我刚刚尝试过它,它实际上更慢了。 - Alnitak
http://jsfiddle.net/Dpgts/137/ 绘制一百万个圆需要很长时间(约9秒) - Kira
1
在2018年,现在无论是FF还是Chrome中的arc()函数和上下文更改都快了很多,速度差距不再像以前那样大。现在,我可以在400毫秒内绘制70k个r = 3的圆,drawImage()版本只快2倍。因此对于大多数应用程序来说,我认为这种优化已经不再需要了。 - Max

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接