From a3dddb45d908d0fc47b8a1dba13aa820b2b74a43 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Sun, 1 Mar 2020 16:07:39 +0200 Subject: [PATCH] Use global element hidden status for Pie charts (#7156) Use global element hidden status for Pie / polarArea charts --- docs/developers/api.md | 17 +++++++++++++++++ docs/getting-started/v3-migration.md | 1 + src/controllers/controller.doughnut.js | 21 +++++---------------- src/controllers/controller.polarArea.js | 20 ++++++-------------- src/core/core.controller.js | 11 ++++++----- src/core/core.datasetController.js | 7 +++---- src/core/core.element.js | 1 - test/specs/core.controller.tests.js | 13 ++++++++----- test/specs/global.defaults.tests.js | 16 ++++++---------- 9 files changed, 52 insertions(+), 55 deletions(-) diff --git a/docs/developers/api.md b/docs/developers/api.md index 77f184d24..b60ed1928 100644 --- a/docs/developers/api.md +++ b/docs/developers/api.md @@ -166,6 +166,23 @@ chart.setDataVisibility(0, 2, false); // hides the item in dataset 0, at index 2 chart.update(); // chart now renders with item hidden ``` +## toggleDataVisibility(index) + +Toggles the visibility of an item in all datasets. A dataset needs to explicitly support this feature for it to have an effect. From internal chart types, doughnut / pie and polar area use this. + +```javascript +chart.toggleDataVisibility(2); // toggles the item in all datasets, at index 2 +chart.update(); // chart now renders with item hidden +``` + +## getDataVisibility(index) + +Returns the stored visibility state of an data index for all datasets. Set by [toggleDataVisibility](#toggleDataVisibility). A dataset controller should use this method to determine if an item should not be visible. + +```javascript +var visible = chart.getDataVisibility(2); +``` + ## hide(datasetIndex) Sets the visibility for the given dataset to false. Updates the chart and animates the dataset with `'hide'` mode. This animation can be configured under the `hide` key in animation options. Please see [animations](../configuration/animations.md) docs for more details. diff --git a/docs/getting-started/v3-migration.md b/docs/getting-started/v3-migration.md index 1df1a3192..73c27c065 100644 --- a/docs/getting-started/v3-migration.md +++ b/docs/getting-started/v3-migration.md @@ -104,6 +104,7 @@ Animation system was completely rewritten in Chart.js v3. Each property can now * `DatasetController.createMetaDataset` * `Element.getArea` * `Element.height` +* `Element.hidden` was replaced by chart level status, usable with `getDataVisibility(index)` / `toggleDataVisibility(index)` * `Element.initialize` * `Element.inLabelRange` * `helpers.addEvent` diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 362125447..361322de9 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -36,7 +36,7 @@ defaults.set('doughnut', { fillStyle: style.backgroundColor, strokeStyle: style.borderColor, lineWidth: style.borderWidth, - hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden, + hidden: !chart.getDataVisibility(i), // Extra data used for toggling the correct item index: i @@ -48,19 +48,8 @@ defaults.set('doughnut', { }, onClick(e, legendItem) { - const index = legendItem.index; - const chart = this.chart; - let i, ilen, meta; - - for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { - meta = chart.getDatasetMeta(i); - // toggle visibility of index if exists - if (meta.data[index]) { - meta.data[index].hidden = !meta.data[index].hidden; - } - } - - chart.update(); + this.chart.toggleDataVisibility(legendItem.index); + this.chart.update(); } }, @@ -202,7 +191,7 @@ export default class DoughnutController extends DatasetController { const me = this; const opts = me.chart.options; const meta = me._cachedMeta; - return reset && opts.animation.animateRotate ? 0 : meta.data[i].hidden ? 0 : me.calculateCircumference(meta._parsed[i] * opts.circumference / DOUBLE_PI); + return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * opts.circumference / DOUBLE_PI) : 0; } updateElements(arcs, start, mode) { @@ -258,7 +247,7 @@ export default class DoughnutController extends DatasetController { for (i = 0; i < metaData.length; i++) { const value = meta._parsed[i]; - if (!isNaN(value) && !metaData[i].hidden) { + if (!isNaN(value) && this.chart.getDataVisibility(i)) { total += Math.abs(value); } } diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 28a92fbed..8d6475530 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -44,7 +44,7 @@ defaults.set('polarArea', { fillStyle: style.backgroundColor, strokeStyle: style.borderColor, lineWidth: style.borderWidth, - hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden, + hidden: !chart.getDataVisibility(i), // Extra data used for toggling the correct item index: i @@ -56,16 +56,8 @@ defaults.set('polarArea', { }, onClick(e, legendItem) { - const index = legendItem.index; - const chart = this.chart; - let 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; - } - - chart.update(); + this.chart.toggleDataVisibility(legendItem.index); + this.chart.update(); } }, @@ -160,7 +152,7 @@ export default class PolarAreaController extends DatasetController { const index = start + i; let startAngle = angle; let endAngle = angle + me._computeAngle(index); - let outerRadius = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); + let outerRadius = this.chart.getDataVisibility(index) ? scale.getDistanceFromCenterForValue(dataset.data[index]) : 0; angle = endAngle; if (reset) { @@ -193,7 +185,7 @@ export default class PolarAreaController extends DatasetController { let count = 0; meta.data.forEach((element, index) => { - if (!isNaN(dataset.data[index]) && !element.hidden) { + if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { count++; } }); @@ -210,7 +202,7 @@ export default class PolarAreaController extends DatasetController { const count = meta.count; const dataset = me.getDataset(); - if (isNaN(dataset.data[index]) || meta.data[index].hidden) { + if (isNaN(dataset.data[index]) || !this.chart.getDataVisibility(index)) { return 0; } diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 5f8ef2f81..731888b8c 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -222,6 +222,7 @@ export default class Chart { this.scale = undefined; this.$plugins = undefined; this.$proxies = {}; + this._hiddenIndices = {}; // Add the chart instance to the global namespace Chart.instances[me.id] = me; @@ -864,12 +865,12 @@ export default class Chart { meta.hidden = !visible; } - setDataVisibility(datasetIndex, index, visible) { - const meta = this.getDatasetMeta(datasetIndex); + toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + } - if (meta.data[index]) { - meta.data[index].hidden = !visible; - } + getDataVisibility(index) { + return !this._hiddenIndices[index]; } /** diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 752bb5b27..02f6ab03a 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -624,7 +624,7 @@ export default class DatasetController { */ getMinMax(scale, canStack) { const meta = this._cachedMeta; - const {data, _parsed} = meta; + const _parsed = meta._parsed; const sorted = meta._sorted && scale === meta.iScale; const ilen = _parsed.length; const otherScale = this._getOtherScale(scale); @@ -632,7 +632,7 @@ export default class DatasetController { let min = Number.POSITIVE_INFINITY; let max = Number.NEGATIVE_INFINITY; const {min: otherMin, max: otherMax} = getUserBounds(otherScale); - let i, item, value, parsed, otherValue; + let i, value, parsed, otherValue; function _compute() { if (stack) { @@ -648,11 +648,10 @@ export default class DatasetController { } function _skip() { - item = data[i]; parsed = _parsed[i]; value = parsed[scale.axis]; otherValue = parsed[otherScale.axis]; - return ((item && item.hidden) || isNaN(value) || otherMin > otherValue || otherMax < otherValue); + return (isNaN(value) || otherMin > otherValue || otherMax < otherValue); } for (i = 0; i < ilen; ++i) { diff --git a/src/core/core.element.js b/src/core/core.element.js index db4ebaa63..5e4aa7934 100644 --- a/src/core/core.element.js +++ b/src/core/core.element.js @@ -8,7 +8,6 @@ export default class Element { constructor(cfg) { this.x = undefined; this.y = undefined; - this.hidden = false; this.active = false; this.options = undefined; this.$animations = undefined; diff --git a/test/specs/core.controller.tests.js b/test/specs/core.controller.tests.js index e234862db..42832301c 100644 --- a/test/specs/core.controller.tests.js +++ b/test/specs/core.controller.tests.js @@ -1365,9 +1365,9 @@ describe('Chart', function() { expect(meta.hidden).toBe(true); }); - it('should hide a single data item', function() { + it('should toggle data visibility by index', function() { var chart = acquireChart({ - type: 'polarArea', + type: 'pie', data: { datasets: [{ data: [1, 2, 3] @@ -1375,10 +1375,13 @@ describe('Chart', function() { } }); - chart.setDataVisibility(0, 1, false); + expect(chart.getDataVisibility(1)).toBe(true); - var meta = chart.getDatasetMeta(0); - expect(meta.data[1].hidden).toBe(true); + chart.toggleDataVisibility(1); + expect(chart.getDataVisibility(1)).toBe(false); + + chart.update(); + expect(chart.getDataVisibility(1)).toBe(false); }); }); }); diff --git a/test/specs/global.defaults.tests.js b/test/specs/global.defaults.tests.js index bf9e589d1..30652473a 100644 --- a/test/specs/global.defaults.tests.js +++ b/test/specs/global.defaults.tests.js @@ -121,7 +121,7 @@ describe('Default Configs', function() { }, { text: 'label3', fillStyle: 'blue', - hidden: true, + hidden: false, index: 2, strokeStyle: '#000', lineWidth: 2 @@ -144,18 +144,16 @@ describe('Default Configs', function() { }, options: config }); - var meta = chart.getDatasetMeta(0); - spyOn(chart, 'update').and.callThrough(); var legendItem = chart.legend.legendItems[0]; config.legend.onClick.call(chart.legend, null, legendItem); - expect(meta.data[0].hidden).toBe(true); + expect(chart.getDataVisibility(0)).toBe(false); expect(chart.update).toHaveBeenCalled(); config.legend.onClick.call(chart.legend, null, legendItem); - expect(meta.data[0].hidden).toBe(false); + expect(chart.getDataVisibility(0)).toBe(true); }); }); @@ -219,7 +217,7 @@ describe('Default Configs', function() { }, { text: 'label3', fillStyle: 'blue', - hidden: true, + hidden: false, index: 2, strokeStyle: '#000', lineWidth: 2 @@ -242,18 +240,16 @@ describe('Default Configs', function() { }, options: config }); - var meta = chart.getDatasetMeta(0); - spyOn(chart, 'update').and.callThrough(); var legendItem = chart.legend.legendItems[0]; config.legend.onClick.call(chart.legend, null, legendItem); - expect(meta.data[0].hidden).toBe(true); + expect(chart.getDataVisibility(0)).toBe(false); expect(chart.update).toHaveBeenCalled(); config.legend.onClick.call(chart.legend, null, legendItem); - expect(meta.data[0].hidden).toBe(false); + expect(chart.getDataVisibility(0)).toBe(true); }); }); }); -- 2.47.2