diff --git a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx index 23cd58e4429..dcbd62023a9 100644 --- a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx +++ b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx @@ -44,7 +44,7 @@ export const GraphLegendListItem: React.FunctionComponent onLabelClick(item, event); } }} - className={cx(styles.label, !item.isVisible && styles.labelDisabled)} + className={cx(styles.label, item.disabled && styles.labelDisabled)} > {item.label} diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx index 471b4234f59..0dc8e04b701 100644 --- a/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx +++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx @@ -123,8 +123,7 @@ export const graphWithLegend = () => { } return s; }), - displayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List, - isLegendVisible: true, + legendDisplayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List, onToggleSort: () => {}, timeRange: { from: dateTime(1546372800000), diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx index 4dc33ff40e2..c1998365925 100644 --- a/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx +++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx @@ -15,8 +15,7 @@ export type SeriesColorChangeHandler = SeriesOptionChangeHandler; export type SeriesAxisToggleHandler = SeriesOptionChangeHandler; export interface GraphWithLegendProps extends GraphProps, LegendRenderOptions { - isLegendVisible: boolean; - displayMode: LegendDisplayMode; + legendDisplayMode: LegendDisplayMode; sortLegendBy?: string; sortLegendDesc?: boolean; onSeriesColorChange?: SeriesColorChangeHandler; @@ -59,8 +58,7 @@ export const GraphWithLegend: React.FunctionComponent = (p showPoints, sortLegendBy, sortLegendDesc, - isLegendVisible, - displayMode, + legendDisplayMode, placement, onSeriesAxisToggle, onSeriesColorChange, @@ -84,7 +82,7 @@ export const GraphWithLegend: React.FunctionComponent = (p { label: s.label, color: s.color || '', - isVisible: s.isVisible, + disabled: !s.isVisible, yAxis: s.yAxis.index, displayValues: s.info || [], }, @@ -103,7 +101,6 @@ export const GraphWithLegend: React.FunctionComponent = (p showBars={showBars} width={width} height={height} - key={isLegendVisible ? 'legend-visible' : 'legend-invisible'} isStacked={isStacked} lineWidth={lineWidth} onHorizontalRegionSelected={onHorizontalRegionSelected} @@ -112,12 +109,12 @@ export const GraphWithLegend: React.FunctionComponent = (p - {isLegendVisible && ( + {legendDisplayMode !== LegendDisplayMode.Hidden && (
{ + return { + unit: text('Unit', 'short'), + legendPlacement: select( + 'Legend placement', + { + bottom: 'bottom', + right: 'right', + }, + 'bottom' + ), + }; +}; + export const Lines: React.FC = () => { + const { unit, legendPlacement } = getKnobs(); + const theme = useTheme(); const seriesA = toDataFrame({ target: 'SeriesA', @@ -29,7 +46,7 @@ export const Lines: React.FC = () => { seriesA.fields[1].config.custom = { line: { show: true } }; 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); @@ -46,7 +63,7 @@ export const Lines: React.FC = () => { to: dateTime(1546380000000), }, }} - legend={{ isVisible: true, displayMode: LegendDisplayMode.List, placement: 'bottom' }} + legend={{ displayMode: LegendDisplayMode.List, placement: legendPlacement }} timeZone="browser" > ); diff --git a/packages/grafana-ui/src/components/GraphNG/GraphNG.test.tsx b/packages/grafana-ui/src/components/GraphNG/GraphNG.test.tsx index 97a0d901750..041b4f0996f 100644 --- a/packages/grafana-ui/src/components/GraphNG/GraphNG.test.tsx +++ b/packages/grafana-ui/src/components/GraphNG/GraphNG.test.tsx @@ -35,7 +35,6 @@ const mockData = () => { }; const defaultLegendOptions: LegendOptions = { - isVisible: false, displayMode: LegendDisplayMode.List, placement: 'bottom', }; diff --git a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx index 423bbb49633..68c79f2c76a 100644 --- a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx +++ b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx @@ -15,7 +15,7 @@ import { UPlotChart } from '../uPlot/Plot'; import { AxisSide, GraphCustomFieldConfig, PlotProps } from '../uPlot/types'; import { useTheme } from '../../themes'; import { VizLayout } from '../VizLayout/VizLayout'; -import { LegendItem, LegendOptions } from '../Legend/Legend'; +import { LegendDisplayMode, LegendItem, LegendOptions } from '../Legend/Legend'; import { GraphLegend } from '../Graph/GraphLegend'; const defaultFormatter = (v: any) => (v == null ? '-' : v.toFixed(1)); @@ -63,6 +63,7 @@ export const GraphNG: React.FC = ({ let seriesIdx = 0; const legendItems: LegendItem[] = []; const uniqueScales: Record = {}; + const hasLegend = legend && legend.displayMode !== LegendDisplayMode.Hidden; for (let i = 0; i < alignedData.fields.length; i++) { const seriesGeometry = []; @@ -132,11 +133,10 @@ export const GraphNG: React.FC = ({ geometries.push(seriesGeometry); } - if (legend?.isVisible) { + if (hasLegend) { legendItems.push({ color: seriesColor, label: getFieldDisplayName(field, alignedData), - isVisible: true, yAxis: customConfig?.axis?.side === 1 ? 3 : 1, }); } @@ -146,10 +146,10 @@ export const GraphNG: React.FC = ({ let legendElement: React.ReactElement | undefined; - if (legend?.isVisible && legendItems.length > 0) { + if (hasLegend && legendItems.length > 0) { legendElement = ( - - + + ); } diff --git a/packages/grafana-ui/src/components/Legend/Legend.story.tsx b/packages/grafana-ui/src/components/Legend/Legend.story.tsx index ece49a03dad..f73fa86bcf7 100644 --- a/packages/grafana-ui/src/components/Legend/Legend.story.tsx +++ b/packages/grafana-ui/src/components/Legend/Legend.story.tsx @@ -19,8 +19,8 @@ const getStoriesKnobs = (table = false) => { const rawRenderer = (item: LegendItem) => ( <> - Label: {item.label}, Color: {item.color}, isVisible:{' '} - {item.isVisible ? 'yes' : 'no'} + Label: {item.label}, Color: {item.color}, disabled:{' '} + {item.disabled ? 'yes' : 'no'} ); diff --git a/packages/grafana-ui/src/components/Legend/Legend.tsx b/packages/grafana-ui/src/components/Legend/Legend.tsx index a585fb0e992..014aa74302f 100644 --- a/packages/grafana-ui/src/components/Legend/Legend.tsx +++ b/packages/grafana-ui/src/components/Legend/Legend.tsx @@ -11,7 +11,6 @@ export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: Dis return { label: `${alphabet[i].toUpperCase()}-series`, color: tinycolor.fromRatio({ h: i / alphabet.length, s: 1, v: 1 }).toHexString(), - isVisible: true, yAxis: 1, displayValues: statsToDisplay || [], }; @@ -21,9 +20,9 @@ export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: Dis export enum LegendDisplayMode { List = 'list', Table = 'table', + Hidden = 'hidden', } export interface LegendBasicOptions { - isVisible: boolean; displayMode: LegendDisplayMode; } @@ -40,8 +39,8 @@ export interface LegendOptions extends LegendBasicOptions, LegendRenderOptions { export interface LegendItem { label: string; color: string; - isVisible: boolean; yAxis: number; + disabled?: boolean; displayValues?: DisplayValue[]; } diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx index 94d2cd8bb9b..0cbeabd3fb0 100644 --- a/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx +++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.story.tsx @@ -34,7 +34,7 @@ export const BottomLegend = () => { ); return ( - + {(vizWidth: number, vizHeight: number) => { return
; }} @@ -57,7 +57,7 @@ export const RightLegend = () => { ); return ( - + {(vizWidth: number, vizHeight: number) => { return
; }} diff --git a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx index 885cf287c34..419a3c63ac1 100644 --- a/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx +++ b/packages/grafana-ui/src/components/VizLayout/VizLayout.tsx @@ -38,7 +38,7 @@ export const VizLayout: VizLayoutComponentType = ({ width, height, legend, child let size: VizSize | null = null; const vizStyle: CSSProperties = { - flexGrow: 1, + flexGrow: 2, }; const legendStyle: CSSProperties = {}; @@ -62,6 +62,16 @@ export const VizLayout: VizLayoutComponentType = ({ width, height, legend, child 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 (
{size && children(size.width, size.height)}
diff --git a/packages/grafana-ui/src/components/uPlot/geometries/Axis.tsx b/packages/grafana-ui/src/components/uPlot/geometries/Axis.tsx index 66c232d622f..9b2bd7683af 100644 --- a/packages/grafana-ui/src/components/uPlot/geometries/Axis.tsx +++ b/packages/grafana-ui/src/components/uPlot/geometries/Axis.tsx @@ -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 */ diff --git a/packages/grafana-ui/src/components/uPlot/hooks.test.ts b/packages/grafana-ui/src/components/uPlot/hooks.test.ts index e49edcc4eb2..757f91ebc07 100644 --- a/packages/grafana-ui/src/components/uPlot/hooks.test.ts +++ b/packages/grafana-ui/src/components/uPlot/hooks.test.ts @@ -17,7 +17,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -59,7 +59,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -108,7 +108,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -155,7 +155,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -203,7 +203,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -253,7 +253,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -297,7 +297,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -341,7 +341,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -391,7 +391,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -439,7 +439,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -484,7 +484,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, @@ -538,7 +538,7 @@ describe('usePlotConfig', () => { "alpha": 1, }, "gutters": Object { - "x": 16, + "x": 8, "y": 8, }, "height": 0, diff --git a/packages/grafana-ui/src/components/uPlot/hooks.ts b/packages/grafana-ui/src/components/uPlot/hooks.ts index e37d75703f3..47d10f313b4 100644 --- a/packages/grafana-ui/src/components/uPlot/hooks.ts +++ b/packages/grafana-ui/src/components/uPlot/hooks.ts @@ -95,7 +95,7 @@ export const DEFAULT_PLOT_CONFIG = { show: false, }, gutters: { - x: 16, + x: 8, y: 8, }, series: [], diff --git a/public/app/features/explore/ExploreGraphPanel.tsx b/public/app/features/explore/ExploreGraphPanel.tsx index 41f2a362963..4b1c2f991af 100644 --- a/public/app/features/explore/ExploreGraphPanel.tsx +++ b/public/app/features/explore/ExploreGraphPanel.tsx @@ -113,9 +113,8 @@ class UnThemedExploreGraphPanel extends PureComponent { return ( = ({ timeZone={timeZone} width={width} height={height} - displayMode={legendOptions.displayMode} - isLegendVisible={legendOptions.isVisible} + legendDisplayMode={legendOptions.displayMode} placement={legendOptions.placement} sortLegendBy={legendOptions.sortBy} sortLegendDesc={legendOptions.sortDesc} diff --git a/public/app/plugins/panel/graph2/types.ts b/public/app/plugins/panel/graph2/types.ts index 85650995c65..6e817ac3d91 100644 --- a/public/app/plugins/panel/graph2/types.ts +++ b/public/app/plugins/panel/graph2/types.ts @@ -28,7 +28,6 @@ export const defaults: Options = { showPoints: false, }, legend: { - isVisible: true, displayMode: LegendDisplayMode.List, placement: 'bottom', }, diff --git a/public/app/plugins/panel/graph3/GraphPanel.tsx b/public/app/plugins/panel/graph3/GraphPanel.tsx index c818b090f67..4c8e5dd9de7 100644 --- a/public/app/plugins/panel/graph3/GraphPanel.tsx +++ b/public/app/plugins/panel/graph3/GraphPanel.tsx @@ -22,7 +22,7 @@ export const GraphPanel: React.FC = ({ timeRange={timeRange} timeZone={timeZone} width={width} - height={height - 8} + height={height} legend={options.legend} > diff --git a/public/app/plugins/panel/graph3/module.tsx b/public/app/plugins/panel/graph3/module.tsx index e12705efe71..c026899846c 100644 --- a/public/app/plugins/panel/graph3/module.tsx +++ b/public/app/plugins/panel/graph3/module.tsx @@ -1,10 +1,9 @@ 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 { Options } from './types'; export const plugin = new PanelPlugin(GraphPanel) - .setNoPadding() .useFieldConfig({ standardOptions: { [FieldConfigProperty.Color]: { @@ -133,29 +132,26 @@ export const plugin = new PanelPlugin(GraphPane defaultValue: 'single', settings: { options: [ - { value: 'single', label: 'Single series' }, - { value: 'multi', label: 'All series' }, - { value: 'none', label: 'No tooltip' }, + { value: 'single', label: 'Single' }, + { value: 'multi', label: 'All' }, + { value: 'none', label: 'Hidden' }, ], }, }) - .addBooleanSwitch({ - category: ['Legend'], - path: 'legend.isVisible', - name: 'Show legend', + .addRadio({ + path: 'legend.displayMode', + name: 'Legend mode', description: '', - defaultValue: true, - }) - .addBooleanSwitch({ - category: ['Legend'], - path: 'legend.asTable', - name: 'Display legend as table', - description: '', - defaultValue: false, - showIf: c => c.legend.isVisible, + defaultValue: LegendDisplayMode.List, + settings: { + options: [ + { value: LegendDisplayMode.List, label: 'List' }, + { value: LegendDisplayMode.Table, label: 'Table' }, + { value: LegendDisplayMode.Hidden, label: 'Hidden' }, + ], + }, }) .addRadio({ - category: ['Legend'], path: 'legend.placement', name: 'Legend placement', description: '', @@ -166,6 +162,6 @@ export const plugin = new PanelPlugin(GraphPane { value: 'right', label: 'Right' }, ], }, - showIf: c => c.legend.isVisible, + showIf: c => c.legend.displayMode !== LegendDisplayMode.Hidden, }); });