10

クロスワード パズルで見られるグリッドと非常によく似ていますが、4 つの異なる色を使用して各セルを塗りつぶします (黒または白だけではありません)。

グリッド サイズは約 160x120 で、セル オートマトンアニメーションの表示に使用されるため、できるだけ速くレンダリングする必要があります。

グリッドをレンダリングするために、次の 2 つの異なるアプローチを試しました。

  • 次のようなものを使用して各セルをレンダリングします。

    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

何かをするための最速の方法は、それをまったくしないことです。

1 つのキャンバスに不変のグリッドを 1 回描画し、その上 (または下) に重ねられた別のキャンバスにセル オートマトンを描画 (およびクリアして再描画) します。ブラウザー (すべてネイティブ コンパイルの最適化された栄光) に、ダーティと再描画と合成を処理させます。

または (より良い) グリッド サイズを変更しない場合は、小さな画像を作成し、CSS で背景として塗りつぶします。

Canvas への CSS 背景画像のデモ: http://jsfiddle.net/LdmFw/3/

この優れたデモに基づいて、完全に 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/

mn列の場合、1 回のパスでm + nの線を引く必要があります。これをm × nの個々の四角形の描画と比較すると、パフォーマンスの違いが非常に大きいことがわかります。

たとえば、8×8 セルの 512×512 グリッドは単純なケースでは 4,096回の呼び出しが必要ですが、上記のコードを使用して1 回fillRect()の呼び出しで 128 行だけストロークする必要があります。 stroke()

于 2012-08-03T15:24:21.550 に答える
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 に答える
3

パフォーマンスがどこに向かっているのかを知るためにすべてのコードを見ずに助けるのは本当に難しいですが、すぐに始めましょう:

  • ストロークを使用して背景グリッドを描画する代わりに、drawImage を 1 回呼び出すだけで描画できますか? それははるかに高速になります。本当に静的な場合はbackground-image、キャンバス上の css を必要なグリッドの画像に設定するだけです。
  • fillRect と strokeRect を頻繁に使用していますが、これらはおそらくrect()(パスコマンド)への複数の呼び出しと、最後に への単一の呼び出しに置き換えることができfillます。したがって、すべての塗りつぶされたセルは、1 つの塗りつぶし (またはストローク、またはその両方) コマンドで一度にレンダリングされます。
  • fillStyle/strokeStyle をできるだけ小さく設定します(回避できる場合はループ内ではありません)
于 2012-08-03T15:24:29.133 に答える