Project

General

Profile

1
(function(){
2
	"use strict";
3

    
4
	var root = this,
5
		Chart = root.Chart,
6
		//Cache a local reference to Chart.helpers
7
		helpers = Chart.helpers;
8

    
9
	var defaultConfig = {
10
		//Boolean - Show a backdrop to the scale label
11
		scaleShowLabelBackdrop : true,
12

    
13
		//String - The colour of the label backdrop
14
		scaleBackdropColor : "rgba(255,255,255,0.75)",
15

    
16
		// Boolean - Whether the scale should begin at zero
17
		scaleBeginAtZero : true,
18

    
19
		//Number - The backdrop padding above & below the label in pixels
20
		scaleBackdropPaddingY : 2,
21

    
22
		//Number - The backdrop padding to the side of the label in pixels
23
		scaleBackdropPaddingX : 2,
24

    
25
		//Boolean - Show line for each value in the scale
26
		scaleShowLine : true,
27

    
28
		//Boolean - Stroke a line around each segment in the chart
29
		segmentShowStroke : true,
30

    
31
		//String - The colour of the stroke on each segement.
32
		segmentStrokeColor : "#fff",
33

    
34
		//Number - The width of the stroke value in pixels
35
		segmentStrokeWidth : 2,
36

    
37
		//Number - Amount of animation steps
38
		animationSteps : 100,
39

    
40
		//String - Animation easing effect.
41
		animationEasing : "easeOutBounce",
42

    
43
		//Boolean - Whether to animate the rotation of the chart
44
		animateRotate : true,
45

    
46
		//Boolean - Whether to animate scaling the chart from the centre
47
		animateScale : false,
48

    
49
		//String - A legend template
50
		legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
51
	};
52

    
53

    
54
	Chart.Type.extend({
55
		//Passing in a name registers this chart in the Chart namespace
56
		name: "PolarArea",
57
		//Providing a defaults will also register the deafults in the chart namespace
58
		defaults : defaultConfig,
59
		//Initialize is fired when the chart is initialized - Data is passed in as a parameter
60
		//Config is automatically merged by the core of Chart.js, and is available at this.options
61
		initialize:  function(data){
62
			this.segments = [];
63
			//Declare segment class as a chart instance specific class, so it can share props for this instance
64
			this.SegmentArc = Chart.Arc.extend({
65
				showStroke : this.options.segmentShowStroke,
66
				strokeWidth : this.options.segmentStrokeWidth,
67
				strokeColor : this.options.segmentStrokeColor,
68
				ctx : this.chart.ctx,
69
				innerRadius : 0,
70
				x : this.chart.width/2,
71
				y : this.chart.height/2
72
			});
73
			this.scale = new Chart.RadialScale({
74
				display: this.options.showScale,
75
				fontStyle: this.options.scaleFontStyle,
76
				fontSize: this.options.scaleFontSize,
77
				fontFamily: this.options.scaleFontFamily,
78
				fontColor: this.options.scaleFontColor,
79
				showLabels: this.options.scaleShowLabels,
80
				showLabelBackdrop: this.options.scaleShowLabelBackdrop,
81
				backdropColor: this.options.scaleBackdropColor,
82
				backdropPaddingY : this.options.scaleBackdropPaddingY,
83
				backdropPaddingX: this.options.scaleBackdropPaddingX,
84
				lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
85
				lineColor: this.options.scaleLineColor,
86
				lineArc: true,
87
				width: this.chart.width,
88
				height: this.chart.height,
89
				xCenter: this.chart.width/2,
90
				yCenter: this.chart.height/2,
91
				ctx : this.chart.ctx,
92
				templateString: this.options.scaleLabel,
93
				valuesCount: data.length
94
			});
95

    
96
			this.updateScaleRange(data);
97

    
98
			this.scale.update();
99

    
100
			helpers.each(data,function(segment,index){
101
				this.addData(segment,index,true);
102
			},this);
103

    
104
			//Set up tooltip events on the chart
105
			if (this.options.showTooltips){
106
				helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
107
					var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
108
					helpers.each(this.segments,function(segment){
109
						segment.restore(["fillColor"]);
110
					});
111
					helpers.each(activeSegments,function(activeSegment){
112
						activeSegment.fillColor = activeSegment.highlightColor;
113
					});
114
					this.showTooltip(activeSegments);
115
				});
116
			}
117

    
118
			this.render();
119
		},
120
		getSegmentsAtEvent : function(e){
121
			var segmentsArray = [];
122

    
123
			var location = helpers.getRelativePosition(e);
124

    
125
			helpers.each(this.segments,function(segment){
126
				if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
127
			},this);
128
			return segmentsArray;
129
		},
130
		addData : function(segment, atIndex, silent){
131
			var index = atIndex || this.segments.length;
132

    
133
			this.segments.splice(index, 0, new this.SegmentArc({
134
				fillColor: segment.color,
135
				highlightColor: segment.highlight || segment.color,
136
				label: segment.label,
137
				value: segment.value,
138
				outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
139
				circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
140
				startAngle: Math.PI * 1.5
141
			}));
142
			if (!silent){
143
				this.reflow();
144
				this.update();
145
			}
146
		},
147
		removeData: function(atIndex){
148
			var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
149
			this.segments.splice(indexToDelete, 1);
150
			this.reflow();
151
			this.update();
152
		},
153
		calculateTotal: function(data){
154
			this.total = 0;
155
			helpers.each(data,function(segment){
156
				this.total += segment.value;
157
			},this);
158
			this.scale.valuesCount = this.segments.length;
159
		},
160
		updateScaleRange: function(datapoints){
161
			var valuesArray = [];
162
			helpers.each(datapoints,function(segment){
163
				valuesArray.push(segment.value);
164
			});
165

    
166
			var scaleSizes = (this.options.scaleOverride) ?
167
				{
168
					steps: this.options.scaleSteps,
169
					stepValue: this.options.scaleStepWidth,
170
					min: this.options.scaleStartValue,
171
					max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
172
				} :
173
				helpers.calculateScaleRange(
174
					valuesArray,
175
					helpers.min([this.chart.width, this.chart.height])/2,
176
					this.options.scaleFontSize,
177
					this.options.scaleBeginAtZero,
178
					this.options.scaleIntegersOnly
179
				);
180

    
181
			helpers.extend(
182
				this.scale,
183
				scaleSizes,
184
				{
185
					size: helpers.min([this.chart.width, this.chart.height]),
186
					xCenter: this.chart.width/2,
187
					yCenter: this.chart.height/2
188
				}
189
			);
190

    
191
		},
192
		update : function(){
193
			this.calculateTotal(this.segments);
194

    
195
			helpers.each(this.segments,function(segment){
196
				segment.save();
197
			});
198
			
199
			this.reflow();
200
			this.render();
201
		},
202
		reflow : function(){
203
			helpers.extend(this.SegmentArc.prototype,{
204
				x : this.chart.width/2,
205
				y : this.chart.height/2
206
			});
207
			this.updateScaleRange(this.segments);
208
			this.scale.update();
209

    
210
			helpers.extend(this.scale,{
211
				xCenter: this.chart.width/2,
212
				yCenter: this.chart.height/2
213
			});
214

    
215
			helpers.each(this.segments, function(segment){
216
				segment.update({
217
					outerRadius : this.scale.calculateCenterOffset(segment.value)
218
				});
219
			}, this);
220

    
221
		},
222
		draw : function(ease){
223
			var easingDecimal = ease || 1;
224
			//Clear & draw the canvas
225
			this.clear();
226
			helpers.each(this.segments,function(segment, index){
227
				segment.transition({
228
					circumference : this.scale.getCircumference(),
229
					outerRadius : this.scale.calculateCenterOffset(segment.value)
230
				},easingDecimal);
231

    
232
				segment.endAngle = segment.startAngle + segment.circumference;
233

    
234
				// If we've removed the first segment we need to set the first one to
235
				// start at the top.
236
				if (index === 0){
237
					segment.startAngle = Math.PI * 1.5;
238
				}
239

    
240
				//Check to see if it's the last segment, if not get the next and update the start angle
241
				if (index < this.segments.length - 1){
242
					this.segments[index+1].startAngle = segment.endAngle;
243
				}
244
				segment.draw();
245
			}, this);
246
			this.scale.draw();
247
		}
248
	});
249

    
250
}).call(this);
(5-5/6)