2016-04-10 61 views
1

我想使用“D3.JS”开发“向下钻取”“饼图”。我找到了下面的示例,对我来说很完美。部分文本标签不显示在D3.JS中向下钻取饼图

D3 Js sample drill down pie chart

上述样品是非常适合我。

另外从示例下钻饼图中,我想将TEXT LABEL放置在饼图的每个分区中。

我跟着许多样品,

  1. Sample 1 - pie chart with section text label

  2. Sample 2 - JSFiddle - pie chart with section text label

基于放置文本标签在饼图部分上述样品,我跟着下面的代码,我尝试添加样本“var dataSet”,“var arcs = svg.selectAll(”g.slice“)”代码。 但是,当我执行该程序时,它不会在饼图中的每个部分的中心显示任何文本标签。

有人可以指导我解决这个问题吗?

<!doctype html> 
<html> 
<head> 
    <head> 
    <meta charset="utf-8"> 
    <title>Drill down pie chart test</title> 
    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js?2.9.6"></script> 
    <style type="text/css"> 
     body { 
     text-align: center; 
     padding: 50px; 
     font-family: "Helvetica Neue",Arial,Sans-serif; 
     font-weight: 200; 
     color: #333; 
     } 
     .header {   
     font-size: 20px; 
     } 
     .sector { 
     cursor: pointer; 
     } 
     .slice text { 
      font-size: 16pt; 
      font-family: Arial; 
     } 

    </style> 
    </head> 
    <body> 
    <script type="text/javascript"> 


    // Globals 
    var width = 500, 
     height = 400, 
     margin = 50, 
     radius = Math.min(width - margin, height - margin)/2, 
     // Pie layout will use the "val" property of each data object entry 
     pieChart = d3.layout.pie().sort(null).value(function(d){return d.val;}), 
     arc = d3.svg.arc().outerRadius(radius), 
     MAX_SECTORS = 15, // Less than 20 please 
     colors = d3.scale.category20(); 

    var dataSet = [ 
        {"legendLabel":"One", "magnitude":20}, 
        {"legendLabel":"Two", "magnitude":40}, 
        {"legendLabel":"Three", "magnitude":50}, 
        {"legendLabel":"Four", "magnitude":16}, 
        {"legendLabel":"Five", "magnitude":50}, 
        {"legendLabel":"Six", "magnitude":8}, 
        {"legendLabel":"Seven", "magnitude":30}]; 

     //mydata = {"Medical", "Agriculture", "Security"}; 

     var st = {}; 
     st.data = [{"label":"less than a week","value":169,"pos":0},{"label":"1 week - 30 days","value":1,"pos":1},{"label":"30 - 90 days","value":22,"pos":2},{"label":"90 - 180 days","value":35,"pos":3},{"label":"180 days - 1 year","value":47,"pos":4},{"label":"more than 1 year","value":783,"pos":5}] ; 


    // Synthetic data generation ------------------------------------------------ 
    var data = []; 
    var numSectors = 8; //Math.ceil(Math.random()*MAX_SECTORS); 
    for(i = -1; i++ < numSectors;) { 
     var children = []; 
     var numChildSectors = Math.ceil(Math.random()*MAX_SECTORS); 
     var color = colors(i); 
     for(j=-1; j++ < numChildSectors;){ 

     // Add children categories with shades of the parent color 
     children.push(
      { cat: "cat"+((i+1)*100+j), 
      val: Math.random(), 
      color: d3.rgb(color).darker(1/(j+1)) 
      }); 
     } 
     data.push({ 
     cat: "cat"+i, 
     val: Math.random(), 
     color: color, 
     children: children}); 
    } 
    // -------------------------------------------------------------------------- 


    // SVG elements init 
    var svg = d3.select("body").append("svg").data([dataSet]).attr("width", width).attr("height", height), 
     defs = svg.append("svg:defs"), 
     // .data(pieChart) 

     // Declare a main gradient with the dimensions for all gradient entries to refer 
     mainGrad = defs.append("svg:radialGradient") 
      .attr("gradientUnits", "userSpaceOnUse") 
      .attr("cx", 0).attr("cy", 0).attr("r", radius).attr("fx", 0).attr("fy", 0) 
      .attr("id", "master"), 
     // The pie sectors container 
     arcGroup = svg.append("svg:g") 
      .attr("class", "arcGroup") 
      .attr("filter", "url(#shadow)") 
      .attr("transform", "translate(" + (width/2) + "," + (height/2) + ")"), 
     // Header text 
     header = svg.append("text").text("Biotechnology") 
        .attr("transform", "translate(10, 20)").attr("class", "header"); 

       //svg.append("text").attr("text-anchor", "middle").text("$" + "sample"), 
       //svg.append("text").text("sample").attr("text-anchor", "middle") 

     /*svg.append("text") 
       .attr("transform", "translate(" + arcGroup.centroid(d) + ")") 
       .attr("dy", ".35em") 
       .attr("text-anchor", "middle") 
       .text("sample"); 
       */ 

     // Declare shadow filter 
     var shadow = defs.append("filter").attr("id", "shadow") 
         .attr("filterUnits", "userSpaceOnUse") 
         .attr("x", -1*(width/2)).attr("y", -1*(height/2)) 
         .attr("width", width).attr("height", height); 
     shadow.append("feGaussianBlur") 
      .attr("in", "SourceAlpha") 
      .attr("stdDeviation", "4") 
      .attr("result", "blur"); 
     shadow.append("feOffset") 
      .attr("in", "blur") 
      .attr("dx", "4").attr("dy", "4") 
      .attr("result", "offsetBlur"); 
     shadow.append("feBlend") 
      .attr("in", "SourceGraphic") 
      .attr("in2", "offsetBlur") 
      .attr("mode", "normal"); 

     /* var arcs = svg.selectAll("g.slice") 

     arcs.append("text") 
    .attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; }) 
    .attr("dy", ".35em") 
    .attr("text-anchor", "middle") 
    .text(function(d) { return d.value; }); 
     */ 



    // Redraw the graph given a certain level of data 
    function updateGraph(cat){ 
     var currData = data; 

     // Simple header text 
     if(cat != undefined){ 
     currData = findChildenByCat(cat); 
     d3.select(".header").text("Biotechnology → "+cat); 
     } else { 
     d3.select(".header").text("Biotechnology"); 
     } 


     // Create a gradient for each entry (each entry identified by its unique category) 
     var gradients = defs.selectAll(".gradient").data(currData, function(d){return d.cat;});  
     gradients.enter().append("svg:radialGradient") 
     .attr("id", function(d, i) { return "gradient" + d.cat; }) 
     .attr("class", "gradient") 
     .attr("xlink:href", "#master");  

     gradients.append("svg:stop").attr("offset", "0%").attr("stop-color", getColor); 
     gradients.append("svg:stop").attr("offset", "90%").attr("stop-color", getColor); 
     gradients.append("svg:stop").attr("offset", "100%").attr("stop-color", getDarkerColor);  


     /*var arcs = defs.selectAll("g.slice").data(pie).enter().append("svg:g").attr("class","slice"); 
     arcs.append("svg:text").attr("transform", function(d){ 
     d.innerRadius = 0; 
     d.outerRadius = r; 
     return "translate(" + arc.centroid(d) + ")";}).attr("text-anchor", "middle").text(function(d, i) { 
     return (data[i].value/tot) * 100 > 10 ? ((data[i].value/tot) * 100).toFixed(1) + "%" : ""; 
     } 
    ).attr("fill","#fff") 
     .classed("slice-label",true); 
     */ 

     // Create a sector for each entry in the enter selection 
     var paths = arcGroup.selectAll("path") 
        .data(pieChart(currData), function(d) {return d.data.cat;});    
     paths.enter().append("svg:path").attr("class", "sector"); 

     // Each sector will refer to its gradient fill 
     paths.attr("fill", function(d, i) { return "url(#gradient"+d.data.cat+")"; }) 
     .transition().duration(1000).attrTween("d", tweenIn).each("end", function(){ 
      this._listenToEvents = true; 
     }); 

     // Mouse interaction handling 
     paths.on("click", function(d){ 
       if(this._listenToEvents){ 
        // Reset inmediatelly 
        d3.select(this).attr("transform", "translate(0,0)") 
        // Change level on click if no transition has started     
        paths.each(function(){ 
        this._listenToEvents = false; 
        }); 
        updateGraph(d.data.children? d.data.cat : undefined); 
       } 
       }) 
      .on("mouseover", function(d){ 
       // Mouseover effect if no transition has started     
       if(this._listenToEvents){ 
        // Calculate angle bisector 
        var ang = d.startAngle + (d.endAngle - d.startAngle)/2; 
        // Transformate to SVG space 
        ang = (ang - (Math.PI/2)) * -1; 

        // Calculate a 10% radius displacement 
        var x = Math.cos(ang) * radius * 0.1; 
        var y = Math.sin(ang) * radius * -0.1; 

        d3.select(this).transition() 
        .duration(250).attr("transform", "translate("+x+","+y+")"); 
       } 
       }) 
      .on("mouseout", function(d){ 
       // Mouseout effect if no transition has started     
       if(this._listenToEvents){ 
       d3.select(this).transition() 
        .duration(150).attr("transform", "translate(0,0)"); 
       } 
      }); 


     // Collapse sectors for the exit selection 
     paths.exit().transition() 
     .duration(1000) 
     .attrTween("d", tweenOut).remove(); 

    // NEWLY ADDED START 

     // Select all <g> elements with class slice (there aren't any yet) 
     var arcs = svg.selectAll("g.slice") 
      // Associate the generated pie data (an array of arcs, each having startAngle, 
      // endAngle and value properties) 
      .data(pie) 
      // This will create <g> elements for every "extra" data element that should be associated 
      // with a selection. The result is creating a <g> for every object in the data array 
      .enter() 
      // Create a group to hold each slice (we will have a <path> and a <text> 
      // element associated with each slice) 
      .append("svg:g") 
      .attr("class", "slice"); //allow us to style things in the slices (like text) 

     arcs.append("svg:path") 
      //set the color for each slice to be chosen from the color function defined above 
      .attr("fill", function(d, i) { return color(i); }) 
      //this creates the actual SVG path using the associated data (pie) with the arc drawing function 
      .attr("d", arc); 

     // Add a legendLabel to each arc slice... 
     arcs.append("svg:text") 
      .attr("transform", function(d) { //set the label's origin to the center of the arc 
      //we have to make sure to set these before calling arc.centroid 
      d.outerRadius = outerRadius + 50; // Set Outer Coordinate 
      d.innerRadius = outerRadius + 45; // Set Inner Coordinate 
      return "translate(" + arc.centroid(d) + ")"; 
      }) 
      .attr("text-anchor", "middle") //center the text on it's origin 
      .style("fill", "Purple") 
      .style("font", "bold 12px Arial") 
      <!-- .text(function(d, i) { return dataSet[i].legendLabel; }); //get the label from our original dat --> 
      .text(function(d, i) { return "Test"; }); //get the label from our original dat 

     // Add a magnitude value to the larger arcs, translated to the arc centroid and rotated. 
      arcs.filter(function(d) { return d.endAngle - d.startAngle > .2; }).append("svg:text") 
      .attr("dy", ".35em") 
      .attr("text-anchor", "middle") 
      //.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; }) 
      .attr("transform", function(d) { //set the label's origin to the center of the arc 
       //we have to make sure to set these before calling arc.centroid 
       d.outerRadius = outerRadius; // Set Outer Coordinate 
       d.innerRadius = outerRadius/2; // Set Inner Coordinate 
       return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; 
      }) 
      .style("fill", "White") 
      .style("font", "bold 12px Arial") 
      .text(function(d) { return d.data.magnitude; }); 

     function angle(d) { 
      var a = (d.startAngle + d.endAngle) * 90/Math.PI - 90; 
      return a > 90 ? a - 180 : a; 
      } 
      // END 
    } 


    // "Fold" pie sectors by tweening its current start/end angles 
    // into 2*PI 
    function tweenOut(data) { 
     data.startAngle = data.endAngle = (2 * Math.PI);  
     var interpolation = d3.interpolate(this._current, data); 
     this._current = interpolation(0); 
     return function(t) { 
      return arc(interpolation(t)); 
     }; 
    } 


    // "Unfold" pie sectors by tweening its start/end angles 
    // from 0 into their final calculated values 
    function tweenIn(data) { 
     var interpolation = d3.interpolate({startAngle: 0, endAngle: 0}, data); 
     this._current = interpolation(0); 
     return function(t) { 
      return arc(interpolation(t)); 
     }; 
    } 


    // Helper function to extract color from data object 
    function getColor(data, index){ 
     return data.color; 
    } 


    // Helper function to extract a darker version of the color 
    function getDarkerColor(data, index){ 
     return d3.rgb(getColor(data, index)).darker(); 
    } 


    function findChildenByCat(cat){  
     for(i=-1; i++ < data.length - 1;){ 
     if(data[i].cat == cat){ 
      return data[i].children; 
     } 
     } 
     return data; 
    } 
    //.text(function(d, i) { return categorydata[i].label; }); 
    // Start by updating graph at root level 
    updateGraph(); 

    </script> 
    <!-- <p>Drill down pie chart test by Marc Baiges Camprubí <a href="mailto:[email protected]">([email protected])</a> in D3.js --> 
    </body> 
</html> 

回答

0

而不是做这个的:

var arcs = svg.selectAll("g.slice") 

做到这一点

var arcs = arcGroup.selectAll("g.slice") 

原因使得文本标签和馅饼的路径都是在同一组。

给予适当的内,外半径为放置在中心的标签(从而使质心的圆弧的新的内层外半径的基础上计算)

arcs.append("svg:text") 
      .attr("transform", function(d) { //set the label's origin to the center of the arc 
      //we have to make sure to set these before calling arc.centroid 
      d.outerRadius = radius - 20; // Set Outer Coordinate 
      d.innerRadius = radius - 100; // Set Inner Coordinate 
      return "translate(" + arc.centroid(d) + ")"; 
      }) 

接着给予适当的数据在文本:

 .text(function(d, i) { return "Test"; }); //get the label from our original data 

做到这一点

 .text(function(d, i) { return d.data.cat; }); //get the label from our original data 

工作代码here

+0

非常好!非常感谢。 – Stella

+0

(2.)一旦我点击某个部分,就需要向下钻取视图。然后点击它回到初始视图,消失所有部分的文字。我正在检查解决这个问题。 – Stella

+0

我试图将我的dataSet - 文本放在饼图部分标签中。我试过“.text(function(d,i){return dataSet [i] .legendLabel;});” ,它将我的文本放置在“dataSet”数组的饼图部分。精细。我想根据我的意愿调整饼图的百分比大小。你能告诉我,在哪里我可以调整这个价值,让饼图部分大小? – Stella