2017-10-08 170 views
0

我在教自己如何在d3.js中製作交互式可視化,目前通過Elijah Meeks的D3.js In Action工作。我試圖讓他的餅圖示例交互使用三個按鈕。我在補間時做了一些錯誤 - 我試圖保存當前顯示的餅圖,以便在它和新選擇的餅圖之間進行過渡。但是,我目前的派不斷重置爲初始派。我認爲這可能很簡單,但我無法弄清楚我做錯了什麼。d3.js:如何解決我的交互式餅圖?

有人可以告訴我要改變什麼來使我的轉換工作?再次

  1. 運行下面的代碼,
  2. 點擊「統計2」按鈕,
  3. 點擊「統計2」按鈕 - 你會看到餡餅重置爲「統計:爲了說明問題1',然後平穩過渡到'Stat 2'。

.as-console-wrapper { max-height: 20% !important;}
<!DOCTYPE html> 
 
<html> 
 
    <head> 
 
    <meta charset="utf-8" /> 
 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
 
    </head> 
 

 
    <body> 
 
    <div id="viz"> 
 
     <button id="0"> Stat 1 </button> 
 
     <button id="1"> Stat 2 </button> 
 
     <button id="2"> Stat 3 </button> 
 
     <br> 
 
     <svg style="width:400px;height:300px;border:1px lightgray solid;" /> 
 
    </div> 
 
    </body> 
 

 
    <script> 
 
    var obj = [{ 
 
     name: "a", 
 
     stat1: 10, 
 
     stat2: 20, 
 
     stat3: 30, 
 
    }, { 
 
     name: "b", 
 
     stat1: 30, 
 
     stat2: 20, 
 
     stat3: 10, 
 
    }, { 
 
     name: "c", 
 
     stat1: 15, 
 
     stat2: 25, 
 
     stat3: 50, 
 
    }]; 
 

 
    function piechart(data) { 
 

 
     var currentPie = 0; //Initialize to stat1 
 

 
     var fillScale = d3.scaleOrdinal(d3.schemeCategory10); 
 
     var pieChart = d3.pie().sort(null); 
 
     var newArc = d3.arc().innerRadius(50).outerRadius(100); 
 

 
     // Create each pie chart 
 
     pieChart.value(d => d.stat1); 
 
     var stat1Pie = pieChart(data); 
 

 
     pieChart.value(d => d.stat2); 
 
     var stat2Pie = pieChart(data); 
 

 
     pieChart.value(d => d.stat3); 
 
     var stat3Pie = pieChart(data); 
 

 
     // Embed slices on each name 
 
     data.forEach((d, i) => { 
 
     var slices = [stat1Pie[i], stat2Pie[i], stat3Pie[i]]; 
 
     d.slices = slices; 
 
     }); 
 

 
     d3.select("svg") 
 
     .append("g") 
 
     .attr("transform", "translate(200, 150)") 
 
     .selectAll("path") 
 
     .data(data) 
 
     .enter() 
 
     .append("path") 
 
     .attr("d", d => newArc(d.slices[currentPie])) 
 
     .attr("fill", (d, i) => fillScale(i)) 
 
     .attr("stroke", "black") 
 
     .attr("stroke-width", "2px"); 
 

 
     function transPie(d) { 
 

 
     var newPie = this.id; 
 
     console.log("Transition from pie " + currentPie + " to pie " + newPie); 
 

 
     d3.selectAll("path") 
 
      .transition() 
 
      .delay(500) 
 
      .duration(1500) 
 
      .attrTween("d", tweenPies) 
 

 
     function tweenPies(d, i) { 
 
      console.log(i + ":start tween function \n current pie = " + currentPie + "\n new pie = " + newPie); 
 
      var currentAngleStart = d.slices[currentPie].startAngle; 
 
      var newAngleStart = d.slices[newPie].startAngle; 
 

 
      var currentAngleEnd = d.slices[currentPie].endAngle; 
 
      var newAngleEnd = d.slices[newPie].endAngle; 
 

 
      return t => { 
 
      var interpolateStartAngle = d3.interpolate(currentAngleStart, newAngleStart); 
 
      var interpolateEndAngle = d3.interpolate(currentAngleEnd, newAngleEnd); 
 
      d.startAngle = interpolateStartAngle(t); 
 
      d.endAngle = interpolateEndAngle(t); 
 
      return newArc(d); 
 
      }; 
 
     }; 
 
     }; 
 

 
     d3.selectAll("button").on("click", transPie); 
 
    }; 
 
    piechart(obj); 
 

 
    </script> 
 

 
</html>

+1

如果你想讓人們運行您的代碼,使用堆棧段('<>'符號)。 –

回答

1

你從未設置的currentPie的狀態到新狀態的選擇之後。我添加了一個.on('end',處理器過渡到設置此狀態:

.on('end', function(){ 
    currentPie = newPie; 
}); 

運行代碼:

<html> 
 

 
    <head> 
 
    <script src="https://d3js.org/d3.v4.min.js"></script> 
 
    </head> 
 

 
    <body> 
 
    <div id="viz"> 
 
     <button id="0"> Stat 1 </button> 
 
     <button id="1"> Stat 2 </button> 
 
     <button id="2"> Stat 3 </button> 
 
     <br /> 
 
     <svg style="width:1000px;height:500px;border:1px lightgray solid;"></svg> 
 
    </div> 
 
    <script> 
 
    var obj = [{name: "a",stat1: 10,stat2: 20,stat3: 30,}, 
 
       {name: "b",stat1: 30,stat2: 20,stat3: 10,}, 
 
       {name: "c",stat1: 15,stat2: 25,stat3: 50,}]; 
 

 
    function piechart(data){ 
 

 
     var currentPie = 0; //Initialize to stat1 
 

 
     var fillScale = d3.scaleOrdinal(d3.schemeCategory10); 
 
     var pieChart = d3.pie().sort(null); 
 
     var newArc = d3.arc().innerRadius(50).outerRadius(100);    
 

 
     // Create each pie chart 
 
     pieChart.value(d => d.stat1); 
 
     var stat1Pie = pieChart(data); 
 

 
     pieChart.value(d => d.stat2); 
 
     var stat2Pie = pieChart(data); 
 

 
     pieChart.value(d => d.stat3); 
 
     var stat3Pie = pieChart(data); 
 

 
     // Embed slices on each name 
 
     data.forEach((d,i) => { 
 
      var slices = [stat1Pie[i], stat2Pie[i], stat3Pie[i]]; 
 
      d.slices = slices; 
 
     }); 
 

 
     d3.select("svg") 
 
      .append("g") 
 
      .attr("transform", "translate(250, 250)") 
 
      .selectAll("path") 
 
      .data(data) 
 
      .enter() 
 
      .append("path") 
 
      .attr("d", d => newArc(d.slices[currentPie])) 
 
      .attr("fill", (d,i) => fillScale(i)) 
 
      .attr("stroke", "black") 
 
      .attr("stroke-width", "2px"); 
 

 
     function transPie(d) { 
 

 
      var newPie = +this.id; 
 
      console.log("Transition from pie " +currentPie+ " to pie " + newPie); 
 

 
      d3.selectAll("path") 
 
       .transition() 
 
       .delay(500) 
 
       .duration(1500) 
 
       .attrTween("d", tweenPies) 
 
       .on('end', function(){ 
 
        currentPie = newPie; 
 
       }) 
 

 
      function tweenPies(d, i) { 
 
       console.log(i + ":start tween function \n current pie = " + currentPie + "\n new pie = "+newPie); 
 
       var currentAngleStart = d.slices[currentPie].startAngle; 
 
       var newAngleStart  = d.slices[newPie].startAngle; 
 

 
       var currentAngleEnd  = d.slices[currentPie].endAngle; 
 
       var newAngleEnd   = d.slices[newPie].endAngle; 
 

 
       return t => { 
 
        var interpolateStartAngle = d3.interpolate(currentAngleStart, newAngleStart); 
 
        var interpolateEndAngle = d3.interpolate(currentAngleEnd, newAngleEnd); 
 
        d.startAngle = interpolateStartAngle(t); 
 
        d.endAngle = interpolateEndAngle(t); 
 
        return newArc(d); 
 
       }; 
 
      }; 
 
     }; 
 

 
     d3.selectAll("button").on("click", transPie); 
 
    }; 
 
    piechart(obj); 
 
    </script> 
 
    </body> 
 

 
</html>