mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TimeSeries: Use graph min/max for percentage threshold (#38528)
* TimeSeries: Use graph min/max as baseis for percentage threshold calculation. * respect hard and soft axis limits for % threshold steps * revert state-timeline changes * enable by-threshold coloring in histogram and barchart * revert yMin Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
parent
96557ecadc
commit
b248c119ef
@ -236,6 +236,10 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
|||||||
show: !customConfig.hideFrom?.viz,
|
show: !customConfig.hideFrom?.viz,
|
||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: config.thresholds,
|
thresholds: config.thresholds,
|
||||||
|
hardMin: field.config.min,
|
||||||
|
hardMax: field.config.max,
|
||||||
|
softMin: customConfig.axisSoftMin,
|
||||||
|
softMax: customConfig.axisSoftMax,
|
||||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||||
dataFrameFieldIndex: field.state?.origin,
|
dataFrameFieldIndex: field.state?.origin,
|
||||||
});
|
});
|
||||||
@ -249,6 +253,10 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
|||||||
thresholds: config.thresholds,
|
thresholds: config.thresholds,
|
||||||
scaleKey,
|
scaleKey,
|
||||||
theme,
|
theme,
|
||||||
|
hardMin: field.config.min,
|
||||||
|
hardMax: field.config.max,
|
||||||
|
softMin: customConfig.axisSoftMin,
|
||||||
|
softMax: customConfig.axisSoftMax,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,15 @@ export interface SeriesProps extends LineConfig, BarConfig, FillConfig, PointsCo
|
|||||||
scaleKey: string;
|
scaleKey: string;
|
||||||
pxAlign?: boolean;
|
pxAlign?: boolean;
|
||||||
gradientMode?: GraphGradientMode;
|
gradientMode?: GraphGradientMode;
|
||||||
|
|
||||||
/** Used when gradientMode is set to Scheme */
|
/** Used when gradientMode is set to Scheme */
|
||||||
thresholds?: ThresholdsConfig;
|
thresholds?: ThresholdsConfig;
|
||||||
/** Used when gradientMode is set to Scheme */
|
|
||||||
colorMode?: FieldColorMode;
|
colorMode?: FieldColorMode;
|
||||||
|
hardMin?: number | null;
|
||||||
|
hardMax?: number | null;
|
||||||
|
softMin?: number | null;
|
||||||
|
softMax?: number | null;
|
||||||
|
|
||||||
drawStyle?: GraphDrawStyle;
|
drawStyle?: GraphDrawStyle;
|
||||||
pathBuilder?: Series.PathBuilder;
|
pathBuilder?: Series.PathBuilder;
|
||||||
pointsFilter?: Series.Points.Filter;
|
pointsFilter?: Series.Points.Filter;
|
||||||
@ -138,17 +143,29 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getLineColor(): Series.Stroke {
|
private getLineColor(): Series.Stroke {
|
||||||
const { lineColor, gradientMode, colorMode, thresholds, theme } = this.props;
|
const { lineColor, gradientMode, colorMode, thresholds, theme, hardMin, hardMax, softMin, softMax } = this.props;
|
||||||
|
|
||||||
if (gradientMode === GraphGradientMode.Scheme && colorMode?.id !== FieldColorModeId.Fixed) {
|
if (gradientMode === GraphGradientMode.Scheme && colorMode?.id !== FieldColorModeId.Fixed) {
|
||||||
return getScaleGradientFn(1, theme, colorMode, thresholds);
|
return getScaleGradientFn(1, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
return lineColor ?? FALLBACK_COLOR;
|
return lineColor ?? FALLBACK_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getFill(): Series.Fill | undefined {
|
private getFill(): Series.Fill | undefined {
|
||||||
const { lineColor, fillColor, gradientMode, fillOpacity, colorMode, thresholds, theme } = this.props;
|
const {
|
||||||
|
lineColor,
|
||||||
|
fillColor,
|
||||||
|
gradientMode,
|
||||||
|
fillOpacity,
|
||||||
|
colorMode,
|
||||||
|
thresholds,
|
||||||
|
theme,
|
||||||
|
hardMin,
|
||||||
|
hardMax,
|
||||||
|
softMin,
|
||||||
|
softMax,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (fillColor) {
|
if (fillColor) {
|
||||||
return fillColor;
|
return fillColor;
|
||||||
@ -164,7 +181,7 @@ export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
|||||||
return getHueGradientFn((fillColor ?? lineColor)!, opacityPercent, theme);
|
return getHueGradientFn((fillColor ?? lineColor)!, opacityPercent, theme);
|
||||||
case GraphGradientMode.Scheme:
|
case GraphGradientMode.Scheme:
|
||||||
if (colorMode?.id !== FieldColorModeId.Fixed) {
|
if (colorMode?.id !== FieldColorModeId.Fixed) {
|
||||||
return getScaleGradientFn(opacityPercent, theme, colorMode, thresholds);
|
return getScaleGradientFn(opacityPercent, theme, colorMode, thresholds, hardMin, hardMax, softMin, softMax);
|
||||||
}
|
}
|
||||||
// intentional fall-through to handle Scheme with Fixed color
|
// intentional fall-through to handle Scheme with Fixed color
|
||||||
default:
|
default:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { GrafanaTheme2, ThresholdsConfig, ThresholdsMode } from '@grafana/data';
|
import { GrafanaTheme2, ThresholdsConfig, ThresholdsMode } from '@grafana/data';
|
||||||
import { GraphThresholdsStyleConfig, GraphTresholdsStyleMode } from '@grafana/schema';
|
import { GraphThresholdsStyleConfig, GraphTresholdsStyleMode } from '@grafana/schema';
|
||||||
import { getDataRange, GradientDirection, scaleGradient } from './gradientFills';
|
import { getThresholdRange, GradientDirection, scaleGradient } from './gradientFills';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
|
||||||
export interface UPlotThresholdOptions {
|
export interface UPlotThresholdOptions {
|
||||||
@ -8,23 +8,27 @@ export interface UPlotThresholdOptions {
|
|||||||
thresholds: ThresholdsConfig;
|
thresholds: ThresholdsConfig;
|
||||||
config: GraphThresholdsStyleConfig;
|
config: GraphThresholdsStyleConfig;
|
||||||
theme: GrafanaTheme2;
|
theme: GrafanaTheme2;
|
||||||
|
hardMin?: number | null;
|
||||||
|
hardMax?: number | null;
|
||||||
|
softMin?: number | null;
|
||||||
|
softMax?: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getThresholdsDrawHook(options: UPlotThresholdOptions) {
|
export function getThresholdsDrawHook(options: UPlotThresholdOptions) {
|
||||||
return (u: uPlot) => {
|
return (u: uPlot) => {
|
||||||
const ctx = u.ctx;
|
const ctx = u.ctx;
|
||||||
const { scaleKey, thresholds, theme, config } = options;
|
const { scaleKey, thresholds, theme, config, hardMin, hardMax, softMin, softMax } = options;
|
||||||
const { min: xMin, max: xMax } = u.scales.x;
|
const { min: xMin, max: xMax } = u.scales.x;
|
||||||
const { min: yMin, max: yMax } = u.scales[scaleKey];
|
const { min: yMin, max: yMax } = u.scales[scaleKey];
|
||||||
|
|
||||||
if (xMin === undefined || xMax === undefined || yMin === undefined || yMax === undefined) {
|
if (xMin == null || xMax == null || yMin == null || yMax == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { steps, mode } = thresholds;
|
let { steps, mode } = thresholds;
|
||||||
|
|
||||||
if (mode === ThresholdsMode.Percentage) {
|
if (mode === ThresholdsMode.Percentage) {
|
||||||
let [min, max] = getDataRange(u, scaleKey);
|
let [min, max] = getThresholdRange(u, scaleKey, hardMin, hardMax, softMin, softMax);
|
||||||
let range = max - min;
|
let range = max - min;
|
||||||
|
|
||||||
steps = steps.map((step) => ({
|
steps = steps.map((step) => ({
|
||||||
|
@ -172,11 +172,36 @@ export function getDataRange(plot: uPlot, scaleKey: string) {
|
|||||||
return [min, max];
|
return [min, max];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getThresholdRange(
|
||||||
|
u: uPlot,
|
||||||
|
scaleKey: string,
|
||||||
|
hardMin?: number | null,
|
||||||
|
hardMax?: number | null,
|
||||||
|
softMin?: number | null,
|
||||||
|
softMax?: number | null
|
||||||
|
) {
|
||||||
|
let min = hardMin ?? softMin ?? null;
|
||||||
|
let max = hardMax ?? softMax ?? null;
|
||||||
|
|
||||||
|
if (min == null || max == null) {
|
||||||
|
let [dataMin, dataMax] = getDataRange(u, scaleKey);
|
||||||
|
|
||||||
|
min = min ?? dataMin ?? 0;
|
||||||
|
max = max ?? dataMax ?? 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [min, max];
|
||||||
|
}
|
||||||
|
|
||||||
export function getScaleGradientFn(
|
export function getScaleGradientFn(
|
||||||
opacity: number,
|
opacity: number,
|
||||||
theme: GrafanaTheme2,
|
theme: GrafanaTheme2,
|
||||||
colorMode?: FieldColorMode,
|
colorMode?: FieldColorMode,
|
||||||
thresholds?: ThresholdsConfig
|
thresholds?: ThresholdsConfig,
|
||||||
|
hardMin?: number | null,
|
||||||
|
hardMax?: number | null,
|
||||||
|
softMin?: number | null,
|
||||||
|
softMax?: number | null
|
||||||
): (self: uPlot, seriesIdx: number) => CanvasGradient | string {
|
): (self: uPlot, seriesIdx: number) => CanvasGradient | string {
|
||||||
if (!colorMode) {
|
if (!colorMode) {
|
||||||
throw Error('Missing colorMode required for color scheme gradients');
|
throw Error('Missing colorMode required for color scheme gradients');
|
||||||
@ -199,7 +224,7 @@ export function getScaleGradientFn(
|
|||||||
);
|
);
|
||||||
gradient = scaleGradient(plot, scaleKey, GradientDirection.Up, valueStops, true);
|
gradient = scaleGradient(plot, scaleKey, GradientDirection.Up, valueStops, true);
|
||||||
} else {
|
} else {
|
||||||
const [min, max] = getDataRange(plot, scaleKey);
|
const [min, max] = getThresholdRange(plot, scaleKey, hardMin, hardMax, softMin, softMax);
|
||||||
const range = max - min;
|
const range = max - min;
|
||||||
const valueStops = thresholds.steps.map(
|
const valueStops = thresholds.steps.map(
|
||||||
(step) =>
|
(step) =>
|
||||||
@ -212,7 +237,7 @@ export function getScaleGradientFn(
|
|||||||
}
|
}
|
||||||
} else if (colorMode.getColors) {
|
} else if (colorMode.getColors) {
|
||||||
const colors = colorMode.getColors(theme);
|
const colors = colorMode.getColors(theme);
|
||||||
const [min, max] = getDataRange(plot, scaleKey);
|
const [min, max] = getThresholdRange(plot, scaleKey, hardMin, hardMax, softMin, softMax);
|
||||||
const range = max - min;
|
const range = max - min;
|
||||||
const valueStops = colors.map(
|
const valueStops = colors.map(
|
||||||
(color, i) =>
|
(color, i) =>
|
||||||
|
@ -17,7 +17,7 @@ export const plugin = new PanelPlugin<BarChartOptions, BarChartFieldConfig>(BarC
|
|||||||
standardOptions: {
|
standardOptions: {
|
||||||
[FieldConfigProperty.Color]: {
|
[FieldConfigProperty.Color]: {
|
||||||
settings: {
|
settings: {
|
||||||
byValueSupport: false,
|
byValueSupport: true,
|
||||||
},
|
},
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
mode: FieldColorModeId.PaletteClassic,
|
mode: FieldColorModeId.PaletteClassic,
|
||||||
|
@ -134,6 +134,10 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<BarChartOptions> = ({
|
|||||||
show: !customConfig.hideFrom?.viz,
|
show: !customConfig.hideFrom?.viz,
|
||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: field.config.thresholds,
|
thresholds: field.config.thresholds,
|
||||||
|
hardMin: field.config.min,
|
||||||
|
hardMax: field.config.max,
|
||||||
|
softMin: customConfig.axisSoftMin,
|
||||||
|
softMax: customConfig.axisSoftMax,
|
||||||
|
|
||||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||||
dataFrameFieldIndex: {
|
dataFrameFieldIndex: {
|
||||||
|
@ -182,6 +182,11 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
|
|||||||
gradientMode: customConfig.gradientMode,
|
gradientMode: customConfig.gradientMode,
|
||||||
thresholds: field.config.thresholds,
|
thresholds: field.config.thresholds,
|
||||||
|
|
||||||
|
hardMin: field.config.min,
|
||||||
|
hardMax: field.config.max,
|
||||||
|
softMin: customConfig.axisSoftMin,
|
||||||
|
softMax: customConfig.axisSoftMax,
|
||||||
|
|
||||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||||
dataFrameFieldIndex: {
|
dataFrameFieldIndex: {
|
||||||
fieldIndex: i,
|
fieldIndex: i,
|
||||||
|
@ -52,7 +52,7 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(HistogramP
|
|||||||
standardOptions: {
|
standardOptions: {
|
||||||
[FieldConfigProperty.Color]: {
|
[FieldConfigProperty.Color]: {
|
||||||
settings: {
|
settings: {
|
||||||
byValueSupport: false,
|
byValueSupport: true,
|
||||||
},
|
},
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
mode: FieldColorModeId.PaletteClassic,
|
mode: FieldColorModeId.PaletteClassic,
|
||||||
|
Loading…
Reference in New Issue
Block a user