/
donut-chart.directive.js
96 lines (88 loc) · 3.17 KB
/
donut-chart.directive.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
app.directive('donutChart', function() {
return {
scope: { // isolate scope
'data': '=',
'onClick': '&',
'accessor': '='
},
restrict: 'E',
link: link
};
function link(scope, element) {
// the d3 bits
console.log('scope.data', scope.data);
var color = d3.scale.category10();
var el = element[0];
var width = el.clientWidth;
var height = el.clientHeight;
var min = Math.min(width, height);
var accessor = scope.accessor || Number;
var pie = d3.layout.pie().sort(null).value(accessor);
var arc = d3.svg.arc()
.outerRadius(min / 2 * 0.9)
.innerRadius(min / 2 * 0.5);
var svg = d3.select(el).append('svg')
.attr({width: width, height: height})
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')');
svg.on('mousedown', function(d) {
// yo angular, the code in this callback might make a change to the scope!
// so be sure to apply $watch's and catch errors.
scope.$apply(function(){
if(scope.onClick) scope.onClick();
});
});
function arcTween(a) {
// see: http://bl.ocks.org/mbostock/1346410
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) {
return arc(i(t));
};
}
// add the <path>s for each arc slice
var arcs = svg.selectAll('path.arc').data(pie(scope.data))
.enter().append('path')
.attr('class', 'arc')
.style('stroke', 'white')
.attr('fill', function(d, i) { return color(i) })
// store the initial angles
.each(function(d) { return this._current = d });
// our data changed! update the arcs, adding, updating, or removing
// elements as needed
scope.$watch('data', function(newData, oldData){
console.log('data changed!');
var data = newData.slice(0); // copy
var duration = 500;
var PI = Math.PI;
while(data.length < oldData.length) data.push(0);
arcs = svg.selectAll('.arc').data(pie(data));
arcs.transition().duration(duration).attrTween('d', arcTween);
// transition in any new slices
arcs.enter().append('path')
.style('stroke', 'white')
.attr('class', 'arc')
.attr('fill', function(d, i){ return color(i) })
.each(function(d) {
this._current = { startAngle: 2 * PI - 0.001, endAngle: 2 * PI }
})
.transition().duration(duration).attrTween('d', arcTween);
// transition out any slices with size = 0
arcs.filter(function(d){ return d.data === 0 })
.transition()
.duration(duration)
.each(function(d){ d.startAngle = 2 * PI - 0.001; d.endAngle = 2 * PI; })
.attrTween('d', arcTween).remove();
// IMPORTANT! the third argument, `true`, tells angular to watch for
// changes to array elements.
}, true);
}
});
app.controller('MainController', function($scope){
// controller "knows" nothing about donut charts
$scope.shared = { data: [1] };
$scope.chartClicked = function(){
var n = Math.round(Math.random() * 9) + 1;
$scope.shared.data = d3.range(n).map(function(d){ return Math.random(); });
}
});