2018-08-31 13:24:49 +03:00
|
|
|
import _ from 'lodash';
|
|
|
|
|
import React from 'react';
|
2018-09-03 16:54:52 +03:00
|
|
|
import { TimeSeries } from 'app/core/core';
|
2018-09-07 16:12:28 +03:00
|
|
|
import CustomScrollbar from 'app/core/components/CustomScrollbar/CustomScrollbar';
|
2018-10-17 15:07:31 +03:00
|
|
|
import { LegendItem, LEGEND_STATS } from './LegendSeriesItem';
|
2018-08-31 13:24:49 +03:00
|
|
|
|
2018-09-03 16:54:52 +03:00
|
|
|
interface LegendProps {
|
|
|
|
|
seriesList: TimeSeries[];
|
|
|
|
|
optionalClass?: string;
|
2018-09-04 12:49:13 +03:00
|
|
|
onToggleSeries?: (series: TimeSeries, event: Event) => void;
|
|
|
|
|
onToggleSort?: (sortBy, sortDesc) => void;
|
2018-10-17 15:07:31 +03:00
|
|
|
onToggleAxis?: (series: TimeSeries) => void;
|
2018-10-16 16:50:43 +03:00
|
|
|
onColorChange?: (series: TimeSeries, color: string) => void;
|
2018-09-03 16:54:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface LegendDisplayProps {
|
2018-08-31 13:24:49 +03:00
|
|
|
hiddenSeries: any;
|
2018-09-03 16:54:52 +03:00
|
|
|
hideEmpty?: boolean;
|
|
|
|
|
hideZero?: boolean;
|
|
|
|
|
alignAsTable?: boolean;
|
|
|
|
|
rightSide?: boolean;
|
|
|
|
|
sideWidth?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface LegendValuesProps {
|
2018-08-31 13:24:49 +03:00
|
|
|
values?: boolean;
|
|
|
|
|
min?: boolean;
|
|
|
|
|
max?: boolean;
|
|
|
|
|
avg?: boolean;
|
|
|
|
|
current?: boolean;
|
|
|
|
|
total?: boolean;
|
2018-09-03 16:54:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface LegendSortProps {
|
2018-08-31 13:24:49 +03:00
|
|
|
sort?: 'min' | 'max' | 'avg' | 'current' | 'total';
|
|
|
|
|
sortDesc?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:54:52 +03:00
|
|
|
export type GraphLegendProps = LegendProps & LegendDisplayProps & LegendValuesProps & LegendSortProps;
|
|
|
|
|
|
2018-10-17 15:07:31 +03:00
|
|
|
export class GraphLegend extends React.PureComponent<GraphLegendProps> {
|
|
|
|
|
static defaultProps: Partial<GraphLegendProps> = {
|
|
|
|
|
values: false,
|
|
|
|
|
min: false,
|
|
|
|
|
max: false,
|
|
|
|
|
avg: false,
|
|
|
|
|
current: false,
|
|
|
|
|
total: false,
|
|
|
|
|
alignAsTable: false,
|
|
|
|
|
rightSide: false,
|
|
|
|
|
sort: undefined,
|
|
|
|
|
sortDesc: false,
|
|
|
|
|
optionalClass: '',
|
|
|
|
|
onToggleSeries: () => {},
|
|
|
|
|
onToggleSort: () => {},
|
|
|
|
|
onToggleAxis: () => {},
|
|
|
|
|
onColorChange: () => {},
|
|
|
|
|
};
|
2018-09-03 16:54:52 +03:00
|
|
|
|
2018-08-31 13:24:49 +03:00
|
|
|
sortLegend() {
|
|
|
|
|
let seriesList = this.props.seriesList || [];
|
|
|
|
|
if (this.props.sort) {
|
2018-09-03 16:54:52 +03:00
|
|
|
seriesList = _.sortBy(seriesList, series => {
|
2018-08-31 13:24:49 +03:00
|
|
|
let sort = series.stats[this.props.sort];
|
|
|
|
|
if (sort === null) {
|
|
|
|
|
sort = -Infinity;
|
|
|
|
|
}
|
|
|
|
|
return sort;
|
|
|
|
|
});
|
|
|
|
|
if (this.props.sortDesc) {
|
|
|
|
|
seriesList = seriesList.reverse();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return seriesList;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-04 12:49:13 +03:00
|
|
|
onToggleSeries(series: TimeSeries, event: Event) {
|
|
|
|
|
// const scrollPosition = legendScrollbar.scroller.scrollTop;
|
|
|
|
|
this.props.onToggleSeries(series, event);
|
|
|
|
|
// legendScrollbar.scroller.scrollTop = scrollPosition;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-31 13:24:49 +03:00
|
|
|
render() {
|
2018-09-04 12:49:13 +03:00
|
|
|
const { optionalClass, hiddenSeries, rightSide, sideWidth, sort, sortDesc, hideEmpty, hideZero } = this.props;
|
2018-08-31 13:24:49 +03:00
|
|
|
const { values, min, max, avg, current, total } = this.props;
|
|
|
|
|
const seriesValuesProps = { values, min, max, avg, current, total };
|
2018-09-03 16:54:52 +03:00
|
|
|
const seriesHideProps = { hideEmpty, hideZero };
|
2018-09-04 12:49:13 +03:00
|
|
|
const sortProps = { sort, sortDesc };
|
2018-09-03 16:54:52 +03:00
|
|
|
const seriesList = _.filter(this.sortLegend(), series => !series.hideFromLegend(seriesHideProps));
|
2018-09-06 15:06:54 +03:00
|
|
|
const legendClass = `${this.props.alignAsTable ? 'graph-legend-table' : ''} ${optionalClass}`;
|
2018-08-31 17:27:57 +03:00
|
|
|
|
|
|
|
|
// Set min-width if side style and there is a value, otherwise remove the CSS property
|
|
|
|
|
// Set width so it works with IE11
|
|
|
|
|
const width: any = rightSide && sideWidth ? sideWidth : undefined;
|
|
|
|
|
const ieWidth: any = rightSide && sideWidth ? sideWidth - 1 : undefined;
|
2018-08-31 16:34:22 +03:00
|
|
|
const legendStyle: React.CSSProperties = {
|
2018-08-31 17:27:57 +03:00
|
|
|
minWidth: width,
|
|
|
|
|
width: ieWidth,
|
2018-08-31 13:24:49 +03:00
|
|
|
};
|
|
|
|
|
|
2018-09-04 12:49:13 +03:00
|
|
|
const legendProps: GraphLegendProps = {
|
|
|
|
|
seriesList: seriesList,
|
|
|
|
|
hiddenSeries: hiddenSeries,
|
|
|
|
|
onToggleSeries: (s, e) => this.onToggleSeries(s, e),
|
|
|
|
|
onToggleSort: (sortBy, sortDesc) => this.props.onToggleSort(sortBy, sortDesc),
|
2018-10-16 16:50:43 +03:00
|
|
|
onColorChange: (series, color) => this.props.onColorChange(series, color),
|
2018-10-17 15:07:31 +03:00
|
|
|
onToggleAxis: series => this.props.onToggleAxis(series),
|
2018-09-04 12:49:13 +03:00
|
|
|
...seriesValuesProps,
|
|
|
|
|
...sortProps,
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-31 13:24:49 +03:00
|
|
|
return (
|
2018-09-06 15:06:54 +03:00
|
|
|
<div className={`graph-legend-content ${legendClass}`} style={legendStyle}>
|
|
|
|
|
{this.props.alignAsTable ? <LegendTable {...legendProps} /> : <LegendSeriesList {...legendProps} />}
|
2018-08-31 16:34:22 +03:00
|
|
|
</div>
|
2018-08-31 13:24:49 +03:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:54:52 +03:00
|
|
|
class LegendSeriesList extends React.PureComponent<GraphLegendProps> {
|
|
|
|
|
render() {
|
|
|
|
|
const { seriesList, hiddenSeries, values, min, max, avg, current, total } = this.props;
|
|
|
|
|
const seriesValuesProps = { values, min, max, avg, current, total };
|
|
|
|
|
return seriesList.map((series, i) => (
|
2018-10-17 15:07:31 +03:00
|
|
|
<LegendItem
|
2018-09-04 12:49:13 +03:00
|
|
|
key={series.id}
|
|
|
|
|
series={series}
|
|
|
|
|
index={i}
|
|
|
|
|
hiddenSeries={hiddenSeries}
|
|
|
|
|
{...seriesValuesProps}
|
|
|
|
|
onLabelClick={e => this.props.onToggleSeries(series, e)}
|
2018-10-16 16:50:43 +03:00
|
|
|
onColorChange={color => this.props.onColorChange(series, color)}
|
2018-10-17 15:07:31 +03:00
|
|
|
onToggleAxis={() => this.props.onToggleAxis(series)}
|
2018-09-04 12:49:13 +03:00
|
|
|
/>
|
2018-09-03 16:54:52 +03:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class LegendTable extends React.PureComponent<Partial<GraphLegendProps>> {
|
2018-09-04 12:49:13 +03:00
|
|
|
onToggleSort(stat) {
|
|
|
|
|
let sortDesc = this.props.sortDesc;
|
|
|
|
|
let sortBy = this.props.sort;
|
|
|
|
|
if (stat !== sortBy) {
|
|
|
|
|
sortDesc = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if already sort ascending, disable sorting
|
|
|
|
|
if (sortDesc === false) {
|
|
|
|
|
sortBy = null;
|
|
|
|
|
sortDesc = null;
|
|
|
|
|
} else {
|
|
|
|
|
sortDesc = !sortDesc;
|
|
|
|
|
sortBy = stat;
|
|
|
|
|
}
|
|
|
|
|
this.props.onToggleSort(sortBy, sortDesc);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-31 16:34:22 +03:00
|
|
|
render() {
|
|
|
|
|
const seriesList = this.props.seriesList;
|
2018-09-03 16:54:52 +03:00
|
|
|
const { values, min, max, avg, current, total, sort, sortDesc } = this.props;
|
2018-08-31 16:34:22 +03:00
|
|
|
const seriesValuesProps = { values, min, max, avg, current, total };
|
|
|
|
|
return (
|
|
|
|
|
<table>
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr>
|
|
|
|
|
<th style={{ textAlign: 'left' }} />
|
|
|
|
|
{LEGEND_STATS.map(
|
2018-09-03 16:54:52 +03:00
|
|
|
statName =>
|
|
|
|
|
seriesValuesProps[statName] && (
|
2018-09-04 12:49:13 +03:00
|
|
|
<LegendTableHeaderItem
|
|
|
|
|
key={statName}
|
|
|
|
|
statName={statName}
|
|
|
|
|
sort={sort}
|
|
|
|
|
sortDesc={sortDesc}
|
|
|
|
|
onClick={e => this.onToggleSort(statName)}
|
|
|
|
|
/>
|
2018-09-03 16:54:52 +03:00
|
|
|
)
|
2018-08-31 16:34:22 +03:00
|
|
|
)}
|
|
|
|
|
</tr>
|
|
|
|
|
{seriesList.map((series, i) => (
|
2018-10-17 15:07:31 +03:00
|
|
|
<LegendItem
|
2018-08-31 16:34:22 +03:00
|
|
|
key={series.id}
|
2018-10-17 15:07:31 +03:00
|
|
|
asTable={true}
|
2018-08-31 16:34:22 +03:00
|
|
|
series={series}
|
|
|
|
|
index={i}
|
|
|
|
|
hiddenSeries={this.props.hiddenSeries}
|
2018-09-04 12:49:13 +03:00
|
|
|
onLabelClick={e => this.props.onToggleSeries(series, e)}
|
2018-10-16 16:50:43 +03:00
|
|
|
onColorChange={color => this.props.onColorChange(series, color)}
|
2018-10-17 15:07:31 +03:00
|
|
|
onToggleAxis={() => this.props.onToggleAxis(series)}
|
|
|
|
|
{...seriesValuesProps}
|
2018-08-31 16:34:22 +03:00
|
|
|
/>
|
|
|
|
|
))}
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-03 16:54:52 +03:00
|
|
|
interface LegendTableHeaderProps {
|
|
|
|
|
statName: string;
|
2018-09-04 12:49:13 +03:00
|
|
|
onClick?: (event) => void;
|
2018-09-03 16:54:52 +03:00
|
|
|
}
|
|
|
|
|
|
2018-09-04 12:49:13 +03:00
|
|
|
function LegendTableHeaderItem(props: LegendTableHeaderProps & LegendSortProps) {
|
2018-09-03 16:54:52 +03:00
|
|
|
const { statName, sort, sortDesc } = props;
|
|
|
|
|
return (
|
2018-10-17 15:07:31 +03:00
|
|
|
<th className="pointer" onClick={e => props.onClick(e)}>
|
2018-09-03 16:54:52 +03:00
|
|
|
{statName}
|
|
|
|
|
{sort === statName && <span className={sortDesc ? 'fa fa-caret-down' : 'fa fa-caret-up'} />}
|
|
|
|
|
</th>
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-08-31 16:34:22 +03:00
|
|
|
|
2018-10-17 15:07:31 +03:00
|
|
|
export class Legend extends React.Component<GraphLegendProps> {
|
2018-09-06 22:52:56 +03:00
|
|
|
render() {
|
|
|
|
|
return (
|
2018-09-07 16:12:28 +03:00
|
|
|
<CustomScrollbar>
|
2018-09-06 22:52:56 +03:00
|
|
|
<GraphLegend {...this.props} />
|
2018-09-07 16:12:28 +03:00
|
|
|
</CustomScrollbar>
|
2018-09-06 22:52:56 +03:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-06 15:06:54 +03:00
|
|
|
export default Legend;
|