mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
GraphNG: Fix annotations and exemplars plugins (#29613)
This commit is contained in:
parent
a5e43535b3
commit
56e7ce6f16
@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import uPlot, { AlignedData, AlignedDataWithGapTest, Options } from 'uplot';
|
import uPlot, { AlignedData, AlignedDataWithGapTest, Options } from 'uplot';
|
||||||
import { buildPlotContext, PlotContext } from './context';
|
import { buildPlotContext, PlotContext } from './context';
|
||||||
import { pluginLog } from './utils';
|
import { pluginLog } from './utils';
|
||||||
@ -15,6 +15,7 @@ import usePrevious from 'react-use/lib/usePrevious';
|
|||||||
export const UPlotChart: React.FC<PlotProps> = props => {
|
export const UPlotChart: React.FC<PlotProps> = props => {
|
||||||
const canvasRef = useRef<HTMLDivElement>(null);
|
const canvasRef = useRef<HTMLDivElement>(null);
|
||||||
const plotInstance = useRef<uPlot>();
|
const plotInstance = useRef<uPlot>();
|
||||||
|
const [isPlotReady, setIsPlotReady] = useState(false);
|
||||||
const prevProps = usePrevious(props);
|
const prevProps = usePrevious(props);
|
||||||
const { isConfigReady, currentConfig, registerPlugin } = usePlotConfig(
|
const { isConfigReady, currentConfig, registerPlugin } = usePlotConfig(
|
||||||
props.width,
|
props.width,
|
||||||
@ -36,6 +37,7 @@ export const UPlotChart: React.FC<PlotProps> = props => {
|
|||||||
// 1. When config is ready and there is no uPlot instance, create new uPlot and return
|
// 1. When config is ready and there is no uPlot instance, create new uPlot and return
|
||||||
if (isConfigReady && !plotInstance.current) {
|
if (isConfigReady && !plotInstance.current) {
|
||||||
plotInstance.current = initializePlot(prepareData(props.data), currentConfig.current, canvasRef.current);
|
plotInstance.current = initializePlot(prepareData(props.data), currentConfig.current, canvasRef.current);
|
||||||
|
setIsPlotReady(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +70,8 @@ export const UPlotChart: React.FC<PlotProps> = props => {
|
|||||||
|
|
||||||
// Memoize plot context
|
// Memoize plot context
|
||||||
const plotCtx = useMemo(() => {
|
const plotCtx = useMemo(() => {
|
||||||
return buildPlotContext(canvasRef, props.data, registerPlugin, getPlotInstance);
|
return buildPlotContext(isPlotReady, canvasRef, props.data, registerPlugin, getPlotInstance);
|
||||||
}, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance]);
|
}, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance, isPlotReady]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlotContext.Provider value={plotCtx}>
|
<PlotContext.Provider value={plotCtx}>
|
||||||
|
@ -21,6 +21,7 @@ interface PlotPluginsContextType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface PlotContextType extends PlotPluginsContextType {
|
interface PlotContextType extends PlotPluginsContextType {
|
||||||
|
isPlotReady: boolean;
|
||||||
getPlotInstance: () => uPlot | undefined;
|
getPlotInstance: () => uPlot | undefined;
|
||||||
getSeries: () => Series[];
|
getSeries: () => Series[];
|
||||||
getCanvas: () => PlotCanvasContextType;
|
getCanvas: () => PlotCanvasContextType;
|
||||||
@ -126,12 +127,14 @@ export const usePlotData = (): PlotDataAPI => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const buildPlotContext = (
|
export const buildPlotContext = (
|
||||||
|
isPlotReady: boolean,
|
||||||
canvasRef: any,
|
canvasRef: any,
|
||||||
data: AlignedFrameWithGapTest,
|
data: AlignedFrameWithGapTest,
|
||||||
registerPlugin: any,
|
registerPlugin: any,
|
||||||
getPlotInstance: () => uPlot | undefined
|
getPlotInstance: () => uPlot | undefined
|
||||||
): PlotContextType => {
|
): PlotContextType => {
|
||||||
return {
|
return {
|
||||||
|
isPlotReady,
|
||||||
canvasRef,
|
canvasRef,
|
||||||
data,
|
data,
|
||||||
registerPlugin,
|
registerPlugin,
|
||||||
|
@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
|||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (plotCtx.getPlotInstance()) {
|
if (plotCtx.isPlotReady) {
|
||||||
const views: Array<DataFrameView<AnnotationsDataFrameViewDTO>> = [];
|
const views: Array<DataFrameView<AnnotationsDataFrameViewDTO>> = [];
|
||||||
|
|
||||||
for (const frame of annotations) {
|
for (const frame of annotations) {
|
||||||
@ -41,7 +41,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
|||||||
|
|
||||||
annotationsRef.current = views;
|
annotationsRef.current = views;
|
||||||
}
|
}
|
||||||
}, [plotCtx, annotations]);
|
}, [plotCtx.isPlotReady, annotations]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unregister = plotCtx.registerPlugin({
|
const unregister = plotCtx.registerPlugin({
|
||||||
@ -70,7 +70,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const xpos = u.valToPos(annotation.time / 1000, 'x', true);
|
const xpos = u.valToPos(annotation.time, 'x', true);
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.lineWidth = 2;
|
ctx.lineWidth = 2;
|
||||||
ctx.strokeStyle = theme.palette.red;
|
ctx.strokeStyle = theme.palette.red;
|
||||||
|
@ -42,7 +42,7 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim
|
|||||||
|
|
||||||
// THIS EVENT ONLY MOCKS EXEMPLAR Y VALUE!!!! TO BE REMOVED WHEN WE GET CORRECT EXEMPLARS SHAPE VIA PROPS
|
// THIS EVENT ONLY MOCKS EXEMPLAR Y VALUE!!!! TO BE REMOVED WHEN WE GET CORRECT EXEMPLARS SHAPE VIA PROPS
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (plotCtx.getPlotInstance()) {
|
if (plotCtx.isPlotReady) {
|
||||||
const mocks: DataFrame[] = [];
|
const mocks: DataFrame[] = [];
|
||||||
|
|
||||||
for (const frame of exemplars) {
|
for (const frame of exemplars) {
|
||||||
@ -61,22 +61,23 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim
|
|||||||
|
|
||||||
setExemplarsMock(mocks);
|
setExemplarsMock(mocks);
|
||||||
}
|
}
|
||||||
}, [plotCtx, exemplars]);
|
}, [plotCtx.isPlotReady, exemplars]);
|
||||||
|
|
||||||
const mapExemplarToXYCoords = useCallback(
|
const mapExemplarToXYCoords = useCallback(
|
||||||
(exemplar: ExemplarsDataFrameViewDTO) => {
|
(exemplar: ExemplarsDataFrameViewDTO) => {
|
||||||
const plotInstance = plotCtx.getPlotInstance();
|
const plotInstance = plotCtx.getPlotInstance();
|
||||||
if (!exemplar.time || !plotInstance) {
|
|
||||||
|
if (!exemplar.time || !plotCtx.isPlotReady || !plotInstance) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
x: plotInstance.valToPos(exemplar.time / 1000, 'x'),
|
x: plotInstance.valToPos(exemplar.time, 'x'),
|
||||||
// exemplar.y is a temporary mock for an examplar. This Needs to be calculated according to examplar scale!
|
// exemplar.y is a temporary mock for an examplar. This Needs to be calculated according to examplar scale!
|
||||||
y: Math.floor((exemplar.y * plotInstance.bbox.height) / window.devicePixelRatio),
|
y: Math.floor((exemplar.y * plotInstance.bbox.height) / window.devicePixelRatio),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[plotCtx.getPlotInstance]
|
[plotCtx.isPlotReady, plotCtx.getPlotInstance]
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderMarker = useCallback(
|
const renderMarker = useCallback(
|
||||||
|
Loading…
Reference in New Issue
Block a user