6 //Cache a local reference to Chart.helpers
7 helpers = Chart.helpers;
10 //Boolean - Whether we should show a stroke on each segment
11 segmentShowStroke : true,
13 //String - The colour of each segment stroke
14 segmentStrokeColor : "#fff",
16 //Number - The width of each segment stroke
17 segmentStrokeWidth : 2,
19 //The percentage of the chart that we cut out of the middle.
20 percentageInnerCutout : 50,
22 //Number - Amount of animation steps
25 //String - Animation easing effect
26 animationEasing : "easeOutBounce",
28 //Boolean - Whether we animate the rotation of the Doughnut
31 //Boolean - Whether we animate scaling the Doughnut from the centre
34 //String - A legend template
35 legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>"
40 //Passing in a name registers this chart in the Chart namespace
42 //Providing a defaults will also register the deafults in the chart namespace
43 defaults : defaultConfig,
44 //Initialize is fired when the chart is initialized - Data is passed in as a parameter
45 //Config is automatically merged by the core of Chart.js, and is available at this.options
46 initialize: function(data){
48 //Declare segments as a static property to prevent inheriting across the Chart type prototype
50 this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
52 this.SegmentArc = Chart.Arc.extend({
54 x : this.chart.width/2,
55 y : this.chart.height/2
58 //Set up tooltip events on the chart
59 if (this.options.showTooltips){
60 helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
61 var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
63 helpers.each(this.segments,function(segment){
64 segment.restore(["fillColor"]);
66 helpers.each(activeSegments,function(activeSegment){
67 activeSegment.fillColor = activeSegment.highlightColor;
69 this.showTooltip(activeSegments);
72 this.calculateTotal(data);
74 helpers.each(data,function(datapoint, index){
75 if (!datapoint.color) {
76 datapoint.color = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
78 this.addData(datapoint, index, true);
83 getSegmentsAtEvent : function(e){
84 var segmentsArray = [];
86 var location = helpers.getRelativePosition(e);
88 helpers.each(this.segments,function(segment){
89 if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
93 addData : function(segment, atIndex, silent){
94 var index = atIndex || this.segments.length;
95 this.segments.splice(index, 0, new this.SegmentArc({
96 value : segment.value,
97 outerRadius : (this.options.animateScale) ? 0 : this.outerRadius,
98 innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout,
99 fillColor : segment.color,
100 highlightColor : segment.highlight || segment.color,
101 showStroke : this.options.segmentShowStroke,
102 strokeWidth : this.options.segmentStrokeWidth,
103 strokeColor : this.options.segmentStrokeColor,
104 startAngle : Math.PI * 1.5,
105 circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
106 label : segment.label
113 calculateCircumference : function(value) {
114 if ( this.total > 0 ) {
115 return (Math.PI*2)*(value / this.total);
120 calculateTotal : function(data){
122 helpers.each(data,function(segment){
123 this.total += Math.abs(segment.value);
127 this.calculateTotal(this.segments);
129 // Reset any highlight colours before updating.
130 helpers.each(this.activeElements, function(activeElement){
131 activeElement.restore(['fillColor']);
134 helpers.each(this.segments,function(segment){
140 removeData: function(atIndex){
141 var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
142 this.segments.splice(indexToDelete, 1);
148 helpers.extend(this.SegmentArc.prototype,{
149 x : this.chart.width/2,
150 y : this.chart.height/2
152 this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
153 helpers.each(this.segments, function(segment){
155 outerRadius : this.outerRadius,
156 innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
160 draw : function(easeDecimal){
161 var animDecimal = (easeDecimal) ? easeDecimal : 1;
163 helpers.each(this.segments,function(segment,index){
165 circumference : this.calculateCircumference(segment.value),
166 outerRadius : this.outerRadius,
167 innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
170 segment.endAngle = segment.startAngle + segment.circumference;
174 segment.startAngle = Math.PI * 1.5;
176 //Check to see if it's the last segment, if not get the next and update the start angle
177 if (index < this.segments.length-1){
178 this.segments[index+1].startAngle = segment.endAngle;
185 Chart.types.Doughnut.extend({
187 defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0})