New Chart.Element.hidden bool flag storing the visibility state of its associated data. Since elements belong to a specific chart, this change allows to manage data visibility per chart (e.g. when clicking the legend of some charts).
This commit also changes (fixes?) the polar chart animation when data visibility changes. Previous implementation was affected by an edge effect due to the use of NaN as hidden implementation.
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
- var arc = chart.getDatasetMeta(0).data[i];
+ var arc = meta.data[i];
var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor);
var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor);
var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth);
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
- hidden: isNaN(data.datasets[0].data[i]),
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
// Extra data used for toggling the correct item
index: i
}
}
},
+
onClick: function(e, legendItem) {
- helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
- var meta = this.chart.getDatasetMeta(datasetIndex);
- var idx = legendItem.index;
-
- if (!isNaN(dataset.data[idx])) {
- meta.hiddenData[idx] = dataset.data[idx];
- dataset.data[idx] = NaN;
- } else if (!isNaN(meta.hiddenData[idx])) {
- dataset.data[idx] = meta.hiddenData[idx];
- }
- }, this);
+ var index = legendItem.index;
+ var chart = this.chart;
+ var i, ilen, meta;
+
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ meta.data[index].hidden = !meta.data[index].hidden;
+ }
- this.chart.update();
+ chart.update();
}
},
this.chart.offsetX = offset.x * this.chart.outerRadius;
this.chart.offsetY = offset.y * this.chart.outerRadius;
- this.getDataset().total = 0;
- helpers.each(this.getDataset().data, function(value) {
- if (!isNaN(value)) {
- this.getDataset().total += Math.abs(value);
- }
- }, this);
+ this.getMeta().total = this.calculateTotal();
this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index));
this.innerRadius = this.outerRadius - this.chart.radiusLength;
this.updateElement(arc, index, reset);
}, this);
},
+
updateElement: function(arc, index, reset) {
var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
var startAngle = this.chart.options.rotation; // non reset case handled later
var endAngle = this.chart.options.rotation; // non reset case handled later
- var circumference = reset && this.chart.options.animation.animateRotate ? 0 : this.calculateCircumference(this.getDataset().data[index]) * (this.chart.options.circumference / (2.0 * Math.PI));
+ var circumference = reset && this.chart.options.animation.animateRotate ? 0 : arc.hidden? 0 : this.calculateCircumference(this.getDataset().data[index]) * (this.chart.options.circumference / (2.0 * Math.PI));
var innerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.innerRadius;
var outerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.outerRadius;
arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth);
},
+ calculateTotal: function() {
+ var meta = this.getMeta();
+ var total = 0;
+
+ this.getDataset().data.forEach(function(value, index) {
+ if (!isNaN(value) && !meta.data[index].hidden) {
+ total += Math.abs(value);
+ }
+ });
+
+ return total;
+ },
+
calculateCircumference: function(value) {
- if (this.getDataset().total > 0 && !isNaN(value)) {
- return (Math.PI * 2.0) * (value / this.getDataset().total);
+ var total = this.getMeta().total;
+ if (total > 0 && !isNaN(value)) {
+ return (Math.PI * 2.0) * (value / total);
} else {
return 0;
}
var data = chart.data;
if (data.labels.length && data.datasets.length) {
return data.labels.map(function(label, i) {
+ var meta = chart.getDatasetMeta(0);
var ds = data.datasets[0];
- var arc = chart.getDatasetMeta(0).data[i];
+ var arc = meta.data[i];
var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor);
var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor);
var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth);
fillStyle: fill,
strokeStyle: stroke,
lineWidth: bw,
- hidden: isNaN(data.datasets[0].data[i]),
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
// Extra data used for toggling the correct item
index: i
}
}
},
+
onClick: function(e, legendItem) {
- helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
- var meta = this.chart.getDatasetMeta(datasetIndex);
- var idx = legendItem.index;
-
- if (!isNaN(dataset.data[idx])) {
- meta.hiddenData[idx] = dataset.data[idx];
- dataset.data[idx] = NaN;
- } else if (!isNaN(meta.hiddenData[idx])) {
- dataset.data[idx] = meta.hiddenData[idx];
- }
- }, this);
+ var index = legendItem.index;
+ var chart = this.chart;
+ var i, ilen, meta;
+
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
+ meta = chart.getDatasetMeta(i);
+ meta.data[index].hidden = !meta.data[index].hidden;
+ }
- this.chart.update();
+ chart.update();
}
},
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.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.innerRadius = this.outerRadius - this.chart.radiusLength;
// If there is NaN data before us, we need to calculate the starting angle correctly.
// We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
- var notNullIndex = 0;
+ var visibleCount = 0;
+ var meta = this.getMeta();
for (var i = 0; i < index; ++i) {
- if (!isNaN(this.getDataset().data[i])) {
- ++notNullIndex;
+ if (!isNaN(this.getDataset().data[i]) && !meta.data[i].hidden) {
+ ++visibleCount;
}
}
- var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex);
- var endAngle = startAngle + circumference;
+ var distance = arc.hidden? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]);
+ var startAngle = (-0.5 * Math.PI) + (circumference * visibleCount);
+ var endAngle = startAngle + (arc.hidden? 0 : circumference);
var resetModel = {
x: centerX,
y: centerY,
innerRadius: 0,
- outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
+ outerRadius: this.chart.options.animateScale ? 0 : distance,
startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle,
endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle,
x: centerX,
y: centerY,
innerRadius: 0,
- outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
+ outerRadius: distance,
startAngle: startAngle,
endAngle: endAngle,
calculateCircumference: function(value) {
if (isNaN(value)) {
return 0;
- } else {
- // Count the number of NaN values
- var numNaN = helpers.where(this.getDataset().data, function(data) {
- return isNaN(data);
- }).length;
-
- return (2 * Math.PI) / (this.getDataset().data.length - numNaN);
}
+
+ // Count the number of "visible"" values
+ var meta = this.getMeta();
+ var count = 0;
+
+ this.getDataset().data.forEach(function(value, index) {
+ if (!isNaN(value) && !meta.data[index].hidden) {
+ count++;
+ }
+ });
+
+ return (2 * Math.PI) / count;
}
});
-};
\ No newline at end of file
+};
data: [],
dataset: null,
controller: null,
- hiddenData: {},
hidden: null, // See isDatasetVisible() comment
xAxisID: null,
yAxisID: null
this.initialize.apply(this, arguments);
};
helpers.extend(Chart.Element.prototype, {
- initialize: function() {},
+ initialize: function() {
+ this.hidden = false;
+ },
pivot: function() {
if (!this._view) {
this._view = helpers.clone(this._model);
if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
-
var value = +this.getRightValue(rawValue);
- if (isNaN(value)) {
+ if (isNaN(value) || meta.data[index].hidden) {
return;
}
if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = +this.getRightValue(rawValue);
- if (isNaN(value)) {
+ if (isNaN(value) || meta.data[index].hidden) {
return;
}
helpers.each(dataset.data, function(rawValue, index) {
var values = valuesPerType[meta.type];
var value = +this.getRightValue(rawValue);
- if (isNaN(value)) {
+ if (isNaN(value) || meta.data[index].hidden) {
return;
}
} else {
helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
var meta = this.chart.getDatasetMeta(datasetIndex);
- if (this.chart.isDatasetVisible(dataset, datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) {
+ if (this.chart.isDatasetVisible(datasetIndex) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) {
helpers.each(dataset.data, function(rawValue, index) {
var value = +this.getRightValue(rawValue);
- if (isNaN(value)) {
+ if (isNaN(value) || meta.data[index].hidden) {
return;
}
helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
if (this.chart.isDatasetVisible(datasetIndex)) {
+ var meta = this.chart.getDatasetMeta(datasetIndex);
helpers.each(dataset.data, function(rawValue, index) {
var value = +this.getRightValue(rawValue);
- if (isNaN(value)) {
+ if (isNaN(value) || meta.data[index].hidden) {
return;
}