GraphPanelController.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import React from 'react';
  2. import { PanelData } from '@grafana/ui';
  3. import { GraphSeriesXY } from '@grafana/data';
  4. import difference from 'lodash/difference';
  5. import { getGraphSeriesModel } from './getGraphSeriesModel';
  6. import { Options, SeriesOptions } from './types';
  7. import { SeriesColorChangeHandler, SeriesAxisToggleHandler } from '@grafana/ui/src/components/Graph/GraphWithLegend';
  8. interface GraphPanelControllerAPI {
  9. series: GraphSeriesXY[];
  10. onSeriesAxisToggle: SeriesAxisToggleHandler;
  11. onSeriesColorChange: SeriesColorChangeHandler;
  12. onSeriesToggle: (label: string, event: React.MouseEvent<HTMLElement>) => void;
  13. onToggleSort: (sortBy: string) => void;
  14. }
  15. interface GraphPanelControllerProps {
  16. children: (api: GraphPanelControllerAPI) => JSX.Element;
  17. options: Options;
  18. data: PanelData;
  19. onOptionsChange: (options: Options) => void;
  20. }
  21. interface GraphPanelControllerState {
  22. graphSeriesModel: GraphSeriesXY[];
  23. hiddenSeries: string[];
  24. }
  25. export class GraphPanelController extends React.Component<GraphPanelControllerProps, GraphPanelControllerState> {
  26. constructor(props: GraphPanelControllerProps) {
  27. super(props);
  28. this.onSeriesToggle = this.onSeriesToggle.bind(this);
  29. this.onSeriesColorChange = this.onSeriesColorChange.bind(this);
  30. this.onSeriesAxisToggle = this.onSeriesAxisToggle.bind(this);
  31. this.onToggleSort = this.onToggleSort.bind(this);
  32. this.state = {
  33. graphSeriesModel: getGraphSeriesModel(
  34. props.data,
  35. props.options.series,
  36. props.options.graph,
  37. props.options.legend
  38. ),
  39. hiddenSeries: [],
  40. };
  41. }
  42. static getDerivedStateFromProps(props: GraphPanelControllerProps, state: GraphPanelControllerState) {
  43. return {
  44. ...state,
  45. graphSeriesModel: getGraphSeriesModel(
  46. props.data,
  47. props.options.series,
  48. props.options.graph,
  49. props.options.legend
  50. ),
  51. };
  52. }
  53. onSeriesOptionsUpdate(label: string, optionsUpdate: SeriesOptions) {
  54. const { onOptionsChange, options } = this.props;
  55. const updatedSeriesOptions: { [label: string]: SeriesOptions } = { ...options.series };
  56. updatedSeriesOptions[label] = optionsUpdate;
  57. onOptionsChange({
  58. ...options,
  59. series: updatedSeriesOptions,
  60. });
  61. }
  62. onSeriesAxisToggle(label: string, yAxis: number) {
  63. const {
  64. options: { series },
  65. } = this.props;
  66. const seriesOptionsUpdate: SeriesOptions = series[label]
  67. ? {
  68. ...series[label],
  69. yAxis,
  70. }
  71. : {
  72. yAxis,
  73. };
  74. this.onSeriesOptionsUpdate(label, seriesOptionsUpdate);
  75. }
  76. onSeriesColorChange(label: string, color: string) {
  77. const {
  78. options: { series },
  79. } = this.props;
  80. const seriesOptionsUpdate: SeriesOptions = series[label]
  81. ? {
  82. ...series[label],
  83. color,
  84. }
  85. : {
  86. color,
  87. };
  88. this.onSeriesOptionsUpdate(label, seriesOptionsUpdate);
  89. }
  90. onToggleSort(sortBy: string) {
  91. const { onOptionsChange, options } = this.props;
  92. onOptionsChange({
  93. ...options,
  94. legend: {
  95. ...options.legend,
  96. sortBy,
  97. sortDesc: sortBy === options.legend.sortBy ? !options.legend.sortDesc : false,
  98. },
  99. });
  100. }
  101. onSeriesToggle(label: string, event: React.MouseEvent<HTMLElement>) {
  102. const { hiddenSeries, graphSeriesModel } = this.state;
  103. if (event.ctrlKey || event.metaKey || event.shiftKey) {
  104. // Toggling series with key makes the series itself to toggle
  105. if (hiddenSeries.indexOf(label) > -1) {
  106. this.setState({
  107. hiddenSeries: hiddenSeries.filter(series => series !== label),
  108. });
  109. } else {
  110. this.setState({
  111. hiddenSeries: hiddenSeries.concat([label]),
  112. });
  113. }
  114. } else {
  115. // Toggling series with out key toggles all the series but the clicked one
  116. const allSeriesLabels = graphSeriesModel.map(series => series.label);
  117. if (hiddenSeries.length + 1 === allSeriesLabels.length) {
  118. this.setState({ hiddenSeries: [] });
  119. } else {
  120. this.setState({
  121. hiddenSeries: difference(allSeriesLabels, [label]),
  122. });
  123. }
  124. }
  125. }
  126. render() {
  127. const { children } = this.props;
  128. const { graphSeriesModel, hiddenSeries } = this.state;
  129. return children({
  130. series: graphSeriesModel.map(series => ({
  131. ...series,
  132. isVisible: hiddenSeries.indexOf(series.label) === -1,
  133. })),
  134. onSeriesToggle: this.onSeriesToggle,
  135. onSeriesColorChange: this.onSeriesColorChange,
  136. onSeriesAxisToggle: this.onSeriesAxisToggle,
  137. onToggleSort: this.onToggleSort,
  138. });
  139. }
  140. }