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
...