mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
XY Chart: share legend config with timeseries (#30559)
This commit is contained in:
parent
e818bdd75f
commit
8c1a79f24b
@ -259,6 +259,10 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
label: seriesConfig.fieldName,
|
||||
yAxis: axisPlacement === AxisPlacement.Left ? 1 : 2,
|
||||
getDisplayValues: () => {
|
||||
if (!legend.calcs?.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const fmt = field.display ?? defaultFormatter;
|
||||
const fieldCalcs = reduceField({
|
||||
field,
|
||||
|
@ -3,7 +3,10 @@ import {
|
||||
FieldConfigProperty,
|
||||
FieldType,
|
||||
identityOverrideProcessor,
|
||||
PanelOptionsEditorBuilder,
|
||||
SetFieldConfigOptionsArgs,
|
||||
standardEditorsRegistry,
|
||||
StatsPickerConfigSettings,
|
||||
stringOverrideProcessor,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
@ -17,11 +20,13 @@ import {
|
||||
ScaleDistribution,
|
||||
ScaleDistributionConfig,
|
||||
GraphGradientMode,
|
||||
LegendDisplayMode,
|
||||
} from '@grafana/ui';
|
||||
import { SeriesConfigEditor } from './HideSeriesConfigEditor';
|
||||
import { ScaleDistributionEditor } from './ScaleDistributionEditor';
|
||||
import { LineStyleEditor } from './LineStyleEditor';
|
||||
import { FillBellowToEditor } from './FillBelowToEditor';
|
||||
import { OptionsWithLegend } from './types';
|
||||
|
||||
export const defaultGraphConfig: GraphFieldConfig = {
|
||||
drawStyle: DrawStyle.Line,
|
||||
@ -224,3 +229,45 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function addLegendOptions(builder: PanelOptionsEditorBuilder<OptionsWithLegend>) {
|
||||
builder
|
||||
.addRadio({
|
||||
path: 'legend.displayMode',
|
||||
name: 'Legend mode',
|
||||
description: '',
|
||||
defaultValue: LegendDisplayMode.List,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LegendDisplayMode.List, label: 'List' },
|
||||
{ value: LegendDisplayMode.Table, label: 'Table' },
|
||||
{ value: LegendDisplayMode.Hidden, label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'legend.placement',
|
||||
name: 'Legend placement',
|
||||
description: '',
|
||||
defaultValue: 'bottom',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'bottom', label: 'Bottom' },
|
||||
{ value: 'right', label: 'Right' },
|
||||
],
|
||||
},
|
||||
showIf: (c) => c.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||
})
|
||||
.addCustomEditor<StatsPickerConfigSettings, string[]>({
|
||||
id: 'legend.calcs',
|
||||
path: 'legend.calcs',
|
||||
name: 'Legend calculations',
|
||||
description: 'Choose a reducer functions / calculations to include in legend',
|
||||
editor: standardEditorsRegistry.get('stats-picker').editor as any,
|
||||
defaultValue: [],
|
||||
settings: {
|
||||
allowMultiple: true,
|
||||
},
|
||||
showIf: (currentConfig) => currentConfig.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||
});
|
||||
}
|
||||
|
@ -1,64 +1,26 @@
|
||||
import { PanelPlugin, standardEditorsRegistry, StatsPickerConfigSettings } from '@grafana/data';
|
||||
import { GraphFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { GraphFieldConfig } from '@grafana/ui';
|
||||
import { TimeSeriesPanel } from './TimeSeriesPanel';
|
||||
import { graphPanelChangedHandler } from './migrations';
|
||||
import { Options } from './types';
|
||||
import { defaultGraphConfig, getGraphFieldConfig } from './config';
|
||||
import { addLegendOptions, defaultGraphConfig, getGraphFieldConfig } from './config';
|
||||
|
||||
export const plugin = new PanelPlugin<Options, GraphFieldConfig>(TimeSeriesPanel)
|
||||
.setPanelChangeHandler(graphPanelChangedHandler)
|
||||
.useFieldConfig(getGraphFieldConfig(defaultGraphConfig))
|
||||
.setPanelOptions((builder) => {
|
||||
builder
|
||||
.addRadio({
|
||||
path: 'tooltipOptions.mode',
|
||||
name: 'Tooltip mode',
|
||||
description: '',
|
||||
defaultValue: 'single',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'single', label: 'Single' },
|
||||
{ value: 'multi', label: 'All' },
|
||||
{ value: 'none', label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'legend.displayMode',
|
||||
name: 'Legend mode',
|
||||
description: '',
|
||||
defaultValue: LegendDisplayMode.List,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LegendDisplayMode.List, label: 'List' },
|
||||
{ value: LegendDisplayMode.Table, label: 'Table' },
|
||||
{ value: LegendDisplayMode.Hidden, label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'legend.placement',
|
||||
name: 'Legend placement',
|
||||
description: '',
|
||||
defaultValue: 'bottom',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'bottom', label: 'Bottom' },
|
||||
{ value: 'right', label: 'Right' },
|
||||
],
|
||||
},
|
||||
showIf: (c) => c.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||
})
|
||||
.addCustomEditor<StatsPickerConfigSettings, string[]>({
|
||||
id: 'legend.calcs',
|
||||
path: 'legend.calcs',
|
||||
name: 'Legend calculations',
|
||||
description: 'Choose a reducer functions / calculations to include in legend',
|
||||
editor: standardEditorsRegistry.get('stats-picker').editor as any,
|
||||
defaultValue: [],
|
||||
settings: {
|
||||
allowMultiple: true,
|
||||
},
|
||||
showIf: (currentConfig) => currentConfig.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||
});
|
||||
builder.addRadio({
|
||||
path: 'tooltipOptions.mode',
|
||||
name: 'Tooltip mode',
|
||||
description: '',
|
||||
defaultValue: 'single',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'single', label: 'Single' },
|
||||
{ value: 'multi', label: 'All' },
|
||||
{ value: 'none', label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
});
|
||||
addLegendOptions(builder);
|
||||
});
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { VizLegendOptions, GraphTooltipOptions } from '@grafana/ui';
|
||||
|
||||
export interface GraphOptions {
|
||||
// Redraw as time passes
|
||||
realTimeUpdates?: boolean;
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
graph: GraphOptions;
|
||||
export interface OptionsWithLegend {
|
||||
legend: VizLegendOptions;
|
||||
}
|
||||
|
||||
export interface Options extends OptionsWithLegend {
|
||||
graph: GraphOptions;
|
||||
tooltipOptions: GraphTooltipOptions;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { FC, useCallback, useMemo } from 'react';
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { IconButton, Label, Select, stylesFactory, Switch, useTheme } from '@grafana/ui';
|
||||
import { IconButton, Label, Select, stylesFactory, useTheme } from '@grafana/ui';
|
||||
import {
|
||||
SelectableValue,
|
||||
getFrameDisplayName,
|
||||
@ -84,13 +84,6 @@ export const XYDimsEditor: FC<StandardEditorProps<XYDimensionConfig, any, Option
|
||||
return v;
|
||||
}, [dims, context.data, value]);
|
||||
|
||||
const toggleSort = useCallback(() => {
|
||||
onChange({
|
||||
...value,
|
||||
sort: !value?.sort,
|
||||
});
|
||||
}, [value, onChange]);
|
||||
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme);
|
||||
|
||||
@ -118,10 +111,6 @@ export const XYDimsEditor: FC<StandardEditorProps<XYDimensionConfig, any, Option
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className={styles.sorter}>
|
||||
<Switch value={value?.sort ?? false} onClick={toggleSort} />
|
||||
<div onClick={toggleSort}> Sort field</div>
|
||||
</div>
|
||||
<br />
|
||||
<Label>Y Fields</Label>
|
||||
<div>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName, sortDataFrame } from '@grafana/data';
|
||||
import { DataFrame, Field, FieldMatcher, FieldType, getFieldDisplayName } from '@grafana/data';
|
||||
import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/GraphNG';
|
||||
import { XYDimensionConfig } from './types';
|
||||
|
||||
@ -49,11 +49,6 @@ export function getXYDimensions(cfg: XYDimensionConfig, data?: DataFrame[]): XYD
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally sort
|
||||
if (cfg.sort) {
|
||||
frame = sortDataFrame(frame, xIndex);
|
||||
}
|
||||
|
||||
let hasTime = false;
|
||||
const x = frame.fields[xIndex];
|
||||
const fields: Field[] = [x];
|
||||
@ -92,12 +87,14 @@ function getSimpleFieldMatcher(f: Field): FieldMatcher {
|
||||
if (!f) {
|
||||
return () => false;
|
||||
}
|
||||
return (field) => f === field;
|
||||
// the field may change if sorted
|
||||
return (field) => f === field || !!(f.state && f.state === field.state);
|
||||
}
|
||||
|
||||
function getSimpleFieldNotMatcher(f: Field): FieldMatcher {
|
||||
if (!f) {
|
||||
return () => false;
|
||||
}
|
||||
return (field) => f !== field;
|
||||
const m = getSimpleFieldMatcher(f);
|
||||
return (field) => !m(field, undefined as any, undefined as any);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { DrawStyle, GraphFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
||||
import { DrawStyle, GraphFieldConfig } from '@grafana/ui';
|
||||
import { XYChartPanel } from './XYChartPanel';
|
||||
import { Options } from './types';
|
||||
import { XYDimsEditor } from './XYDimsEditor';
|
||||
import { getGraphFieldConfig, defaultGraphConfig } from '../timeseries/config';
|
||||
import { getGraphFieldConfig, defaultGraphConfig, addLegendOptions } from '../timeseries/config';
|
||||
|
||||
export const plugin = new PanelPlugin<Options, GraphFieldConfig>(XYChartPanel)
|
||||
.useFieldConfig(
|
||||
@ -32,31 +32,7 @@ export const plugin = new PanelPlugin<Options, GraphFieldConfig>(XYChartPanel)
|
||||
{ value: 'none', label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'legend.displayMode',
|
||||
name: 'Legend mode',
|
||||
description: '',
|
||||
defaultValue: LegendDisplayMode.List,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LegendDisplayMode.List, label: 'List' },
|
||||
{ value: LegendDisplayMode.Table, label: 'Table' },
|
||||
{ value: LegendDisplayMode.Hidden, label: 'Hidden' },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
path: 'legend.placement',
|
||||
name: 'Legend placement',
|
||||
description: '',
|
||||
defaultValue: 'bottom',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: 'bottom', label: 'Bottom' },
|
||||
{ value: 'right', label: 'Right' },
|
||||
],
|
||||
},
|
||||
showIf: (c) => c.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||
});
|
||||
|
||||
addLegendOptions(builder);
|
||||
});
|
||||
|
@ -1,14 +1,13 @@
|
||||
import { VizLegendOptions, GraphTooltipOptions } from '@grafana/ui';
|
||||
import { GraphTooltipOptions } from '@grafana/ui';
|
||||
import { OptionsWithLegend } from '../timeseries/types';
|
||||
|
||||
export interface XYDimensionConfig {
|
||||
frame: number;
|
||||
sort?: boolean;
|
||||
x?: string; // name | first
|
||||
exclude?: string[]; // all other numbers except
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
export interface Options extends OptionsWithLegend {
|
||||
dims: XYDimensionConfig;
|
||||
legend: VizLegendOptions;
|
||||
tooltipOptions: GraphTooltipOptions;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user