94 lines
2.9 KiB
JavaScript
94 lines
2.9 KiB
JavaScript
|
/**
|
||
|
* An element which displays a donut chart of data.
|
||
|
*/
|
||
|
angular.module('quay').directive('donutChart', function () {
|
||
|
var directiveDefinitionObject = {
|
||
|
priority: 0,
|
||
|
templateUrl: '/static/directives/donut-chart.html',
|
||
|
replace: false,
|
||
|
transclude: false,
|
||
|
restrict: 'C',
|
||
|
scope: {
|
||
|
'width': '@width',
|
||
|
'minPercent': '@minPercent',
|
||
|
'data': '=data',
|
||
|
},
|
||
|
controller: function($scope, $element) {
|
||
|
$scope.created = false;
|
||
|
|
||
|
// Based on: http://bl.ocks.org/erichoco/6694616
|
||
|
var chart = d3.select($element.find('.donut-chart-element')[0]);
|
||
|
|
||
|
var renderChart = function() {
|
||
|
if (!$scope.data || !$scope.data.length) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Adjust the data to make sure each non-zero entry is at minimum. While technically
|
||
|
// not accurate, it will make the section visible to the user.
|
||
|
var adjustedData = []
|
||
|
var total = 0;
|
||
|
$scope.data.map(function(entry) {
|
||
|
total += entry.value;
|
||
|
});
|
||
|
|
||
|
adjustedData = $scope.data.map(function(entry) {
|
||
|
var value = entry.value;
|
||
|
if ($scope.minPercent) {
|
||
|
if (value / total < $scope.minPercent / 100) {
|
||
|
value = total * $scope.minPercent / 100;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var copy = $.extend({}, entry);
|
||
|
copy.value = value;
|
||
|
return copy;
|
||
|
});
|
||
|
|
||
|
|
||
|
var $chart = $element.find('.donut-chart-element');
|
||
|
$chart.empty();
|
||
|
|
||
|
var width = $scope.width * 1;
|
||
|
var chart_m = width / 2 * 0.14;
|
||
|
var chart_r = width / 2 * 0.85;
|
||
|
|
||
|
var topG = chart.append('svg:svg')
|
||
|
.attr('width', (chart_r + chart_m) * 2)
|
||
|
.attr('height', (chart_r + chart_m) * 2)
|
||
|
.append('svg:g')
|
||
|
.attr('class', 'donut')
|
||
|
.attr('transform', 'translate(' + (chart_r + chart_m) + ',' +
|
||
|
(chart_r + chart_m) + ')');
|
||
|
|
||
|
|
||
|
var arc = d3.svg.arc()
|
||
|
.innerRadius(chart_r * 0.6)
|
||
|
.outerRadius(function(d, i) {
|
||
|
return i == adjustedData.length - 1 ? chart_r * 1.2 : chart_r * 1;
|
||
|
});
|
||
|
|
||
|
var pie = d3.layout.pie()
|
||
|
.sort(null)
|
||
|
.value(function(d) {
|
||
|
return d.value;
|
||
|
});
|
||
|
|
||
|
var reversed = adjustedData.reverse();
|
||
|
var g = topG.selectAll(".arc")
|
||
|
.data(pie(reversed))
|
||
|
.enter().append("g")
|
||
|
.attr("class", "arc");
|
||
|
|
||
|
g.append("path")
|
||
|
.attr("d", arc)
|
||
|
.style('stroke', '#fff')
|
||
|
.style("fill", function(d) { return d.data.color; });
|
||
|
|
||
|
};
|
||
|
|
||
|
$scope.$watch('data', renderChart);
|
||
|
}
|
||
|
};
|
||
|
return directiveDefinitionObject;
|
||
|
});
|