Pie Chart With Color
HTML
<h1>Pie Chart rendered with HTML5 Canvas</h1>
<p>The data controls are meant to simulate a "live" data set, which could just as easily be delivered via WebSockets, or some other mechanism.</p>
<div ng-app="pieChartApp" ng-controller="PieCtrl">
<div ng-repeat="obj in data">
<input type="color" ng-model="obj.hex"/>
<strong><label for="obj.label" title="Increment speed for {{obj.label}}">{{obj.label}}</label></strong>
<input title="Adjust the control to change the increment speed for the associated sentiment" type="range" min="1" max="5" ng-model="obj.incrementInterval" ng-init="obj.incrementInterval = 1" id="{{obj.label}}"/>
= {{obj.incrementInterval}}
</div>
<pre>data: {{data | json}}</pre>
<canvas id="canvas" width="420" height="420"></canvas>
<!-- These controls are just to indicate a fallback alternative -->
<label class="clearfix">Rendering using <em>{{PIE.getTimeoutType()}}</em> </label>
<button ng-click="PIE.toggleTimeoutType()">Switch to {{PIE.getAltTimeoutType()}}</button>
<label ng-hide="PIE.getTimeoutType() == 'requestAnimationFrame'"> setTimeout delay = </label>
<input ng-hide="PIE.getTimeoutType() == 'requestAnimationFrame'" type="range" min="1" max="5" ng-model="PIE.delay"/>
</div>
CSS
pre {float:right;}
canvas {float:right;}
.clearfix {display:none; clear:both;}
JavaScript
var pieChartApp = angular.module('pieChartApp', [])
.value("π", Math.PI)
.controller('PieCtrl', function($scope, increment, PIE) {
$scope.data = [
{val:10, label: "Positive", hex: "#88bb88"},
{val:30, label: "Negative", hex: "#C02942"},
{val:20, label: "Neutral", hex: "#CFD803"},
{val:60, label: "Mixed", hex: "#999999"}
];
angular.forEach($scope.data, function(value, key) {
increment.init(value);
});
$scope.PIE = PIE;
PIE.configure({
canvas: document.getElementById("canvas"),
data: $scope.data,
continuous: true
}).render();
})
.factory('PIE', function(π, $timeout){
var canvas, myData, continuous = false, raf = true, st = false, timeoutType = "requestAnimationFrame", altTimeoutType = "setTimeout",
that = {};
function configure(obj) {
canvas = obj.canvas;
myData = obj.data;
continuous = obj.continuous ? obj.continuous : false;
return that;
};
function clear() {
canvas.width = canvas.width;
return that;
}
function render() {
plotData();
return that;
}
function getTotal(){
var myTotal = 0;
for (var j = 0; j < myData.length; j++) {
myTotal += (typeof myData[j].val == 'number') ? myData[j].val : 0;
}
return myTotal;
}
function centroid(radius, angle, lastend, offset) {
var r = radius * 0.7,
a = (angle + lastend) / 2 + offset;
return [ Math.cos(a) * r, Math.sin(a) * r ];
}
function plotData() {
var ctx, lastend = 0, angle = 0, myTotal = getTotal(), radius = 150, percentageLocation;
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < myData.length; i++) {
angle = lastend+(π*2*(myData[i].val/myTotal));
// The arc segments rendering instructions
...