2017-07-18 44 views
1

我想開發一個應用程序,用戶可以點擊D3餅圖並查看與選擇相關的信息。我該如何旋轉弧線,使點擊的弧線到達底部(點擊弧線的中心應該在底部)?我一直在通過選擇弧組來旋轉餡餅,但我會很感激關於如何實現這一點的任何想法。 這是我迄今爲止的一些代碼。如何旋轉D3圖表,使選定的弧線位於底部?

var self = this; 
    var instanceId = Math.floor(Math.random() * 100000); 

    var margin = { 
     top: 5, 
     right: 15, 
     bottom: 50, 
     left: 20 
    }; 

    self.width = this.htmlElement.parentElement.parentElement.offsetWidth - margin.right - margin.left; 
    self.height = window.innerHeight/3 ; 
    self.curAngle = 0; 

    self.svgParent.html("<h4 style='color:green;'>Sponsors </h4><br>"); 

    // Update data for the chart 
    self.updateChartData = function() { 

     if(!self.svg) { 
      this.svg = this.svgParent 
       .classed("svg-container", true) 
       .append("svg") 
       .attr("preserveAspectRatio", "xMinYMin meet") 
       .attr("viewBox", "0 0 " + this.width + " " + this.height) 
       .append("g") 
       .classed("svg-content-responsive", true); 
       //.attr("transform", "translate(" + this.width/2 + "," + this.height/2 + ")"); 
     } 

     var svgg = this.svg 
      .append("g") 
      .classed("svg-content-responsive", true) 
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

     self.svg.selectAll(".arctext").remove(); 
     self.svg.selectAll(".pie-widget-total-label").remove(); 

     var pie = d3.pie().sort(sort)(self.selectedData.map(function (d: any) { 
      return d.count; 
     })); 

     var path = d3.arc() 
      .outerRadius(radius) 
      .innerRadius(radius/2); 

     var outsideLabel = d3.arc() 
      .outerRadius(radius * 0.9) 
      .innerRadius(radius * 0.9); 

     var middleLabel = d3.arc() 
      .outerRadius(radius * 0.75) 
      .innerRadius(radius * 0.75); 

     var insideLabel = d3.arc() 
      .outerRadius(radius * 0.6) 
      .innerRadius(radius * 0.6); 

     var g = self.svg 
      .attr("width", self.width + margin.left + margin.right) 
      .attr("height", self.height + margin.top + margin.bottom) 
      .append("g") 
      .attr("transform", "translate(" + self.width/2 + "," + self.height/2 + ")"); 

     var defs = g.append("defs"); 

     var lightGradients = defs.selectAll(".arc") 
      .data(pie) 
      .enter() 
      .append("radialGradient") 
      .attr("id", function (d: any) { 
       return "lightGradient-" + instanceId + "-" + d.index; 
      }) 
      .attr("gradientUnits", "userSpaceOnUse") 
      .attr("cx", "0") 
      .attr("cy", "0") 
      .attr("r", "120%"); 

     var darkGradients = defs.selectAll(".arc") 
      .data(pie) 
      .enter() 
      .append("radialGradient") 
      .attr("id", function (d: any) { 
       return "darkGradient-" + instanceId + "-" + d.index; 
      }) 
      .attr("gradientUnits", "userSpaceOnUse") 
      .attr("cx", "0") 
      .attr("cy", "0") 
      .attr("r", "120%"); 

     lightGradients.append("stop") 
      .attr("offset", "0%") 
      .attr("style", function (d: any) { 
       return "stop-color: " + d3.color(color(d.index)) + ";"; 
      }); 

     lightGradients.append("stop") 
      .attr("offset", "100%") 
      .attr("style", function (d: any) { 
       return "stop-color: black;"; 
      }); 

     darkGradients.append("stop") 
      .attr("offset", "0%") 
      .attr("style", function (d: any) { 
       return "stop-color: " + d3.color(color(d.index)).darker(0.5) + ";"; 
      }); 

     darkGradients.append("stop") 
      .attr("offset", "100%") 
      .attr("style", function (d: any) { 
       return "stop-color: black;"; 
      }); 

     self.tooltip = d3.select("body") 
      .append("div") 
      .attr("class", "pie-widget-tooltip") 
      .style("opacity", 0); 

     self.arc = g.selectAll(".arc") 
      .data(pie) 
      .enter() 
      .append("g") 
      .attr("class", "arc"); 

     var arcpath = self.arc.append("path") 
      .attr("id", function (d: any) { 
       return d.index; 
      }) 
      .attr("d", path) 
      .attr("stroke", "white") 
      .attr("stroke-width", "2px") 
      .attr("fill", function (d: any) { 
       return "url(#lightGradient-" + instanceId + "-" + d.index + ")"; 
      }) 
      .on("click", function (d: any) { 
       console.log("About to send::::" + getStudyLabel(d.index)); 
       self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index)); 
       self.showDialog(); 
       self.rotateChart(); 
      }) 

      .transition() 
      .duration(function(d:any, i:any) { 
       return i * 800; 
      }) 
      .attrTween('d', function(d:any) { 
       var i = d3.interpolate(d.startAngle + 0.1, d.endAngle); 
       return function (t: any) { 
        d.endAngle = i(t); 
        return path(d); 
       } 
      }); 

     function arcTween(a: any) { 
      var i = d3.interpolate(this._current, a); 
      this._current = i(0); 
      return function(t: any) { 
       return path(i(t)); 
      }; 
     } 

     var gtext = self.svg 
      .append("g") 
      .attr("transform", "translate(" + self.width/2 + "," + self.height/2 + ")"); 

     var arctext = gtext.selectAll(".arctext") 
      .data(pie) 
      .enter() 
      .append("g") 
      .attr("class", "arctext"); 

     var primaryLabelText = arctext.append("text") 
      .on("click", function (d: any) { 
      console.log("About to send::::" + getStudyLabel(d.index)); 
      self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index)); 
      self.showDialog(); 
      }) 
      .transition() 
      .duration(750) 
      .attr("transform", function (d: any) { 
       return "translate(" + middleLabel.centroid(d) + ")"; 
      }) 
      .attr("dy", "-0.75em") 
      .attr("font-family", "sans-serif") 
      .attr("font-size", "15px") 
      .attr("class", "sponsor-pie-widget-label") 
      .text(function (d: any) { 
       if (d.endAngle - d.startAngle < 0.3) { 
        return ""; 
       } else { 
        return getStudyLabel(d.index); 
       } 
      }); 

     var secondaryLabelText = arctext.append("text") 
      .on("click", function (d: any) { 
      console.log("About to send::::" + getStudyLabel(d.index)); 
      self.selectedIndustryTypeService.sendMessage(getStudyLabel(d.index)); 
      self.showDialog(); 
      }) 
      .transition() 
      .duration(750) 
      .attr("transform", function (d: any) { 
       return "translate(" + middleLabel.centroid(d) + ")"; 
      }) 
      .attr("dy", "0.75em") 
      .attr("font-family", "sans-serif") 
      .attr("font-size", "10px") 
      .attr("class", "sponsor-pie-widget-label") 
      .text(function (d: any) { 
       if (d.endAngle - d.startAngle < 0.3) { 
        return ""; 
       } else { 
        return getPatientsLabel(d.index); 
       } 
      }); 

     var n = 0; 
     for (var i = 0; i < self.selectedData.length; i++) { 
      n = n + this.selectedData[i]["count"]; 
     } 
     var total = self.svg 
      .append("g") 
      .attr("transform", "translate(" + (self.width/2 - 20) + "," + self.height/2 + ")") 
     total.append("text") 
      .attr("class", "pie-widget-total-label") 
      .text("Total\r\n" + n); 
    }.bind(self); 


    self.showDialog = function() { 
     this.router.navigateByUrl('/myRouteName'); 
    }.bind(self); 

    self.rotateChart = function() { 
     self.arc.attr("transform", "rotate(-45)"); 
    }.bind(self); 

回答

3

您可以通過適當地更改其開始/結束角度來旋轉弧,但這會比需要的更加複雜。

一個更簡單的解決方案是旋轉一個g來保存整個餅圖,同時以任何方式旋轉任何標籤以保持水平。

我只是用規範的餅圖從this block爲例:

var svg = d3.select("svg"), 
 
    width = +svg.attr("width"), 
 
    height = +svg.attr("height"), 
 
    radius = Math.min(width, height)/2, 
 
    g = svg.append("g").attr("transform", "translate(" + width/2 + "," + height/2 + ")"); 
 

 
var color = d3.scaleOrdinal(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]); 
 

 
var data = [ {age:"<5", population: 2704659},{age:"5-13", population: 4499890},{age:"14-17", population: 2159981},{age:"18-24", population: 3853788},{age:"25-44", population: 14106543},{age:"45-64", population: 8819342},{age:"≥65", population: 612463} ] 
 

 
var pie = d3.pie() 
 
    .sort(null) 
 
    .value(function(d) { return d.population; }); 
 

 
var path = d3.arc() 
 
    .outerRadius(radius - 10) 
 
    .innerRadius(0); 
 

 
var label = d3.arc() 
 
    .outerRadius(radius - 40) 
 
    .innerRadius(radius - 40); 
 

 
var arc = g.selectAll(".arc") 
 
    .data(pie(data)) 
 
    .enter().append("g") 
 
     .attr("class", "arc"); 
 

 
arc.append("path") 
 
    .attr("d", path) 
 
    .attr("fill", function(d) { return color(d.data.age); }) 
 
    .on("click",function(d) { 
 
     // The amount we need to rotate: 
 
     var rotate = 180-(d.startAngle + d.endAngle)/2/Math.PI * 180; 
 
    
 
     // Transition the pie chart 
 
     g.transition() 
 
     .attr("transform", "translate(" + width/2 + "," + height/2 + ") rotate(" + rotate + ")") 
 
     .duration(1000); 
 
     
 
    // Τransition the labels: 
 
    text.transition() 
 
     .attr("transform", function(dd) { 
 
     return "translate(" + label.centroid(dd) + ") rotate(" + (-rotate) + ")"; }) 
 
     .duration(1000); 
 

 
    }); 
 

 
var text = arc.append("text") 
 
     .attr("transform", function(d) { return "translate(" + label.centroid(d) + ")"; }) 
 
     .attr("dy", "0.35em") 
 
     .text(function(d) { return d.data.age; }); 
 

 

 
.arc text { 
 
    font: 10px sans-serif; 
 
    text-anchor: middle; 
 
} 
 

 
.arc path { 
 
    stroke: #fff; 
 
}
<svg width="960" height="500"></svg> 
 
<script src="https://d3js.org/d3.v4.min.js"></script>

+0

真棒!謝謝安德魯,我從這個答案中學到了一些東西。 – userx

+0

我無法獲得標籤工作的轉換。我在這裏發佈了另一個問題:https://stackoverflow.com/questions/45223993/getting-error-too-late-for-d3-transition。如果你可以花一點時間看看,那會很有幫助。謝謝! – userx

+0

得到它的工作!再次感謝您的努力。 – userx