首页 文章

在<canvas>中绘制填字游戏网格的最快算法?

提问于
浏览
10

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

网格大小约为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

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

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

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

3 回答

  • 3

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

    在一个画布上绘制一次不变的网格,并在另一个分层上方(或下方)的画布上绘制(并清除和重绘)细胞自动机 . 让浏览器(在其所有本机编译优化的荣耀中)为您处理弄脏,重绘和合成 .

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

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

    基于this excellent demo,这是一个完全通过CSS创建的背景图像网格;使用此功能,您可以根据需要更改大小(以整像素为增量) .

    CSS3 Grid to 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个别行为,您可以看到性能差异非常显着 .

    例如,在原始情况下,512×512网格的8×8个小区将需要4,096个 fillRect() 个呼叫,但是在使用上面的代码进行呼叫时,只需要抚摸128个线路 .

  • 8

    如果没有看到所有代码知道性能的去向,那真的很难帮助,但是刚刚开始:

    • 而不是使用笔划绘制背景网格,您可以使用一次调用drawImage来绘制它吗?那会更快 . 如果它真的是静态的那么你可以在画布上将css background-image 设置为你想要的网格图像 .

    • 你正在使用fillRect和strokeRect很多,这些可能会被多次调用 rect() (路径命令)所取代,最后只能调用 fill . 因此,所有填充的单元格都可以使用单个填充(或抚摸或两者)命令一次渲染 .

    • 尽可能少地设置fillStyle / strokeStyle(如果可以避免的话,不要在循环内部)

  • 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();
    

相关问题