GraphPanelController.tsx 4.5 KB

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