mirror of
https://github.com/JonnyBro/JaBa.git
synced 2024-11-26 15:14:59 +05:00
303 lines
9.5 KiB
JavaScript
303 lines
9.5 KiB
JavaScript
|
(function(){
|
||
|
"use strict";
|
||
|
|
||
|
var root = this,
|
||
|
Chart = root.Chart,
|
||
|
helpers = Chart.helpers;
|
||
|
|
||
|
|
||
|
var defaultConfig = {
|
||
|
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
|
||
|
scaleBeginAtZero : true,
|
||
|
|
||
|
//Boolean - Whether grid lines are shown across the chart
|
||
|
scaleShowGridLines : true,
|
||
|
|
||
|
//String - Colour of the grid lines
|
||
|
scaleGridLineColor : "rgba(0,0,0,.05)",
|
||
|
|
||
|
//Number - Width of the grid lines
|
||
|
scaleGridLineWidth : 1,
|
||
|
|
||
|
//Boolean - Whether to show horizontal lines (except X axis)
|
||
|
scaleShowHorizontalLines: true,
|
||
|
|
||
|
//Boolean - Whether to show vertical lines (except Y axis)
|
||
|
scaleShowVerticalLines: true,
|
||
|
|
||
|
//Boolean - If there is a stroke on each bar
|
||
|
barShowStroke : true,
|
||
|
|
||
|
//Number - Pixel width of the bar stroke
|
||
|
barStrokeWidth : 2,
|
||
|
|
||
|
//Number - Spacing between each of the X value sets
|
||
|
barValueSpacing : 5,
|
||
|
|
||
|
//Number - Spacing between data sets within X values
|
||
|
barDatasetSpacing : 1,
|
||
|
|
||
|
//String - A legend template
|
||
|
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
Chart.Type.extend({
|
||
|
name: "Bar",
|
||
|
defaults : defaultConfig,
|
||
|
initialize: function(data){
|
||
|
|
||
|
//Expose options as a scope variable here so we can access it in the ScaleClass
|
||
|
var options = this.options;
|
||
|
|
||
|
this.ScaleClass = Chart.Scale.extend({
|
||
|
offsetGridLines : true,
|
||
|
calculateBarX : function(datasetCount, datasetIndex, barIndex){
|
||
|
//Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
|
||
|
var xWidth = this.calculateBaseWidth(),
|
||
|
xAbsolute = this.calculateX(barIndex) - (xWidth/2),
|
||
|
barWidth = this.calculateBarWidth(datasetCount);
|
||
|
|
||
|
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
|
||
|
},
|
||
|
calculateBaseWidth : function(){
|
||
|
return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
|
||
|
},
|
||
|
calculateBarWidth : function(datasetCount){
|
||
|
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
|
||
|
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
|
||
|
|
||
|
return (baseWidth / datasetCount);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.datasets = [];
|
||
|
|
||
|
//Set up tooltip events on the chart
|
||
|
if (this.options.showTooltips){
|
||
|
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
|
||
|
var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
|
||
|
|
||
|
this.eachBars(function(bar){
|
||
|
bar.restore(['fillColor', 'strokeColor']);
|
||
|
});
|
||
|
helpers.each(activeBars, function(activeBar){
|
||
|
activeBar.fillColor = activeBar.highlightFill;
|
||
|
activeBar.strokeColor = activeBar.highlightStroke;
|
||
|
});
|
||
|
this.showTooltip(activeBars);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
//Declare the extension of the default point, to cater for the options passed in to the constructor
|
||
|
this.BarClass = Chart.Rectangle.extend({
|
||
|
strokeWidth : this.options.barStrokeWidth,
|
||
|
showStroke : this.options.barShowStroke,
|
||
|
ctx : this.chart.ctx
|
||
|
});
|
||
|
|
||
|
//Iterate through each of the datasets, and build this into a property of the chart
|
||
|
helpers.each(data.datasets,function(dataset,datasetIndex){
|
||
|
|
||
|
var datasetObject = {
|
||
|
label : dataset.label || null,
|
||
|
fillColor : dataset.fillColor,
|
||
|
strokeColor : dataset.strokeColor,
|
||
|
bars : []
|
||
|
};
|
||
|
|
||
|
this.datasets.push(datasetObject);
|
||
|
|
||
|
helpers.each(dataset.data,function(dataPoint,index){
|
||
|
//Add a new point for each piece of data, passing any required data to draw.
|
||
|
datasetObject.bars.push(new this.BarClass({
|
||
|
value : dataPoint,
|
||
|
label : data.labels[index],
|
||
|
datasetLabel: dataset.label,
|
||
|
strokeColor : dataset.strokeColor,
|
||
|
fillColor : dataset.fillColor,
|
||
|
highlightFill : dataset.highlightFill || dataset.fillColor,
|
||
|
highlightStroke : dataset.highlightStroke || dataset.strokeColor
|
||
|
}));
|
||
|
},this);
|
||
|
|
||
|
},this);
|
||
|
|
||
|
this.buildScale(data.labels);
|
||
|
|
||
|
this.BarClass.prototype.base = this.scale.endPoint;
|
||
|
|
||
|
this.eachBars(function(bar, index, datasetIndex){
|
||
|
helpers.extend(bar, {
|
||
|
width : this.scale.calculateBarWidth(this.datasets.length),
|
||
|
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||
|
y: this.scale.endPoint
|
||
|
});
|
||
|
bar.save();
|
||
|
}, this);
|
||
|
|
||
|
this.render();
|
||
|
},
|
||
|
update : function(){
|
||
|
this.scale.update();
|
||
|
// Reset any highlight colours before updating.
|
||
|
helpers.each(this.activeElements, function(activeElement){
|
||
|
activeElement.restore(['fillColor', 'strokeColor']);
|
||
|
});
|
||
|
|
||
|
this.eachBars(function(bar){
|
||
|
bar.save();
|
||
|
});
|
||
|
this.render();
|
||
|
},
|
||
|
eachBars : function(callback){
|
||
|
helpers.each(this.datasets,function(dataset, datasetIndex){
|
||
|
helpers.each(dataset.bars, callback, this, datasetIndex);
|
||
|
},this);
|
||
|
},
|
||
|
getBarsAtEvent : function(e){
|
||
|
var barsArray = [],
|
||
|
eventPosition = helpers.getRelativePosition(e),
|
||
|
datasetIterator = function(dataset){
|
||
|
barsArray.push(dataset.bars[barIndex]);
|
||
|
},
|
||
|
barIndex;
|
||
|
|
||
|
for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
|
||
|
for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
|
||
|
if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){
|
||
|
helpers.each(this.datasets, datasetIterator);
|
||
|
return barsArray;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return barsArray;
|
||
|
},
|
||
|
buildScale : function(labels){
|
||
|
var self = this;
|
||
|
|
||
|
var dataTotal = function(){
|
||
|
var values = [];
|
||
|
self.eachBars(function(bar){
|
||
|
values.push(bar.value);
|
||
|
});
|
||
|
return values;
|
||
|
};
|
||
|
|
||
|
var scaleOptions = {
|
||
|
templateString : this.options.scaleLabel,
|
||
|
height : this.chart.height,
|
||
|
width : this.chart.width,
|
||
|
ctx : this.chart.ctx,
|
||
|
textColor : this.options.scaleFontColor,
|
||
|
fontSize : this.options.scaleFontSize,
|
||
|
fontStyle : this.options.scaleFontStyle,
|
||
|
fontFamily : this.options.scaleFontFamily,
|
||
|
valuesCount : labels.length,
|
||
|
beginAtZero : this.options.scaleBeginAtZero,
|
||
|
integersOnly : this.options.scaleIntegersOnly,
|
||
|
calculateYRange: function(currentHeight){
|
||
|
var updatedRanges = helpers.calculateScaleRange(
|
||
|
dataTotal(),
|
||
|
currentHeight,
|
||
|
this.fontSize,
|
||
|
this.beginAtZero,
|
||
|
this.integersOnly
|
||
|
);
|
||
|
helpers.extend(this, updatedRanges);
|
||
|
},
|
||
|
xLabels : labels,
|
||
|
font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
|
||
|
lineWidth : this.options.scaleLineWidth,
|
||
|
lineColor : this.options.scaleLineColor,
|
||
|
showHorizontalLines : this.options.scaleShowHorizontalLines,
|
||
|
showVerticalLines : this.options.scaleShowVerticalLines,
|
||
|
gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
|
||
|
gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
|
||
|
padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
|
||
|
showLabels : this.options.scaleShowLabels,
|
||
|
display : this.options.showScale
|
||
|
};
|
||
|
|
||
|
if (this.options.scaleOverride){
|
||
|
helpers.extend(scaleOptions, {
|
||
|
calculateYRange: helpers.noop,
|
||
|
steps: this.options.scaleSteps,
|
||
|
stepValue: this.options.scaleStepWidth,
|
||
|
min: this.options.scaleStartValue,
|
||
|
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
|
||
|
});
|
||
|
}
|
||
|
|
||
|
this.scale = new this.ScaleClass(scaleOptions);
|
||
|
},
|
||
|
addData : function(valuesArray,label){
|
||
|
//Map the values array for each of the datasets
|
||
|
helpers.each(valuesArray,function(value,datasetIndex){
|
||
|
//Add a new point for each piece of data, passing any required data to draw.
|
||
|
this.datasets[datasetIndex].bars.push(new this.BarClass({
|
||
|
value : value,
|
||
|
label : label,
|
||
|
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
|
||
|
y: this.scale.endPoint,
|
||
|
width : this.scale.calculateBarWidth(this.datasets.length),
|
||
|
base : this.scale.endPoint,
|
||
|
strokeColor : this.datasets[datasetIndex].strokeColor,
|
||
|
fillColor : this.datasets[datasetIndex].fillColor
|
||
|
}));
|
||
|
},this);
|
||
|
|
||
|
this.scale.addXLabel(label);
|
||
|
//Then re-render the chart.
|
||
|
this.update();
|
||
|
},
|
||
|
removeData : function(){
|
||
|
this.scale.removeXLabel();
|
||
|
//Then re-render the chart.
|
||
|
helpers.each(this.datasets,function(dataset){
|
||
|
dataset.bars.shift();
|
||
|
},this);
|
||
|
this.update();
|
||
|
},
|
||
|
reflow : function(){
|
||
|
helpers.extend(this.BarClass.prototype,{
|
||
|
y: this.scale.endPoint,
|
||
|
base : this.scale.endPoint
|
||
|
});
|
||
|
var newScaleProps = helpers.extend({
|
||
|
height : this.chart.height,
|
||
|
width : this.chart.width
|
||
|
});
|
||
|
this.scale.update(newScaleProps);
|
||
|
},
|
||
|
draw : function(ease){
|
||
|
var easingDecimal = ease || 1;
|
||
|
this.clear();
|
||
|
|
||
|
var ctx = this.chart.ctx;
|
||
|
|
||
|
this.scale.draw(easingDecimal);
|
||
|
|
||
|
//Draw all the bars for each dataset
|
||
|
helpers.each(this.datasets,function(dataset,datasetIndex){
|
||
|
helpers.each(dataset.bars,function(bar,index){
|
||
|
if (bar.hasValue()){
|
||
|
bar.base = this.scale.endPoint;
|
||
|
//Transition then draw
|
||
|
bar.transition({
|
||
|
x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
|
||
|
y : this.scale.calculateY(bar.value),
|
||
|
width : this.scale.calculateBarWidth(this.datasets.length)
|
||
|
}, easingDecimal).draw();
|
||
|
}
|
||
|
},this);
|
||
|
|
||
|
},this);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
|
||
|
}).call(this);
|