mirror of https://github.com/grafana/grafana.git
Trend/TimeSeries: Add "Show values" option (#108090)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
parent
67a6866c7b
commit
9fb5790166
|
@ -57,6 +57,7 @@
|
|||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"showValues": true,
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
|
|
|
@ -635,6 +635,7 @@ export interface GraphFieldConfig extends LineConfig, FillConfig, PointsConfig,
|
|||
drawStyle?: GraphDrawStyle;
|
||||
gradientMode?: GraphGradientMode;
|
||||
insertNulls?: (boolean | number);
|
||||
showValues?: boolean;
|
||||
thresholdsStyle?: GraphThresholdsStyleConfig;
|
||||
transform?: GraphTransform;
|
||||
}
|
||||
|
|
|
@ -229,6 +229,7 @@ GraphFieldConfig: {
|
|||
gradientMode?: GraphGradientMode
|
||||
thresholdsStyle?: GraphThresholdsStyleConfig
|
||||
transform?: GraphTransform
|
||||
showValues?: bool
|
||||
insertNulls?: bool | number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ export interface SeriesProps extends LineConfig, BarConfig, FillConfig, PointsCo
|
|||
dataFrameFieldIndex?: DataFrameFieldIndex;
|
||||
theme: GrafanaTheme2;
|
||||
value?: uPlot.Series.Value;
|
||||
showValues?: boolean;
|
||||
}
|
||||
|
||||
export class UPlotSeriesBuilder extends PlotConfigBuilder<SeriesProps, Series> {
|
||||
|
|
|
@ -59,6 +59,7 @@ for (let i = 0; i < BIN_INCRS.length; i++) {
|
|||
BIN_INCRS[i] = 2 ** i;
|
||||
}
|
||||
|
||||
import { DrawStyle } from '@grafana/ui';
|
||||
import {
|
||||
UPlotConfigBuilder,
|
||||
UPlotConfigPrepFn,
|
||||
|
@ -74,6 +75,7 @@ const defaultConfig: GraphFieldConfig = {
|
|||
drawStyle: GraphDrawStyle.Line,
|
||||
showPoints: VisibilityMode.Auto,
|
||||
axisPlacement: AxisPlacement.Auto,
|
||||
showValues: false,
|
||||
};
|
||||
|
||||
export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({
|
||||
|
@ -529,6 +531,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({
|
|||
softMax: customConfig.axisSoftMax,
|
||||
// The following properties are not used in the uPlot config, but are utilized as transport for legend config
|
||||
dataFrameFieldIndex: field.state?.origin,
|
||||
showValues: customConfig.showValues,
|
||||
});
|
||||
|
||||
// Render thresholds in graph
|
||||
|
@ -553,6 +556,79 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({
|
|||
|
||||
builder.setStackingGroups(stackingGroups);
|
||||
|
||||
const mightShowValues = frame.fields.some((field, i) => {
|
||||
if (i === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const customConfig = field.config.custom ?? {};
|
||||
|
||||
return (
|
||||
customConfig.showValues &&
|
||||
(customConfig.drawStyle === GraphDrawStyle.Points || customConfig.showPoints !== VisibilityMode.Never)
|
||||
);
|
||||
});
|
||||
|
||||
if (mightShowValues) {
|
||||
// since bars style doesnt show points in Auto mode, we can't piggyback on series.points.show()
|
||||
// so we make a simple density-based callback to use here
|
||||
const barsShowValues = (u: uPlot) => {
|
||||
let width = u.bbox.width / uPlot.pxRatio;
|
||||
let count = u.data[0].length;
|
||||
|
||||
// render values when each has at least 30px of width available
|
||||
return width / count >= 30;
|
||||
};
|
||||
|
||||
builder.addHook('draw', (u: uPlot) => {
|
||||
const baseFontSize = 12;
|
||||
const font = `${baseFontSize * uPlot.pxRatio}px ${theme.typography.fontFamily}`;
|
||||
|
||||
const { ctx } = u;
|
||||
|
||||
ctx.save();
|
||||
ctx.fillStyle = theme.colors.text.primary;
|
||||
ctx.font = font;
|
||||
ctx.textAlign = 'center';
|
||||
|
||||
for (let seriesIdx = 1; seriesIdx < u.data.length; seriesIdx++) {
|
||||
const series = u.series[seriesIdx];
|
||||
const field = frame.fields[seriesIdx];
|
||||
|
||||
if (
|
||||
field.config.custom?.showValues &&
|
||||
// @ts-ignore points.show() is always callable on the instance (but may be boolean when passed to uPlot as init option)
|
||||
(series.points?.show?.(u, seriesIdx) ||
|
||||
(field.config.custom?.drawStyle === DrawStyle.Bars && barsShowValues(u)))
|
||||
) {
|
||||
const xData = u.data[0];
|
||||
const yData = u.data[seriesIdx];
|
||||
const yScale = series.scale!;
|
||||
|
||||
for (let dataIdx = 0; dataIdx < yData.length; dataIdx++) {
|
||||
const yVal = yData[dataIdx];
|
||||
|
||||
if (yVal != null) {
|
||||
const text = formattedValueToString(field.display!(yVal));
|
||||
|
||||
const isNegative = yVal < 0;
|
||||
const textOffset = isNegative ? 15 : -5;
|
||||
ctx.textBaseline = isNegative ? 'top' : 'bottom';
|
||||
|
||||
const xVal = xData[dataIdx];
|
||||
const x = u.valToPos(xVal, 'x', true);
|
||||
const y = u.valToPos(yVal, yScale, true);
|
||||
|
||||
ctx.fillText(text, x, y + textOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
});
|
||||
}
|
||||
|
||||
// hook up custom/composite renderers
|
||||
renderers?.forEach((r) => {
|
||||
if (!indexByName) {
|
||||
|
|
|
@ -41,6 +41,7 @@ export const defaultGraphConfig: GraphFieldConfig = {
|
|||
axisGridShow: true,
|
||||
axisCenteredZero: false,
|
||||
axisBorderShow: false,
|
||||
showValues: false,
|
||||
};
|
||||
|
||||
export type NullEditorSettings = { isTime: boolean };
|
||||
|
@ -208,6 +209,13 @@ export function getGraphFieldConfig(cfg: GraphFieldConfig, isTime = true): SetFi
|
|||
},
|
||||
showIf: (config) => config.drawStyle !== GraphDrawStyle.Points,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'showValues',
|
||||
name: t('timeseries.config.get-graph-field-config.name-show-values', 'Show values'),
|
||||
category: categoryStyles,
|
||||
defaultValue: false,
|
||||
showIf: (config) => config.showPoints !== VisibilityMode.Never || config.drawStyle === GraphDrawStyle.Points,
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'pointSize',
|
||||
name: t('timeseries.config.get-graph-field-config.name-point-size', 'Point size'),
|
||||
|
|
|
@ -13059,6 +13059,7 @@
|
|||
"name-point-size": "Point size",
|
||||
"name-show-points": "Show points",
|
||||
"name-show-thresholds": "Show thresholds",
|
||||
"name-show-values": "Show values",
|
||||
"name-style": "Style",
|
||||
"name-transform": "Transform",
|
||||
"transform-options": {
|
||||
|
|
Loading…
Reference in New Issue