mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TimeSeries: Fix fill below for dataframes with name (#35453)
Use original dataframes for matching config.
This commit is contained in:
@@ -51,7 +51,7 @@ export function getFieldDisplayName(field: Field, frame?: DataFrame, allFrames?:
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an appropriate display name. If the 'displayName' field config is set, use that
|
||||
* Get an appropriate display name. If the 'displayName' field config is set, use that.
|
||||
*/
|
||||
function calculateFieldDisplayName(field: Field, frame?: DataFrame, allFrames?: DataFrame[]): string {
|
||||
const hasConfigTitle = field.config?.displayName && field.config?.displayName.length;
|
||||
|
||||
@@ -38,7 +38,7 @@ export interface GraphNGProps extends Themeable2 {
|
||||
fields?: XYFieldMatchers; // default will assume timeseries data
|
||||
onLegendClick?: (event: GraphNGLegendEvent) => void;
|
||||
children?: (builder: UPlotConfigBuilder, alignedFrame: DataFrame) => React.ReactNode;
|
||||
prepConfig: (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => UPlotConfigBuilder;
|
||||
prepConfig: (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => UPlotConfigBuilder;
|
||||
propsToDiff?: string[];
|
||||
preparePlotFrame?: (frames: DataFrame[], dimFields: XYFieldMatchers) => DataFrame;
|
||||
renderLegend: (config: UPlotConfigBuilder) => React.ReactElement | null;
|
||||
@@ -105,7 +105,7 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
|
||||
pluginLog('GraphNG', false, 'data prepared', state.alignedData);
|
||||
|
||||
if (withConfig) {
|
||||
state.config = props.prepConfig(alignedFrame, this.getTimeRange);
|
||||
state.config = props.prepConfig(alignedFrame, this.props.frames, this.getTimeRange);
|
||||
pluginLog('GraphNG', false, 'config prepared', state.config);
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
|
||||
propsChanged;
|
||||
|
||||
if (shouldReconfig) {
|
||||
newState.config = this.props.prepConfig(newState.alignedFrame, this.getTimeRange);
|
||||
newState.config = this.props.prepConfig(newState.alignedFrame, this.props.frames, this.getTimeRange);
|
||||
pluginLog('GraphNG', false, 'config recreated', newState.config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ describe('GraphNG utils', () => {
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
sync: DashboardCursorSync.Tooltip,
|
||||
allFrames: [frame!],
|
||||
}).getConfig();
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -16,10 +16,10 @@ export class UnthemedTimeSeries extends React.Component<TimeSeriesProps> {
|
||||
static contextType = PanelContextRoot;
|
||||
panelContext: PanelContext = {} as PanelContext;
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => {
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
const { eventBus, sync } = this.context;
|
||||
const { theme, timeZone } = this.props;
|
||||
return preparePlotConfigBuilder({ frame: alignedFrame, theme, timeZone, getTimeRange, eventBus, sync });
|
||||
return preparePlotConfigBuilder({ frame: alignedFrame, theme, timeZone, getTimeRange, eventBus, sync, allFrames });
|
||||
};
|
||||
|
||||
renderLegend = (config: UPlotConfigBuilder) => {
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
FieldType,
|
||||
formattedValueToString,
|
||||
getFieldColorModeForField,
|
||||
getFieldDisplayName,
|
||||
getFieldSeriesColor,
|
||||
getFieldDisplayName,
|
||||
} from '@grafana/data';
|
||||
|
||||
import { UPlotConfigBuilder, UPlotConfigPrepFn } from '../uPlot/config/UPlotConfigBuilder';
|
||||
@@ -41,6 +41,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
sync,
|
||||
allFrames,
|
||||
}) => {
|
||||
const builder = new UPlotConfigBuilder(timeZone);
|
||||
|
||||
@@ -97,7 +98,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
||||
|
||||
const stackingGroups: Map<string, number[]> = new Map();
|
||||
|
||||
let indexByName: Map<string, number> | undefined = undefined;
|
||||
let indexByName: Map<string, number> | undefined;
|
||||
|
||||
for (let i = 1; i < frame.fields.length; i++) {
|
||||
const field = frame.fields[i];
|
||||
@@ -150,11 +151,15 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
||||
|
||||
let { fillOpacity } = customConfig;
|
||||
|
||||
if (customConfig.fillBelowTo) {
|
||||
if (customConfig.fillBelowTo && field.state?.origin) {
|
||||
if (!indexByName) {
|
||||
indexByName = getNamesToFieldIndex(frame);
|
||||
indexByName = getNamesToFieldIndex(frame, allFrames);
|
||||
}
|
||||
const t = indexByName.get(getFieldDisplayName(field, frame));
|
||||
|
||||
const originFrame = allFrames[field.state.origin.frameIndex];
|
||||
const originField = originFrame.fields[field.state.origin.fieldIndex];
|
||||
|
||||
const t = indexByName.get(getFieldDisplayName(originField, originFrame, allFrames));
|
||||
const b = indexByName.get(customConfig.fillBelowTo);
|
||||
if (isNumber(b) && isNumber(t)) {
|
||||
builder.addBand({
|
||||
@@ -259,10 +264,20 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync: DashboardCursor
|
||||
return builder;
|
||||
};
|
||||
|
||||
export function getNamesToFieldIndex(frame: DataFrame): Map<string, number> {
|
||||
const names = new Map<string, number>();
|
||||
export function getNamesToFieldIndex(frame: DataFrame, allFrames: DataFrame[]): Map<string, number> {
|
||||
const originNames = new Map<string, number>();
|
||||
for (let i = 0; i < frame.fields.length; i++) {
|
||||
names.set(getFieldDisplayName(frame.fields[i], frame), i);
|
||||
const origin = frame.fields[i].state?.origin;
|
||||
if (origin) {
|
||||
originNames.set(
|
||||
getFieldDisplayName(
|
||||
allFrames[origin.frameIndex].fields[origin.fieldIndex],
|
||||
allFrames[origin.frameIndex],
|
||||
allFrames
|
||||
),
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
return originNames;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,7 @@ type UPlotConfigPrepOpts<T extends Record<string, any> = {}> = {
|
||||
timeZone: TimeZone;
|
||||
getTimeRange: () => TimeRange;
|
||||
eventBus: EventBus;
|
||||
allFrames: DataFrame[];
|
||||
} & T;
|
||||
|
||||
/** @alpha */
|
||||
|
||||
@@ -34,7 +34,7 @@ export const BarChart: React.FC<BarChartProps> = (props) => {
|
||||
return <PlotLegend data={props.frames} config={config} maxHeight="35%" maxWidth="60%" {...props.legend} />;
|
||||
};
|
||||
|
||||
const prepConfig = (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => {
|
||||
const prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
const { timeZone, orientation, barWidth, showValue, groupWidth, stacking, legend, tooltip, text } = props;
|
||||
|
||||
return preparePlotConfigBuilder({
|
||||
@@ -51,6 +51,7 @@ export const BarChart: React.FC<BarChartProps> = (props) => {
|
||||
legend,
|
||||
tooltip,
|
||||
text,
|
||||
allFrames: props.frames,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -105,6 +105,7 @@ describe('BarChart utils', () => {
|
||||
timeZone: DefaultTimeZone,
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig();
|
||||
expect(result).toMatchSnapshot();
|
||||
});
|
||||
@@ -119,6 +120,7 @@ describe('BarChart utils', () => {
|
||||
timeZone: DefaultTimeZone,
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
@@ -133,6 +135,7 @@ describe('BarChart utils', () => {
|
||||
timeZone: DefaultTimeZone,
|
||||
getTimeRange: getDefaultTimeRange,
|
||||
eventBus: new EventBusSrv(),
|
||||
allFrames: [frame],
|
||||
}).getConfig()
|
||||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ export class TimelineChart extends React.Component<TimelineProps> {
|
||||
static contextType = PanelContextRoot;
|
||||
panelContext: PanelContext = {} as PanelContext;
|
||||
|
||||
prepConfig = (alignedFrame: DataFrame, getTimeRange: () => TimeRange) => {
|
||||
prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => {
|
||||
this.panelContext = this.context as PanelContext;
|
||||
const { eventBus } = this.panelContext;
|
||||
|
||||
@@ -43,6 +43,7 @@ export class TimelineChart extends React.Component<TimelineProps> {
|
||||
frame: alignedFrame,
|
||||
getTimeRange,
|
||||
eventBus,
|
||||
allFrames: this.props.frames,
|
||||
...this.props,
|
||||
|
||||
// When there is only one row, use the full space
|
||||
|
||||
Reference in New Issue
Block a user