diff --git a/packages/grafana-ui/src/components/uPlot/Plot.tsx b/packages/grafana-ui/src/components/uPlot/Plot.tsx index 8b202e18bd6..e030ef4bc0b 100755 --- a/packages/grafana-ui/src/components/uPlot/Plot.tsx +++ b/packages/grafana-ui/src/components/uPlot/Plot.tsx @@ -23,10 +23,6 @@ export const UPlotChart: React.FC = props => { props.config ); const getPlotInstance = useCallback(() => { - if (!plotInstance.current) { - throw new Error("Plot hasn't initialised yet"); - } - return plotInstance.current; }, []); @@ -72,13 +68,15 @@ export const UPlotChart: React.FC = props => { // Memoize plot context const plotCtx = useMemo(() => { - return buildPlotContext(Boolean(plotInstance.current), canvasRef, props.data, registerPlugin, getPlotInstance); + return buildPlotContext(canvasRef, props.data, registerPlugin, getPlotInstance); }, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance]); return ( -
- {props.children} +
+
+ {props.children} +
); }; diff --git a/packages/grafana-ui/src/components/uPlot/context.ts b/packages/grafana-ui/src/components/uPlot/context.ts index cc6d4806b4f..558e88c2104 100644 --- a/packages/grafana-ui/src/components/uPlot/context.ts +++ b/packages/grafana-ui/src/components/uPlot/context.ts @@ -21,8 +21,7 @@ interface PlotPluginsContextType { } interface PlotContextType extends PlotPluginsContextType { - isPlotReady: boolean; - getPlotInstance: () => uPlot; + getPlotInstance: () => uPlot | undefined; getSeries: () => Series[]; getCanvas: () => PlotCanvasContextType; canvasRef: any; @@ -127,28 +126,31 @@ export const usePlotData = (): PlotDataAPI => { }; export const buildPlotContext = ( - isPlotReady: boolean, canvasRef: any, data: AlignedFrameWithGapTest, registerPlugin: any, - getPlotInstance: () => uPlot + getPlotInstance: () => uPlot | undefined ): PlotContextType => { return { - isPlotReady, canvasRef, data, registerPlugin, getPlotInstance, - getSeries: () => getPlotInstance().series, - getCanvas: () => ({ - width: getPlotInstance().width, - height: getPlotInstance().height, - plot: { - width: getPlotInstance().bbox.width / window.devicePixelRatio, - height: getPlotInstance().bbox.height / window.devicePixelRatio, - top: getPlotInstance().bbox.top / window.devicePixelRatio, - left: getPlotInstance().bbox.left / window.devicePixelRatio, - }, - }), + getSeries: () => getPlotInstance()!.series, + getCanvas: () => { + const plotInstance = getPlotInstance()!; + const bbox = plotInstance.bbox; + const pxRatio = window.devicePixelRatio; + return { + width: plotInstance.width, + height: plotInstance.height, + plot: { + width: bbox.width / pxRatio, + height: bbox.height / pxRatio, + top: bbox.top / pxRatio, + left: bbox.left / pxRatio, + }, + }; + }, }; }; diff --git a/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx b/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx index 0c5c8ac6262..cc247362a5a 100644 --- a/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx +++ b/packages/grafana-ui/src/components/uPlot/geometries/EventsCanvas.tsx @@ -18,8 +18,7 @@ export function EventsCanvas({ id, events, renderEventMarker, mapEventToXYCoo const eventMarkers = useMemo(() => { const markers: React.ReactNode[] = []; - - if (!plotCtx.isPlotReady || events.length === 0) { + if (!plotCtx.getPlotInstance() || events.length === 0) { return markers; } @@ -41,9 +40,9 @@ export function EventsCanvas({ id, events, renderEventMarker, mapEventToXYCoo } return <>{markers}; - }, [events, renderEventMarker, renderToken, plotCtx.isPlotReady]); + }, [events, renderEventMarker, renderToken, plotCtx]); - if (!plotCtx.isPlotReady) { + if (!plotCtx.getPlotInstance()) { return null; } diff --git a/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx b/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx index 0ded2517c74..352d34cb0df 100644 --- a/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx +++ b/packages/grafana-ui/src/components/uPlot/geometries/XYCanvas.tsx @@ -10,8 +10,9 @@ interface XYCanvasProps {} */ export const XYCanvas: React.FC = ({ children }) => { const plotContext = usePlotContext(); + const plotInstance = plotContext.getPlotInstance(); - if (!plotContext.isPlotReady) { + if (!plotInstance) { return null; } @@ -20,8 +21,8 @@ export const XYCanvas: React.FC = ({ children }) => { className={css` position: absolute; overflow: visible; - left: ${plotContext.getPlotInstance().bbox.left / window.devicePixelRatio}px; - top: ${plotContext.getPlotInstance().bbox.top / window.devicePixelRatio}px; + left: ${plotInstance.bbox.left / window.devicePixelRatio}px; + top: ${plotInstance.bbox.top / window.devicePixelRatio}px; `} > {children} diff --git a/packages/grafana-ui/src/components/uPlot/plugins/SelectionPlugin.tsx b/packages/grafana-ui/src/components/uPlot/plugins/SelectionPlugin.tsx index af351aa18a2..eff8b96a341 100644 --- a/packages/grafana-ui/src/components/uPlot/plugins/SelectionPlugin.tsx +++ b/packages/grafana-ui/src/components/uPlot/plugins/SelectionPlugin.tsx @@ -75,7 +75,7 @@ export const SelectionPlugin: React.FC = ({ onSelect, onDi }; }, []); - if (!plotCtx.isPlotReady || !children || !selection) { + if (!plotCtx.getPlotInstance() || !children || !selection) { return null; } diff --git a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx index be3cbb9f0d2..feed5e7fd4d 100644 --- a/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx +++ b/packages/grafana-ui/src/components/uPlot/plugins/TooltipPlugin.tsx @@ -25,7 +25,7 @@ export const TooltipPlugin: React.FC = ({ mode = 'single', t return ( {({ focusedSeriesIdx, focusedPointIdx, coords }) => { - if (!plotContext.isPlotReady) { + if (!plotContext.getPlotInstance()) { return null; } diff --git a/public/app/plugins/panel/graph3/plugins/AnnotationsPlugin.tsx b/public/app/plugins/panel/graph3/plugins/AnnotationsPlugin.tsx index 57d615d59ab..3175239b16b 100644 --- a/public/app/plugins/panel/graph3/plugins/AnnotationsPlugin.tsx +++ b/public/app/plugins/panel/graph3/plugins/AnnotationsPlugin.tsx @@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC = ({ annotation ); useEffect(() => { - if (plotCtx.isPlotReady) { + if (plotCtx.getPlotInstance()) { const views: Array> = []; for (const frame of annotations) { @@ -41,7 +41,7 @@ export const AnnotationsPlugin: React.FC = ({ annotation annotationsRef.current = views; } - }, [plotCtx.isPlotReady, annotations]); + }, [plotCtx, annotations]); useEffect(() => { const unregister = plotCtx.registerPlugin({ @@ -93,13 +93,14 @@ export const AnnotationsPlugin: React.FC = ({ annotation const mapAnnotationToXYCoords = useCallback( (annotation: AnnotationsDataFrameViewDTO) => { - if (!annotation.time) { + const plotInstance = plotCtx.getPlotInstance(); + if (!annotation.time || !plotInstance) { return undefined; } return { - x: plotCtx.getPlotInstance().valToPos(annotation.time / 1000, 'x'), - y: plotCtx.getPlotInstance().bbox.height / window.devicePixelRatio + 4, + x: plotInstance.valToPos(annotation.time, 'x'), + y: plotInstance.bbox.height / window.devicePixelRatio + 4, }; }, [plotCtx.getPlotInstance] diff --git a/public/app/plugins/panel/graph3/plugins/ExemplarsPlugin.tsx b/public/app/plugins/panel/graph3/plugins/ExemplarsPlugin.tsx index 2489f7ce785..14b0a5cc8aa 100644 --- a/public/app/plugins/panel/graph3/plugins/ExemplarsPlugin.tsx +++ b/public/app/plugins/panel/graph3/plugins/ExemplarsPlugin.tsx @@ -42,7 +42,7 @@ export const ExemplarsPlugin: React.FC = ({ exemplars, tim // THIS EVENT ONLY MOCKS EXEMPLAR Y VALUE!!!! TO BE REMOVED WHEN WE GET CORRECT EXEMPLARS SHAPE VIA PROPS useEffect(() => { - if (plotCtx.isPlotReady) { + if (plotCtx.getPlotInstance()) { const mocks: DataFrame[] = []; for (const frame of exemplars) { @@ -61,18 +61,19 @@ export const ExemplarsPlugin: React.FC = ({ exemplars, tim setExemplarsMock(mocks); } - }, [plotCtx.isPlotReady, exemplars]); + }, [plotCtx, exemplars]); const mapExemplarToXYCoords = useCallback( (exemplar: ExemplarsDataFrameViewDTO) => { - if (!exemplar.time) { + const plotInstance = plotCtx.getPlotInstance(); + if (!exemplar.time || !plotInstance) { return undefined; } return { - x: plotCtx.getPlotInstance().valToPos(exemplar.time / 1000, 'x'), + x: plotInstance.valToPos(exemplar.time / 1000, 'x'), // exemplar.y is a temporary mock for an examplar. This Needs to be calculated according to examplar scale! - y: Math.floor((exemplar.y * plotCtx.getPlotInstance().bbox.height) / window.devicePixelRatio), + y: Math.floor((exemplar.y * plotInstance.bbox.height) / window.devicePixelRatio), }; }, [plotCtx.getPlotInstance]