github.com/thanos-io/thanos@v0.32.5/pkg/ui/react-app/src/pages/graph/Legend.tsx (about)

     1  import React, { PureComponent, SyntheticEvent } from 'react';
     2  import SeriesName from './SeriesName';
     3  import { GraphSeries } from './Graph';
     4  
     5  interface LegendProps {
     6    chartData: GraphSeries[];
     7    shouldReset: boolean;
     8    onLegendMouseOut: (ev: SyntheticEvent<HTMLDivElement>) => void;
     9    onSeriesToggle: (selected: number[], index: number) => void;
    10    onHover: (index: number) => (ev: SyntheticEvent<HTMLDivElement>) => void;
    11  }
    12  
    13  interface LegendState {
    14    selectedIndexes: number[];
    15  }
    16  
    17  export class Legend extends PureComponent<LegendProps, LegendState> {
    18    state = {
    19      selectedIndexes: [] as number[],
    20    };
    21    componentDidUpdate(prevProps: LegendProps): void {
    22      if (this.props.shouldReset && prevProps.shouldReset !== this.props.shouldReset) {
    23        this.setState({ selectedIndexes: [] });
    24      }
    25    }
    26    handleSeriesSelect =
    27      (index: number) =>
    28      (ev: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
    29        // TODO: add proper event type
    30        const { selectedIndexes } = this.state;
    31  
    32        let selected = [index];
    33        if (ev.ctrlKey || ev.metaKey) {
    34          const { chartData } = this.props;
    35          if (selectedIndexes.includes(index)) {
    36            selected = selectedIndexes.filter((idx) => idx !== index);
    37          } else {
    38            selected =
    39              // Flip the logic - In case none is selected ctrl + click should deselect clicked series.
    40              selectedIndexes.length === 0
    41                ? chartData.reduce<number[]>((acc, _, i) => (i === index ? acc : [...acc, i]), [])
    42                : [...selectedIndexes, index]; // Select multiple.
    43          }
    44        } else if (selectedIndexes.length === 1 && selectedIndexes.includes(index)) {
    45          selected = [];
    46        }
    47  
    48        this.setState({ selectedIndexes: selected });
    49        this.props.onSeriesToggle(selected, index);
    50      };
    51  
    52    render(): JSX.Element {
    53      const { chartData, onLegendMouseOut, onHover } = this.props;
    54      const { selectedIndexes } = this.state;
    55      const canUseHover = chartData.length > 1 && selectedIndexes.length === 0;
    56  
    57      return (
    58        <div className="graph-legend" onMouseOut={canUseHover ? onLegendMouseOut : undefined}>
    59          {chartData.map(({ index, color, labels }) => (
    60            <div
    61              style={{ opacity: selectedIndexes.length === 0 || selectedIndexes.includes(index) ? 1 : 0.5 }}
    62              onClick={chartData.length > 1 ? this.handleSeriesSelect(index) : undefined}
    63              onMouseOver={canUseHover ? onHover(index) : undefined}
    64              key={index}
    65              className="legend-item"
    66            >
    67              <span className="legend-swatch" style={{ backgroundColor: color }}></span>
    68              <SeriesName labels={labels} format />
    69            </div>
    70          ))}
    71          {chartData.length > 1 && (
    72            <div className="pl-1 mt-1 text-muted" style={{ fontSize: 13 }}>
    73              Click: select series, {navigator.platform.includes('Mac') ? 'CMD' : 'CTRL'} + click: toggle multiple series
    74            </div>
    75          )}
    76        </div>
    77      );
    78    }
    79  }