D3 - Polylines from label to arc in Donut or Pie Chart

时间秒杀一切 提交于 2019-12-12 04:28:23

问题


I am making a simple donut chart. I am providing data and generating the donut as expected. Also, labels to the same are added at a distant. Now, I want to add lines right from labels to the center of arc. However, I am not getting any error and also I am not seeing any line. Pls help!

SNIPPET:

     //module declaration 
            var app = angular.module('myApp',[]);

            //Controller declaration
            app.controller('myCtrl',function($scope){

            $scope.svgWidth = 800; //svg Width
            $scope.svgHeight = 500; //svg Height 

            //Data in proper format 
            var data = [{  
            "letter": "A",
              "frequency": "60"
            }, {
              "letter": "B",
              "frequency": "30"
            }, {
              "letter": "C",
              "frequency": "10"
            }];

            //removing prior svg elements ie clean up svg 
            d3.select('svg').selectAll("*").remove();

            //resetting svg height and width in current svg 
            d3.select("svg").attr("width", $scope.svgWidth).attr("height", $scope.svgHeight);

            //Setting up of our svg with proper calculations 
            var svg = d3.select("svg");
            var margin = {top: 20,right: 20,bottom: 30,left: 40};
            var width = svg.attr("width") - margin.left - margin.right;
            var height = svg.attr("height") - margin.top - margin.bottom;
            var radius = 200;

            //Plotting our base area in svg in which chart will be shown 
            var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

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

            var piedata = pie(data);

            var arc = d3.arc()
              .innerRadius(radius - 100)
              .outerRadius(radius - 50);

            var path = g.selectAll("path")
              .data(piedata)
              .enter().append("path")
              .attr("fill", function() {
                return "hsl(" + Math.random() * 360 + ",100%,50%)";
              })
              .attr("d", arc);

            g.selectAll("text").data(piedata)
              .enter()
              .append("text")
              .attr("text-anchor", "middle")
              .attr("x", function(d) {
                var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
                d.cx = Math.cos(a) * (radius - 75);
                return d.x = Math.cos(a) * (radius - 20);
              })
              .attr("y", function(d) {
                var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
                d.cy = Math.sin(a) * (radius - 75);
                return d.y = Math.sin(a) * (radius - 20);
              })
              .text(function(d) {
                return d.data.letter;
              });

              var polyline = g.select(".lines")
                      .selectAll("polyline")
                      .data(pie(data), function(d){ return d.data.letter });

              polyline.enter().append("polyline");



          });
    <head>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script> 
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script> 
        <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>

    </head> 

    <body ng-app="myApp" ng-controller="myCtrl"> 

        <svg></svg>
      </body>


       
            

REFERENCE:

http://bl.ocks.org/juan-cb/1984c7f2b446fffeedde


回答1:


Looking at your linked example, the author introduces a helper function to compute an angle off the arc and then uses a polyline to draw. Stealing their implementation and applying it to your chart looks like this:

<!DOCTYPE html>
<html>


<head>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>

</head>

<body ng-app="myApp" ng-controller="myCtrl">

  <svg></svg>


  <script>
    //module declaration 
    //var app = angular.module('myApp', []);

    //Controller declaration
    //app.controller('myCtrl', function($scope) {

    var $scope = {};

    $scope.svgWidth = 800; //svg Width
    $scope.svgHeight = 500; //svg Height 

    //Data in proper format 
    var data = [{
      "letter": "A",
      "frequency": "60"
    }, {
      "letter": "B",
      "frequency": "30"
    }, {
      "letter": "C",
      "frequency": "10"
    }];

    //removing prior svg elements ie clean up svg 
    d3.select('svg').selectAll("*").remove();

    //resetting svg height and width in current svg 
    d3.select("svg").attr("width", $scope.svgWidth).attr("height", $scope.svgHeight);

    //Setting up of our svg with proper calculations 
    var svg = d3.select("svg");
    var margin = {
      top: 20,
      right: 20,
      bottom: 30,
      left: 40
    };
    var width = svg.attr("width") - margin.left - margin.right;
    var height = svg.attr("height") - margin.top - margin.bottom;
    var radius = 200;

    //Plotting our base area in svg in which chart will be shown 
    var g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

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

    var piedata = pie(data);

    var arc = d3.arc()
      .innerRadius(radius - 100)
      .outerRadius(radius - 50);
      
    var outerArc = d3.arc()
	    .innerRadius(radius * 0.9)
	    .outerRadius(radius * 0.9);

    var path = g.selectAll("path")
      .data(piedata)
      .enter().append("path")
      .attr("fill", function() {
        return "hsl(" + Math.random() * 360 + ",100%,50%)";
      })
      .attr("d", arc);

    g.selectAll("text").data(piedata)
      .enter()
      .append("text")
      .attr("text-anchor", "middle")
      /*
      .attr("x", function(d) {
        var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
        d.cx = Math.cos(a) * (radius - 75);
        return d.x = Math.cos(a) * (radius - 20);
      })
      .attr("y", function(d) {
        var a = d.startAngle + (d.endAngle - d.startAngle) / 2 - Math.PI / 2;
        d.cy = Math.sin(a) * (radius - 75);
        return d.y = Math.sin(a) * (radius - 20);
      })
      */
      .attr("transform", function(d){
        var pos = outerArc.centroid(d);
        pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1);
        return "translate("+ pos +")";
      })
      .text(function(d) {
        return d.data.letter;
      });

    function midAngle(d) {
      return d.startAngle + (d.endAngle - d.startAngle) / 2;
    }

    var polyline = g.selectAll("polyline")
      .data(piedata, function(d) {
        return d.data.letter
      })
      .enter()
      .append("polyline")
      .attr("points", function(d) {
        var pos = outerArc.centroid(d);
            pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1);
            
        return [arc.centroid(d), outerArc.centroid(d), pos];
      })
      .style("fill", "none")
      .style("stroke", "black")
      .style("stroke-width", "2px");

    //});
  </script>
</body>

</html>


来源:https://stackoverflow.com/questions/41016249/d3-polylines-from-label-to-arc-in-donut-or-pie-chart

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!