]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Group stacked bar charts (#2643) (#3563)
authorpotatopeelings <potato.peelings@gmail.com>
Sun, 1 Jan 2017 14:36:01 +0000 (01:36 +1100)
committerEvert Timberg <evert.timberg+github@gmail.com>
Sun, 1 Jan 2017 14:36:01 +0000 (09:36 -0500)
Group stacked bar charts (#2643)

docs/04-Bar-Chart.md
samples/bar/bar-stacked-group.html [new file with mode: 0644]
src/controllers/controller.bar.js
src/scales/scale.linear.js
src/scales/scale.logarithmic.js
test/controller.bar.tests.js

index 777acc7a7e73b91ed801a84dbbc26080e0d7f394..ef2cd3c19a61babb103391764a70a9ea97dca2b1 100644 (file)
@@ -49,6 +49,7 @@ borderSkipped | `String or Array<String>` | Which edge to skip drawing the borde
 hoverBackgroundColor | `Color or Array<Color>` | Bar background color when hovered
 hoverBorderColor | `Color or Array<Color>` | Bar border color when hovered
 hoverBorderWidth | `Number or Array<Number>` | Border width of bar when hovered
+stack | `String` | The ID of the group to which this dataset belongs to (when stacked, each group will be a separate stack)
 
 An example data object using these attributes is shown below.
 
diff --git a/samples/bar/bar-stacked-group.html b/samples/bar/bar-stacked-group.html
new file mode 100644 (file)
index 0000000..074e3ea
--- /dev/null
@@ -0,0 +1,105 @@
+<!doctype html>
+<html>
+
+<head>
+    <title>Stacked Bar Chart with Groups</title>
+    <script src="../../dist/Chart.bundle.js"></script>
+    <script src="../utils.js"></script>
+    <style>
+    canvas {
+        -moz-user-select: none;
+        -webkit-user-select: none;
+        -ms-user-select: none;
+    }
+    </style>
+</head>
+
+<body>
+    <div style="width: 75%">
+        <canvas id="canvas"></canvas>
+    </div>
+    <button id="randomizeData">Randomize Data</button>
+    <script>
+        var barChartData = {
+            labels: ["January", "February", "March", "April", "May", "June", "July"],
+            datasets: [{
+                label: 'Dataset 1',
+                backgroundColor: window.chartColors.red,
+                stack: 'Stack 0',
+                data: [
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor()
+                ]
+            }, {
+                label: 'Dataset 2',
+                backgroundColor: window.chartColors.blue,
+                stack: 'Stack 0',
+                data: [
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor()
+                ]
+            }, {
+                label: 'Dataset 3',
+                backgroundColor: window.chartColors.green,
+                stack: 'Stack 1',
+                data: [
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor(), 
+                    randomScalingFactor()
+                ]
+            }]
+
+        };
+        window.onload = function() {
+            var ctx = document.getElementById("canvas").getContext("2d");
+            window.myBar = new Chart(ctx, {
+                type: 'bar',
+                data: barChartData,
+                options: {
+                    title:{
+                        display:true,
+                        text:"Chart.js Bar Chart - Stacked"
+                    },
+                    tooltips: {
+                        mode: 'index',
+                        intersect: false
+                    },
+                    responsive: true,
+                    scales: {
+                        xAxes: [{
+                            stacked: true,
+                        }],
+                        yAxes: [{
+                            stacked: true
+                        }]
+                    }
+                }
+            });
+        };
+
+        document.getElementById('randomizeData').addEventListener('click', function() {
+            barChartData.datasets.forEach(function(dataset, i) {
+                dataset.data = dataset.data.map(function() {
+                    return randomScalingFactor();
+                });
+            });
+            window.myBar.update();
+        });
+    </script>
+</body>
+
+</html>
index ecf43b19bce6d91046bc6afb7e68436a115b690a..1d41386b6d7d2b1038836ffb0ebfcaed2d747fca 100644 (file)
@@ -35,21 +35,33 @@ module.exports = function(Chart) {
                initialize: function(chart, datasetIndex) {
                        Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
 
+                       var me = this;
+                       var meta = me.getMeta();
+                       var dataset = me.getDataset();
+
+                       meta.stack = dataset.stack;
                        // Use this to indicate that this is a bar dataset.
-                       this.getMeta().bar = true;
+                       meta.bar = true;
                },
 
-               // Get the number of datasets that display bars. We use this to correctly calculate the bar width
-               getBarCount: function() {
+               // Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible
+               getStackCount: function() {
                        var me = this;
-                       var barCount = 0;
+                       var meta = me.getMeta();
+                       var yScale = me.getScaleForId(meta.yAxisID);
+
+                       var stacks = [];
                        helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
-                               var meta = me.chart.getDatasetMeta(datasetIndex);
-                               if (meta.bar && me.chart.isDatasetVisible(datasetIndex)) {
-                                       ++barCount;
+                               var dsMeta = me.chart.getDatasetMeta(datasetIndex);
+                               if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) &&
+                                       (yScale.options.stacked === false ||
+                                       (yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
+                                       (yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
+                                       stacks.push(dsMeta.stack);
                                }
                        }, me);
-                       return barCount;
+
+                       return stacks.length;
                },
 
                update: function(reset) {
@@ -103,7 +115,8 @@ module.exports = function(Chart) {
                        var base = yScale.getBaseValue();
                        var original = base;
 
-                       if (yScale.options.stacked) {
+                       if ((yScale.options.stacked === true) ||
+                               (yScale.options.stacked === undefined && meta.stack !== undefined)) {
                                var chart = me.chart;
                                var datasets = chart.data.datasets;
                                var value = Number(datasets[datasetIndex].data[index]);
@@ -111,7 +124,8 @@ module.exports = function(Chart) {
                                for (var i = 0; i < datasetIndex; i++) {
                                        var currentDs = datasets[i];
                                        var currentDsMeta = chart.getDatasetMeta(i);
-                                       if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
+                                       if (currentDsMeta.bar && currentDsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i) &&
+                                               meta.stack === currentDsMeta.stack) {
                                                var currentVal = Number(currentDs.data[index]);
                                                base += value < 0 ? Math.min(currentVal, original) : Math.max(currentVal, original);
                                        }
@@ -127,18 +141,18 @@ module.exports = function(Chart) {
                        var me = this;
                        var meta = me.getMeta();
                        var xScale = me.getScaleForId(meta.xAxisID);
-                       var datasetCount = me.getBarCount();
+                       var stackCount = me.getStackCount();
 
-                       var tickWidth = xScale.width / xScale.ticks.length;
+                       var tickWidth = xScale.width / xScale.ticks.length;\r
                        var categoryWidth = tickWidth * xScale.options.categoryPercentage;
                        var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
-                       var fullBarWidth = categoryWidth / datasetCount;
+                       var fullBarWidth = categoryWidth / stackCount;
 
                        var barWidth = fullBarWidth * xScale.options.barPercentage;
                        var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);
 
                        return {
-                               datasetCount: datasetCount,
+                               stackCount: stackCount,
                                tickWidth: tickWidth,
                                categoryWidth: categoryWidth,
                                categorySpacing: categorySpacing,
@@ -149,46 +163,50 @@ module.exports = function(Chart) {
                },
 
                calculateBarWidth: function(ruler) {
-                       var xScale = this.getScaleForId(this.getMeta().xAxisID);
+                       var me = this;
+                       var meta = me.getMeta();
+                       var xScale = me.getScaleForId(meta.xAxisID);
                        if (xScale.options.barThickness) {
                                return xScale.options.barThickness;
                        }
-                       return xScale.options.stacked ? ruler.categoryWidth * xScale.options.barPercentage : ruler.barWidth;
+                       return ruler.barWidth;\r
                },
 
-               // Get bar index from the given dataset index accounting for the fact that not all bars are visible
-               getBarIndex: function(datasetIndex) {
-                       var barIndex = 0;
-                       var meta, j;
+               // Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible
+               getStackIndex: function(datasetIndex) {
+                       var me = this;
+                       var meta = me.chart.getDatasetMeta(datasetIndex);
+                       var yScale = me.getScaleForId(meta.yAxisID);
+                       var dsMeta, j;
+                       var stacks = [meta.stack];
 
                        for (j = 0; j < datasetIndex; ++j) {
-                               meta = this.chart.getDatasetMeta(j);
-                               if (meta.bar && this.chart.isDatasetVisible(j)) {
-                                       ++barIndex;
+                               dsMeta = this.chart.getDatasetMeta(j);
+                               if (dsMeta.bar && this.chart.isDatasetVisible(j) &&
+                                       (yScale.options.stacked === false ||
+                                       (yScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
+                                       (yScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
+                                       stacks.push(dsMeta.stack);
                                }
                        }
 
-                       return barIndex;
+                       return stacks.length - 1;
                },
 
                calculateBarX: function(index, datasetIndex, ruler) {
                        var me = this;
                        var meta = me.getMeta();
                        var xScale = me.getScaleForId(meta.xAxisID);
-                       var barIndex = me.getBarIndex(datasetIndex);
+                       var stackIndex = me.getStackIndex(datasetIndex);
                        var leftTick = xScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
                        leftTick -= me.chart.isCombo ? (ruler.tickWidth / 2) : 0;
 
-                       if (xScale.options.stacked) {
-                               return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing;
-                       }
-
                        return leftTick +
                                (ruler.barWidth / 2) +
                                ruler.categorySpacing +
-                               (ruler.barWidth * barIndex) +
+                               (ruler.barWidth * stackIndex) +
                                (ruler.barSpacing / 2) +
-                               (ruler.barSpacing * barIndex);
+                               (ruler.barSpacing * stackIndex);
                },
 
                calculateBarY: function(index, datasetIndex) {
@@ -197,16 +215,17 @@ module.exports = function(Chart) {
                        var yScale = me.getScaleForId(meta.yAxisID);
                        var value = Number(me.getDataset().data[index]);
 
-                       if (yScale.options.stacked) {
-
+                       if (yScale.options.stacked ||
+                               (yScale.options.stacked === undefined && meta.stack !== undefined)) {
                                var base = yScale.getBaseValue();
                                var sumPos = base,
-                                       sumNeg = base;
+                                       sumNeg = base;\r
 
                                for (var i = 0; i < datasetIndex; i++) {
                                        var ds = me.chart.data.datasets[i];
                                        var dsMeta = me.chart.getDatasetMeta(i);
-                                       if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i)) {
+                                       if (dsMeta.bar && dsMeta.yAxisID === yScale.id && me.chart.isDatasetVisible(i) &&
+                                               meta.stack === dsMeta.stack) {
                                                var stackedVal = Number(ds.data[index]);
                                                if (stackedVal < 0) {
                                                        sumNeg += stackedVal || 0;
@@ -324,6 +343,27 @@ module.exports = function(Chart) {
        };
 
        Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
+
+               // Correctly calculate the bar width accounting for stacks and the fact that not all bars are visible
+               getStackCount: function() {
+                       var me = this;
+                       var meta = me.getMeta();
+                       var xScale = me.getScaleForId(meta.xAxisID);
+
+                       var stacks = [];
+                       helpers.each(me.chart.data.datasets, function(dataset, datasetIndex) {
+                               var dsMeta = me.chart.getDatasetMeta(datasetIndex);
+                               if (dsMeta.bar && me.chart.isDatasetVisible(datasetIndex) &&
+                                       (xScale.options.stacked === false ||
+                                       (xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
+                                       (xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
+                                       stacks.push(dsMeta.stack);
+                               }
+                       }, me);
+
+                       return stacks.length;
+               },
+
                updateElement: function(rectangle, index, reset) {
                        var me = this;
                        var meta = me.getMeta();
@@ -368,7 +408,8 @@ module.exports = function(Chart) {
                        var base = xScale.getBaseValue();
                        var originalBase = base;
 
-                       if (xScale.options.stacked) {
+                       if (xScale.options.stacked ||
+                               (xScale.options.stacked === undefined && meta.stack !== undefined)) {
                                var chart = me.chart;
                                var datasets = chart.data.datasets;
                                var value = Number(datasets[datasetIndex].data[index]);
@@ -376,7 +417,8 @@ module.exports = function(Chart) {
                                for (var i = 0; i < datasetIndex; i++) {
                                        var currentDs = datasets[i];
                                        var currentDsMeta = chart.getDatasetMeta(i);
-                                       if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i)) {
+                                       if (currentDsMeta.bar && currentDsMeta.xAxisID === xScale.id && chart.isDatasetVisible(i) &&
+                                               meta.stack === currentDsMeta.stack) {
                                                var currentVal = Number(currentDs.data[index]);
                                                base += value < 0 ? Math.min(currentVal, originalBase) : Math.max(currentVal, originalBase);
                                        }
@@ -392,18 +434,18 @@ module.exports = function(Chart) {
                        var me = this;
                        var meta = me.getMeta();
                        var yScale = me.getScaleForId(meta.yAxisID);
-                       var datasetCount = me.getBarCount();
+                       var stackCount = me.getStackCount();
 
                        var tickHeight = yScale.height / yScale.ticks.length;
                        var categoryHeight = tickHeight * yScale.options.categoryPercentage;
                        var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2;
-                       var fullBarHeight = categoryHeight / datasetCount;
+                       var fullBarHeight = categoryHeight / stackCount;
 
                        var barHeight = fullBarHeight * yScale.options.barPercentage;
                        var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage);
 
                        return {
-                               datasetCount: datasetCount,
+                               stackCount: stackCount,
                                tickHeight: tickHeight,
                                categoryHeight: categoryHeight,
                                categorySpacing: categorySpacing,
@@ -415,11 +457,33 @@ module.exports = function(Chart) {
 
                calculateBarHeight: function(ruler) {
                        var me = this;
-                       var yScale = me.getScaleForId(me.getMeta().yAxisID);
+                       var meta = me.getMeta();
+                       var yScale = me.getScaleForId(meta.yAxisID);
                        if (yScale.options.barThickness) {
                                return yScale.options.barThickness;
                        }
-                       return yScale.options.stacked ? ruler.categoryHeight * yScale.options.barPercentage : ruler.barHeight;
+                       return ruler.barHeight;
+               },
+
+               // Get stack index from the given dataset index accounting for stacks and the fact that not all bars are visible
+               getStackIndex: function(datasetIndex) {
+                       var me = this;
+                       var meta = me.chart.getDatasetMeta(datasetIndex);
+                       var xScale = me.getScaleForId(meta.xAxisID);
+                       var dsMeta, j;
+                       var stacks = [meta.stack];
+
+                       for (j = 0; j < datasetIndex; ++j) {
+                               dsMeta = this.chart.getDatasetMeta(j);
+                               if (dsMeta.bar && this.chart.isDatasetVisible(j) &&
+                                       (xScale.options.stacked === false ||
+                                       (xScale.options.stacked === true && stacks.indexOf(dsMeta.stack) === -1) ||
+                                       (xScale.options.stacked === undefined && (dsMeta.stack === undefined || stacks.indexOf(dsMeta.stack) === -1)))) {
+                                       stacks.push(dsMeta.stack);
+                               }
+                       }
+
+                       return stacks.length - 1;\r
                },
 
                calculateBarX: function(index, datasetIndex) {
@@ -428,16 +492,17 @@ module.exports = function(Chart) {
                        var xScale = me.getScaleForId(meta.xAxisID);
                        var value = Number(me.getDataset().data[index]);
 
-                       if (xScale.options.stacked) {
-
+                       if (xScale.options.stacked ||
+                               (xScale.options.stacked === undefined && meta.stack !== undefined)) {
                                var base = xScale.getBaseValue();
                                var sumPos = base,
-                                       sumNeg = base;
+                                       sumNeg = base;\r
 
                                for (var i = 0; i < datasetIndex; i++) {
                                        var ds = me.chart.data.datasets[i];
                                        var dsMeta = me.chart.getDatasetMeta(i);
-                                       if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i)) {
+                                       if (dsMeta.bar && dsMeta.xAxisID === xScale.id && me.chart.isDatasetVisible(i) &&
+                                               meta.stack === dsMeta.stack) {
                                                var stackedVal = Number(ds.data[index]);
                                                if (stackedVal < 0) {
                                                        sumNeg += stackedVal || 0;
@@ -460,20 +525,16 @@ module.exports = function(Chart) {
                        var me = this;
                        var meta = me.getMeta();
                        var yScale = me.getScaleForId(meta.yAxisID);
-                       var barIndex = me.getBarIndex(datasetIndex);
+                       var stackIndex = me.getStackIndex(datasetIndex);
                        var topTick = yScale.getPixelForValue(null, index, datasetIndex, me.chart.isCombo);
                        topTick -= me.chart.isCombo ? (ruler.tickHeight / 2) : 0;
 
-                       if (yScale.options.stacked) {
-                               return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
-                       }
-
                        return topTick +
                                (ruler.barHeight / 2) +
                                ruler.categorySpacing +
-                               (ruler.barHeight * barIndex) +
+                               (ruler.barHeight * stackIndex) +
                                (ruler.barSpacing / 2) +
-                               (ruler.barSpacing * barIndex);
+                               (ruler.barSpacing * stackIndex);
                }
        });
 };
index 301af6bc98690d78e7f206e18300aab2f0825ff1..319243b23e5b566d666c8ae7d628b584ab95d4bb 100644 (file)
@@ -28,21 +28,43 @@ module.exports = function(Chart) {
                        me.min = null;
                        me.max = null;
 
-                       if (opts.stacked) {
-                               var valuesPerType = {};
+                       var hasStacks = opts.stacked;
+                       if (hasStacks === undefined) {
+                               helpers.each(datasets, function(dataset, datasetIndex) {
+                                       if (hasStacks) {
+                                               return;
+                                       }
+
+                                       var meta = chart.getDatasetMeta(datasetIndex);
+                                       if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                               meta.stack !== undefined) {
+                                               hasStacks = true;
+                                       }
+                               });
+                       }
+
+                       if (opts.stacked || hasStacks) {
+                               var valuesPerStack = {};
 
                                helpers.each(datasets, function(dataset, datasetIndex) {
                                        var meta = chart.getDatasetMeta(datasetIndex);
-                                       if (valuesPerType[meta.type] === undefined) {
-                                               valuesPerType[meta.type] = {
+                                       var key = [
+                                               meta.type,
+                                               // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                               ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                               meta.stack
+                                       ].join('.');
+
+                                       if (valuesPerStack[key] === undefined) {
+                                               valuesPerStack[key] = {
                                                        positiveValues: [],
                                                        negativeValues: []
                                                };
                                        }
 
                                        // Store these per type
-                                       var positiveValues = valuesPerType[meta.type].positiveValues;
-                                       var negativeValues = valuesPerType[meta.type].negativeValues;
+                                       var positiveValues = valuesPerStack[key].positiveValues;
+                                       var negativeValues = valuesPerStack[key].negativeValues;
 
                                        if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
                                                helpers.each(dataset.data, function(rawValue, index) {
@@ -65,7 +87,7 @@ module.exports = function(Chart) {
                                        }
                                });
 
-                               helpers.each(valuesPerType, function(valuesForType) {
+                               helpers.each(valuesPerStack, function(valuesForType) {
                                        var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
                                        var minVal = helpers.min(values);
                                        var maxVal = helpers.max(values);
index 160d35f23fdda9b825cdb20aa3d19395c71942b6..5d1d329f9ab0d21a48a772c9bb0947ad05dc3f39 100644 (file)
@@ -32,18 +32,40 @@ module.exports = function(Chart) {
                        me.max = null;
                        me.minNotZero = null;
 
-                       if (opts.stacked) {
-                               var valuesPerType = {};
+                       var hasStacks = opts.stacked;
+                       if (hasStacks === undefined) {
+                               helpers.each(datasets, function(dataset, datasetIndex) {
+                                       if (hasStacks) {
+                                               return;
+                                       }
+
+                                       var meta = chart.getDatasetMeta(datasetIndex);
+                                       if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
+                                               meta.stack !== undefined) {
+                                               hasStacks = true;
+                                       }
+                               });
+                       }
+
+                       if (opts.stacked || hasStacks) {
+                               var valuesPerStack = {};
 
                                helpers.each(datasets, function(dataset, datasetIndex) {
                                        var meta = chart.getDatasetMeta(datasetIndex);
+                                       var key = [
+                                               meta.type,
+                                               // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
+                                               ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
+                                               meta.stack
+                                       ].join('.');
+
                                        if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
-                                               if (valuesPerType[meta.type] === undefined) {
-                                                       valuesPerType[meta.type] = [];
+                                               if (valuesPerStack[key] === undefined) {
+                                                       valuesPerStack[key] = [];
                                                }
 
                                                helpers.each(dataset.data, function(rawValue, index) {
-                                                       var values = valuesPerType[meta.type];
+                                                       var values = valuesPerStack[key];
                                                        var value = +me.getRightValue(rawValue);
                                                        if (isNaN(value) || meta.data[index].hidden) {
                                                                return;
@@ -61,7 +83,7 @@ module.exports = function(Chart) {
                                        }
                                });
 
-                               helpers.each(valuesPerType, function(valuesForType) {
+                               helpers.each(valuesPerStack, function(valuesForType) {
                                        var minVal = helpers.min(valuesForType);
                                        var maxVal = helpers.max(valuesForType);
                                        me.min = me.min === null ? minVal : Math.min(me.min, minVal);
index fea88633ce9d218c0cc7590f9aea86885432d14e..38f1b733a1add2f9e40a3ffda2871ee882be8dfc 100644 (file)
@@ -52,41 +52,612 @@ describe('Bar controller tests', function() {
                expect(meta.yAxisID).toBe('firstYScaleID');
        });
 
-       it('should correctly count the number of bar datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: [], type: 'line'},
-                                       {data: [], hidden: true},
-                                       {data: []},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
+       it('should correctly count the number of stacks ignoring datasets of other types and hidden datasets', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], type: 'line'},
+                                               {data: [], hidden: true},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackCount()).toBe(2);
                });
+       });
 
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller.getBarCount()).toBe(2);
+       it('should correctly count the number of stacks when a group is not specified', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackCount()).toBe(4);
+               });
        });
 
-       it('should correctly get the bar index accounting for hidden datasets', function() {
-               var chart = window.acquireChart({
-                       type: 'bar',
-                       data: {
-                               datasets: [
-                                       {data: []},
-                                       {data: [], hidden: true},
-                                       {data: [], type: 'line'},
-                                       {data: []}
-                               ],
-                               labels: []
-                       }
+       it('should correctly count the number of stacks when a group is not specified and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackCount()).toBe(1);
                });
+       });
 
-               var meta = chart.getDatasetMeta(1);
-               expect(meta.controller.getBarIndex(0)).toBe(0);
-               expect(meta.controller.getBarIndex(3)).toBe(1);
+       it('should correctly count the number of stacks when a group is not specified and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackCount()).toBe(4);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for some', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(3);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for some and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(2);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for some and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(4);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for all', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(2);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for all and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(2);
+               });
+       });
+
+       it('should correctly count the number of stacks when a group is specified for all and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(3);
+                       expect(meta.controller.getStackCount()).toBe(4);
+               });
+       });
+
+       it('should correctly get the stack index accounting for datasets of other types and hidden datasets', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: [], hidden: true},
+                                               {data: [], type: 'line'},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(3)).toBe(1);
+               });
+       });
+
+       it('should correctly get the stack index when a group is not specified', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(1);
+                       expect(meta.controller.getStackIndex(2)).toBe(2);
+                       expect(meta.controller.getStackIndex(3)).toBe(3);
+               });
+       });
+
+       it('should correctly get the stack index when a group is not specified and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(0);
+                       expect(meta.controller.getStackIndex(2)).toBe(0);
+                       expect(meta.controller.getStackIndex(3)).toBe(0);
+               });
+       });
+
+       it('should correctly get the stack index when a group is not specified and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: []},
+                                               {data: []},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(1);
+                       expect(meta.controller.getStackIndex(2)).toBe(2);
+                       expect(meta.controller.getStackIndex(3)).toBe(3);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for some', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(0);
+                       expect(meta.controller.getStackIndex(2)).toBe(1);
+                       expect(meta.controller.getStackIndex(3)).toBe(2);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for some and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(0);
+                       expect(meta.controller.getStackIndex(2)).toBe(1);
+                       expect(meta.controller.getStackIndex(3)).toBe(1);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for some and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: []},
+                                               {data: []}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(1);
+                       expect(meta.controller.getStackIndex(2)).toBe(2);
+                       expect(meta.controller.getStackIndex(3)).toBe(3);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for all', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(0);
+                       expect(meta.controller.getStackIndex(2)).toBe(1);
+                       expect(meta.controller.getStackIndex(3)).toBe(1);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for all and the scale is stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(0);
+                       expect(meta.controller.getStackIndex(2)).toBe(1);
+                       expect(meta.controller.getStackIndex(3)).toBe(1);
+               });
+       });
+
+       it('should correctly get the stack index when a group is specified for all and the scale is not stacked', function() {
+               [
+                       'bar',
+                       'horizontalBar'
+               ].forEach(function(barType) {
+                       var chart = window.acquireChart({
+                               type: barType,
+                               data: {
+                                       datasets: [
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack1'},
+                                               {data: [], stack: 'stack2'},
+                                               {data: [], stack: 'stack2'}
+                                       ],
+                                       labels: []
+                               },
+                               options: {
+                                       scales: {
+                                               xAxes: [{
+                                                       stacked: false
+                                               }],
+                                               yAxes: [{
+                                                       stacked: false
+                                               }]
+                                       }
+                               }
+                       });
+
+                       var meta = chart.getDatasetMeta(1);
+                       expect(meta.controller.getStackIndex(0)).toBe(0);
+                       expect(meta.controller.getStackIndex(1)).toBe(1);
+                       expect(meta.controller.getStackIndex(2)).toBe(2);
+                       expect(meta.controller.getStackIndex(3)).toBe(3);
+               });
        });
 
        it('should create rectangle elements for each data item during initialization', function() {
@@ -239,9 +810,7 @@ describe('Bar controller tests', function() {
                        options: {
                                scales: {
                                        xAxes: [{
-                                               type: 'category',
-                                               stacked: true,
-                                               barPercentage: 1
+                                               type: 'category'
                                        }],
                                        yAxes: [{
                                                type: 'linear',
@@ -254,10 +823,10 @@ describe('Bar controller tests', function() {
                var meta0 = chart.getDatasetMeta(0);
 
                [
-                       {b: 290, w: 93, x: 86, y: 161},
-                       {b: 290, w: 93, x: 202, y: 419},
-                       {b: 290, w: 93, x: 318, y: 161},
-                       {b: 290, w: 93, x: 436, y: 419}
+                       {b: 290, w: 83, x: 86, y: 161},
+                       {b: 290, w: 83, x: 202, y: 419},
+                       {b: 290, w: 83, x: 318, y: 161},
+                       {b: 290, w: 83, x: 434, y: 419}
                ].forEach(function(values, i) {
                        expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
                        expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
@@ -268,10 +837,10 @@ describe('Bar controller tests', function() {
                var meta1 = chart.getDatasetMeta(1);
 
                [
-                       {b: 161, w: 93, x: 86, y: 32},
-                       {b: 290, w: 93, x: 202, y: 97},
-                       {b: 161, w: 93, x: 318, y: 161},
-                       {b: 419, w: 93, x: 436, y: 471}
+                       {b: 161, w: 83, x: 86, y: 32},
+                       {b: 290, w: 83, x: 202, y: 97},
+                       {b: 161, w: 83, x: 318, y: 161},
+                       {b: 419, w: 83, x: 434, y: 471}
                ].forEach(function(values, i) {
                        expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
                        expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
@@ -296,9 +865,7 @@ describe('Bar controller tests', function() {
                        options: {
                                scales: {
                                        xAxes: [{
-                                               type: 'category',
-                                               stacked: true,
-                                               barPercentage: 1
+                                               type: 'category'
                                        }],
                                        yAxes: [{
                                                type: 'linear',
@@ -311,10 +878,10 @@ describe('Bar controller tests', function() {
                var meta0 = chart.getDatasetMeta(0);
 
                [
-                       {b: 290, w: 93, x: 86, y: 161},
-                       {b: 290, w: 93, x: 202, y: 419},
-                       {b: 290, w: 93, x: 318, y: 161},
-                       {b: 290, w: 93, x: 436, y: 419}
+                       {b: 290, w: 83, x: 86, y: 161},
+                       {b: 290, w: 83, x: 202, y: 419},
+                       {b: 290, w: 83, x: 318, y: 161},
+                       {b: 290, w: 83, x: 434, y: 419}
                ].forEach(function(values, i) {
                        expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
                        expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
@@ -325,10 +892,10 @@ describe('Bar controller tests', function() {
                var meta1 = chart.getDatasetMeta(1);
 
                [
-                       {b: 161, w: 93, x: 86, y: 32},
-                       {b: 290, w: 93, x: 202, y: 97},
-                       {b: 161, w: 93, x: 318, y: 161},
-                       {b: 419, w: 93, x: 436, y: 471}
+                       {b: 161, w: 83, x: 86, y: 32},
+                       {b: 290, w: 83, x: 202, y: 97},
+                       {b: 161, w: 83, x: 318, y: 161},
+                       {b: 419, w: 83, x: 434, y: 471}
                ].forEach(function(values, i) {
                        expect(meta1.data[i]._model.base).toBeCloseToPixel(values.b);
                        expect(meta1.data[i]._model.width).toBeCloseToPixel(values.w);
@@ -337,6 +904,144 @@ describe('Bar controller tests', function() {
                });
        });
 
+       it('should get the correct bar points for grouped stacked chart if the group name is same', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       data: [10, -10, 10, -10],
+                                       label: 'dataset1',
+                                       stack: 'stack1'
+                               }, {
+                                       data: [10, 15, 0, -4],
+                                       label: 'dataset2',
+                                       stack: 'stack1'
+                               }],
+                               labels: ['label1', 'label2', 'label3', 'label4']
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               type: 'category'
+                                       }],
+                                       yAxes: [{
+                                               type: 'linear',
+                                               stacked: true
+                                       }]
+                               }
+                       }
+               });
+
+               var meta0 = chart.getDatasetMeta(0);
+
+               [
+                       {b: 290, w: 83, x: 86, y: 161},
+                       {b: 290, w: 83, x: 202, y: 419},
+                       {b: 290, w: 83, x: 318, y: 161},
+                       {b: 290, w: 83, x: 434, y: 419}
+               ].forEach(function(values, i) {
+                       expect(meta0.data[i]._model.base).toBeCloseToPixel(values.b);
+                       expect(meta0.data[i]._model.width).toBeCloseToPixel(values.w);
+                       expect(meta0.data[i]._model.x).toBeCloseToPixel(values.x);
+                       expect(meta0.data[i]._model.y).toBeCloseToPixel(values.y);
+               });
+
+               var meta = chart.getDatasetMeta(1);
+
+               [
+                       {b: 161, w: 83, x: 86, y: 32},
+                       {b: 290, w: 83, x: 202, y: 97},
+                       {b: 161, w: 83, x: 318, y: 161},
+                       {b: 419, w: 83, x: 434, y: 471}
+               ].forEach(function(values, i) {
+                       expect(meta.data[i]._model.base).toBeCloseToPixel(values.b);
+                       expect(meta.data[i]._model.width).toBeCloseToPixel(values.w);
+                       expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
+                       expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
+               });
+       });
+
+       it('should get the correct bar points for grouped stacked chart if the group name is different', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       data: [1, 2],
+                                       stack: 'stack1'
+                               }, {
+                                       data: [1, 2],
+                                       stack: 'stack2'
+                               }],
+                               labels: ['label1', 'label2', 'label3', 'label4']
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               type: 'category'
+                                       }],
+                                       yAxes: [{
+                                               stacked: true,
+                                               type: 'linear'
+                                       }]
+                               }
+                       }
+               });
+
+               var meta = chart.getDatasetMeta(1);
+
+               [
+                       {x: 108, y: 258},
+                       {x: 224, y: 32}
+               ].forEach(function(values, i) {
+                       expect(meta.data[i]._model.base).toBeCloseToPixel(484);
+                       expect(meta.data[i]._model.width).toBeCloseToPixel(40);
+                       expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
+                       expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
+               });
+       });
+
+       it('should get the correct bar points for grouped stacked chart', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       data: [1, 2],
+                                       stack: 'stack1'
+                               }, {
+                                       data: [0.5, 1],
+                                       stack: 'stack2'
+                               }, {
+                                       data: [0.5, 1],
+                                       stack: 'stack2'
+                               }],
+                               labels: ['label1', 'label2', 'label3', 'label4']
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               type: 'category'
+                                       }],
+                                       yAxes: [{
+                                               stacked: true,
+                                               type: 'linear'
+                                       }]
+                               }
+                       }
+               });
+
+               var meta = chart.getDatasetMeta(2);
+
+               [
+                       {b: 371, x: 108, y: 258},
+                       {b: 258, x: 224, y: 32}
+               ].forEach(function(values, i) {
+                       expect(meta.data[i]._model.base).toBeCloseToPixel(values.b);
+                       expect(meta.data[i]._model.width).toBeCloseToPixel(40);
+                       expect(meta.data[i]._model.x).toBeCloseToPixel(values.x);
+                       expect(meta.data[i]._model.y).toBeCloseToPixel(values.y);
+               });
+       });
+
        it('should update elements when the scales are stacked and the y axis is logarithmic', function() {
                var chart = window.acquireChart({
                        type: 'bar',
@@ -564,10 +1269,11 @@ describe('Bar controller tests', function() {
                        var chart = window.acquireChart(this.config);
                        var meta = chart.getDatasetMeta(0);
                        var xScale = chart.scales[meta.xAxisID];
+                       var yScale = chart.scales[meta.yAxisID];
 
                        var categoryPercentage = xScale.options.categoryPercentage;
                        var barPercentage = xScale.options.barPercentage;
-                       var stacked = xScale.options.stacked;
+                       var stacked = yScale.options.stacked;
 
                        var totalBarWidth = 0;
                        for (var i = 0; i < chart.data.datasets.length; i++) {
@@ -613,8 +1319,10 @@ describe('Bar controller tests', function() {
                                                        ticks: {
                                                                min: 'March',
                                                                max: 'May',
-                                                       },
-                                                       stacked: true,
+                                                       }
+                                               }],
+                                               yAxes: [{
+                                                       stacked: true
                                                }]
                                        }
                                }
@@ -638,11 +1346,12 @@ describe('Bar controller tests', function() {
                afterEach(function() {
                        var chart = window.acquireChart(this.config);
                        var meta = chart.getDatasetMeta(0);
+                       var xScale = chart.scales[meta.xAxisID];
                        var yScale = chart.scales[meta.yAxisID];
 
                        var categoryPercentage = yScale.options.categoryPercentage;
                        var barPercentage = yScale.options.barPercentage;
-                       var stacked = yScale.options.stacked;
+                       var stacked = xScale.options.stacked;
 
                        var totalBarHeight = 0;
                        for (var i = 0; i < chart.data.datasets.length; i++) {
@@ -684,12 +1393,14 @@ describe('Bar controller tests', function() {
                                data: this.data,
                                options: {
                                        scales: {
+                                               xAxes: [{
+                                                       stacked: true
+                                               }],
                                                yAxes: [{
                                                        ticks: {
                                                                min: 'March',
                                                                max: 'May',
-                                                       },
-                                                       stacked: true,
+                                                       }
                                                }]
                                        }
                                }