2016-10-16 4 views
0

私は迷路を持っています。私が望むのは、そのセルのすべてに円を作成し、それらの円を木のように迷路の右側に移動することです。私はd3トランジションとhtml5キャンバスを使用します。私の質問は、私ができる最適化があるかどうかです。私はキャンバスのパフォーマンスを知らないので、どれくらい期待できるのかわかりません。キャンバスレンダリングの最適化

1600要素(600 px x 600 pxおよび15 px cellSize)の場合、アニメーションはスムーズです。 3600要素についてはそうではありません。

mazeSelection.selectAll('cell') 
    .data(root.descendants()) 
    .enter() 
    .append('cell') 
    .attr('radius', 0) 
    .attr('cx', d => d.data.ix * cellSize + 0.5 * cellSize,) 
    .attr('cy', d => d.data.iy * cellSize + 0.5 * cellSize) 
    .transition().duration(2000) 
    .attr('radius', cellSize/2) 
    .transition().duration(3000) 
    .attr('radius', cellSize/4) 
    .tween('position', function(d) { 
     const i = d3.interpolate([this.getAttribute('cx'), this.getAttribute('cy')], [width + d.x, cellSize * 0.5 + d.y]); 
     return (t) => { 
      [d.cx, d.cy] = i(t); 
      this.setAttribute('cx', d.cx); 
      this.setAttribute('cy', d.cy); 
     }; 
    }); 

context.fillStyle = "white"; 

let timer = d3.timer(function redraw() { 
    // clear maze 
    context.beginPath(); 
    context.fillRect(0, 0, width * 2, height); 

    //drawMaze(grid, context, width, height, cellSize); 
    context.beginPath(); 

    // here we must use a function to have access to "this" 
    mazeSelection.selectAll('cell') 
     .each(function (d) { 
      const radius = this.getAttribute('radius'), 
       x = this.getAttribute('cx'), 
       y = this.getAttribute('cy'); 

      context.moveTo(x, y); 
      context.arc(x, y, radius * 0.5, 0, 2 * Math.PI); 

      (d.children || []).forEach(child => { 
       context.moveTo(x, y); 
       context.lineTo(child.cx, child.cy); 
      }); 
     }); 

    context.stroke(); 
    context.fill(); 
}); 
+1

ここでDOM要素を作成していますが、これを避けて、javascript構造のリストを作成してから繰り返します。 –

+0

返信ありがとうございます。私は2つの質問があります:1.私がappendを使用しても、私はchrome開発ツールを使用すると、DOMツリーに要素が表示されません。彼らはとても悪いですか? 2. DOM要素を作成せずに遷移を適用する方法を知っていますか? –

+1

1. DOMツリー上に複数のフォルダを作成することはできますが、chrome開発ツールはドキュメントに添付したものだけを表示することができます。 1b)はい2.私の最初のコメントにつきコードを記入してください。 –

答えて

0

最高のパフォーマンスを得るには古い学校に行ってください。

私は前半を無視します。前半は無視します。あなたは意志のオブジェクトを反復するために次のことをしようと私は

// why use a let in global scope???? 
let timer = d3.timer(function redraw() { 
    context.beginPath(); 
    context.fillRect(0, 0, width * 2, height); 
    context.beginPath(); 

    // You wrote "here we must use a function to have access to "this"" 
    // What 'this'? I assume it is the iterated cell `this`. Just use the 
    // cell referance, you dont have to use `this` 
    mazeSelection.selectAll('cell') 
     .each(function (d) {  // dont use callbacks to iterate. For loops are much quicker 
      // on chrome const and let are half the speed of var 
      const radius = this.getAttribute('radius'), // why use getAttribute, a pointless and very CPU expensive way to get an object's property 
       x = this.getAttribute('cx'), 
       y = this.getAttribute('cy'); 
      // why even assign the above properties to a const when you can use them directly 

      context.moveTo(x, y); 
      context.arc(x, y, radius * 0.5, 0, 2 * Math.PI); 

      // use a for loop and don't test for the existence of children 
      // by creating a new Array if they don't exist and then calling 
      // the array method forEach, a complete waste of CPU time 
      (d.children || []).forEach(child => { 
       context.moveTo(x, y); 
       context.lineTo(child.cx, child.cy); 
      }); 
     }); 

    context.stroke(); 
    context.fill(); 
}); 

下のコード内のコメントとして、あなたはパフォーマンスの面で間違ってやっている、これは.each反復

にあるものへと推測しています余分なパフォーマンスを得る。しかし、3000+はまだ手の届かないところにいるかもしれません。

var timer = d3.timer(function redraw() { 
    context.beginPath(); 
    context.fillRect(0, 0, width * 2, height); 
    context.beginPath(); 

    var cells = mazeSelection.selectAll('cell') 
    for(var i = 0; i < cells.length; i ++){ 
     var d = cell[i]; 
     var x = d.x; // create a local referance as x & y may be used many times 
     var y = d.y; 
     context.moveTo(x, y); 
     context.arc(x, y, d.radius * 0.5, 0, 2 * Math.PI); 
     if(d.children){ 
      var c = d.children; 
      for(var j = 0; j < c.length; j++){  
       context.moveTo(x, y); 
       context.lineTo(c[j].cx, c[j].cy); 
      } 
     } 

     context.stroke(); 
     context.fill(); 
    }; 

あなたがレンダリングされているアークはあなたがオフスクリーンキャンバス(スプライトシート)に弧をレンダリングして、ハードウェア/ブラウザにもよるがdrawImage(spriteSheet,...で弧を描くことにより、いくつかの性能向上を得ることができ、同じサイズの周りにある場合これはマイナーな、または大幅なパフォーマンスの向上です。

+0

ありがとうございました! 1.グローバルな範囲でのletの正確な問題は何ですか?私はあなたが示したように未定義のように見えるので、属性はセルのプロパティだとは思わない。 3.アークのサイズは同じですが、動いています。この状況でdrawImageを使用できますか? –

+0

2.私はd3で 'attr()'の代わりに 'property()'を使うべきです。 –

+0

@JulianRubin 'let'はChromeの' var'の半分の速度です.GTでは 'let'と' var'の間にdifがないので、なぜletを使用しますか?あなたが 'console.log(this)'を反復しているものをコンソールに出力し、 'this'が何であるかを調べます。スプライトの移動に' drawImage'を使うことができます。あなたは、単に呼び出すだけの関数呼び出し(プロパティまたはattr)ではなく、直接参照を使用する必要があります。 – Blindman67