LegendSeriesItem.tsx 5.3 KB

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