]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Update controllers to handle datasets that are not visible
authorEvert Timberg <evert.timberg@gmail.com>
Wed, 7 Oct 2015 23:54:11 +0000 (19:54 -0400)
committerEvert Timberg <evert.timberg@gmail.com>
Wed, 7 Oct 2015 23:54:11 +0000 (19:54 -0400)
src/controllers/controller.bar.js
src/controllers/controller.doughnut.js
src/controllers/controller.polarArea.js
src/core/core.controller.js
test/controller.bar.tests.js
test/controller.doughnut.tests.js

index 3ec3be6da2b8eb84b600395aaaee1f59d915538c..a850269a0a994768cff674b46f1574e4f5ce765e 100644 (file)
                // Get the number of datasets that display bars. We use this to correctly calculate the bar width
                getBarCount: function getBarCount() {
                        var barCount = 0;
-
                        helpers.each(this.chart.data.datasets, function(dataset) {
-                               if (dataset.type === 'bar') {
-                                       ++barCount;
-                               } else if (dataset.type === undefined && this.chart.config.type === 'bar') {
-                                       ++barCount;
+                               if (helpers.isDatasetVisible(dataset)) {
+                                       if (dataset.type === 'bar') {
+                                               ++barCount;
+                                       } else if (dataset.type === undefined && this.chart.config.type === 'bar') {
+                                               ++barCount;
+                                       }
                                }
                        }, this);
-
                        return barCount;
                },
 
 
                                if (value < 0) {
                                        for (var i = 0; i < datasetIndex; i++) {
-                                               if (this.chart.data.datasets[i].yAxisID === yScale.id) {
-                                                       base += this.chart.data.datasets[i].data[index] < 0 ? this.chart.data.datasets[i].data[index] : 0;
+                                               var negDS = this.chart.data.datasets[i];
+                                               if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id) {
+                                                       base += negDS.data[index] < 0 ? negDS.data[index] : 0;
                                                }
                                        }
                                } else {
                                        for (var j = 0; j < datasetIndex; j++) {
-                                               if (this.chart.data.datasets[j].yAxisID === yScale.id) {
-                                                       base += this.chart.data.datasets[j].data[index] > 0 ? this.chart.data.datasets[j].data[index] : 0;
+                                               var posDS = this.chart.data.datasets[j];
+                                               if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id) {
+                                                       base += posDS.data[index] > 0 ? posDS.data[index] : 0;
                                                }
                                        }
                                }
 
                        var xScale = this.getScaleForID(this.getDataset().xAxisID);
                        var yScale = this.getScaleForID(this.getDataset().yAxisID);
-
-                       var datasetCount = !this.chart.isCombo ? this.chart.data.datasets.length : helpers.where(this.chart.data.datasets, function(ds) {
+                       /*var datasetCount = !this.chart.isCombo ? this.chart.data.datasets.length : helpers.where(this.chart.data.datasets, function(ds) {
                                return ds.type == 'bar';
-                       }).length;
+                       }).length;*/
+                       var datasetCount = this.getBarCount();
+
                        var tickWidth = (function() {
                                var min = xScale.getPixelForValue(null, 1) - xScale.getPixelForValue(null, 0);
                                for (var i = 2; i < this.getDataset().data.length; i++) {
 
                },
 
+               // Get bar index from the given dataset index accounting for the fact that not all bars are visible
+               getBarIndex: function(datasetIndex) {
+                       var barIndex = 0;
+
+                       for (var j = 0; j < datasetIndex; ++j) {
+                               if (helpers.isDatasetVisible(this.chart.data.datasets[j]) &&
+                                       (this.chart.data.datasets[j].type === 'bar' || (this.chart.data.datasets[j].type === undefined && this.chart.config.type === 'bar'))) {
+                                       ++barIndex;
+                               }
+                       }
+
+                       return barIndex;
+               },
 
                calculateBarX: function(index, datasetIndex) {
 
                        var yScale = this.getScaleForID(this.getDataset().yAxisID);
                        var xScale = this.getScaleForID(this.getDataset().xAxisID);
+                       var barIndex = this.getBarIndex(datasetIndex);
 
                        var ruler = this.getRuler();
-                       var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
+                       var leftTick = xScale.getPixelForValue(null, index, barIndex, this.chart.isCombo);
                        leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
 
                        if (yScale.options.stacked) {
                        return leftTick +
                                (ruler.barWidth / 2) +
                                ruler.categorySpacing +
-                               (ruler.barWidth * datasetIndex) +
+                               (ruler.barWidth * barIndex) +
                                (ruler.barSpacing / 2) +
-                               (ruler.barSpacing * datasetIndex);
+                               (ruler.barSpacing * barIndex);
                },
 
                calculateBarY: function(index, datasetIndex) {
                                        sumNeg = 0;
 
                                for (var i = 0; i < datasetIndex; i++) {
-                                       if (this.chart.data.datasets[i].data[index] < 0) {
-                                               sumNeg += this.chart.data.datasets[i].data[index] || 0;
-                                       } else {
-                                               sumPos += this.chart.data.datasets[i].data[index] || 0;
+                                       var ds = this.chart.data.datasets[i];
+                                       if (helpers.isDatasetVisible(ds)) {
+                                               if (ds.data[index] < 0) {
+                                                       sumNeg += ds.data[index] || 0;
+                                               } else {
+                                                       sumPos += ds.data[index] || 0;
+                                               }
                                        }
                                }
 
index da3386e311a077843730d0e6737bf2a92b6593a3..4ab4850589bf3a8e0c0506f3e57bc55f83c60c8b 100644 (file)
                        }
                },
 
+               getVisibleDatasetCount: function getVisibleDatasetCount() {
+                       return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
+               },
+
+               // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+               getRingIndex: function getRingIndex(datasetIndex) {
+                       var ringIndex = 0;
+
+                       for (var j = 0; j < datasetIndex; ++j) {
+                               if (helpers.isDatasetVisible(this.chart.data.datasets[j])) {
+                                       ++ringIndex;
+                               }
+                       }
+
+                       return ringIndex;
+               },
+
                update: function update(reset) {
 
                        this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
                        this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
-                       this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;
+                       this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
 
                        this.getDataset().total = 0;
                        helpers.each(this.getDataset().data, function(value) {
                                this.getDataset().total += Math.abs(value);
                        }, this);
 
-                       this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index);
+                       this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index));
                        this.innerRadius = this.outerRadius - this.chart.radiusLength;
 
                        helpers.each(this.getDataset().metaData, function(arc, index) {
index c962b9c3870287561a0198ff17963286face26ae..709cc15913c7847714f50630257c3493de5a9370 100644 (file)
                        }
                },
 
+               getVisibleDatasetCount: function getVisibleDatasetCount() {
+                       return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
+               },
+
                update: function update(reset) {
                        this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
                        this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
-                       this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length;
+                       this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
 
                        this.getDataset().total = 0;
                        helpers.each(this.getDataset().data, function(value) {
index 6d8d5e25e2b922ba2b022aef5c13bd5a3f057f9f..773f54319b9f6f9ece60277f487a244edce349be 100644 (file)
 
                        // Draw each dataset via its respective controller (reversed to support proper line stacking)
                        helpers.each(this.data.datasets, function(dataset, datasetIndex) {
-                               dataset.controller.draw(ease);
+                               if (helpers.isDatasetVisible(dataset)) {
+                                       dataset.controller.draw(ease);
+                               }
                        }, this);
 
                        // Finally draw the tooltip
                        var elementsArray = [];
 
                        helpers.each(this.data.datasets, function(dataset, datasetIndex) {
-                               helpers.each(dataset.metaData, function(element, index) {
-                                       if (element.inRange(eventPosition.x, eventPosition.y)) {
-                                               elementsArray.push(element);
-                                               return elementsArray;
-                                       }
-                               }, this);
+                               if (helpers.isDatasetVisible(dataset)) {
+                                       helpers.each(dataset.metaData, function(element, index) {
+                                               if (element.inRange(eventPosition.x, eventPosition.y)) {
+                                                       elementsArray.push(element);
+                                                       return elementsArray;
+                                               }
+                                       }, this);
+                               }
                        }, this);
 
                        return elementsArray;
                        var elementsArray = [];
 
                        helpers.each(this.data.datasets, function(dataset, datasetIndex) {
-                               helpers.each(dataset.metaData, function(element, index) {
-                                       if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
-                                               elementsArray.push(element);
-                                       }
-                               }, this);
+                               if (helpers.isDatasetVisible(dataset)) {
+                                       helpers.each(dataset.metaData, function(element, index) {
+                                               if (element.inLabelRange(eventPosition.x, eventPosition.y)) {
+                                                       elementsArray.push(element);
+                                               }
+                                       }, this);
+                               }
                        }, this);
 
                        return elementsArray;
                        var eventPosition = helpers.getRelativePosition(e, this.chart);
                        var elementsArray = [];
 
-                       for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) {
-                               for (var elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; elementIndex++) {
-                                       if (this.data.datasets[datasetIndex].metaData[elementIndex].inLabelRange(eventPosition.x, eventPosition.y)) {
-                                               helpers.each(this.data.datasets[datasetIndex].metaData, function(element, index) {
-                                                       elementsArray.push(element);
-                                               }, this);
+                       helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+                               if (helpers.isDatasetVisible(dataset)) {
+                                       for (var elementIndex = 0; elementIndex < dataset.metaData.length; elementIndex++) {
+                                               if (dataset.metaData[elementIndex].inLabelRange(eventPosition.x, eventPosition.y)) {
+                                                       helpers.each(dataset.metaData, function(element, index) {
+                                                               elementsArray.push(element);
+                                                       }, this);
+                                               }
                                        }
                                }
-                       }
+                       }, this);
 
                        return elementsArray.length ? elementsArray : [];
                },
index d71dc0986351891208eccbb424649eb68326742c..028ed368aecc0592fe83df75c4ae4917eea60007 100644 (file)
@@ -78,6 +78,39 @@ describe('Bar controller tests', function() {
                expect(controller.getBarCount()).toBe(2);
        });
 
+       it('should correctly get the bar index accounting for hidden datasets', function() {
+               var chart = {
+                       data: {
+                               datasets: [{
+                                       
+                               }, {
+                                       hidden: true
+                               }, {
+                                       type: 'line'
+                               }, {
+                                       
+                               }]
+                       },
+                       config: {
+                               type: 'bar'
+                       },
+                       options: {
+                               scales: {
+                                       xAxes: [{
+                                               id: 'firstXScaleID'
+                                       }],
+                                       yAxes: [{
+                                               id: 'firstYScaleID'
+                                       }]
+                               }
+                       }
+               };
+
+               var controller = new Chart.controllers.bar(chart, 1);
+               expect(controller.getBarIndex(0)).toBe(0);
+               expect(controller.getBarIndex(3)).toBe(1);
+       });
+
        it('Should create rectangle elements for each data item during initialization', function() {
                var chart = {
                        data: {
index d4ff2ff51dc1371d6f044417b23885feaa6f9db1..29811e1117b4a66837921d9b242ef73f943e5ee9 100644 (file)
@@ -68,6 +68,8 @@ describe('Doughnut controller tests', function() {
                        },
                        data: {
                                datasets: [{
+                                       hidden: true
+                               }, {
                                        data: [10, 15, 0, 4]
                                }, {
                                        data: [1]
@@ -94,10 +96,10 @@ describe('Doughnut controller tests', function() {
                        }
                };
 
-               var controller = new Chart.controllers.doughnut(chart, 0);
+               var controller = new Chart.controllers.doughnut(chart, 1);
                controller.reset(); // reset first
 
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[0]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: Math.PI * -0.5,
@@ -106,7 +108,7 @@ describe('Doughnut controller tests', function() {
                        innerRadius: 36.75,
                });
 
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[1]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: Math.PI * -0.5,
@@ -115,7 +117,7 @@ describe('Doughnut controller tests', function() {
                        innerRadius: 36.75,
                });
 
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[2]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: Math.PI * -0.5,
@@ -124,7 +126,7 @@ describe('Doughnut controller tests', function() {
                        innerRadius: 36.75,
                });
 
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[3]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: Math.PI * -0.5,
@@ -135,7 +137,7 @@ describe('Doughnut controller tests', function() {
 
                controller.update();
 
-               expect(chart.data.datasets[0].metaData[0]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[0]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: Math.PI * -0.5,
@@ -152,7 +154,7 @@ describe('Doughnut controller tests', function() {
                        label: 'label0',
                });
 
-               expect(chart.data.datasets[0].metaData[1]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[1]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: 0.5958182130626666,
@@ -169,7 +171,7 @@ describe('Doughnut controller tests', function() {
                        label: 'label1'
                });
 
-               expect(chart.data.datasets[0].metaData[2]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[2]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: 3.8457400228490113,
@@ -186,7 +188,7 @@ describe('Doughnut controller tests', function() {
                        label: 'label2'
                });
 
-               expect(chart.data.datasets[0].metaData[3]._model).toEqual({
+               expect(chart.data.datasets[1].metaData[3]._model).toEqual({
                        x: 50,
                        y: 100,
                        startAngle: 3.8457400228490113,
@@ -204,24 +206,24 @@ describe('Doughnut controller tests', function() {
                });
 
                // Change the amount of data and ensure that arcs are updated accordingly
-               chart.data.datasets[0].data = [1, 2]; // remove 2 elements from dataset 0
+               chart.data.datasets[1].data = [1, 2]; // remove 2 elements from dataset 0
                controller.buildOrUpdateElements();
                controller.update();
 
-               expect(chart.data.datasets[0].metaData.length).toBe(2);
-               expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
-               expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData.length).toBe(2);
+               expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Arc).toBe(true);
 
                // Add data
-               chart.data.datasets[0].data = [1, 2, 3, 4];
+               chart.data.datasets[1].data = [1, 2, 3, 4];
                controller.buildOrUpdateElements();
                controller.update();
 
-               expect(chart.data.datasets[0].metaData.length).toBe(4);
-               expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Arc).toBe(true);
-               expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Arc).toBe(true);
-               expect(chart.data.datasets[0].metaData[2] instanceof Chart.elements.Arc).toBe(true);
-               expect(chart.data.datasets[0].metaData[3] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData.length).toBe(4);
+               expect(chart.data.datasets[1].metaData[0] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData[1] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData[2] instanceof Chart.elements.Arc).toBe(true);
+               expect(chart.data.datasets[1].metaData[3] instanceof Chart.elements.Arc).toBe(true);
        });
 
        it ('should draw all arcs', function() {