]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Bar chart converted to new scale system. Added bar chart multi axis sample.
authorEvert Timberg <evert.timberg@gmail.com>
Sat, 23 May 2015 22:26:34 +0000 (18:26 -0400)
committerEvert Timberg <evert.timberg@gmail.com>
Sat, 23 May 2015 22:26:34 +0000 (18:26 -0400)
samples/bar-multi-axis.html [new file with mode: 0644]
samples/bar.html
src/Chart.Bar.js

diff --git a/samples/bar-multi-axis.html b/samples/bar-multi-axis.html
new file mode 100644 (file)
index 0000000..4a7ccb8
--- /dev/null
@@ -0,0 +1,134 @@
+<!doctype html>
+<html>
+
+<head>
+    <title>Bar Chart Multi Axis</title>
+    <script src="../node_modules/jquery/dist/jquery.min.js"></script>
+    <script src="../Chart.js"></script>
+</head>
+
+<body>
+    <div style="width: 50%">
+        <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);
+    };
+
+    var barChartData = {
+        labels: ["January", "February", "March", "April", "May", "June", "July"],
+        datasets: [{
+            label: 'Dataset 1',
+            backgroundColor: "rgba(220,220,220,0.5)",
+            yAxisID: "y-axis-1",
+            data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+        }, {
+            label: 'Dataset 2',
+            backgroundColor: "rgba(151,187,205,0.5)",
+            yAxisID: "y-axis-2",
+            data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
+        }, {
+            label: 'Dataset 3',
+            backgroundColor: "rgba(151,187,205,0.5)",
+            yAxisID: "y-axis-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({
+            data: barChartData, 
+            options: {
+                responsive: true,
+                hoverMode: 'label',
+                hoverAnimationDuration: 400,
+                stacked: false,
+                scales: {
+                    yAxes: [{
+                        scaleType: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
+                        show: true,
+                        position: "left",
+                        horizontal: false, 
+                        id: "y-axis-1",
+                
+                        // grid line settings
+                        gridLines: {
+                            show: true,
+                            color: "rgba(0, 0, 0, 0.05)",
+                            lineWidth: 1,
+                            drawOnChartArea: true,
+                            drawTicks: true,
+                            zeroLineWidth: 1,
+                            zeroLineColor: "rgba(0,0,0,0.25)",
+                        },
+
+                        // scale numbers
+                        beginAtZero: false,
+                        integersOnly: false,
+                        override: null,
+
+                        // label settings
+                        labels: {
+                            show: true,
+                            template: "<%=value%>",
+                            fontSize: 12,
+                            fontStyle: "normal",
+                            fontColor: "#666",
+                            fontFamily: "Helvetica Neue",
+                        }
+                    }, {
+                        scaleType: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
+                        show: true,
+                        position: "right",
+                        horizontal: false, 
+                        id: "y-axis-2",
+                
+                        // grid line settings
+                        gridLines: {
+                            show: true,
+                            color: "rgba(0, 0, 0, 0.05)",
+                            lineWidth: 1,
+                            drawOnChartArea: false, // only want the grid lines for one axis to show up
+                            drawTicks: false,
+                            zeroLineWidth: 1,
+                            zeroLineColor: "rgba(0,0,0,0.25)",
+                        },
+
+                        // scale numbers
+                        beginAtZero: false,
+                        integersOnly: false,
+                        override: null,
+
+                        // label settings
+                        labels: {
+                            show: true,
+                            template: "<%=value%>",
+                            fontSize: 12,
+                            fontStyle: "normal",
+                            fontColor: "#666",
+                            fontFamily: "Helvetica Neue",
+                        }
+                    }],
+                }
+            }
+        });
+    };
+
+    $('#randomizeData').click(function() {
+        $.each(barChartData.datasets, function(i, dataset) {
+            dataset.backgroundColor = 'rgba(' + randomColorFactor() + ',' + randomColorFactor() + ',' + randomColorFactor() + ',.7)';
+            dataset.data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()];
+
+        });
+        window.myBar.update();
+    });
+    </script>
+</body>
+
+</html>
index b0f82cf1bf9353790605a54bbd41c5fb707e74a8..d9a5dc4d1664818ef8b17b43590f2be2746e0a81 100644 (file)
@@ -8,7 +8,7 @@
 </head>
 
 <body>
-    <div style="width: 100%">
+    <div style="width: 50%">
         <canvas id="canvas" height="450" width="600"></canvas>
     </div>
     <button id="randomizeData">Randomize Data</button>
index e181be4fc8f7f5a568a82301ca5217f7079ca111..a7d3f0e98f7507a19a3636f6704198128ec83d6b 100644 (file)
@@ -7,23 +7,75 @@
 
 
     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,
+        scales: {
+            xAxes: [{
+                scaleType: "dataset", // scatter should not use a dataset axis
+                show: true,
+                position: "bottom",
+                horizontal: true,
+                id: "x-axis-1", // need an ID so datasets can reference the scale
+                
+                // grid line settings
+                gridLines: {
+                    show: true,
+                    color: "rgba(0, 0, 0, 0.05)",
+                    lineWidth: 1,
+                    drawOnChartArea: true,
+                    drawTicks: true,
+                    zeroLineWidth: 1,
+                    zeroLineColor: "rgba(0,0,0,0.25)",
+                    offsetGridLines: true,
+                },
 
-        //Boolean - Whether to show horizontal lines (except X axis)
-        scaleShowHorizontalLines: true,
+                // scale numbers
+                beginAtZero: false,
+                integersOnly: false,
+                override: null,
+
+                // label settings
+                labels: {
+                    show: true,
+                    template: "<%=value%>",
+                    fontSize: 12,
+                    fontStyle: "normal",
+                    fontColor: "#666",
+                    fontFamily: "Helvetica Neue",
+                },
+            }],
+            yAxes: [{
+                scaleType: "linear", // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
+                show: true,
+                position: "left",
+                horizontal: false, 
+                id: "y-axis-1",
+        
+                // grid line settings
+                gridLines: {
+                    show: true,
+                    color: "rgba(0, 0, 0, 0.05)",
+                    lineWidth: 1,
+                    drawOnChartArea: true,
+                    drawTicks: true, // draw ticks extending towards the label
+                    zeroLineWidth: 1,
+                    zeroLineColor: "rgba(0,0,0,0.25)",
+                },
 
-        //Boolean - Whether to show vertical lines (except Y axis)
-        scaleShowVerticalLines: true,
+                // scale numbers
+                beginAtZero: false,
+                integersOnly: false,
+                override: null,
+
+                // label settings
+                labels: {
+                    show: true,
+                    template: "<%=value%>",
+                    fontSize: 12,
+                    fontStyle: "normal",
+                    fontColor: "#666",
+                    fontFamily: "Helvetica Neue",
+                }
+            }],
+        },
 
         //Number - Pixel width of the bar border
         barBorderWidth: 2,
         name: "Bar",
         defaults: defaultConfig,
         initialize: function() {
-            var options = this.options;
-
-            var _this = this;
-
-            // Custom Scale Methods and Options
-            this.ScaleClass = Chart.Scale.extend({
-                offsetGridLines: true,
-                calculateBarBase: function(datasetIndex, index) {
-
-                    var base = 0;
-
-                    if (_this.options.stacked) {
-                        var bar = _this.data.datasets[datasetIndex].metaData[index];
-                        if (bar.value < 0) {
-                            for (var i = 0; i < datasetIndex; i++) {
-                                base += _this.data.datasets[i].metaData[index].value < base ? _this.data.datasets[i].metaData[index].value : 0;
-                            }
-                        } else {
-                            for (var i = 0; i < datasetIndex; i++) {
-                                base += _this.data.datasets[i].metaData[index].value > base ? _this.data.datasets[i].metaData[index].value : 0;
-                            }
-                        }
-                        return this.calculateY(base);
-                    }
-
-                    base = this.endPoint;
-
-                    if (this.beginAtZero || ((this.min <= 0 && this.max >= 0) || (this.min >= 0 && this.max <= 0))) {
-                        base = this.calculateY(0);
-                        base += _this.options.scaleGridLineWidth;
-                    } else if (this.min < 0 && this.max < 0) {
-                        // All values are negative. Use the top as the base
-                        base = this.startPoint;
-                    }
-
-                    return base;
-
-                },
-                calculateBarX: function(datasetCount, datasetIndex, elementIndex) {
-                    var xWidth = this.calculateBaseWidth(),
-                        xAbsolute = this.calculateX(elementIndex) - (xWidth / 2),
-                        barWidth = this.calculateBarWidth(datasetCount);
-
-                    if (_this.options.stacked) {
-                        return xAbsolute + barWidth / 2;
-                    }
-
-                    return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth / 2;
-                },
-                calculateBarY: function(datasets, datasetIndex, barIndex, value) {
-
-                    if (_this.options.stacked) {
-
-                        var sumPos = 0,
-                            sumNeg = 0;
-
-                        for (var i = 0; i < datasetIndex; i++) {
-                            if (datasets[i].metaData[barIndex].value < 0) {
-                                sumNeg += datasets[i].metaData[barIndex].value || 0;
-                            } else {
-                                sumPos += datasets[i].metaData[barIndex].value || 0;
-                            }
-                        }
-
-                        if (value < 0) {
-                            return this.calculateY(sumNeg + value);
-                        } else {
-                            return this.calculateY(sumPos + value);
-                        }
-
-                        /*if (options.relativeBars) {
-                            offset = offset / sum * 100;
-                        }*/
-
-                        return this.calculateY(0);
-                    }
-
-                    var offset = 0;
-
-                    for (i = datasetIndex; i < datasets.length; i++) {
-                        if (i === datasetIndex && value) {
-                            offset += value;
-                        } else {
-                            offset = offset + (datasets[i].metaData[barIndex].value);
-                        }
-                    }
-
-                    return this.calculateY(value);
-                },
-                calculateBaseWidth: function() {
-                    return (this.calculateX(1) - this.calculateX(0)) - (2 * options.barValueSpacing);
-                },
-                calculateBaseHeight: function() {
-                    return (this.calculateY(1) - this.calculateY(0));
-                },
-                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);
-
-                    if (_this.options.stacked) {
-                        return baseWidth;
-                    }
-                    return (baseWidth / datasetCount);
-                },
-            });
-
             // Events
-            helpers.bindEvents(this, this.options.tooltipEvents, this.onHover);
+            helpers.bindEvents(this, this.options.events, this.onHover);
 
             //Declare the extension of the default point, to cater for the options passed in to the constructor
             this.BarClass = Chart.Rectangle.extend({
                 ctx: this.chart.ctx,
             });
 
-            // Build Scale
-            this.buildScale(this.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) {
                     dataset.metaData.push(new this.BarClass());
                 }, this);
+
+                 // The bar chart only supports a single x axis because the x axis is always a dataset axis
+                dataset.xAxisID = this.options.scales.xAxes[0].id;
+
+                if (!dataset.yAxisID) {
+                    dataset.yAxisID = this.options.scales.yAxes[0].id;
+                }
             }, this);
 
+            // Build and fit the scale. Needs to happen after the axis IDs have been set
+            this.buildScale();
+            Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
+
             // Set defaults for bars
             this.eachElement(function(bar, index, dataset, datasetIndex) {
+                var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
+                var yScale = this.scales[this.data.datasets[datasetIndex].yAxisID];
+
                 helpers.extend(bar, {
-                    base: this.scale.zeroPoint,
-                    width: this.scale.calculateBarWidth(this.data.datasets.length),
-                    x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
-                    y: this.scale.calculateBarY(this.data.datasets, datasetIndex, index, this.data.datasets[datasetIndex].data[index]),
+                    base: yScale.getPixelForValue(0),
+                    width: xScale.calculateBarWidth(this.data.datasets.length),
+                    x: xScale.calculateBarX(this.data.datasets.length, datasetIndex, index),
+                    y: yScale.calculateBarY(this.data.datasets, datasetIndex, index, this.data.datasets[datasetIndex].data[index]),
                     _datasetIndex: datasetIndex,
                     _index: index,
                 });
             return this;
         },
         update: function() {
-
-            this.scale.update();
+            // Update the scale sizes
+            Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height);
 
             this.eachElement(function(bar, index, dataset, datasetIndex) {
                 helpers.extend(bar, {
                     value: this.data.datasets[datasetIndex].data[index],
                 });
+
                 bar.pivot();
             }, this);
 
             this.eachElement(function(bar, index, dataset, datasetIndex) {
+                var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID];
+                var yScale = this.scales[this.data.datasets[datasetIndex].yAxisID];
+
                 helpers.extend(bar, {
-                    base: this.scale.calculateBarBase(datasetIndex, index),
-                    x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, index),
-                    y: this.scale.calculateBarY(this.data.datasets, datasetIndex, index, this.data.datasets[datasetIndex].data[index]),
-                    width: this.scale.calculateBarWidth(this.data.datasets.length),
+                    base: yScale.calculateBarBase(datasetIndex, index),
+                    x: xScale.calculateBarX(this.data.datasets.length, datasetIndex, index),
+                    y: yScale.calculateBarY(this.data.datasets, datasetIndex, index, this.data.datasets[datasetIndex].data[index]),
+                    width: xScale.calculateBarWidth(this.data.datasets.length),
                     label: this.data.labels[index],
                     datasetLabel: this.data.datasets[datasetIndex].label,
                     borderColor: this.data.datasets[datasetIndex].borderColor,
                     _datasetIndex: datasetIndex,
                     _index: index,
                 });
+
                 bar.pivot();
             }, this);
 
             this.render();
         },
         buildScale: function(labels) {
-            var self = this;
+             var self = this;
 
-            var dataTotal = function() {
-                var values = [];
+            // Function to determine the range of all the 
+            var calculateYRange = function() {
+                this.min = null;
+                this.max = null;
+
+                var positiveValues = [];
                 var negativeValues = [];
 
                 if (self.options.stacked) {
-                    self.eachValue(function(value, index) {
-                        values[index] = values[index] || 0;
-                        negativeValues[index] = negativeValues[index] || 0;
-                        if (self.options.relativeBars) {
-                            values[index] = 100;
-                        } else {
-                            if (value < 0) {
-                                negativeValues[index] += value;
-                            } else {
-                                values[index] += value;
-                            }
+                    helpers.each(self.data.datasets, function(dataset) {
+                        if (dataset.yAxisID === this.id) {
+                            helpers.each(dataset.data, function(value, index) {
+                                positiveValues[index] = positiveValues[index] || 0;
+                                negativeValues[index] = negativeValues[index] || 0;
+
+                                if (self.options.relativePoints) {
+                                    positiveValues[index] = 100;
+                                } else {
+                                    if (value < 0) {
+                                        negativeValues[index] += value;
+                                    } else {
+                                        positiveValues[index] += value;
+                                    }
+                                }
+                            }, this);
                         }
-                    });
-                    return values.concat(negativeValues);
+                    }, this);
+
+                    var values = positiveValues.concat(negativeValues);
+                    this.min = helpers.min(values);
+                    this.max = helpers.max(values);
+                } else {
+                    helpers.each(self.data.datasets, function(dataset) {
+                        if (dataset.yAxisID === this.id) {
+                            helpers.each(dataset.data, function(value, index) {
+                                if (this.min === null) {
+                                    this.min = value;
+                                } else if (value < this.min) {
+                                    this.min = value;
+                                }
+                                
+                                if (this.max === null) {
+                                    this.max = value;
+                                } else if (value > this.max) {
+                                    this.max = value;
+                                }
+                            }, this);
+                        }
+                    }, this);
                 }
+            };
 
-                self.eachValue(function(value, index) {
-                    values.push(value);
-                });
+            // Map of scale ID to scale object so we can lookup later 
+            this.scales = {};
 
-                return values;
+            // Build the x axis. The line chart only supports a single x axis
+            var ScaleClass = Chart.scales.getScaleConstructor(this.options.scales.xAxes[0].scaleType);
+            var xScale = new ScaleClass({
+                ctx: this.chart.ctx,
+                options: this.options.scales.xAxes[0],
+                id: this.options.scales.xAxes[0].id,
+                calculateRange: function() {
+                    this.labels = self.data.labels;
+                    this.min = 0;
+                    this.max = this.labels.length;
+                },
+                calculateBaseWidth: function() {
+                    return (this.getPixelForValue(null, 1, true) - this.getPixelForValue(null, 0, true)) - (2 * self.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) * self.options.barDatasetSpacing);
 
-            };
+                    if (self.options.stacked) {
+                        return baseWidth;
+                    }
+                    return (baseWidth / datasetCount);
+                },
+                calculateBarX: function(datasetCount, datasetIndex, elementIndex) {
+                    var xWidth = this.calculateBaseWidth(),
+                        xAbsolute = this.getPixelForValue(null, elementIndex, true) - (xWidth / 2),
+                        barWidth = this.calculateBarWidth(datasetCount);
 
-            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);
+                    if (self.options.stacked) {
+                        return xAbsolute + barWidth / 2;
+                    }
+
+                    return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * self.options.barDatasetSpacing) + barWidth / 2;
                 },
-                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.borderWidth,
-                showLabels: this.options.scaleShowLabels,
-                display: this.options.showScale
-            };
+            });
+            this.scales[xScale.id] = xScale;
+
+            // Build up all the y scales
+            helpers.each(this.options.scales.yAxes, function(yAxisOptions) {
+                var ScaleClass = Chart.scales.getScaleConstructor(yAxisOptions.scaleType);
+                var scale = new ScaleClass({
+                    ctx: this.chart.ctx,
+                    options: yAxisOptions,
+                    calculateRange: calculateYRange,
+                    calculateBarBase: function(datasetIndex, index) {
+                        var base = 0;
+
+                        if (self.options.stacked) {
+                            var bar = self.data.datasets[datasetIndex].metaData[index];
+
+                            if (bar.value < 0) {
+                                for (var i = 0; i < datasetIndex; i++) {
+                                    if (self.data.datasets[i].yAxisID === this.id) {
+                                        base += self.data.datasets[i].metaData[index].value < base ? self.data.datasets[i].metaData[index].value : 0;
+                                    }
+                                }
+                            } else {
+                                for (var i = 0; i < datasetIndex; i++) {
+                                    if (self.data.datasets[i].yAxisID === this.id) {
+                                        base += self.data.datasets[i].metaData[index].value > base ? self.data.datasets[i].metaData[index].value : 0;
+                                    }
+                                }
+                            }
+
+                            return this.getPixelForValue(base);
+                        }
+
+                        base = this.getPixelForValue(this.min);
+
+                        if (this.beginAtZero || ((this.min <= 0 && this.max >= 0) || (this.min >= 0 && this.max <= 0))) {
+                            base = this.getPixelForValue(0);
+                            base += this.options.gridLines.lineWidth;
+                        } else if (this.min < 0 && this.max < 0) {
+                            // All values are negative. Use the top as the base
+                            base = this.getPixelForValue(this.max);
+                        }
 
-            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)
+                        return base;
+
+                    },
+                    calculateBarY: function(datasets, datasetIndex, barIndex, value) {
+
+                        if (self.options.stacked) {
+
+                            var sumPos = 0,
+                                sumNeg = 0;
+
+                            for (var i = 0; i < datasetIndex; i++) {
+                                if (datasets[i].metaData[barIndex].value < 0) {
+                                    sumNeg += datasets[i].metaData[barIndex].value || 0;
+                                } else {
+                                    sumPos += datasets[i].metaData[barIndex].value || 0;
+                                }
+                            }
+
+                            if (value < 0) {
+                                return this.getPixelForValue(sumNeg + value);
+                            } else {
+                                return this.getPixelForValue(sumPos + value);
+                            }
+
+                            /*if (options.relativeBars) {
+                                offset = offset / sum * 100;
+                            }*/
+
+                            return this.getPixelForValue(0);
+                        }
+
+                        var offset = 0;
+
+                        for (i = datasetIndex; i < datasets.length; i++) {
+                            if (i === datasetIndex && value) {
+                                offset += value;
+                            } else {
+                                offset = offset + (datasets[i].metaData[barIndex].value);
+                            }
+                        }
+
+                        return this.getPixelForValue(value);
+                    },
+                    
+                    calculateBaseHeight: function() {
+                        return (this.getPixelForValue(1) - this.getPixelForValue(0));
+                    },
+                    id: yAxisOptions.id,
                 });
-            }
 
-            this.scale = new this.ScaleClass(scaleOptions);
+                this.scales[scale.id] = scale;
+            }, this);
         },
         // This should be incorportated into the init as something like a default value. "Reflow" seems like a weird word for a fredraw function
         redraw: function() {
-            var base = this.scale.zeroPoint;
             this.eachElement(function(element, index, datasetIndex) {
+                var yScale = this.scales[this.data.datasets[datasetIndex].yAxisID];
+                var base = yScale.getPixelForValue(yScale.min);
+
+                if (yScale.min <= 0 && yScale.max >= 0) {
+                    // have a 0 point
+                    base = yScale.getPixelForValue(0);
+                } else if (yScale.min < 0 && yScale.max < 0) {
+                    // all megative
+                    base = yScale.getPixelForValue(yScale.max);
+                }
+
                 helpers.extend(element, {
                     y: base,
                     base: base
             var easingDecimal = ease || 1;
             this.clear();
 
-            this.scale.draw(easingDecimal);
+            // Draw all the scales
+            helpers.each(this.scales, function(scale) {
+                scale.draw(this.chartArea);
+            }, this);
 
             //Draw all the bars for each dataset
             this.eachElement(function(bar, index, datasetIndex) {