diff --git a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx index 799dbdeb2b9..8cb23ea2fb5 100755 --- a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx +++ b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx @@ -242,6 +242,7 @@ export const GraphNG: React.FC = ({ lineWidth: customConfig.lineWidth, lineInterpolation: customConfig.lineInterpolation, lineStyle: customConfig.lineStyle, + barAlignment: customConfig.barAlignment, pointSize: customConfig.pointSize, pointColor: customConfig.pointColor ?? seriesColor, spanNulls: customConfig.spanNulls || false, diff --git a/packages/grafana-ui/src/components/Icon/custom/index.tsx b/packages/grafana-ui/src/components/Icon/custom/index.tsx index a7ac22dd718..9059b14b45a 100644 --- a/packages/grafana-ui/src/components/Icon/custom/index.tsx +++ b/packages/grafana-ui/src/components/Icon/custom/index.tsx @@ -81,11 +81,67 @@ const IconNotFound: FC = ({ size, ...rest }) => { return ; }; +const BarAlignmentAfter: FC = ({ size, ...rest }) => { + return ( + + + + + + + + + + ); +}; + +const BarAlignmentBefore: FC = ({ size, ...rest }) => { + return ( + + + + + + + + + + ); +}; + +const BarAlignmentCenter: FC = ({ size, ...rest }) => { + return ( + + + + + + + + + + + + ); +}; + export const customIcons: Record> = { 'gf-interpolation-linear': InterpolationLinear, 'gf-interpolation-smooth': InterpolationSmooth, 'gf-interpolation-step-before': InterpolationStepBefore, 'gf-interpolation-step-after': InterpolationStepAfter, 'gf-logs': Logs, + 'gf-bar-alignment-after': BarAlignmentAfter, + 'gf-bar-alignment-before': BarAlignmentBefore, + 'gf-bar-alignment-center': BarAlignmentCenter, notFoundDummy: IconNotFound, }; diff --git a/packages/grafana-ui/src/components/uPlot/config.ts b/packages/grafana-ui/src/components/uPlot/config.ts index c7806f870fc..43789d13bc5 100644 --- a/packages/grafana-ui/src/components/uPlot/config.ts +++ b/packages/grafana-ui/src/components/uPlot/config.ts @@ -40,6 +40,15 @@ export enum LineInterpolation { StepAfter = 'stepAfter', } +/** + * @alpha + */ +export enum BarAlignment { + Before = -1, + Center = 0, + After = 1, +} + /** * @alpha */ @@ -87,6 +96,13 @@ export interface LineConfig { spanNulls?: boolean; } +/** + * @alpha + */ +export interface BarConfig { + barAlignment?: BarAlignment; +} + /** * @alpha */ @@ -156,7 +172,13 @@ export interface HideableFieldConfig { /** * @alpha */ -export interface GraphFieldConfig extends LineConfig, FillConfig, PointsConfig, AxisConfig, HideableFieldConfig { +export interface GraphFieldConfig + extends LineConfig, + FillConfig, + PointsConfig, + AxisConfig, + BarConfig, + HideableFieldConfig { drawStyle?: DrawStyle; gradientMode?: GraphGradientMode; } @@ -178,6 +200,12 @@ export const graphFieldOptions = { { description: 'Step after', value: LineInterpolation.StepAfter, icon: 'gf-interpolation-step-after' }, ] as Array>, + barAlignment: [ + { description: 'Before', value: BarAlignment.Before, icon: 'gf-bar-alignment-before' }, + { description: 'Center', value: BarAlignment.Center, icon: 'gf-bar-alignment-center' }, + { description: 'After', value: BarAlignment.After, icon: 'gf-bar-alignment-after' }, + ] as Array>, + showPoints: [ { label: 'Auto', value: PointVisibility.Auto, description: 'Show points when the density is low' }, { label: 'Always', value: PointVisibility.Always }, diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts index ec22f9f73cb..6ece0f19295 100755 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts @@ -1,20 +1,21 @@ -import { FALLBACK_COLOR, FieldColorMode, GrafanaTheme, ThresholdsConfig } from '@grafana/data'; +import { DataFrameFieldIndex, FALLBACK_COLOR, FieldColorMode, GrafanaTheme, ThresholdsConfig } from '@grafana/data'; import tinycolor from 'tinycolor2'; import uPlot, { Series } from 'uplot'; import { + BarAlignment, + BarConfig, DrawStyle, - LineConfig, FillConfig, + GraphGradientMode, + LineConfig, + LineInterpolation, PointsConfig, PointVisibility, - LineInterpolation, - GraphGradientMode, } from '../config'; import { PlotConfigBuilder } from '../types'; -import { DataFrameFieldIndex } from '@grafana/data'; -import { getScaleGradientFn, getOpacityGradientFn, getHueGradientFn } from './gradientFills'; +import { getHueGradientFn, getOpacityGradientFn, getScaleGradientFn } from './gradientFills'; -export interface SeriesProps extends LineConfig, FillConfig, PointsConfig { +export interface SeriesProps extends LineConfig, BarConfig, FillConfig, PointsConfig { scaleKey: string; gradientMode?: GraphGradientMode; /** Used when gradientMode is set to Scheme */ @@ -40,6 +41,7 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { lineInterpolation, lineWidth, lineStyle, + barAlignment, showPoints, pointColor, pointSize, @@ -66,7 +68,7 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { lineConfig.dash = lineStyle.dash ?? [10, 10]; } lineConfig.paths = (self: uPlot, seriesIdx: number, idx0: number, idx1: number) => { - let pathsBuilder = mapDrawStyleToPathBuilder(drawStyle, lineInterpolation); + let pathsBuilder = mapDrawStyleToPathBuilder(drawStyle, lineInterpolation, barAlignment); return pathsBuilder(self, seriesIdx, idx0, idx1); }; } @@ -146,11 +148,13 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { } interface PathBuilders { - bars: Series.PathBuilder; linear: Series.PathBuilder; smooth: Series.PathBuilder; stepBefore: Series.PathBuilder; stepAfter: Series.PathBuilder; + bars: Series.PathBuilder; + barsAfter: Series.PathBuilder; + barsBefore: Series.PathBuilder; } let builders: PathBuilders | undefined = undefined; @@ -158,24 +162,32 @@ let builders: PathBuilders | undefined = undefined; function mapDrawStyleToPathBuilder( style: DrawStyle, lineInterpolation?: LineInterpolation, - opts?: any + barAlignment?: BarAlignment ): Series.PathBuilder { - // This should be global static, but Jest initalization was failing so we lazy load to avoid the issue if (!builders) { + // This should be global static, but Jest initalization was failing so we lazy load to avoid the issue const pathBuilders = uPlot.paths; const barWidthFactor = 0.6; const barMaxWidth = Infinity; builders = { - bars: pathBuilders.bars!({ size: [barWidthFactor, barMaxWidth] }), linear: pathBuilders.linear!(), smooth: pathBuilders.spline!(), stepBefore: pathBuilders.stepped!({ align: -1 }), stepAfter: pathBuilders.stepped!({ align: 1 }), + bars: pathBuilders.bars!({ size: [barWidthFactor, barMaxWidth] }), + barsBefore: pathBuilders.bars!({ size: [barWidthFactor, barMaxWidth], align: -1 }), + barsAfter: pathBuilders.bars!({ size: [barWidthFactor, barMaxWidth], align: 1 }), }; } if (style === DrawStyle.Bars) { + if (barAlignment === BarAlignment.After) { + return builders.barsAfter; + } + if (barAlignment === BarAlignment.Before) { + return builders.barsBefore; + } return builders.bars; } if (style === DrawStyle.Line) { diff --git a/public/app/plugins/panel/timeseries/config.ts b/public/app/plugins/panel/timeseries/config.ts index 67a1a367080..84d0d8cfb95 100644 --- a/public/app/plugins/panel/timeseries/config.ts +++ b/public/app/plugins/panel/timeseries/config.ts @@ -12,6 +12,7 @@ import { } from '@grafana/data'; import { AxisPlacement, + BarAlignment, DrawStyle, GraphFieldConfig, graphFieldOptions, @@ -36,6 +37,7 @@ export const defaultGraphConfig: GraphFieldConfig = { lineWidth: 1, fillOpacity: 0, gradientMode: GraphGradientMode.None, + barAlignment: BarAlignment.Center, }; export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOptionsArgs { @@ -71,6 +73,15 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig): SetFieldConfigOption }, showIf: (c) => c.drawStyle === DrawStyle.Line, }) + .addRadio({ + path: 'barAlignment', + name: 'Bar alignment', + defaultValue: cfg.barAlignment, + settings: { + options: graphFieldOptions.barAlignment, + }, + showIf: (c) => c.drawStyle === DrawStyle.Bars, + }) .addSliderInput({ path: 'lineWidth', name: 'Line width',