mirror of
https://github.com/grafana/grafana.git
synced 2025-09-20 01:39:53 +08:00
Legend/GraphNG: Refactoring legend types and options (#29067)
* Legend/GraphNG: Refactoring legend types and options * Rename label * Minor update * Fixed legend placement crash issue * remove unused * Minor tweaks and fixes
This commit is contained in:
@ -44,7 +44,7 @@ export const GraphLegendListItem: React.FunctionComponent<GraphLegendItemProps>
|
|||||||
onLabelClick(item, event);
|
onLabelClick(item, event);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className={cx(styles.label, !item.isVisible && styles.labelDisabled)}
|
className={cx(styles.label, item.disabled && styles.labelDisabled)}
|
||||||
>
|
>
|
||||||
{item.label}
|
{item.label}
|
||||||
</div>
|
</div>
|
||||||
|
@ -123,8 +123,7 @@ export const graphWithLegend = () => {
|
|||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
}),
|
}),
|
||||||
displayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List,
|
legendDisplayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List,
|
||||||
isLegendVisible: true,
|
|
||||||
onToggleSort: () => {},
|
onToggleSort: () => {},
|
||||||
timeRange: {
|
timeRange: {
|
||||||
from: dateTime(1546372800000),
|
from: dateTime(1546372800000),
|
||||||
|
@ -15,8 +15,7 @@ export type SeriesColorChangeHandler = SeriesOptionChangeHandler<string>;
|
|||||||
export type SeriesAxisToggleHandler = SeriesOptionChangeHandler<number>;
|
export type SeriesAxisToggleHandler = SeriesOptionChangeHandler<number>;
|
||||||
|
|
||||||
export interface GraphWithLegendProps extends GraphProps, LegendRenderOptions {
|
export interface GraphWithLegendProps extends GraphProps, LegendRenderOptions {
|
||||||
isLegendVisible: boolean;
|
legendDisplayMode: LegendDisplayMode;
|
||||||
displayMode: LegendDisplayMode;
|
|
||||||
sortLegendBy?: string;
|
sortLegendBy?: string;
|
||||||
sortLegendDesc?: boolean;
|
sortLegendDesc?: boolean;
|
||||||
onSeriesColorChange?: SeriesColorChangeHandler;
|
onSeriesColorChange?: SeriesColorChangeHandler;
|
||||||
@ -59,8 +58,7 @@ export const GraphWithLegend: React.FunctionComponent<GraphWithLegendProps> = (p
|
|||||||
showPoints,
|
showPoints,
|
||||||
sortLegendBy,
|
sortLegendBy,
|
||||||
sortLegendDesc,
|
sortLegendDesc,
|
||||||
isLegendVisible,
|
legendDisplayMode,
|
||||||
displayMode,
|
|
||||||
placement,
|
placement,
|
||||||
onSeriesAxisToggle,
|
onSeriesAxisToggle,
|
||||||
onSeriesColorChange,
|
onSeriesColorChange,
|
||||||
@ -84,7 +82,7 @@ export const GraphWithLegend: React.FunctionComponent<GraphWithLegendProps> = (p
|
|||||||
{
|
{
|
||||||
label: s.label,
|
label: s.label,
|
||||||
color: s.color || '',
|
color: s.color || '',
|
||||||
isVisible: s.isVisible,
|
disabled: !s.isVisible,
|
||||||
yAxis: s.yAxis.index,
|
yAxis: s.yAxis.index,
|
||||||
displayValues: s.info || [],
|
displayValues: s.info || [],
|
||||||
},
|
},
|
||||||
@ -103,7 +101,6 @@ export const GraphWithLegend: React.FunctionComponent<GraphWithLegendProps> = (p
|
|||||||
showBars={showBars}
|
showBars={showBars}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
key={isLegendVisible ? 'legend-visible' : 'legend-invisible'}
|
|
||||||
isStacked={isStacked}
|
isStacked={isStacked}
|
||||||
lineWidth={lineWidth}
|
lineWidth={lineWidth}
|
||||||
onHorizontalRegionSelected={onHorizontalRegionSelected}
|
onHorizontalRegionSelected={onHorizontalRegionSelected}
|
||||||
@ -112,12 +109,12 @@ export const GraphWithLegend: React.FunctionComponent<GraphWithLegendProps> = (p
|
|||||||
</Graph>
|
</Graph>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLegendVisible && (
|
{legendDisplayMode !== LegendDisplayMode.Hidden && (
|
||||||
<div className={legendContainer}>
|
<div className={legendContainer}>
|
||||||
<CustomScrollbar hideHorizontalTrack>
|
<CustomScrollbar hideHorizontalTrack>
|
||||||
<GraphLegend
|
<GraphLegend
|
||||||
items={legendItems}
|
items={legendItems}
|
||||||
displayMode={displayMode}
|
displayMode={legendDisplayMode}
|
||||||
placement={placement}
|
placement={placement}
|
||||||
sortBy={sortLegendBy}
|
sortBy={sortLegendBy}
|
||||||
sortDesc={sortLegendDesc}
|
sortDesc={sortLegendDesc}
|
||||||
|
@ -6,6 +6,7 @@ import { dateTime } from '@grafana/data';
|
|||||||
import { LegendDisplayMode } from '../Legend/Legend';
|
import { LegendDisplayMode } from '../Legend/Legend';
|
||||||
import { prepDataForStorybook } from '../../utils/storybook/data';
|
import { prepDataForStorybook } from '../../utils/storybook/data';
|
||||||
import { useTheme } from '../../themes';
|
import { useTheme } from '../../themes';
|
||||||
|
import { text, select } from '@storybook/addon-knobs';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'Visualizations/GraphNG',
|
title: 'Visualizations/GraphNG',
|
||||||
@ -16,7 +17,23 @@ export default {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getKnobs = () => {
|
||||||
|
return {
|
||||||
|
unit: text('Unit', 'short'),
|
||||||
|
legendPlacement: select(
|
||||||
|
'Legend placement',
|
||||||
|
{
|
||||||
|
bottom: 'bottom',
|
||||||
|
right: 'right',
|
||||||
|
},
|
||||||
|
'bottom'
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const Lines: React.FC = () => {
|
export const Lines: React.FC = () => {
|
||||||
|
const { unit, legendPlacement } = getKnobs();
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const seriesA = toDataFrame({
|
const seriesA = toDataFrame({
|
||||||
target: 'SeriesA',
|
target: 'SeriesA',
|
||||||
@ -29,7 +46,7 @@ export const Lines: React.FC = () => {
|
|||||||
|
|
||||||
seriesA.fields[1].config.custom = { line: { show: true } };
|
seriesA.fields[1].config.custom = { line: { show: true } };
|
||||||
seriesA.fields[1].config.color = { mode: FieldColorModeId.PaletteClassic };
|
seriesA.fields[1].config.color = { mode: FieldColorModeId.PaletteClassic };
|
||||||
seriesA.fields[1].config.unit = 'degree';
|
seriesA.fields[1].config.unit = unit;
|
||||||
|
|
||||||
const data = prepDataForStorybook([seriesA], theme);
|
const data = prepDataForStorybook([seriesA], theme);
|
||||||
|
|
||||||
@ -46,7 +63,7 @@ export const Lines: React.FC = () => {
|
|||||||
to: dateTime(1546380000000),
|
to: dateTime(1546380000000),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
legend={{ isVisible: true, displayMode: LegendDisplayMode.List, placement: 'bottom' }}
|
legend={{ displayMode: LegendDisplayMode.List, placement: legendPlacement }}
|
||||||
timeZone="browser"
|
timeZone="browser"
|
||||||
></GraphNG>
|
></GraphNG>
|
||||||
);
|
);
|
||||||
|
@ -35,7 +35,6 @@ const mockData = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const defaultLegendOptions: LegendOptions = {
|
const defaultLegendOptions: LegendOptions = {
|
||||||
isVisible: false,
|
|
||||||
displayMode: LegendDisplayMode.List,
|
displayMode: LegendDisplayMode.List,
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ import { UPlotChart } from '../uPlot/Plot';
|
|||||||
import { AxisSide, GraphCustomFieldConfig, PlotProps } from '../uPlot/types';
|
import { AxisSide, GraphCustomFieldConfig, PlotProps } from '../uPlot/types';
|
||||||
import { useTheme } from '../../themes';
|
import { useTheme } from '../../themes';
|
||||||
import { VizLayout } from '../VizLayout/VizLayout';
|
import { VizLayout } from '../VizLayout/VizLayout';
|
||||||
import { LegendItem, LegendOptions } from '../Legend/Legend';
|
import { LegendDisplayMode, LegendItem, LegendOptions } from '../Legend/Legend';
|
||||||
import { GraphLegend } from '../Graph/GraphLegend';
|
import { GraphLegend } from '../Graph/GraphLegend';
|
||||||
|
|
||||||
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1));
|
||||||
@ -63,6 +63,7 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
let seriesIdx = 0;
|
let seriesIdx = 0;
|
||||||
const legendItems: LegendItem[] = [];
|
const legendItems: LegendItem[] = [];
|
||||||
const uniqueScales: Record<string, boolean> = {};
|
const uniqueScales: Record<string, boolean> = {};
|
||||||
|
const hasLegend = legend && legend.displayMode !== LegendDisplayMode.Hidden;
|
||||||
|
|
||||||
for (let i = 0; i < alignedData.fields.length; i++) {
|
for (let i = 0; i < alignedData.fields.length; i++) {
|
||||||
const seriesGeometry = [];
|
const seriesGeometry = [];
|
||||||
@ -132,11 +133,10 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
geometries.push(seriesGeometry);
|
geometries.push(seriesGeometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (legend?.isVisible) {
|
if (hasLegend) {
|
||||||
legendItems.push({
|
legendItems.push({
|
||||||
color: seriesColor,
|
color: seriesColor,
|
||||||
label: getFieldDisplayName(field, alignedData),
|
label: getFieldDisplayName(field, alignedData),
|
||||||
isVisible: true,
|
|
||||||
yAxis: customConfig?.axis?.side === 1 ? 3 : 1,
|
yAxis: customConfig?.axis?.side === 1 ? 3 : 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -146,10 +146,10 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
|||||||
|
|
||||||
let legendElement: React.ReactElement | undefined;
|
let legendElement: React.ReactElement | undefined;
|
||||||
|
|
||||||
if (legend?.isVisible && legendItems.length > 0) {
|
if (hasLegend && legendItems.length > 0) {
|
||||||
legendElement = (
|
legendElement = (
|
||||||
<VizLayout.Legend position={legend.placement} maxHeight="35%" maxWidth="60%">
|
<VizLayout.Legend position={legend!.placement} maxHeight="35%" maxWidth="60%">
|
||||||
<GraphLegend placement={legend.placement} items={legendItems} displayMode={legend.displayMode} />
|
<GraphLegend placement={legend!.placement} items={legendItems} displayMode={legend!.displayMode} />
|
||||||
</VizLayout.Legend>
|
</VizLayout.Legend>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ const getStoriesKnobs = (table = false) => {
|
|||||||
|
|
||||||
const rawRenderer = (item: LegendItem) => (
|
const rawRenderer = (item: LegendItem) => (
|
||||||
<>
|
<>
|
||||||
Label: <strong>{item.label}</strong>, Color: <strong>{item.color}</strong>, isVisible:{' '}
|
Label: <strong>{item.label}</strong>, Color: <strong>{item.color}</strong>, disabled:{' '}
|
||||||
<strong>{item.isVisible ? 'yes' : 'no'}</strong>
|
<strong>{item.disabled ? 'yes' : 'no'}</strong>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: Dis
|
|||||||
return {
|
return {
|
||||||
label: `${alphabet[i].toUpperCase()}-series`,
|
label: `${alphabet[i].toUpperCase()}-series`,
|
||||||
color: tinycolor.fromRatio({ h: i / alphabet.length, s: 1, v: 1 }).toHexString(),
|
color: tinycolor.fromRatio({ h: i / alphabet.length, s: 1, v: 1 }).toHexString(),
|
||||||
isVisible: true,
|
|
||||||
yAxis: 1,
|
yAxis: 1,
|
||||||
displayValues: statsToDisplay || [],
|
displayValues: statsToDisplay || [],
|
||||||
};
|
};
|
||||||
@ -21,9 +20,9 @@ export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: Dis
|
|||||||
export enum LegendDisplayMode {
|
export enum LegendDisplayMode {
|
||||||
List = 'list',
|
List = 'list',
|
||||||
Table = 'table',
|
Table = 'table',
|
||||||
|
Hidden = 'hidden',
|
||||||
}
|
}
|
||||||
export interface LegendBasicOptions {
|
export interface LegendBasicOptions {
|
||||||
isVisible: boolean;
|
|
||||||
displayMode: LegendDisplayMode;
|
displayMode: LegendDisplayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +39,8 @@ export interface LegendOptions extends LegendBasicOptions, LegendRenderOptions {
|
|||||||
export interface LegendItem {
|
export interface LegendItem {
|
||||||
label: string;
|
label: string;
|
||||||
color: string;
|
color: string;
|
||||||
isVisible: boolean;
|
|
||||||
yAxis: number;
|
yAxis: number;
|
||||||
|
disabled?: boolean;
|
||||||
displayValues?: DisplayValue[];
|
displayValues?: DisplayValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export const BottomLegend = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VizLayout width={400} height={500} legend={legend}>
|
<VizLayout width={600} height={500} legend={legend}>
|
||||||
{(vizWidth: number, vizHeight: number) => {
|
{(vizWidth: number, vizHeight: number) => {
|
||||||
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
||||||
}}
|
}}
|
||||||
@ -57,7 +57,7 @@ export const RightLegend = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VizLayout width={400} height={500} legend={legend}>
|
<VizLayout width={810} height={400} legend={legend}>
|
||||||
{(vizWidth: number, vizHeight: number) => {
|
{(vizWidth: number, vizHeight: number) => {
|
||||||
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
return <div style={{ width: vizWidth, height: vizHeight, background: 'red' }} />;
|
||||||
}}
|
}}
|
||||||
|
@ -38,7 +38,7 @@ export const VizLayout: VizLayoutComponentType = ({ width, height, legend, child
|
|||||||
let size: VizSize | null = null;
|
let size: VizSize | null = null;
|
||||||
|
|
||||||
const vizStyle: CSSProperties = {
|
const vizStyle: CSSProperties = {
|
||||||
flexGrow: 1,
|
flexGrow: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const legendStyle: CSSProperties = {};
|
const legendStyle: CSSProperties = {};
|
||||||
@ -62,6 +62,16 @@ export const VizLayout: VizLayoutComponentType = ({ width, height, legend, child
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This happens when position is switched from bottom to right
|
||||||
|
// Then we preserve old with for one render cycle until lenged is measured in it's new position
|
||||||
|
if (size?.width === 0) {
|
||||||
|
size.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size?.height === 0) {
|
||||||
|
size.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={containerStyle}>
|
<div style={containerStyle}>
|
||||||
<div style={vizStyle}>{size && children(size.width, size.height)}</div>
|
<div style={vizStyle}>{size && children(size.width, size.height)}</div>
|
||||||
|
@ -119,7 +119,7 @@ function calculateAxisSize(self: uPlot, values: string[], axisIdx: number) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return measureText(maxLength, 12).width;
|
return measureText(maxLength, 12).width - 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Format time axis ticks */
|
/** Format time axis ticks */
|
||||||
|
@ -17,7 +17,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -59,7 +59,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -108,7 +108,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -155,7 +155,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -203,7 +203,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -253,7 +253,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -297,7 +297,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -341,7 +341,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -391,7 +391,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -439,7 +439,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -484,7 +484,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
@ -538,7 +538,7 @@ describe('usePlotConfig', () => {
|
|||||||
"alpha": 1,
|
"alpha": 1,
|
||||||
},
|
},
|
||||||
"gutters": Object {
|
"gutters": Object {
|
||||||
"x": 16,
|
"x": 8,
|
||||||
"y": 8,
|
"y": 8,
|
||||||
},
|
},
|
||||||
"height": 0,
|
"height": 0,
|
||||||
|
@ -95,7 +95,7 @@ export const DEFAULT_PLOT_CONFIG = {
|
|||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
gutters: {
|
gutters: {
|
||||||
x: 16,
|
x: 8,
|
||||||
y: 8,
|
y: 8,
|
||||||
},
|
},
|
||||||
series: [],
|
series: [],
|
||||||
|
@ -113,9 +113,8 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<GraphWithLegend
|
<GraphWithLegend
|
||||||
ariaLabel={ariaLabel}
|
ariaLabel={ariaLabel}
|
||||||
displayMode={LegendDisplayMode.List}
|
legendDisplayMode={LegendDisplayMode.List}
|
||||||
height={height}
|
height={height}
|
||||||
isLegendVisible={true}
|
|
||||||
placement={'bottom'}
|
placement={'bottom'}
|
||||||
width={width}
|
width={width}
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
|
@ -92,7 +92,7 @@ export const decorateWithGraphResult = (data: ExplorePanelData): ExplorePanelDat
|
|||||||
data.request?.timezone ?? 'browser',
|
data.request?.timezone ?? 'browser',
|
||||||
{},
|
{},
|
||||||
{ showBars: false, showLines: true, showPoints: false },
|
{ showBars: false, showLines: true, showPoints: false },
|
||||||
{ displayMode: LegendDisplayMode.List, isVisible: true, placement: 'bottom' }
|
{ displayMode: LegendDisplayMode.List, placement: 'bottom' }
|
||||||
);
|
);
|
||||||
|
|
||||||
return { ...data, graphResult };
|
return { ...data, graphResult };
|
||||||
|
@ -53,8 +53,7 @@ export const GraphPanel: React.FunctionComponent<GraphPanelProps> = ({
|
|||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
displayMode={legendOptions.displayMode}
|
legendDisplayMode={legendOptions.displayMode}
|
||||||
isLegendVisible={legendOptions.isVisible}
|
|
||||||
placement={legendOptions.placement}
|
placement={legendOptions.placement}
|
||||||
sortLegendBy={legendOptions.sortBy}
|
sortLegendBy={legendOptions.sortBy}
|
||||||
sortLegendDesc={legendOptions.sortDesc}
|
sortLegendDesc={legendOptions.sortDesc}
|
||||||
|
@ -28,7 +28,6 @@ export const defaults: Options = {
|
|||||||
showPoints: false,
|
showPoints: false,
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
isVisible: true,
|
|
||||||
displayMode: LegendDisplayMode.List,
|
displayMode: LegendDisplayMode.List,
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,7 @@ export const GraphPanel: React.FC<GraphPanelProps> = ({
|
|||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
timeZone={timeZone}
|
timeZone={timeZone}
|
||||||
width={width}
|
width={width}
|
||||||
height={height - 8}
|
height={height}
|
||||||
legend={options.legend}
|
legend={options.legend}
|
||||||
>
|
>
|
||||||
<TooltipPlugin mode={options.tooltipOptions.mode as any} timeZone={timeZone} />
|
<TooltipPlugin mode={options.tooltipOptions.mode as any} timeZone={timeZone} />
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data';
|
import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data';
|
||||||
import { AxisSide, GraphCustomFieldConfig } from '@grafana/ui';
|
import { AxisSide, GraphCustomFieldConfig, LegendDisplayMode } from '@grafana/ui';
|
||||||
import { GraphPanel } from './GraphPanel';
|
import { GraphPanel } from './GraphPanel';
|
||||||
import { Options } from './types';
|
import { Options } from './types';
|
||||||
|
|
||||||
export const plugin = new PanelPlugin<Options, GraphCustomFieldConfig>(GraphPanel)
|
export const plugin = new PanelPlugin<Options, GraphCustomFieldConfig>(GraphPanel)
|
||||||
.setNoPadding()
|
|
||||||
.useFieldConfig({
|
.useFieldConfig({
|
||||||
standardOptions: {
|
standardOptions: {
|
||||||
[FieldConfigProperty.Color]: {
|
[FieldConfigProperty.Color]: {
|
||||||
@ -133,29 +132,26 @@ export const plugin = new PanelPlugin<Options, GraphCustomFieldConfig>(GraphPane
|
|||||||
defaultValue: 'single',
|
defaultValue: 'single',
|
||||||
settings: {
|
settings: {
|
||||||
options: [
|
options: [
|
||||||
{ value: 'single', label: 'Single series' },
|
{ value: 'single', label: 'Single' },
|
||||||
{ value: 'multi', label: 'All series' },
|
{ value: 'multi', label: 'All' },
|
||||||
{ value: 'none', label: 'No tooltip' },
|
{ value: 'none', label: 'Hidden' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.addBooleanSwitch({
|
.addRadio({
|
||||||
category: ['Legend'],
|
path: 'legend.displayMode',
|
||||||
path: 'legend.isVisible',
|
name: 'Legend mode',
|
||||||
name: 'Show legend',
|
|
||||||
description: '',
|
description: '',
|
||||||
defaultValue: true,
|
defaultValue: LegendDisplayMode.List,
|
||||||
})
|
settings: {
|
||||||
.addBooleanSwitch({
|
options: [
|
||||||
category: ['Legend'],
|
{ value: LegendDisplayMode.List, label: 'List' },
|
||||||
path: 'legend.asTable',
|
{ value: LegendDisplayMode.Table, label: 'Table' },
|
||||||
name: 'Display legend as table',
|
{ value: LegendDisplayMode.Hidden, label: 'Hidden' },
|
||||||
description: '',
|
],
|
||||||
defaultValue: false,
|
},
|
||||||
showIf: c => c.legend.isVisible,
|
|
||||||
})
|
})
|
||||||
.addRadio({
|
.addRadio({
|
||||||
category: ['Legend'],
|
|
||||||
path: 'legend.placement',
|
path: 'legend.placement',
|
||||||
name: 'Legend placement',
|
name: 'Legend placement',
|
||||||
description: '',
|
description: '',
|
||||||
@ -166,6 +162,6 @@ export const plugin = new PanelPlugin<Options, GraphCustomFieldConfig>(GraphPane
|
|||||||
{ value: 'right', label: 'Right' },
|
{ value: 'right', label: 'Right' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
showIf: c => c.legend.isVisible,
|
showIf: c => c.legend.displayMode !== LegendDisplayMode.Hidden,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user