Advertisement
Guest User

Bar Chart

a guest
Sep 10th, 2014
3,132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (function(){
  2.     "use strict";
  3.  
  4.     var root = this,
  5.         Chart = root.Chart,
  6.         helpers = Chart.helpers;
  7.  
  8.  
  9.     var defaultConfig = {
  10.         //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
  11.         scaleBeginAtZero : true,
  12.  
  13.         //Boolean - Whether grid lines are shown across the chart
  14.         scaleShowGridLines : false,
  15.  
  16.         //String - Colour of the grid lines
  17.         scaleGridLineColor : "rgba(0,0,0,.05)",
  18.  
  19.         //Number - Width of the grid lines
  20.         scaleGridLineWidth : 1,
  21.  
  22.         //Boolean - If there is a stroke on each bar
  23.         barShowStroke : true,
  24.  
  25.         //Number - Pixel width of the bar stroke
  26.         barStrokeWidth : 2,
  27.  
  28.         //Number - Spacing between each of the X value sets
  29.         barValueSpacing : 5,
  30.  
  31.         //Number - Spacing between data sets within X values
  32.         barDatasetSpacing : 1,
  33.  
  34.         //String - A legend template
  35.         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>"
  36.  
  37.     };
  38.  
  39.  
  40.     Chart.Type.extend({
  41.         name: "Bar",
  42.         defaults : defaultConfig,
  43.         initialize:  function(data){
  44.  
  45.             //Expose options as a scope variable here so we can access it in the ScaleClass
  46.             var options = this.options;
  47.  
  48.             this.ScaleClass = Chart.Scale.extend({
  49.                 offsetGridLines : true,
  50.                 calculateBarX : function(datasetCount, datasetIndex, barIndex){
  51.                     //Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
  52.                     var xWidth = this.calculateBaseWidth(),
  53.                         xAbsolute = this.calculateX(barIndex) - (xWidth/2),
  54.                         barWidth = this.calculateBarWidth(datasetCount);
  55.  
  56.                     return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
  57.                 },
  58.                 calculateBaseWidth : function(){
  59.                     return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
  60.                 },
  61.                 calculateBarWidth : function(datasetCount){
  62.                     //The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
  63.                     var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
  64.  
  65.                     return (baseWidth / datasetCount);
  66.                 }
  67.             });
  68.  
  69.             this.datasets = [];
  70.  
  71.             //Set up tooltip events on the chart
  72.             if (this.options.showTooltips){
  73.                 helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
  74.                     var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
  75.  
  76.                     this.eachBars(function(bar){
  77.                         bar.restore(['fillColor', 'strokeColor']);
  78.                     });
  79.                     helpers.each(activeBars, function(activeBar){
  80.                         activeBar.fillColor = activeBar.highlightFill;
  81.                         activeBar.strokeColor = activeBar.highlightStroke;
  82.                     });
  83.                     this.showTooltip(activeBars);
  84.                 });
  85.             }
  86.  
  87.             //Declare the extension of the default point, to cater for the options passed in to the constructor
  88.             this.BarClass = Chart.Rectangle.extend({
  89.                 strokeWidth : this.options.barStrokeWidth,
  90.                 showStroke : this.options.barShowStroke,
  91.                 ctx : this.chart.ctx
  92.             });
  93.  
  94.             //Iterate through each of the datasets, and build this into a property of the chart
  95.             helpers.each(data.datasets,function(dataset,datasetIndex){
  96.                                
  97.                 var datasetObject = {
  98.                     label : dataset.label || null,
  99.                     fillColor : dataset.fillColor,
  100.                     strokeColor : dataset.strokeColor,
  101.                     bars : []
  102.                 };
  103.  
  104.                 this.datasets.push(datasetObject);
  105.                                 var i = 0;
  106.                 helpers.each(dataset.data,function(dataPoint,index){
  107.                     //Add a new point for each piece of data, passing any required data to draw.
  108.                                        
  109.                     datasetObject.bars.push(new this.BarClass({
  110.                         value : dataPoint,
  111.                         label : data.labels[index],
  112.                         datasetLabel: dataset.label,
  113.                         strokeColor : dataset.strokeColor,
  114.                         fillColor : getColor(i),
  115.                         highlightFill : dataset.highlightFill || dataset.fillColor,
  116.                         highlightStroke : dataset.highlightStroke || dataset.strokeColor
  117.                     }));
  118.                                         i++;
  119.                 },this);
  120.  
  121.             },this);
  122.  
  123.             this.buildScale(data.labels);
  124.  
  125.             this.BarClass.prototype.base = this.scale.endPoint;
  126.  
  127.             this.eachBars(function(bar, index, datasetIndex){
  128.                 helpers.extend(bar, {
  129.                     width : this.scale.calculateBarWidth(this.datasets.length),
  130.                     x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
  131.                     y: this.scale.endPoint
  132.                 });
  133.                 bar.save();
  134.             }, this);
  135.  
  136.             this.render();
  137.         },
  138.         update : function(){
  139.             this.scale.update();
  140.             // Reset any highlight colours before updating.
  141.             helpers.each(this.activeElements, function(activeElement){
  142.                 activeElement.restore(['fillColor', 'strokeColor']);
  143.             });
  144.  
  145.             this.eachBars(function(bar){
  146.                 bar.save();
  147.             });
  148.             this.render();
  149.         },
  150.         eachBars : function(callback){
  151.             helpers.each(this.datasets,function(dataset, datasetIndex){
  152.                 helpers.each(dataset.bars, callback, this, datasetIndex);
  153.             },this);
  154.         },
  155.         getBarsAtEvent : function(e){
  156.             var barsArray = [],
  157.                 eventPosition = helpers.getRelativePosition(e),
  158.                 datasetIterator = function(dataset){
  159.                     barsArray.push(dataset.bars[barIndex]);
  160.                 },
  161.                 barIndex;
  162.  
  163.             for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
  164.                 for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
  165.                     if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){
  166.                         helpers.each(this.datasets, datasetIterator);
  167.                         return barsArray;
  168.                     }
  169.                 }
  170.             }
  171.  
  172.             return barsArray;
  173.         },
  174.         buildScale : function(labels){
  175.             var self = this;
  176.  
  177.             var dataTotal = function(){
  178.                 var values = [];
  179.                 self.eachBars(function(bar){
  180.                     values.push(bar.value);
  181.                 });
  182.                 return values;
  183.             };
  184.  
  185.             var scaleOptions = {
  186.                 templateString : this.options.scaleLabel,
  187.                 height : this.chart.height,
  188.                 width : this.chart.width,
  189.                 ctx : this.chart.ctx,
  190.                 textColor : this.options.scaleFontColor,
  191.                 fontSize : this.options.scaleFontSize,
  192.                 fontStyle : this.options.scaleFontStyle,
  193.                 fontFamily : this.options.scaleFontFamily,
  194.                 valuesCount : labels.length,
  195.                 beginAtZero : this.options.scaleBeginAtZero,
  196.                 integersOnly : this.options.scaleIntegersOnly,
  197.                 calculateYRange: function(currentHeight){
  198.                     var updatedRanges = helpers.calculateScaleRange(
  199.                         dataTotal(),
  200.                         currentHeight,
  201.                         this.fontSize,
  202.                         this.beginAtZero,
  203.                         this.integersOnly
  204.                     );
  205.                     helpers.extend(this, updatedRanges);
  206.                 },
  207.                 xLabels : labels,
  208.                 font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
  209.                 lineWidth : this.options.scaleLineWidth,
  210.                 lineColor : this.options.scaleLineColor,
  211.                 gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
  212.                 gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
  213.                 padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
  214.                 showLabels : this.options.scaleShowLabels,
  215.                 display : this.options.showScale
  216.             };
  217.  
  218.             if (this.options.scaleOverride){
  219.                 helpers.extend(scaleOptions, {
  220.                     calculateYRange: helpers.noop,
  221.                     steps: this.options.scaleSteps,
  222.                     stepValue: this.options.scaleStepWidth,
  223.                     min: this.options.scaleStartValue,
  224.                     max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
  225.                 });
  226.             }
  227.  
  228.             this.scale = new this.ScaleClass(scaleOptions);
  229.         },
  230.         addData : function(valuesArray,label){
  231.             //Map the values array for each of the datasets
  232.             helpers.each(valuesArray,function(value,datasetIndex){
  233.                 //Add a new point for each piece of data, passing any required data to draw.
  234.                 this.datasets[datasetIndex].bars.push(new this.BarClass({
  235.                     value : value,
  236.                     label : label,
  237.                     x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
  238.                     y: this.scale.endPoint,
  239.                     width : this.scale.calculateBarWidth(this.datasets.length),
  240.                     base : this.scale.endPoint,
  241.                     strokeColor : this.datasets[datasetIndex].strokeColor,
  242.                     fillColor : this.datasets[datasetIndex].fillColor
  243.                 }));
  244.             },this);
  245.  
  246.             this.scale.addXLabel(label);
  247.             //Then re-render the chart.
  248.             this.update();
  249.         },
  250.         removeData : function(){
  251.             this.scale.removeXLabel();
  252.             //Then re-render the chart.
  253.             helpers.each(this.datasets,function(dataset){
  254.                 dataset.bars.shift();
  255.             },this);
  256.             this.update();
  257.         },
  258.         reflow : function(){
  259.             helpers.extend(this.BarClass.prototype,{
  260.                 y: this.scale.endPoint,
  261.                 base : this.scale.endPoint
  262.             });
  263.             var newScaleProps = helpers.extend({
  264.                 height : this.chart.height,
  265.                 width : this.chart.width
  266.             });
  267.             this.scale.update(newScaleProps);
  268.         },
  269.         draw : function(ease){
  270.             var easingDecimal = ease || 1;
  271.             this.clear();
  272.  
  273.             var ctx = this.chart.ctx;
  274.  
  275.             this.scale.draw(easingDecimal);
  276.  
  277.             //Draw all the bars for each dataset
  278.             helpers.each(this.datasets,function(dataset,datasetIndex){
  279.                 helpers.each(dataset.bars,function(bar,index){
  280.                     if (bar.hasValue()){
  281.                         bar.base = this.scale.endPoint;
  282.                         //Transition then draw
  283.                         bar.transition({
  284.                             x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
  285.                             y : this.scale.calculateY(bar.value),
  286.                             width : this.scale.calculateBarWidth(this.datasets.length)
  287.                         }, easingDecimal).draw();
  288.                     }
  289.                 },this);
  290.  
  291.             },this);
  292.         }
  293.     });
  294.  
  295.  
  296. }).call(this);
  297.  
  298. function getColor(i) {
  299.     var colors = ["#5A8BCE", "#8ADBCC", "#A0EC88", "#E29E9F", "#D8F5F0", "#F8FC9E", "#A2E4D6", "#86ACDD"];
  300.     return colors[i%colors.length];
  301. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement