]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Merge branch 'fix/bar_chart_negative_values' of https://github.com/etimberg/Chart...
authoretimberg <evert.timberg@gmail.com>
Tue, 12 May 2015 12:00:14 +0000 (08:00 -0400)
committeretimberg <evert.timberg@gmail.com>
Tue, 12 May 2015 12:00:14 +0000 (08:00 -0400)
# Conflicts:
# samples/bar.html
# src/Chart.Bar.js
# src/Chart.Core.js

1  2 
samples/bar.html
src/Chart.Bar.js
src/Chart.Core.js

index 493bd99655abd9b747150aa1909317084a976ae9,1b1166a22066416cf1d87ab78156e688266c6347..d1bf880c67af345068924f3df00be2e6e1425bb7
@@@ -1,56 -1,46 +1,55 @@@
  <!doctype html>
  <html>
 -      <head>
 -              <title>Bar Chart</title>
 -              <script src="../Chart.js"></script>
 -      </head>
 -      <body>
 -              <div style="width: 50%">
 -                      <canvas id="canvas" height="450" width="600"></canvas>
 -              </div>
 +<head>
 +    <title>Bar Chart</title>
 +    <script src="../Chart.js"></script>
 +    <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
 +</head>
  
-     var randomScalingFactor = function() {
-         return Math.round(Math.random() * 100)
 +<body>
 +    <div style="width: 100%">
 +        <canvas id="canvas" height="450" width="600"></canvas>
 +    </div>
 +    <button id="randomizeData">Randomize Data</button>
 +    <script>
++    var randomScalingFactor = function(){ 
++        return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random()*100)
 +    };
 +    var randomColorFactor = function() {
 +        return Math.round(Math.random() * 255)
 +    };
  
 -      <script>
 -      var randomScalingFactor = function(){ return (Math.random() > 0.5 ? 1.0 : -1.0) * Math.round(Math.random()*100)};
 +    var barChartData = {
 +        labels: ["January", "February", "March", "April", "May", "June", "July"],
 +        datasets: [{
 +            backgroundColor: "rgba(220,220,220,0.5)",
 +            data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
 +        }, {
 +            backgroundColor: "rgba(151,187,205,0.5)",
 +            data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
 +        }]
  
 -      var barChartData = {
 -              labels : ["January","February","March","April","May","June","July"],
 -              datasets : [
 -                      {
 -                              fillColor : "rgba(220,220,220,0.5)",
 -                              strokeColor : "rgba(220,220,220,0.8)",
 -                              highlightFill: "rgba(220,220,220,0.75)",
 -                              highlightStroke: "rgba(220,220,220,1)",
 -                              data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
 -                      },
 -                      {
 -                              fillColor : "rgba(151,187,205,0.5)",
 -                              strokeColor : "rgba(151,187,205,0.8)",
 -                              highlightFill : "rgba(151,187,205,0.75)",
 -                              highlightStroke : "rgba(151,187,205,1)",
 -                              data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
 -                      }
 -              ]
 +    }
 +    window.onload = function() {
 +        var ctx = document.getElementById("canvas").getContext("2d");
 +        window.myBar = new Chart(ctx).Bar(barChartData, {
 +            responsive: true,
-             hoverMode: 'bar'
++            hoverMode: 'bar',
++            scaleBeginAtZero: false,
 +        });
 +    }
  
 -      }
 -      window.onload = function(){
 -              var ctx = document.getElementById("canvas").getContext("2d");
 -              window.myBar = new Chart(ctx).Bar(barChartData, {
 -                      responsive : true,
 -                      scaleBeginAtZero: false,
 -              });
 -      }
 +    $('#randomizeData').click(function() {
 +        barChartData.datasets[0].backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
 +        barChartData.datasets[0].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
  
 -      </script>
 -      </body>
 +        barChartData.datasets[1].backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
 +        barChartData.datasets[1].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
 +
 +        window.myBar.update();
 +
 +        console.log(window.barChartData);
 +    });
 +    </script>
 +</body>
  </html>
index 1a6ec688fbc9012c1bb48b946c9b4fe2de1057eb,e911cb500b53986e5441d790390c210bedcbbf1e..a65331f30abb37b773babb19bf7b9532438ec5b2
                                }
                        });
  
 -                      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);
 -                              });
 +                              helpers.bindEvents(this, this.options.tooltipEvents, this.onHover);
                        }
  
 +
 +                      
                        //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
 +                              ctx : this.chart.ctx,
 +                              _vm: {}
                        });
  
 -                      //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);
 +                      // Build Scale
 +                      this.buildScale(data.labels);
  
 +                      //Create a new bar for each piece of data
 +                      helpers.each(this.data.datasets,function(dataset,datasetIndex){
 +                              dataset.metaData = [];
                                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
 -                                      }));
 +                                      dataset.metaData.push(new this.BarClass());
                                },this);
 -
                        },this);
  
 -                      this.buildScale(data.labels);
 -
 -                      this.BarClass.prototype.base = this.calculateBarBase();
 -
 +                      // Set defaults for bars
                        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.calculateBarBase() // so that we animate from the baseline
 +                                      width : this.scale.calculateBarWidth(this.data.datasets.length),
 +                                      x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
-                                       y: this.scale.endPoint,
++                                      y: this.calculateBarBase(),
                                });
 +                              // Copy to view model
                                bar.save();
                        }, this);
  
 -                      this.render();
 +                      this.update();
 +              },
 +              onHover: function(e){
 +
 +                      var active;
 +                      if(e.type == 'mouseout'){
 +                              return false;
 +                      }
 +                      if(this.options.hoverMode == 'bar'){
 +                              active = this.getBarAtEvent(e);
 +                      }
 +                      else if(this.options.hoverMode == 'bars'){}
 +
 +
 +                      // Remove styling for last active
 +                      if(this.lastActive){
 +                              if(this.options.hoverMode == 'bar'){
 +                                      this.lastActive.rectangle.backgroundColor = this.data.datasets[this.lastActive.datasetIndex].backgroundColor;
 +                                      this.lastActive.rectangle.borderColor = this.data.datasets[this.lastActive.datasetIndex].borderColor;
 +                                      this.lastActive.rectangle.borderWidth = 0;
 +                              }
 +                              else if(this.options.hoverMode == 'bars'){}
 +                      }
 +
 +                      // Custom Hover actions
 +                      if(this.options.onHover){
 +                              this.options.onHover.call(this, active);
 +                      }
 +                      else if(active){
 +                              // or default hover action
 +                              if(this.options.hoverMode == 'bar'){
 +                                      active.rectangle.backgroundColor = this.data.datasets[active.datasetIndex].hoverBackgroundColor || Color(active.rectangle.backgroundColor).saturate(0.5).darken(0.25).rgbString();
 +                                      active.rectangle.borderColor = this.data.datasets[active.datasetIndex].hoverBorderColor || Color(active.rectangle.borderColor).saturate(0.5).darken(0.25).rgbString();
 +                              }
 +                              else if(this.options.hoverMode == 'bars'){}
 +
 +                      }
 +
 +                      if(!this.animating){
 +                              // If entering
 +                              if(!this.lastActive && active){
 +                                      this.render(false, this.options.hoverDuration);
 +                              }
 +
 +                              // If different bar
 +                              if(this.lastActive && active && this.lastActive.rectangle !== active.rectangle){
 +                                      this.render(false, this.options.hoverDuration);
 +                              }
 +
 +                              // if Leaving
 +                              if (this.lastActive && !active){
 +                                      this.render(false, this.options.hoverDuration);
 +                              }
 +                      }
 +
 +                      this.lastActive = active;
 +
 +                      //this.showTooltip(active);
                },
+               // Calculate the base point for the bar.
+               // If the scale has a 0 point, use that as the base
+               // If the scale min and max are both positive, use the bottom as a base
+               // If the scale min and max are both negative, use the top as a base
+               calculateBarBase: function() {
+                       var base = this.scale.endPoint;
+                       
+                       if (this.scale.beginAtZero || ((this.scale.min <= 0 && this.scale.max >= 0) || (this.scale.min >= 0 && this.scale.max <= 0)))
+                       {
+                               base = this.scale.calculateY(0);
+                               base += this.options.scaleGridLineWidth;
+                       }
+                       else if (this.scale.min < 0 && this.scale.max < 0)
+                       {
+                               // All values are negative. Use the top as the base
+                               base = this.scale.startPoint;
+                       }
+                       
+                       return base;
+               },
                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.eachBars(function(bar, index, datasetIndex){
 +                              helpers.extend(bar, {
 +                                      width : this.scale.calculateBarWidth(this.data.datasets.length),
 +                                      x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
 +                                      y: this.scale.calculateY(this.data.datasets[datasetIndex].data[index]),
 +                                      value : this.data.datasets[datasetIndex].data[index],
 +                                      label : this.data.labels[index],
 +                                      datasetLabel: this.data.datasets[datasetIndex].label,
 +                                      borderColor : this.data.datasets[datasetIndex].borderColor,
 +                                      borderWidth : this.data.datasets[datasetIndex].borderWidth,
 +                                      backgroundColor : this.data.datasets[datasetIndex].backgroundColor,
 +                                      _start: undefined
 +                              });
 +                      }, this);
 +
 +
                        this.render();
                },
                eachBars : function(callback){
                        //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({
 +                              this.data.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.calculateBarBase(), // so that we animate from the 0 point
 -                                      width : this.scale.calculateBarWidth(this.datasets.length),
 +                                      datasetLabel: this.data.datasets[datasetIndex].label,
 +                                      x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, this.scale.valuesCount+1),
-                                       y: this.scale.endPoint,
++                                      y: this.calculateBarBase(),
 +                                      width : this.scale.calculateBarWidth(this.data.datasets.length),
-                                       base : this.scale.endPoint,
+                                       base : this.calculateBarBase(),
 -                                      strokeColor : this.datasets[datasetIndex].strokeColor,
 -                                      fillColor : this.datasets[datasetIndex].fillColor
 +                                      borderColor : this.data.datasets[datasetIndex].borderColor,
 +                                      backgroundColor : this.data.datasets[datasetIndex].backgroundColor
                                }));
                        },this);
  
                        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.calculateBarBase()
 -                                              
 -                                              //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);
 +                      this.eachBars(function(bar, index, datasetIndex){
 +                              if (bar.hasValue()){
 +                                      // Update the bar basepoint
-                                       bar.base = this.scale.endPoint;
++                                      bar.base = this.calculateBarBase();
 +                                      //Transition 
 +                                      bar.transition([
 +                                              'x',
 +                                              'y',
 +                                              'width',
 +                                              'backgroundColor',
 +                                              'borderColor',
 +                                              'borderWidth'
 +                                      ], easingDecimal).draw();
 +                              }
 +                      }, this);
                }
        });
  
index 7c051683d9bc0c51f6f8e13d496248a12a6816ae,b05b6b9715a0ad88d5b355671a081770636e805f..8a476551b0acec260e49f952d935d5597460cb21
                        }
                },
                height : function(){
 -                      return this.base - this.y;
 +                      var vm = this._vm;
 +                      return vm.base - vm.y;
                },
                inRange : function(chartX,chartY){
-                       var vm = this._vm;
-                       return (chartX >= vm.x - vm.width/2 && chartX <= vm.x + vm.width/2) && (chartY >= vm.y && chartY <= vm.base);
+                       if (this.y < this.base)
+                       {
+                               return (chartX >= this.x - this.width/2 && chartX <= this.x + this.width/2) && (chartY >= this.y && chartY <= this.base);
+                       }
+                       else
+                       {
+                               return (chartX >= this.x - this.width / 2 && chartX <= this.x + this.width / 2) && (chartY >= this.base && chartY <= this.y);
+                       }
                }
        });