From d7b208ec58fa559ffb8b5a3fb9aa4686b3d444b2 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Thu, 21 Jul 2022 23:38:22 -0500 Subject: [PATCH] TimeSeries: Add option for symmetrical y axes (align 0) (#52555) --- .../grafana-schema/src/schema/mudball.cue | 1 + .../grafana-schema/src/schema/mudball.gen.ts | 1 + .../src/components/TimeSeries/utils.ts | 1 + .../uPlot/config/UPlotScaleBuilder.ts | 22 +++++++- .../grafana-ui/src/options/builder/axis.tsx | 51 +++++++++++-------- public/app/plugins/panel/timeseries/config.ts | 1 + 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/packages/grafana-schema/src/schema/mudball.cue b/packages/grafana-schema/src/schema/mudball.cue index 8e9f6694ec9..10e7c9331b5 100644 --- a/packages/grafana-schema/src/schema/mudball.cue +++ b/packages/grafana-schema/src/schema/mudball.cue @@ -95,6 +95,7 @@ AxisConfig: { axisSoftMax?: number axisGridShow?: bool scaleDistribution?: ScaleDistributionConfig + axisCenteredZero?: bool } @cuetsy(kind="interface") // TODO docs diff --git a/packages/grafana-schema/src/schema/mudball.gen.ts b/packages/grafana-schema/src/schema/mudball.gen.ts index 70229e5fc5b..1e9ce67d707 100644 --- a/packages/grafana-schema/src/schema/mudball.gen.ts +++ b/packages/grafana-schema/src/schema/mudball.gen.ts @@ -123,6 +123,7 @@ export interface ScaleDistributionConfig { } export interface AxisConfig { + axisCenteredZero?: boolean; axisColorMode?: AxisColorMode; axisGridShow?: boolean; axisLabel?: string; diff --git a/packages/grafana-ui/src/components/TimeSeries/utils.ts b/packages/grafana-ui/src/components/TimeSeries/utils.ts index 8682a00c976..9f9f2de8c3e 100644 --- a/packages/grafana-ui/src/components/TimeSeries/utils.ts +++ b/packages/grafana-ui/src/components/TimeSeries/utils.ts @@ -185,6 +185,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ max: field.config.max, softMin: customConfig.axisSoftMin, softMax: customConfig.axisSoftMax, + centeredZero: customConfig.axisCenteredZero, }, field ) diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts index db2bb0309d1..ee8aee79b68 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts @@ -17,6 +17,7 @@ export interface ScaleProps { orientation: ScaleOrientation; direction: ScaleDirection; log?: number; + centeredZero?: boolean; } export class UPlotScaleBuilder extends PlotConfigBuilder { @@ -26,7 +27,18 @@ export class UPlotScaleBuilder extends PlotConfigBuilder { } getConfig(): Scale { - let { isTime, scaleKey, min: hardMin, max: hardMax, softMin, softMax, range, direction, orientation } = this.props; + let { + isTime, + scaleKey, + min: hardMin, + max: hardMax, + softMin, + softMax, + range, + direction, + orientation, + centeredZero, + } = this.props; const distribution = !isTime ? { distr: @@ -68,6 +80,14 @@ export class UPlotScaleBuilder extends PlotConfigBuilder { let minMax: uPlot.Range.MinMax = [dataMin, dataMax]; if (scale.distr === 1 || scale.distr === 2) { + if (centeredZero) { + let absMin = Math.abs(dataMin); + let absMax = Math.abs(dataMax); + let max = Math.max(absMin, absMax); + dataMin = -max; + dataMax = max; + } + // @ts-ignore here we may use hardMin / hardMax to make sure any extra padding is computed from a more accurate delta minMax = uPlot.rangeNum(hardMinOnly ? hardMin : dataMin, hardMaxOnly ? hardMax : dataMax, rangeConfig); } else if (scale.distr === 3) { diff --git a/packages/grafana-ui/src/options/builder/axis.tsx b/packages/grafana-ui/src/options/builder/axis.tsx index 5e498f68498..117c74f1b4f 100644 --- a/packages/grafana-ui/src/options/builder/axis.tsx +++ b/packages/grafana-ui/src/options/builder/axis.tsx @@ -20,6 +20,8 @@ export function addAxisConfig( hideScale?: boolean ) { const category = ['Axis']; + + // options for axis appearance builder .addRadio({ path: 'axisPlacement', @@ -51,24 +53,6 @@ export function addAxisConfig( }, showIf: (c) => c.axisPlacement !== AxisPlacement.Hidden, }) - .addNumberInput({ - path: 'axisSoftMin', - name: 'Soft min', - defaultValue: defaultConfig.axisSoftMin, - category, - settings: { - placeholder: 'See: Standard options > Min', - }, - }) - .addNumberInput({ - path: 'axisSoftMax', - name: 'Soft max', - defaultValue: defaultConfig.axisSoftMax, - category, - settings: { - placeholder: 'See: Standard options > Max', - }, - }) .addRadio({ path: 'axisGridShow', name: 'Show grid lines', @@ -95,8 +79,9 @@ export function addAxisConfig( }, }); - if (!hideScale) { - builder.addCustomEditor({ + // options for scale range + builder + .addCustomEditor({ id: 'scaleDistribution', path: 'scaleDistribution', name: 'Scale', @@ -106,8 +91,32 @@ export function addAxisConfig( defaultValue: { type: ScaleDistribution.Linear }, shouldApply: (f) => f.type === FieldType.number, process: identityOverrideProcessor, + }) + .addBooleanSwitch({ + path: 'axisCenteredZero', + name: 'Centered zero', + category, + defaultValue: false, + showIf: (c) => c.scaleDistribution?.type !== ScaleDistribution.Log, + }) + .addNumberInput({ + path: 'axisSoftMin', + name: 'Soft min', + defaultValue: defaultConfig.axisSoftMin, + category, + settings: { + placeholder: 'See: Standard options > Min', + }, + }) + .addNumberInput({ + path: 'axisSoftMax', + name: 'Soft max', + defaultValue: defaultConfig.axisSoftMax, + category, + settings: { + placeholder: 'See: Standard options > Max', + }, }); - } } const DISTRIBUTION_OPTIONS: Array> = [ diff --git a/public/app/plugins/panel/timeseries/config.ts b/public/app/plugins/panel/timeseries/config.ts index b75ad5e5b68..747a3e783cd 100644 --- a/public/app/plugins/panel/timeseries/config.ts +++ b/public/app/plugins/panel/timeseries/config.ts @@ -37,6 +37,7 @@ export const defaultGraphConfig: GraphFieldConfig = { group: 'A', }, axisGridShow: true, + axisCenteredZero: false, }; const categoryStyles = ['Graph styles'];