LegendSeriesItem.tsx 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. import React, { PureComponent } from 'react';
  2. import classNames from 'classnames';
  3. import { TimeSeries } from 'app/core/core';
  4. import { SeriesColorPicker } from '@grafana/ui';
  5. import { ThemeProvider } from 'app/core/utils/ConfigProvider';
  6. export const LEGEND_STATS = ['min', 'max', 'avg', 'current', 'total'];
  7. export interface LegendLabelProps {
  8. series: TimeSeries;
  9. asTable?: boolean;
  10. hidden?: boolean;
  11. onLabelClick?: (series, event) => void;
  12. onColorChange?: (series, color: string) => void;
  13. onToggleAxis?: (series) => void;
  14. }
  15. export interface LegendValuesProps {
  16. values?: boolean;
  17. min?: boolean;
  18. max?: boolean;
  19. avg?: boolean;
  20. current?: boolean;
  21. total?: boolean;
  22. }
  23. type LegendItemProps = LegendLabelProps & LegendValuesProps;
  24. interface LegendItemState {
  25. yaxis: number;
  26. }
  27. export class LegendItem extends PureComponent<LegendItemProps, LegendItemState> {
  28. static defaultProps = {
  29. asTable: false,
  30. hidden: false,
  31. onLabelClick: () => {},
  32. onColorChange: () => {},
  33. onToggleAxis: () => {},
  34. };
  35. constructor(props) {
  36. super(props);
  37. this.state = {
  38. yaxis: this.props.series.yaxis,
  39. };
  40. }
  41. onLabelClick = e => this.props.onLabelClick(this.props.series, e);
  42. onToggleAxis = () => {
  43. const yaxis = this.state.yaxis === 2 ? 1 : 2;
  44. const info = { alias: this.props.series.alias, yaxis: yaxis };
  45. this.setState({ yaxis: yaxis });
  46. this.props.onToggleAxis(info);
  47. };
  48. onColorChange = color => {
  49. this.props.onColorChange(this.props.series, color);
  50. // Because of PureComponent nature it makes only shallow props comparison and changing of series.color doesn't run
  51. // component re-render. In this case we can't rely on color, selected by user, because it may be overwritten
  52. // by series overrides. So we need to use forceUpdate() to make sure we have proper series color.
  53. this.forceUpdate();
  54. };
  55. renderLegendValues() {
  56. const { series, asTable } = this.props;
  57. const legendValueItems = [];
  58. for (const valueName of LEGEND_STATS) {
  59. if (this.props[valueName]) {
  60. const valueFormatted = series.formatValue(series.stats[valueName]);
  61. legendValueItems.push(
  62. <LegendValue key={valueName} valueName={valueName} value={valueFormatted} asTable={asTable} />
  63. );
  64. }
  65. }
  66. return legendValueItems;
  67. }
  68. render() {
  69. const { series, values, asTable, hidden } = this.props;
  70. const seriesOptionClasses = classNames({
  71. 'graph-legend-series-hidden': hidden,
  72. 'graph-legend-series--right-y': series.yaxis === 2,
  73. });
  74. const valueItems = values ? this.renderLegendValues() : [];
  75. const seriesLabel = (
  76. <LegendSeriesLabel
  77. label={series.alias}
  78. color={series.color}
  79. yaxis={this.state.yaxis}
  80. onLabelClick={this.onLabelClick}
  81. onColorChange={this.onColorChange}
  82. onToggleAxis={this.onToggleAxis}
  83. />
  84. );
  85. if (asTable) {
  86. return (
  87. <tr className={`graph-legend-series ${seriesOptionClasses}`}>
  88. <td>{seriesLabel}</td>
  89. {valueItems}
  90. </tr>
  91. );
  92. } else {
  93. return (
  94. <div className={`graph-legend-series ${seriesOptionClasses}`}>
  95. {seriesLabel}
  96. {valueItems}
  97. </div>
  98. );
  99. }
  100. }
  101. }
  102. interface LegendSeriesLabelProps {
  103. label: string;
  104. color: string;
  105. yaxis?: number;
  106. onLabelClick?: (event) => void;
  107. }
  108. class LegendSeriesLabel extends PureComponent<LegendSeriesLabelProps & LegendSeriesIconProps> {
  109. static defaultProps = {
  110. yaxis: undefined,
  111. onLabelClick: () => {},
  112. };
  113. render() {
  114. const { label, color, yaxis } = this.props;
  115. const { onColorChange, onToggleAxis } = this.props;
  116. return [
  117. <LegendSeriesIcon
  118. key="icon"
  119. color={color}
  120. yaxis={yaxis}
  121. onColorChange={onColorChange}
  122. onToggleAxis={onToggleAxis}
  123. />,
  124. <a className="graph-legend-alias pointer" title={label} key="label" onClick={e => this.props.onLabelClick(e)}>
  125. {label}
  126. </a>,
  127. ];
  128. }
  129. }
  130. interface LegendSeriesIconProps {
  131. color: string;
  132. yaxis?: number;
  133. onColorChange?: (color: string) => void;
  134. onToggleAxis?: () => void;
  135. }
  136. interface LegendSeriesIconState {
  137. color: string;
  138. }
  139. function SeriesIcon({ color }) {
  140. return <i className="fa fa-minus pointer" style={{ color }} />;
  141. }
  142. class LegendSeriesIcon extends PureComponent<LegendSeriesIconProps, LegendSeriesIconState> {
  143. static defaultProps = {
  144. yaxis: undefined,
  145. onColorChange: () => {},
  146. onToggleAxis: () => {},
  147. };
  148. render() {
  149. return (
  150. <ThemeProvider>
  151. {theme => {
  152. return (
  153. <SeriesColorPicker
  154. yaxis={this.props.yaxis}
  155. color={this.props.color}
  156. onChange={this.props.onColorChange}
  157. onToggleAxis={this.props.onToggleAxis}
  158. theme={theme}
  159. enableNamedColors
  160. >
  161. <span className="graph-legend-icon">
  162. <SeriesIcon color={this.props.color} />
  163. </span>
  164. </SeriesColorPicker>
  165. );
  166. }}
  167. </ThemeProvider>
  168. );
  169. }
  170. }
  171. interface LegendValueProps {
  172. value: string;
  173. valueName: string;
  174. asTable?: boolean;
  175. }
  176. function LegendValue(props: LegendValueProps) {
  177. const value = props.value;
  178. const valueName = props.valueName;
  179. if (props.asTable) {
  180. return <td className={`graph-legend-value ${valueName}`}>{value}</td>;
  181. }
  182. return <div className={`graph-legend-value ${valueName}`}>{value}</div>;
  183. }