2016-10-16 4 views
0

나는 미로를 가지고 있으며 내가 원하는 것은 그 모든 셀에 원을 만들고 그 원을 미로의 오른쪽으로 트리로 옮기는 것이다. 나는 d3 전환과 html5 캔버스를 사용합니다. 내가 할 수있는 최적화가 있다면 내 질문입니다. 캔버스 성능을 알지 못해서 내가 얼마나 기대할 수 있는지 모르겠다.캔버스 렌더링 최적화

1600 개의 요소 (600px x 600px 및 15px 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 요소를 여기에 만들면이를 피하고 자바 스크립트 구조의 목록을 만든 다음 반복합니다. –

+0

답장을 보내 주셔서 감사합니다. 나는 두 가지 질문을 가지고있다. 1. append를 사용하더라도, chrome dev 툴을 사용하면 DOM 트리에 엘리먼트가 나타나지 않는다. 그들은 그렇게 나빠요? 2. DOM 요소를 만들지 않고 전환을 적용하는 방법을 알고 있습니까? –

+1

1. DOM 트리 이상에서 만들 수있는 Chrome 개발자 도구는 문서에 첨부 한 도구 만 표시 할 수 있습니다. 1b) 예 2. 나의 초기 코멘트 당 recode. –

답변

0

최고의 성능을 얻으려면 오래된 학교에 가야합니다.

나는 당신이 무엇을하고 있는지 확실하지 않기 때문에 전반을 무시할 것입니다. 그리고 난이에 무엇으로 추측하고있는 .each 반복

당신은 당신 것 개체를 반복하려면 다음을 시도 할 경우

// 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(); 
}); 

아래 코드에서 주석으로 성능면에서 잘못하고있다 추가 성능을 얻으십시오. 그러나 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. 글로벌 범위에서 무엇이 잘못 되었습니까? 2. 속성이 셀의 속성이라고 생각하지 않습니다. 당신이 보여준대로 정의되지 않은 것처럼 보입니다. 3. 호는 같은 크기이지만 움직이고 있습니다. 이 상황에서 drawImage를 사용할 수 있습니까? –

+0

2. 이제 d3에서'attr()'대신'property()'를 사용해야합니다. –

+0

@JulianRubin'let'은 Chrome에서'var'의 속도의 절반입니다. GS에서'let'과'var' 사이에는 차이가 없으므로 let을 사용하는 이유는 무엇입니까? 'console.log (this)'를 통해 반복하고있는 것을 콘솔에 출력하고'this'가 무엇인지 알아 내라. 예, 스프라이트를 움직이는데'drawImage'를 사용할 수 있습니다. 단순히 호출하는 함수 호출 (속성 또는 attr)보다는 직접 참조를 사용해야합니다. – Blindman67