Commit 563478ec by Dominik Prokop Committed by GitHub

GraphNG: Fix issues with plugins not retrieving plot instance (#29585)

* Fix issues with plugins not retrieving plot instance

* Review
parent 4e0ad501
...@@ -23,10 +23,6 @@ export const UPlotChart: React.FC<PlotProps> = props => { ...@@ -23,10 +23,6 @@ export const UPlotChart: React.FC<PlotProps> = props => {
props.config props.config
); );
const getPlotInstance = useCallback(() => { const getPlotInstance = useCallback(() => {
if (!plotInstance.current) {
throw new Error("Plot hasn't initialised yet");
}
return plotInstance.current; return plotInstance.current;
}, []); }, []);
...@@ -72,13 +68,15 @@ export const UPlotChart: React.FC<PlotProps> = props => { ...@@ -72,13 +68,15 @@ export const UPlotChart: React.FC<PlotProps> = props => {
// Memoize plot context // Memoize plot context
const plotCtx = useMemo(() => { 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]); }, [plotInstance, canvasRef, props.data, registerPlugin, getPlotInstance]);
return ( return (
<PlotContext.Provider value={plotCtx}> <PlotContext.Provider value={plotCtx}>
<div ref={plotCtx.canvasRef} data-testid="uplot-main-div" /> <div style={{ position: 'relative' }}>
{props.children} <div ref={plotCtx.canvasRef} data-testid="uplot-main-div" />
{props.children}
</div>
</PlotContext.Provider> </PlotContext.Provider>
); );
}; };
......
...@@ -21,8 +21,7 @@ interface PlotPluginsContextType { ...@@ -21,8 +21,7 @@ interface PlotPluginsContextType {
} }
interface PlotContextType extends PlotPluginsContextType { interface PlotContextType extends PlotPluginsContextType {
isPlotReady: boolean; getPlotInstance: () => uPlot | undefined;
getPlotInstance: () => uPlot;
getSeries: () => Series[]; getSeries: () => Series[];
getCanvas: () => PlotCanvasContextType; getCanvas: () => PlotCanvasContextType;
canvasRef: any; canvasRef: any;
...@@ -127,28 +126,31 @@ export const usePlotData = (): PlotDataAPI => { ...@@ -127,28 +126,31 @@ 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 getPlotInstance: () => uPlot | undefined
): PlotContextType => { ): PlotContextType => {
return { return {
isPlotReady,
canvasRef, canvasRef,
data, data,
registerPlugin, registerPlugin,
getPlotInstance, getPlotInstance,
getSeries: () => getPlotInstance().series, getSeries: () => getPlotInstance()!.series,
getCanvas: () => ({ getCanvas: () => {
width: getPlotInstance().width, const plotInstance = getPlotInstance()!;
height: getPlotInstance().height, const bbox = plotInstance.bbox;
plot: { const pxRatio = window.devicePixelRatio;
width: getPlotInstance().bbox.width / window.devicePixelRatio, return {
height: getPlotInstance().bbox.height / window.devicePixelRatio, width: plotInstance.width,
top: getPlotInstance().bbox.top / window.devicePixelRatio, height: plotInstance.height,
left: getPlotInstance().bbox.left / window.devicePixelRatio, plot: {
}, width: bbox.width / pxRatio,
}), height: bbox.height / pxRatio,
top: bbox.top / pxRatio,
left: bbox.left / pxRatio,
},
};
},
}; };
}; };
...@@ -18,8 +18,7 @@ export function EventsCanvas<T>({ id, events, renderEventMarker, mapEventToXYCoo ...@@ -18,8 +18,7 @@ export function EventsCanvas<T>({ id, events, renderEventMarker, mapEventToXYCoo
const eventMarkers = useMemo(() => { const eventMarkers = useMemo(() => {
const markers: React.ReactNode[] = []; const markers: React.ReactNode[] = [];
if (!plotCtx.getPlotInstance() || events.length === 0) {
if (!plotCtx.isPlotReady || events.length === 0) {
return markers; return markers;
} }
...@@ -41,9 +40,9 @@ export function EventsCanvas<T>({ id, events, renderEventMarker, mapEventToXYCoo ...@@ -41,9 +40,9 @@ export function EventsCanvas<T>({ id, events, renderEventMarker, mapEventToXYCoo
} }
return <>{markers}</>; return <>{markers}</>;
}, [events, renderEventMarker, renderToken, plotCtx.isPlotReady]); }, [events, renderEventMarker, renderToken, plotCtx]);
if (!plotCtx.isPlotReady) { if (!plotCtx.getPlotInstance()) {
return null; return null;
} }
......
...@@ -10,8 +10,9 @@ interface XYCanvasProps {} ...@@ -10,8 +10,9 @@ interface XYCanvasProps {}
*/ */
export const XYCanvas: React.FC<XYCanvasProps> = ({ children }) => { export const XYCanvas: React.FC<XYCanvasProps> = ({ children }) => {
const plotContext = usePlotContext(); const plotContext = usePlotContext();
const plotInstance = plotContext.getPlotInstance();
if (!plotContext.isPlotReady) { if (!plotInstance) {
return null; return null;
} }
...@@ -20,8 +21,8 @@ export const XYCanvas: React.FC<XYCanvasProps> = ({ children }) => { ...@@ -20,8 +21,8 @@ export const XYCanvas: React.FC<XYCanvasProps> = ({ children }) => {
className={css` className={css`
position: absolute; position: absolute;
overflow: visible; overflow: visible;
left: ${plotContext.getPlotInstance().bbox.left / window.devicePixelRatio}px; left: ${plotInstance.bbox.left / window.devicePixelRatio}px;
top: ${plotContext.getPlotInstance().bbox.top / window.devicePixelRatio}px; top: ${plotInstance.bbox.top / window.devicePixelRatio}px;
`} `}
> >
{children} {children}
......
...@@ -75,7 +75,7 @@ export const SelectionPlugin: React.FC<SelectionPluginProps> = ({ onSelect, onDi ...@@ -75,7 +75,7 @@ export const SelectionPlugin: React.FC<SelectionPluginProps> = ({ onSelect, onDi
}; };
}, []); }, []);
if (!plotCtx.isPlotReady || !children || !selection) { if (!plotCtx.getPlotInstance() || !children || !selection) {
return null; return null;
} }
......
...@@ -25,7 +25,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t ...@@ -25,7 +25,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t
return ( return (
<CursorPlugin id={pluginId}> <CursorPlugin id={pluginId}>
{({ focusedSeriesIdx, focusedPointIdx, coords }) => { {({ focusedSeriesIdx, focusedPointIdx, coords }) => {
if (!plotContext.isPlotReady) { if (!plotContext.getPlotInstance()) {
return null; return null;
} }
......
...@@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation ...@@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
); );
useEffect(() => { useEffect(() => {
if (plotCtx.isPlotReady) { if (plotCtx.getPlotInstance()) {
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 ...@@ -41,7 +41,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
annotationsRef.current = views; annotationsRef.current = views;
} }
}, [plotCtx.isPlotReady, annotations]); }, [plotCtx, annotations]);
useEffect(() => { useEffect(() => {
const unregister = plotCtx.registerPlugin({ const unregister = plotCtx.registerPlugin({
...@@ -93,13 +93,14 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation ...@@ -93,13 +93,14 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
const mapAnnotationToXYCoords = useCallback( const mapAnnotationToXYCoords = useCallback(
(annotation: AnnotationsDataFrameViewDTO) => { (annotation: AnnotationsDataFrameViewDTO) => {
if (!annotation.time) { const plotInstance = plotCtx.getPlotInstance();
if (!annotation.time || !plotInstance) {
return undefined; return undefined;
} }
return { return {
x: plotCtx.getPlotInstance().valToPos(annotation.time / 1000, 'x'), x: plotInstance.valToPos(annotation.time, 'x'),
y: plotCtx.getPlotInstance().bbox.height / window.devicePixelRatio + 4, y: plotInstance.bbox.height / window.devicePixelRatio + 4,
}; };
}, },
[plotCtx.getPlotInstance] [plotCtx.getPlotInstance]
......
...@@ -42,7 +42,7 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim ...@@ -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.isPlotReady) { if (plotCtx.getPlotInstance()) {
const mocks: DataFrame[] = []; const mocks: DataFrame[] = [];
for (const frame of exemplars) { for (const frame of exemplars) {
...@@ -61,18 +61,19 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim ...@@ -61,18 +61,19 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ exemplars, tim
setExemplarsMock(mocks); setExemplarsMock(mocks);
} }
}, [plotCtx.isPlotReady, exemplars]); }, [plotCtx, exemplars]);
const mapExemplarToXYCoords = useCallback( const mapExemplarToXYCoords = useCallback(
(exemplar: ExemplarsDataFrameViewDTO) => { (exemplar: ExemplarsDataFrameViewDTO) => {
if (!exemplar.time) { const plotInstance = plotCtx.getPlotInstance();
if (!exemplar.time || !plotInstance) {
return undefined; return undefined;
} }
return { 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! // 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] [plotCtx.getPlotInstance]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment