6 helpers = Chart.helpers;
10 //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
11 scaleBeginAtZero : true,
13 //Boolean - Whether grid lines are shown across the chart
14 scaleShowGridLines : true,
16 //String - Colour of the grid lines
17 scaleGridLineColor : "rgba(0,0,0,.05)",
19 //Number - Width of the grid lines
20 scaleGridLineWidth : 1,
22 //Boolean - Whether to show horizontal lines (except X axis)
23 scaleShowHorizontalLines: true,
25 //Boolean - Whether to show vertical lines (except Y axis)
26 scaleShowVerticalLines: true,
28 //Boolean - If there is a stroke on each bar
31 //Number - Pixel width of the bar stroke
34 //Number - Spacing between each of the X value sets
37 //Number - Spacing between data sets within X values
38 barDatasetSpacing : 1,
40 //String - A legend template
41 legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>"
48 defaults : defaultConfig,
49 initialize: function(data){
51 //Expose options as a scope variable here so we can access it in the ScaleClass
52 var options = this.options;
54 this.ScaleClass = Chart.Scale.extend({
55 offsetGridLines : true,
56 calculateBarX : function(datasetCount, datasetIndex, barIndex){
57 //Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
58 var xWidth = this.calculateBaseWidth(),
59 xAbsolute = this.calculateX(barIndex) - (xWidth/2),
60 barWidth = this.calculateBarWidth(datasetCount);
62 return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
64 calculateBaseWidth : function(){
65 return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
67 calculateBarWidth : function(datasetCount){
68 //The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
69 var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
71 return (baseWidth / datasetCount);
77 //Set up tooltip events on the chart
78 if (this.options.showTooltips){
79 helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
80 var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
82 this.eachBars(function(bar){
83 bar.restore(['fillColor', 'strokeColor']);
85 helpers.each(activeBars, function(activeBar){
86 activeBar.fillColor = activeBar.highlightFill;
87 activeBar.strokeColor = activeBar.highlightStroke;
89 this.showTooltip(activeBars);
93 //Declare the extension of the default point, to cater for the options passed in to the constructor
94 this.BarClass = Chart.Rectangle.extend({
95 strokeWidth : this.options.barStrokeWidth,
96 showStroke : this.options.barShowStroke,
100 //Iterate through each of the datasets, and build this into a property of the chart
101 helpers.each(data.datasets,function(dataset,datasetIndex){
103 var datasetObject = {
104 label : dataset.label || null,
105 fillColor : dataset.fillColor,
106 strokeColor : dataset.strokeColor,
110 this.datasets.push(datasetObject);
112 helpers.each(dataset.data,function(dataPoint,index){
113 //Add a new point for each piece of data, passing any required data to draw.
114 datasetObject.bars.push(new this.BarClass({
116 label : data.labels[index],
117 datasetLabel: dataset.label,
118 strokeColor : dataset.strokeColor,
119 fillColor : dataset.fillColor,
120 highlightFill : dataset.highlightFill || dataset.fillColor,
121 highlightStroke : dataset.highlightStroke || dataset.strokeColor
127 this.buildScale(data.labels);
129 this.BarClass.prototype.base = this.scale.endPoint;
131 this.eachBars(function(bar, index, datasetIndex){
132 helpers.extend(bar, {
133 width : this.scale.calculateBarWidth(this.datasets.length),
134 x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
135 y: this.scale.endPoint
144 // Reset any highlight colours before updating.
145 helpers.each(this.activeElements, function(activeElement){
146 activeElement.restore(['fillColor', 'strokeColor']);
149 this.eachBars(function(bar){
154 eachBars : function(callback){
155 helpers.each(this.datasets,function(dataset, datasetIndex){
156 helpers.each(dataset.bars, callback, this, datasetIndex);
159 getBarsAtEvent : function(e){
161 eventPosition = helpers.getRelativePosition(e),
162 datasetIterator = function(dataset){
163 barsArray.push(dataset.bars[barIndex]);
167 for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
168 for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
169 if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){
170 helpers.each(this.datasets, datasetIterator);
178 buildScale : function(labels){
181 var dataTotal = function(){
183 self.eachBars(function(bar){
184 values.push(bar.value);
190 templateString : this.options.scaleLabel,
191 height : this.chart.height,
192 width : this.chart.width,
193 ctx : this.chart.ctx,
194 textColor : this.options.scaleFontColor,
195 fontSize : this.options.scaleFontSize,
196 fontStyle : this.options.scaleFontStyle,
197 fontFamily : this.options.scaleFontFamily,
198 valuesCount : labels.length,
199 beginAtZero : this.options.scaleBeginAtZero,
200 integersOnly : this.options.scaleIntegersOnly,
201 calculateYRange: function(currentHeight){
202 var updatedRanges = helpers.calculateScaleRange(
209 helpers.extend(this, updatedRanges);
212 font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
213 lineWidth : this.options.scaleLineWidth,
214 lineColor : this.options.scaleLineColor,
215 showHorizontalLines : this.options.scaleShowHorizontalLines,
216 showVerticalLines : this.options.scaleShowVerticalLines,
217 gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
218 gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
219 padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
220 showLabels : this.options.scaleShowLabels,
221 display : this.options.showScale
224 if (this.options.scaleOverride){
225 helpers.extend(scaleOptions, {
226 calculateYRange: helpers.noop,
227 steps: this.options.scaleSteps,
228 stepValue: this.options.scaleStepWidth,
229 min: this.options.scaleStartValue,
230 max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
234 this.scale = new this.ScaleClass(scaleOptions);
236 addData : function(valuesArray,label){
237 //Map the values array for each of the datasets
238 helpers.each(valuesArray,function(value,datasetIndex){
239 //Add a new point for each piece of data, passing any required data to draw.
240 this.datasets[datasetIndex].bars.push(new this.BarClass({
243 datasetLabel: this.datasets[datasetIndex].label,
244 x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
245 y: this.scale.endPoint,
246 width : this.scale.calculateBarWidth(this.datasets.length),
247 base : this.scale.endPoint,
248 strokeColor : this.datasets[datasetIndex].strokeColor,
249 fillColor : this.datasets[datasetIndex].fillColor
253 this.scale.addXLabel(label);
254 //Then re-render the chart.
257 removeData : function(){
258 this.scale.removeXLabel();
259 //Then re-render the chart.
260 helpers.each(this.datasets,function(dataset){
261 dataset.bars.shift();
266 helpers.extend(this.BarClass.prototype,{
267 y: this.scale.endPoint,
268 base : this.scale.endPoint
270 var newScaleProps = helpers.extend({
271 height : this.chart.height,
272 width : this.chart.width
274 this.scale.update(newScaleProps);
276 draw : function(ease){
277 var easingDecimal = ease || 1;
280 var ctx = this.chart.ctx;
282 this.scale.draw(easingDecimal);
284 //Draw all the bars for each dataset
285 helpers.each(this.datasets,function(dataset,datasetIndex){
286 helpers.each(dataset.bars,function(bar,index){
288 bar.base = this.scale.endPoint;
289 //Transition then draw
291 x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
292 y : this.scale.calculateY(bar.value),
293 width : this.scale.calculateBarWidth(this.datasets.length)
294 }, easingDecimal).draw();