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 { buildPlotContext, PlotContext } from './context';
|
||||
import { pluginLog } from './utils';
|
||||
@ -15,6 +15,7 @@ import usePrevious from 'react-use/lib/usePrevious';
|
||||
export const UPlotChart: React.FC<PlotProps> = props => {
|
||||
const canvasRef = useRef<HTMLDivElement>(null);
|
||||
const plotInstance = useRef<uPlot>();
|
||||
const [isPlotReady, setIsPlotReady] = useState(false);
|
||||
const prevProps = usePrevious(props);
|
||||
const { isConfigReady, currentConfig, registerPlugin } = usePlotConfig(
|
||||
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
|
||||
if (isConfigReady && !plotInstance.current) {
|
||||
plotInstance.current = initializePlot(prepareData(props.data), currentConfig.current, canvasRef.current);
|
||||
setIsPlotReady(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -68,8 +70,8 @@ export const UPlotChart: React.FC<PlotProps> = props => {
|
||||
|
||||
// Memoize plot context
|
||||
const plotCtx = useMemo(() => {
|
||||
return buildPlotContext(canvasRef, props.data, registerPlugin, getPlotInstance);
|
||||
}, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance]);
|
||||
return buildPlotContext(isPlotReady, canvasRef, props.data, registerPlugin, getPlotInstance);
|
||||
}, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance, isPlotReady]);
|
||||
|
||||
return (
|
||||
<PlotContext.Provider value={plotCtx}>
|
||||
|
@ -21,6 +21,7 @@ interface PlotPluginsContextType {
|
||||
}
|
||||
|
||||
interface PlotContextType extends PlotPluginsContextType {
|
||||
isPlotReady: boolean;
|
||||
getPlotInstance: () => uPlot | undefined;
|
||||
getSeries: () => Series[];
|
||||
getCanvas: () => PlotCanvasContextType;
|
||||
@ -126,12 +127,14 @@ export const usePlotData = (): PlotDataAPI => {
|
||||
};
|
||||
|
||||
export const buildPlotContext = (
|
||||
isPlotReady: boolean,
|
||||
canvasRef: any,
|
||||
data: AlignedFrameWithGapTest,
|
||||
registerPlugin: any,
|
||||
getPlotInstance: () => uPlot | undefined
|
||||
): PlotContextType => {
|
||||
return {
|
||||
isPlotReady,
|
||||
canvasRef,
|
||||
data,
|
||||
registerPlugin,
|
||||
|
@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (plotCtx.getPlotInstance()) {
|
||||
if (plotCtx.isPlotReady) {
|
||||
const views: Array<DataFrameView<AnnotationsDataFrameViewDTO>> = [];
|
||||
|
||||
for (const frame of annotations) {
|
||||
@ -41,7 +41,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
||||
|
||||
annotationsRef.current = views;
|
||||
}
|
||||
}, [plotCtx, annotations]);
|
||||
}, [plotCtx.isPlotReady, annotations]);
|
||||
|
||||
useEffect(() => {
|
||||
const unregister = plotCtx.registerPlugin({
|
||||
@ -70,7 +70,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
|
||||
continue;
|
||||
}
|
||||
|
||||
const xpos = u.valToPos(annotation.time / 1000, 'x', true);
|
||||
const xpos = u.valToPos(annotation.time, 'x', true);
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = 2;
|
||||
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
|
||||
useEffect(() => {
|
||||
if (plotCtx.getPlotInstance()) {
|
||||
if (plotCtx.isPlotReady) {
|
||||
const mocks: DataFrame[] = [];
|
||||
|
||||
for (const frame of exemplars) {
|
||||
@ -61,22 +61,23 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim
|
||||
|
||||
setExemplarsMock(mocks);
|
||||
}
|
||||
}, [plotCtx, exemplars]);
|
||||
}, [plotCtx.isPlotReady, exemplars]);
|
||||
|
||||
const mapExemplarToXYCoords = useCallback(
|
||||
(exemplar: ExemplarsDataFrameViewDTO) => {
|
||||
const plotInstance = plotCtx.getPlotInstance();
|
||||
if (!exemplar.time || !plotInstance) {
|
||||
|
||||
if (!exemplar.time || !plotCtx.isPlotReady || !plotInstance) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
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!
|
||||
y: Math.floor((exemplar.y * plotInstance.bbox.height) / window.devicePixelRatio),
|
||||
};
|
||||
},
|
||||
[plotCtx.getPlotInstance]
|
||||
[plotCtx.isPlotReady, plotCtx.getPlotInstance]
|
||||
);
|
||||
|
||||
const renderMarker = useCallback(
|
||||
|
Loading…
Reference in New Issue
Block a user