截面文本标签未显示在D3.JS深入饼图

时间:2016-04-10 07:21:56

标签: javascript d3.js pie-chart

我想开发"向下钻取" "饼图"使用" 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

  3. 基于上面用于在饼图部分放置文本标签的示例,我按照下面的代码,我尝试添加样本" var dataSet"," var arcs = svg.selectAll(&# 34; g.slice&#34)"码。 但是,当我执行程序时,它不会在饼图中的每个部分的中心显示任何文本标签。

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

        <!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>
    

1 个答案:

答案 0 :(得分:1)

而不是这样做:

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