mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-25 01:26:53 +01:00
Update controllers to handle datasets that are not visible
This commit is contained in:
@@ -66,15 +66,15 @@
|
||||
// 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;
|
||||
},
|
||||
|
||||
@@ -192,14 +192,16 @@
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,10 +227,11 @@
|
||||
|
||||
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++) {
|
||||
@@ -266,14 +269,28 @@
|
||||
|
||||
},
|
||||
|
||||
// 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) {
|
||||
@@ -283,9 +300,9 @@
|
||||
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) {
|
||||
@@ -301,10 +318,13 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,18 +101,35 @@
|
||||
}
|
||||
},
|
||||
|
||||
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) {
|
||||
|
||||
@@ -96,10 +96,14 @@
|
||||
}
|
||||
},
|
||||
|
||||
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) {
|
||||
|
||||
@@ -260,7 +260,9 @@
|
||||
|
||||
// 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
|
||||
@@ -275,12 +277,14 @@
|
||||
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;
|
||||
@@ -291,11 +295,13 @@
|
||||
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;
|
||||
@@ -305,15 +311,17 @@
|
||||
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 : [];
|
||||
},
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user