GraphSeriesToggler.tsx 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React from 'react';
  2. import { GraphSeriesXY } from '@grafana/data';
  3. import difference from 'lodash/difference';
  4. import isEqual from 'lodash/isEqual';
  5. interface GraphSeriesTogglerAPI {
  6. onSeriesToggle: (label: string, event: React.MouseEvent<HTMLElement>) => void;
  7. toggledSeries: GraphSeriesXY[];
  8. }
  9. interface GraphSeriesTogglerProps {
  10. children: (api: GraphSeriesTogglerAPI) => JSX.Element;
  11. series: GraphSeriesXY[];
  12. onHiddenSeriesChanged?: (hiddenSeries: string[]) => void;
  13. }
  14. interface GraphSeriesTogglerState {
  15. hiddenSeries: string[];
  16. toggledSeries: GraphSeriesXY[];
  17. }
  18. export class GraphSeriesToggler extends React.Component<GraphSeriesTogglerProps, GraphSeriesTogglerState> {
  19. constructor(props: GraphSeriesTogglerProps) {
  20. super(props);
  21. this.onSeriesToggle = this.onSeriesToggle.bind(this);
  22. this.state = {
  23. hiddenSeries: [],
  24. toggledSeries: props.series,
  25. };
  26. }
  27. componentDidUpdate(prevProps: Readonly<GraphSeriesTogglerProps>) {
  28. const { series } = this.props;
  29. if (!isEqual(prevProps.series, series)) {
  30. this.setState({ hiddenSeries: [], toggledSeries: series });
  31. }
  32. }
  33. onSeriesToggle(label: string, event: React.MouseEvent<HTMLElement>) {
  34. const { series, onHiddenSeriesChanged } = this.props;
  35. const { hiddenSeries } = this.state;
  36. if (event.ctrlKey || event.metaKey || event.shiftKey) {
  37. // Toggling series with key makes the series itself to toggle
  38. const newHiddenSeries =
  39. hiddenSeries.indexOf(label) > -1
  40. ? hiddenSeries.filter(series => series !== label)
  41. : hiddenSeries.concat([label]);
  42. const toggledSeries = series.map(series => ({
  43. ...series,
  44. isVisible: newHiddenSeries.indexOf(series.label) === -1,
  45. }));
  46. this.setState({ hiddenSeries: newHiddenSeries, toggledSeries }, () =>
  47. onHiddenSeriesChanged ? onHiddenSeriesChanged(newHiddenSeries) : undefined
  48. );
  49. return;
  50. }
  51. // Toggling series with out key toggles all the series but the clicked one
  52. const allSeriesLabels = series.map(series => series.label);
  53. const newHiddenSeries =
  54. hiddenSeries.length + 1 === allSeriesLabels.length ? [] : difference(allSeriesLabels, [label]);
  55. const toggledSeries = series.map(series => ({
  56. ...series,
  57. isVisible: newHiddenSeries.indexOf(series.label) === -1,
  58. }));
  59. this.setState({ hiddenSeries: newHiddenSeries, toggledSeries }, () =>
  60. onHiddenSeriesChanged ? onHiddenSeriesChanged(newHiddenSeries) : undefined
  61. );
  62. }
  63. render() {
  64. const { children } = this.props;
  65. const { toggledSeries } = this.state;
  66. return children({
  67. onSeriesToggle: this.onSeriesToggle,
  68. toggledSeries,
  69. });
  70. }
  71. }