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