Skip to content

Commit

Permalink
Add ability to hide specific data element (#9450)
Browse files Browse the repository at this point in the history
  • Loading branch information
kurkle committed Jul 21, 2021
1 parent 151188e commit cf951ac
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 19 deletions.
14 changes: 10 additions & 4 deletions docs/developers/api.md
Expand Up @@ -152,20 +152,26 @@ Returns the stored visibility state of an data index for all datasets. Set by [t
var visible = chart.getDataVisibility(2);
```

## hide(datasetIndex)
## hide(datasetIndex, dataIndex?)

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.
If dataIndex is not specified, 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.

If dataIndex is specified, sets the hidden flag of that element to true and updates the chart.

```javascript
chart.hide(1); // hides dataset at index 1 and does 'hide' animation.
chart.hide(0, 2); // hides the data element at index 2 of the first dataset.
```

## show(datasetIndex)
## show(datasetIndex, dataIndex?)

If dataIndex is not specified, sets the visibility for the given dataset to true. Updates the chart and animates the dataset with `'show'` mode. This animation can be configured under the `show` key in animation options. Please see [animations](../configuration/animations.md) docs for more details.

Sets the visibility for the given dataset to true. Updates the chart and animates the dataset with `'show'` mode. This animation can be configured under the `show` key in animation options. Please see [animations](../configuration/animations.md) docs for more details.
If dataIndex is specified, sets the hidden flag of that element to false and updates the chart.

```javascript
chart.show(1); // shows dataset at index 1 and does 'show' animation.
chart.show(0, 2); // shows the data element at index 2 of the first dataset.
```

## setActiveElements(activeElements)
Expand Down
24 changes: 24 additions & 0 deletions docs/samples/other-charts/doughnut.md
Expand Up @@ -48,6 +48,30 @@ const actions = [
}
}
},
{
name: 'Hide(0)',
handler(chart) {
chart.hide(0);
}
},
{
name: 'Show(0)',
handler(chart) {
chart.show(0);
}
},
{
name: 'Hide (0, 1)',
handler(chart) {
chart.hide(0, 1);
}
},
{
name: 'Show (0, 1)',
handler(chart) {
chart.show(0, 1);
}
},
{
name: 'Remove Dataset',
handler(chart) {
Expand Down
4 changes: 2 additions & 2 deletions src/controllers/controller.doughnut.js
Expand Up @@ -145,7 +145,7 @@ export default class DoughnutController extends DatasetController {
const opts = me.options;
const meta = me._cachedMeta;
const circumference = me._getCircumference();
if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null) {
if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
return 0;
}
return me.calculateCircumference(meta._parsed[i] * circumference / TAU);
Expand Down Expand Up @@ -203,7 +203,7 @@ export default class DoughnutController extends DatasetController {

for (i = 0; i < metaData.length; i++) {
const value = meta._parsed[i];
if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i)) {
if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
total += Math.abs(value);
}
}
Expand Down
26 changes: 15 additions & 11 deletions src/core/core.controller.js
Expand Up @@ -7,7 +7,7 @@ import PluginService from './core.plugins';
import registry from './core.registry';
import Config, {determineAxis, getIndexAxis} from './core.config';
import {retinaScale, _isDomSupported} from '../helpers/helpers.dom';
import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual} from '../helpers/helpers.core';
import {each, callback as callCallback, uid, valueOrDefault, _elementsEqual, isNullOrUndef, setsEqual, defined} from '../helpers/helpers.core';
import {clearCanvas, clipArea, unclipArea, _isPointInArea} from '../helpers/helpers.canvas';
// @ts-ignore
import {version} from '../../package.json';
Expand Down Expand Up @@ -794,25 +794,29 @@ class Chart {
/**
* @private
*/
_updateDatasetVisibility(datasetIndex, visible) {
_updateVisibility(datasetIndex, dataIndex, visible) {
const me = this;
const mode = visible ? 'show' : 'hide';
const meta = me.getDatasetMeta(datasetIndex);
const anims = meta.controller._resolveAnimations(undefined, mode);
me.setDatasetVisibility(datasetIndex, visible);

// Animate visible state, so hide animation can be seen. This could be handled better if update / updateDataset returned a Promise.
anims.update(meta, {visible});

me.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);
if (defined(dataIndex)) {
meta.data[dataIndex].hidden = !visible;
me.update();
} else {
me.setDatasetVisibility(datasetIndex, visible);
// Animate visible state, so hide animation can be seen. This could be handled better if update / updateDataset returned a Promise.
anims.update(meta, {visible});
me.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);
}
}

hide(datasetIndex) {
this._updateDatasetVisibility(datasetIndex, false);
hide(datasetIndex, dataIndex) {
this._updateVisibility(datasetIndex, dataIndex, false);
}

show(datasetIndex) {
this._updateDatasetVisibility(datasetIndex, true);
show(datasetIndex, dataIndex) {
this._updateVisibility(datasetIndex, dataIndex, true);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions src/core/core.datasetController.js
Expand Up @@ -701,6 +701,9 @@ export default class DatasetController {

for (i = start; i < start + count; ++i) {
const element = elements[i];
if (element.hidden) {
continue;
}
if (element.active) {
active.push(element);
} else {
Expand Down
42 changes: 42 additions & 0 deletions test/fixtures/controller.doughnut/doughnut-hidden-single.js
@@ -0,0 +1,42 @@
module.exports = {
config: {
type: 'doughnut',
data: {
labels: ['A', 'B', 'C', 'D', 'E'],
datasets: [{
data: [1, 5, 10, 50, 100],
backgroundColor: [
'rgba(255, 99, 132, 0.8)',
'rgba(54, 162, 235, 0.8)',
'rgba(255, 206, 86, 0.8)',
'rgba(75, 192, 192, 0.8)',
'rgba(153, 102, 255, 0.8)'
],
}, {
data: [1, 5, 10, 50, 100],
backgroundColor: [
'rgba(255, 99, 132, 0.8)',
'rgba(54, 162, 235, 0.8)',
'rgba(255, 206, 86, 0.8)',
'rgba(75, 192, 192, 0.8)',
'rgba(153, 102, 255, 0.8)'
],
}]
},
options: {
responsive: false,
plugins: {
legend: false,
title: false,
tooltip: false,
filler: false
}
},
},
options: {
run(chart) {
chart.hide(0, 4);
chart.hide(1, 2);
}
}
};
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions types/index.esm.d.ts
Expand Up @@ -508,8 +508,8 @@ export declare class Chart<
setDatasetVisibility(datasetIndex: number, visible: boolean): void;
toggleDataVisibility(index: number): void;
getDataVisibility(index: number): boolean;
hide(datasetIndex: number): void;
show(datasetIndex: number): void;
hide(datasetIndex: number, dataIndex?: number): void;
show(datasetIndex: number, dataIndex?: number): void;

getActiveElements(): ActiveElement[];
setActiveElements(active: ActiveDataPoint[]): void;
Expand Down

0 comments on commit cf951ac

Please sign in to comment.