10

我正在渲染一个单元格网格,非常类似于您在填字游戏中找到的网格,但使用四种不同的颜色填充每个单元格(不仅是黑色或白色)。

网格大小约为 160x120,我需要尽可能快地渲染它,因为它将用于显示元胞自动机动画。

我尝试了两种不同的方法来渲染网格:

  • 使用以下内容渲染每个单元格:

    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
    

两种算法都表现不佳:在这两种情况下,绘制网格都比绘制单元格慢。我错过了什么吗?如何优化这些算法?我应该尝试另一种方法吗?

注意:网格移动,因为用户可以移动它或缩放视图。

一般的问题是:在元素上绘制单元格网格的最快算法是什么?

4

3 回答 3

9

做某事最快的方法是根本不做。

在一个画布上画一次你不变的网格,然后在另一个画布上(或下)画(清除和重画)你的元胞自动机。让浏览器(在所有它的本机编译优化的荣耀中)为您处理脏污、重绘和合成。

或者(更好)如果您不打算更改网格大小,只需创建一个小图像并让 CSS 填充它作为背景。

CSS 背景图像到 Canvas 的演示:http: //jsfiddle.net/LdmFw/3/

基于这个优秀的演示,这是一个完全通过 CSS 创建的背景图像网格;有了这个,您可以根据需要更改大小(以整个像素为增量)。

CSS3 Grid 到 Canvas 的演示:http: //jsfiddle.net/LdmFw/5/

如果你必须画一个网格,最快的就是画线:

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
}

网格绘制演示:http: //jsfiddle.net/QScAk/4/

对于m行和n列,这需要一次绘制m + n行。将此与绘制m × n 个单独的矩形进行对比,您可以看到性能差异可能非常显着。

例如,一个 8×8 单元格的 512×512 网格在简单的情况下需要 4,096次调用,但使用上面的代码在一次fillRect()调用中只需要描边 128 行。 stroke()

于 2012-08-03T15:24:21.550 回答
3

如果不查看所有代码以了解性能的进展情况,真的很难提供帮助,但马上就要开始了:

  • 您可以使用一次调用drawImage 来绘制背景网格,而不是使用描边绘制背景网格吗?那会快得多。如果它真的是静态的,那么您可以background-image将画布上的 CSS 设置为您想要的网格图像。
  • 您经常使用 fillRect 和 strokeRect ,它们可能会被多次调用rect()(路径命令)替换,最后只有一次调用fill。因此,所有填充的单元格都使用单个填充(或描边或两者)命令一次呈现。
  • 尽可能少地设置fillStyle/strokeStyle(如果可以避免的话,不要在循环内)
于 2012-08-03T15:24:29.133 回答
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();
于 2012-08-03T15:29:15.593 回答