Pie Chart Labels with D3.js and AngularJS

时间:2021-06-17 15:17:57

I'm new to D3. Trying to show "outside" labels with lines, in D3, similar to Bostock's pie chart here http://bl.ocks.org/dbuezas/9306799 I can't get the labels or lines to show up like Bostock's pie. The pie is working well though! Any help with my code, mainly the directive, would be appreciated!

我是D3的新手。试图在D3中显示带有线条的“外部”标签,类似于Bostock的饼图http://bl.ocks.org/dbuezas/9306799我无法获得像Bostock馅饼那样的标签或线条。馅饼虽然运作良好!任何有关我的代码的帮助,主要是指令,将不胜感激!

HTML:

<div ng-controller="myControl">
   <d3-pie-dir data="d3Data"></d3-pie-dir>
</div>

CSS:

path.slice{
   stroke-width:2px;
}

polyline{
  opacity: .3;
  stroke: black;
  stroke-width: 2px;
  fill: none;
}

Controller:

inAng.controller('myControl', function ( $scope, $http ) {
  var stack = [];
$http.get("/getAPIData").
    success(function (data, status, headers, config) {

     // formatting for easier D3 consumption
      for(var i in data)
        stack.push(data [i]);

    $scope.d3Data = stack;  
    // looks something like $scope.d3Data = [{ name: 'Bill', score: 25}, { name: 'Pete', score: 50}]
    }).
    error(function (data, status, headers, config) {
      $scope.stack = 'Error!';
    });

});

And the problem is in the directive:

问题出在指令中:

inAng.directive('d3PieDir', function () {
    return {
        restrict: 'E',
        scope: {
            data: '='
        },
        link: function (scope, element, attrs) {
            scope.$watch('data', function(values) {
                if(values) { 
                    console.log('values from directive: ', values);                 

                    var width = 960,
                    height = 500,
                    radius = Math.min(width, height) / 2;

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

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

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

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


                        values.forEach(function(d) {
                            d.score = +d.score;
                        });

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

                        g.append("path")
                            .attr("d", arc)
                            .style("fill", function(d) { return color(d.data.name); });

// **** Below is where it stops working! ****

var key = function(d){ return d.data.name; };                           


/* ------- PIE SLICES -------*/
var slice = svg.select(".slices").selectAll("path.slice")
    .data(pie(values), key);

slice.enter()
    .insert("path")
    .style("fill", function(d) { return color(d.data.name); })
    .attr("class", "slice");

slice       
    .transition().duration(1000)
    .attrTween("d", function(d) {
        this._current = this._current || d;
        var interpolate = d3.interpolate(this._current, d);
        this._current = interpolate(0);
        return function(t) {
            return arc(interpolate(t));
        };
    })

slice.exit()
    .remove();

/* ------- TEXT LABELS -------*/

var text = svg.select(".labels").selectAll("text")
    .data(pie(values), key);

text.enter()
    .append("text")
    .attr("dy", ".35em")
    .text(function(d) {
        return d.data.name;
    });

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

text.transition().duration(1000)
    .attrTween("transform", function(d) {
        this._current = this._current || d;
        var interpolate = d3.interpolate(this._current, d);
        this._current = interpolate(0);
        return function(t) {
            var d2 = interpolate(t);
            var pos = outerArc.centroid(d2);
            pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
            return "translate("+ pos +")";
        };
    })
    .styleTween("text-anchor", function(d){
        this._current = this._current || d;
        var interpolate = d3.interpolate(this._current, d);
        this._current = interpolate(0);
        return function(t) {
            var d2 = interpolate(t);
            return midAngle(d2) < Math.PI ? "start":"end";
        };
    });

text.exit()
    .remove();

/* ------- SLICE TO TEXT POLYLINES -------*/

var polyline = svg.select(".lines").selectAll("polyline")
    .data(pie(values), key);

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

polyline.transition().duration(1000)
    .attrTween("points", function(d){
        this._current = this._current || d;
        var interpolate = d3.interpolate(this._current, d);
        this._current = interpolate(0);
        return function(t) {
            var d2 = interpolate(t);
            var pos = outerArc.centroid(d2);
            pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
            return [arc.centroid(d2), outerArc.centroid(d2), pos];
        };          
    });

polyline.exit()
    .remove();

                }
            })}

}});

1 个解决方案

#1


1  

You have two problems the first one is that you forgot to append these elements to your svg

你有两个问题,第一个是你忘了将这些元素附加到你的svg

svg.append("g")
    .attr("class", "slices");
svg.append("g")
    .attr("class", "labels");
svg.append("g")
    .attr("class", "lines");

these are the g elements that d3 draws lines and labels on , so you need to put them after

这些是d3绘制线条和标签的g元素,因此您需要将它们放在后面

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

,, the second issue is that you forgot to define outer arc ,,

,,第二个问题是你忘了定义外弧,

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

which you use in your calculation for creating lines

您在计算中用于创建线条

#1


1  

You have two problems the first one is that you forgot to append these elements to your svg

你有两个问题,第一个是你忘了将这些元素附加到你的svg

svg.append("g")
    .attr("class", "slices");
svg.append("g")
    .attr("class", "labels");
svg.append("g")
    .attr("class", "lines");

these are the g elements that d3 draws lines and labels on , so you need to put them after

这些是d3绘制线条和标签的g元素,因此您需要将它们放在后面

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

,, the second issue is that you forgot to define outer arc ,,

,,第二个问题是你忘了定义外弧,

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

which you use in your calculation for creating lines

您在计算中用于创建线条