我正在渲染一个单元网格,非常类似于填字游戏中的网格,但使用四种不同的颜色来填充每个单元格(不仅是黑色或白色)。
网格大小约为160x120,我需要尽可能快地渲染它,因为它将用于显示Cellular automaton动画。
我尝试了两种不同的方法来渲染网格:
使用以下内容渲染每个单元格:
var w = x + step;
var h = y + step;
canvasContext.fillStyle=cell.color;
canvasContext.fillRect(x+1,y+1,w-1,h-1);
canvasContext.strokeRect(x,y,w,h);
渲染没有边框的所有单元格,然后使用:
渲染网格线var XSteps = Math.floor(width/step);
canvasContext.fillStyle = gridColor;
for (var i = 0, len=XSteps; i<len; i++) {
canvasContext.fillRect(i*step, 0, 1, height);
}
//Similar thing for Y coord
两种算法都表现不佳:在两种情况下,绘制网格的速度都比单元格慢。我错过了什么吗?我该如何优化这些算法?还有其他方法我应该尝试吗?
注意:网格会移动,因为用户可以移动它或缩放视图。
一般的问题是:在元素上绘制单元格网格的最快算法是什么?
答案 0 :(得分:8)
做某事的最快方法就是不要这样做。
在一个画布上绘制一次不变的网格,并在上面(或下面)分层的另一个画布上绘制(并清除和重绘)细胞自动机。让浏览器(在其所有本机编译优化的荣耀中)为您处理弄脏,重绘和合成。
或者(更好)如果您不打算更改网格大小,只需创建一个小图像并让CSS填充它作为背景。
基于this excellent demo,这是一个完全通过CSS创建的背景图像网格;使用此功能,您可以根据需要更改大小(以整像素为增量)。
如果必须绘制网格,最快的方法是绘制线条:
function drawGrid(ctx,size){
var w = ctx.canvas.width,
h = ctx.canvas.height;
ctx.beginPath();
for (var x=0;x<=w;x+=size){
ctx.moveTo(x-0.5,0); // 0.5 offset so that 1px lines are crisp
ctx.lineTo(x-0.5,h);
}
for (var y=0;y<=h;y+=size){
ctx.moveTo(0,y-0.5);
ctx.lineTo(w,y-0.5);
}
ctx.stroke(); // Only do this once, not inside the loops
}
对于 m 行和 n 列,这需要 m + n 行一次绘制。将此与绘制 m × n 个别作品进行对比,您可以看到性能差异非常显着。
例如,在天真的情况下,512×512网格的8×8个小区将需要4,096个fillRect()
个调用,但只需要在单个 stroke()
使用上面的代码调用。
答案 1 :(得分:3)
如果没有看到所有代码知道性能的发展方向,那真的很难提供帮助,但这只是昙花一现:
background-image
到你想要的网格图像。rect()
(路径命令)所取代,最后只能调用fill
。因此,所有填充的单元格都可以使用单个填充(或抚摸或两者)命令一次渲染。答案 2 :(得分:3)
您正在使用填充绘制线条;我认为,定义一条路径并对其进行划分会更快:
canvasContext.beginPath();
var XSteps = Math.floor(width / step);
canvasContext.fillStyle = gridColor;
var x = 0;
for (var i = 0, len = XSteps; i < len; i++) {
canvasContext.moveTo(x, 0);
canvasContext.lineTo(x, height);
x += step;
}
// similar for y
canvasContext.stroke();