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 => {
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<PlotProps> = 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 (
<PlotContext.Provider value={plotCtx}>
<div ref={plotCtx.canvasRef} data-testid="uplot-main-div" />
{props.children}
<div style={{ position: 'relative' }}>
<div ref={plotCtx.canvasRef} data-testid="uplot-main-div" />
{props.children}
</div>
</PlotContext.Provider>
);
};
......
......@@ -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,
},
};
},
};
};
......@@ -18,8 +18,7 @@ export function EventsCanvas<T>({ 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<T>({ id, events, renderEventMarker, mapEventToXYCoo
}
return <>{markers}</>;
}, [events, renderEventMarker, renderToken, plotCtx.isPlotReady]);
}, [events, renderEventMarker, renderToken, plotCtx]);
if (!plotCtx.isPlotReady) {
if (!plotCtx.getPlotInstance()) {
return null;
}
......
......@@ -10,8 +10,9 @@ interface XYCanvasProps {}
*/
export const XYCanvas: React.FC<XYCanvasProps> = ({ children }) => {
const plotContext = usePlotContext();
const plotInstance = plotContext.getPlotInstance();
if (!plotContext.isPlotReady) {
if (!plotInstance) {
return null;
}
......@@ -20,8 +21,8 @@ export const XYCanvas: React.FC<XYCanvasProps> = ({ 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}
......
......@@ -75,7 +75,7 @@ export const SelectionPlugin: React.FC<SelectionPluginProps> = ({ onSelect, onDi
};
}, []);
if (!plotCtx.isPlotReady || !children || !selection) {
if (!plotCtx.getPlotInstance() || !children || !selection) {
return null;
}
......
......@@ -25,7 +25,7 @@ export const TooltipPlugin: React.FC<TooltipPluginProps> = ({ mode = 'single', t
return (
<CursorPlugin id={pluginId}>
{({ focusedSeriesIdx, focusedPointIdx, coords }) => {
if (!plotContext.isPlotReady) {
if (!plotContext.getPlotInstance()) {
return null;
}
......
......@@ -32,7 +32,7 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ annotation
);
useEffect(() => {
if (plotCtx.isPlotReady) {
if (plotCtx.getPlotInstance()) {
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.isPlotReady, annotations]);
}, [plotCtx, annotations]);
useEffect(() => {
const unregister = plotCtx.registerPlugin({
......@@ -93,13 +93,14 @@ export const AnnotationsPlugin: React.FC<AnnotationsPluginProps> = ({ 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]
......
......@@ -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.isPlotReady) {
if (plotCtx.getPlotInstance()) {
const mocks: DataFrame[] = [];
for (const frame of exemplars) {
......@@ -61,18 +61,19 @@ export const ExemplarsPlugin: React.FC<ExemplarsPluginProps> = ({ 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]
......
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