Added more updates
[soho-sigint.git] / client-freqwatch / Chart.js / src / Chart.Bar.js
diff --git a/client-freqwatch/Chart.js/src/Chart.Bar.js b/client-freqwatch/Chart.js/src/Chart.Bar.js
new file mode 100644 (file)
index 0000000..81532b4
--- /dev/null
@@ -0,0 +1,303 @@
+(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%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></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,
+                                       datasetLabel: this.datasets[datasetIndex].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);