章节文本标签没有't显示在D3.JS向下钻取饼图中

Section Text label doesn't display in D3.JS drill down pie chart

本文关键字:JS D3 钻取 显示 文本标签      更新时间:2024-03-29

我想使用"D3.JS"开发"向下钻取"饼图"。我找到了下面的示例,非常适合我使用。

D3 Js样本钻取饼图

上面的样品非常适合我。

此外,在示例的向下钻取饼图中,我希望将TEXT LABEL放置在饼图的每个分割部分中。

我跟踪了很多样品,

  1. 示例1-带有部分文本标签的饼图

  2. 示例2-带有部分文本标签的JSFiddle饼图

基于上面在饼图部分放置文本标签的示例,我遵循了下面的代码,我尝试添加示例"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:marcbc@gmail.com">(marcbc@gmail.com)</a> in D3.js -->
  </body>
</html>

不要这样做:

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

此处的工作代码