diff --git a/packages/grafana-ui/src/components/GraphNG/utils.test.ts b/packages/grafana-ui/src/components/GraphNG/utils.test.ts index 23efa7a7726..71b4f7a673e 100644 --- a/packages/grafana-ui/src/components/GraphNG/utils.test.ts +++ b/packages/grafana-ui/src/components/GraphNG/utils.test.ts @@ -5,6 +5,7 @@ import { DataFrame, DefaultTimeZone, EventBusSrv, + FieldColorModeId, FieldConfig, FieldMatcherID, fieldMatchers, @@ -38,6 +39,9 @@ function mockDataFrame() { const f1Config: FieldConfig = { displayName: 'Metric 1', + color: { + mode: FieldColorModeId.Fixed, + }, decimals: 2, custom: { drawStyle: GraphDrawStyle.Line, @@ -62,6 +66,9 @@ function mockDataFrame() { const f2Config: FieldConfig = { displayName: 'Metric 2', + color: { + mode: FieldColorModeId.Fixed, + }, decimals: 2, custom: { drawStyle: GraphDrawStyle.Bars, @@ -87,6 +94,9 @@ function mockDataFrame() { const f3Config: FieldConfig = { displayName: 'Metric 3', decimals: 2, + color: { + mode: FieldColorModeId.Fixed, + }, custom: { drawStyle: GraphDrawStyle.Line, gradientMode: GraphGradientMode.Opacity, @@ -110,6 +120,9 @@ function mockDataFrame() { const f4Config: FieldConfig = { displayName: 'Metric 4', decimals: 2, + color: { + mode: FieldColorModeId.Fixed, + }, custom: { drawStyle: GraphDrawStyle.Bars, gradientMode: GraphGradientMode.Hue, @@ -133,6 +146,9 @@ function mockDataFrame() { const f5Config: FieldConfig = { displayName: 'Metric 4', decimals: 2, + color: { + mode: FieldColorModeId.Fixed, + }, custom: { drawStyle: GraphDrawStyle.Bars, gradientMode: GraphGradientMode.Hue, diff --git a/packages/grafana-ui/src/components/TimeSeries/utils.ts b/packages/grafana-ui/src/components/TimeSeries/utils.ts index 062378b5124..fe587a7b64f 100644 --- a/packages/grafana-ui/src/components/TimeSeries/utils.ts +++ b/packages/grafana-ui/src/components/TimeSeries/utils.ts @@ -14,6 +14,7 @@ import { getFieldSeriesColor, getFieldDisplayName, getDisplayProcessor, + FieldColorModeId, } from '@grafana/data'; import { AxisPlacement, @@ -54,7 +55,14 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ }) => { const builder = new UPlotConfigBuilder(timeZone); - builder.setPrepData((frames) => preparePlotData2(frames[0], builder.getStackingGroups())); + let alignedFrame: DataFrame; + + builder.setPrepData((frames) => { + // cache alignedFrame + alignedFrame = frames[0]; + + return preparePlotData2(frames[0], builder.getStackingGroups()); + }); // X is the first field in the aligned frame const xField = frame.fields[0]; @@ -278,6 +286,12 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ } } + let dynamicSeriesColor: ((seriesIdx: number) => string | undefined) | undefined = undefined; + + if (colorMode.id === FieldColorModeId.Thresholds) { + dynamicSeriesColor = (seriesIdx) => getFieldSeriesColor(alignedFrame.fields[seriesIdx], theme).color; + } + builder.addSeries({ pathBuilder, pointsBuilder, @@ -287,6 +301,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ colorMode, fillOpacity, theme, + dynamicSeriesColor, drawStyle: customConfig.drawStyle!, lineColor: customConfig.lineColor ?? seriesColor, lineWidth: customConfig.lineWidth, diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts index fe0c7f081f3..cddb4918c57 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotSeriesBuilder.ts @@ -29,6 +29,7 @@ export interface SeriesProps extends LineConfig, BarConfig, FillConfig, PointsCo scaleKey: string; pxAlign?: boolean; gradientMode?: GraphGradientMode; + dynamicSeriesColor?: (seriesIdx: number) => string | undefined; facets?: uPlot.Series.Facet[]; @@ -150,7 +151,22 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { } private getLineColor(): Series.Stroke { - const { lineColor, gradientMode, colorMode, thresholds, theme, hardMin, hardMax, softMin, softMax } = this.props; + const { + lineColor, + gradientMode, + colorMode, + thresholds, + theme, + hardMin, + hardMax, + softMin, + softMax, + dynamicSeriesColor, + } = this.props; + + if (gradientMode === GraphGradientMode.None && dynamicSeriesColor) { + return (plot: uPlot, seriesIdx: number) => dynamicSeriesColor(seriesIdx) ?? lineColor ?? FALLBACK_COLOR; + } if (gradientMode === GraphGradientMode.Scheme && colorMode?.id !== FieldColorModeId.Fixed) { return getScaleGradientFn(1, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax); @@ -172,6 +188,7 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { hardMax, softMin, softMax, + dynamicSeriesColor, } = this.props; if (fillColor) { @@ -181,6 +198,14 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder { const mode = gradientMode ?? GraphGradientMode.None; const opacityPercent = (fillOpacity ?? 0) / 100; + if (mode === GraphGradientMode.None && dynamicSeriesColor && opacityPercent > 0) { + return (u: uPlot, seriesIdx: number) => { + // @ts-ignore + let lineColor = u.series[seriesIdx]._stroke; // cache + return colorManipulator.alpha(lineColor ?? '', opacityPercent); + }; + } + switch (mode) { case GraphGradientMode.Opacity: return getOpacityGradientFn((fillColor ?? lineColor)!, opacityPercent);