mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GraphNG: time range should match the panel timeRange (#29596)
* match time range * less logging * almost working * more logging * more logging * fix snapshot * Use layout effect for the time range ref update Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>
This commit is contained in:
parent
c869ae5791
commit
4e4211965e
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import React, { useCallback, useLayoutEffect, useMemo, useRef } from 'react';
|
||||
import {
|
||||
compareDataFrameStructures,
|
||||
DataFrame,
|
||||
@ -8,6 +8,7 @@ import {
|
||||
formattedValueToString,
|
||||
getFieldColorModeForField,
|
||||
getFieldDisplayName,
|
||||
TimeRange,
|
||||
} from '@grafana/data';
|
||||
import { alignDataFrames } from './utils';
|
||||
import { UPlotChart } from '../uPlot/Plot';
|
||||
@ -58,11 +59,17 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
|
||||
const compareFrames = useCallback((a?: DataFrame | null, b?: DataFrame | null) => {
|
||||
if (a && b) {
|
||||
return compareDataFrameStructures(a, b, ['min', 'max']);
|
||||
return compareDataFrameStructures(a, b);
|
||||
}
|
||||
return false;
|
||||
}, []);
|
||||
|
||||
// reference change will not triger re-render
|
||||
const currentTimeRange = useRef<TimeRange>(timeRange);
|
||||
useLayoutEffect(() => {
|
||||
currentTimeRange.current = timeRange;
|
||||
}, [timeRange]);
|
||||
|
||||
const configRev = useRevision(alignedFrame, compareFrames);
|
||||
|
||||
const configBuilder = useMemo(() => {
|
||||
@ -78,6 +85,10 @@ export const GraphNG: React.FC<GraphNGProps> = ({
|
||||
builder.addScale({
|
||||
scaleKey: 'x',
|
||||
isTime: true,
|
||||
range: () => {
|
||||
const r = currentTimeRange.current!;
|
||||
return [r.from.valueOf(), r.to.valueOf()];
|
||||
},
|
||||
});
|
||||
builder.addAxis({
|
||||
scaleKey: 'x',
|
||||
|
@ -4,8 +4,7 @@ import { buildPlotContext, PlotContext } from './context';
|
||||
import { pluginLog } from './utils';
|
||||
import { usePlotConfig } from './hooks';
|
||||
import { AlignedFrameWithGapTest, PlotProps } from './types';
|
||||
import { DataFrame, FieldType } from '@grafana/data';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
import { DataFrame } from '@grafana/data';
|
||||
import { UPlotConfigBuilder } from './config/UPlotConfigBuilder';
|
||||
import usePrevious from 'react-use/lib/usePrevious';
|
||||
|
||||
@ -62,7 +61,7 @@ export const UPlotChart: React.FC<PlotProps> = props => {
|
||||
}
|
||||
|
||||
// 4. Otherwise, assume only data has changed and update uPlot data
|
||||
updateData(props.data.frame, props.config, plotInstance.current, prepareData(props.data).data);
|
||||
updateData(props.data.frame, props.config, plotInstance.current, prepareData(props.data));
|
||||
}, [props, isConfigReady]);
|
||||
|
||||
// When component unmounts, clean the existing uPlot instance
|
||||
@ -95,38 +94,15 @@ function initializePlot(data: AlignedDataWithGapTest, config: Options, el: HTMLD
|
||||
return new uPlot(config, data, el);
|
||||
}
|
||||
|
||||
function updateData(frame: DataFrame, config: UPlotConfigBuilder, plotInstance?: uPlot, data?: AlignedData | null) {
|
||||
function updateData(
|
||||
frame: DataFrame,
|
||||
config: UPlotConfigBuilder,
|
||||
plotInstance?: uPlot,
|
||||
data?: AlignedDataWithGapTest | null
|
||||
) {
|
||||
if (!plotInstance || !data) {
|
||||
return;
|
||||
}
|
||||
pluginLog('uPlot core', false, 'updating plot data(throttled log!)', data);
|
||||
updateScales(frame, config, plotInstance);
|
||||
plotInstance.setData(data);
|
||||
}
|
||||
|
||||
function updateScales(frame: DataFrame, config: UPlotConfigBuilder, plotInstance: uPlot) {
|
||||
let yRange: [number, number] | undefined = undefined;
|
||||
|
||||
for (let i = 0; i < frame.fields.length; i++) {
|
||||
if (frame.fields[i].type !== FieldType.number) {
|
||||
continue;
|
||||
}
|
||||
if (isNumber(frame.fields[i].config.min) && isNumber(frame.fields[i].config.max)) {
|
||||
yRange = [frame.fields[i].config.min!, frame.fields[i].config.max!];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const scalesConfig = config.getConfig().scales;
|
||||
|
||||
if (scalesConfig && yRange) {
|
||||
for (const scale in scalesConfig) {
|
||||
if (!scalesConfig.hasOwnProperty(scale)) {
|
||||
continue;
|
||||
}
|
||||
if (scale !== 'x') {
|
||||
plotInstance.setScale(scale, { min: yRange[0], max: yRange[1] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,12 @@ describe('UPlotConfigBuilder', () => {
|
||||
"axes": Array [],
|
||||
"scales": Object {
|
||||
"scale-x": Object {
|
||||
"range": [Function],
|
||||
"time": true,
|
||||
},
|
||||
"scale-y": Object {
|
||||
"range": [Function],
|
||||
"time": false,
|
||||
},
|
||||
},
|
||||
"series": Array [
|
||||
|
@ -6,6 +6,7 @@ export interface ScaleProps {
|
||||
isTime?: boolean;
|
||||
min?: number | null;
|
||||
max?: number | null;
|
||||
range?: () => number[]; // min/max
|
||||
}
|
||||
|
||||
export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
@ -14,22 +15,19 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
this.props.max = optMinMax('max', this.props.max, props.max);
|
||||
}
|
||||
|
||||
// uPlot range function
|
||||
range = (u: uPlot, dataMin: number, dataMax: number) => {
|
||||
const { min, max } = this.props;
|
||||
const [smin, smax] = uPlot.rangeNum(min ?? dataMin, max ?? dataMax, 0.1 as any, true);
|
||||
return [min ?? smin, max ?? smax];
|
||||
};
|
||||
|
||||
getConfig() {
|
||||
const { isTime, scaleKey } = this.props;
|
||||
if (isTime) {
|
||||
return {
|
||||
[scaleKey]: {
|
||||
time: true, // TODO? this should be based on the query range, not the data
|
||||
},
|
||||
};
|
||||
}
|
||||
const { isTime, scaleKey, range } = this.props;
|
||||
return {
|
||||
[scaleKey]: {
|
||||
range: (u: uPlot, dataMin: number, dataMax: number) => {
|
||||
const { min, max } = this.props;
|
||||
const [smin, smax] = uPlot.rangeNum(min ?? dataMin, max ?? dataMax, 0.1 as any, true);
|
||||
return [min ?? smin, max ?? smax];
|
||||
},
|
||||
time: isTime,
|
||||
range: range ?? this.range,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user