[APM] Improves, smoothes shared pointer events across different charts (#135137)

* [APM] Improves, smoothes shared pointer events across different charts

* fixes eslint dependency issue
This commit is contained in:
Oliver Gupte 2022-07-13 00:12:38 -07:00 committed by GitHub
parent e337b58f7f
commit 265c405f36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 23 deletions

View file

@ -69,7 +69,7 @@ export function BreakdownChart({
const history = useHistory();
const chartTheme = useChartTheme();
const { core } = useApmPluginContext();
const { chartRef, setPointerEvent } = useChartPointerEventContext();
const { chartRef, updatePointerEvent } = useChartPointerEventContext();
const {
query: { rangeFrom, rangeTo },
} = useApmParams('/services/{serviceName}');
@ -107,7 +107,7 @@ export function BreakdownChart({
theme={chartTheme}
xDomain={{ min, max }}
flatLegend
onPointerUpdate={setPointerEvent}
onPointerUpdate={updatePointerEvent}
externalPointerEvents={{
tooltip: {
visible: true,

View file

@ -86,7 +86,7 @@ export function TimeseriesChart({
const history = useHistory();
const { core } = useApmPluginContext();
const { annotations } = useAnnotationsContext();
const { setPointerEvent, chartRef } = useChartPointerEventContext();
const { chartRef, updatePointerEvent } = useChartPointerEventContext();
const theme = useTheme();
const chartTheme = useChartTheme();
const {
@ -169,7 +169,7 @@ export function TimeseriesChart({
},
...chartTheme,
]}
onPointerUpdate={setPointerEvent}
onPointerUpdate={updatePointerEvent}
externalPointerEvents={{
tooltip: { visible: true },
}}

View file

@ -5,19 +5,14 @@
* 2.0.
*/
import React, {
createContext,
Dispatch,
ReactNode,
SetStateAction,
useState,
} from 'react';
import React, { createContext, ReactNode, useRef } from 'react';
import { PointerEvent } from '@elastic/charts';
export const UPDATE_POINTER_EVENT = 'updatePointerEvent';
export const ChartPointerEventContext = createContext<{
pointerEvent: PointerEvent | null;
setPointerEvent: Dispatch<SetStateAction<PointerEvent | null>>;
pointerEventTargetRef: React.MutableRefObject<EventTarget>;
updatePointerEvent: (pointerEvent: PointerEvent) => void;
} | null>(null);
export function ChartPointerEventContextProvider({
@ -25,11 +20,19 @@ export function ChartPointerEventContextProvider({
}: {
children: ReactNode;
}) {
const [pointerEvent, setPointerEvent] = useState<PointerEvent | null>(null);
const pointerEventTargetRef = useRef(new EventTarget());
const updatePointerEventRef = useRef((pointerEvent: PointerEvent) => {
pointerEventTargetRef.current.dispatchEvent(
new CustomEvent(UPDATE_POINTER_EVENT, { detail: pointerEvent })
);
});
return (
<ChartPointerEventContext.Provider
value={{ pointerEvent, setPointerEvent }}
value={{
pointerEventTargetRef,
updatePointerEvent: updatePointerEventRef.current,
}}
children={children}
/>
);

View file

@ -5,9 +5,13 @@
* 2.0.
*/
import React, { useContext, useEffect } from 'react';
import React, { useContext, useEffect, useCallback, useRef } from 'react';
import { Chart } from '@elastic/charts';
import { ChartPointerEventContext } from './chart_pointer_event_context';
import { PointerEvent } from '@elastic/charts';
import {
ChartPointerEventContext,
UPDATE_POINTER_EVENT,
} from './chart_pointer_event_context';
export function useChartPointerEventContext() {
const context = useContext(ChartPointerEventContext);
@ -16,14 +20,36 @@ export function useChartPointerEventContext() {
throw new Error('Missing ChartPointerEventContext provider');
}
const { pointerEvent } = context;
const { pointerEventTargetRef } = context;
const chartRef = React.createRef<Chart>();
const requestIdRef = useRef(0);
const updatePointerEventHandler = useCallback(
(event: Event) => {
cancelAnimationFrame(requestIdRef.current);
requestIdRef.current = requestAnimationFrame(() => {
const pointerEvent = (
event instanceof CustomEvent ? event.detail : null
) as PointerEvent | null;
if (chartRef.current && pointerEvent) {
chartRef.current.dispatchExternalPointerEvent(pointerEvent);
}
});
},
[chartRef]
);
useEffect(() => {
if (pointerEvent && chartRef.current) {
chartRef.current.dispatchExternalPointerEvent(pointerEvent);
}
}, [pointerEvent, chartRef]);
const pointerEventTarget = pointerEventTargetRef.current;
pointerEventTarget.addEventListener(
UPDATE_POINTER_EVENT,
updatePointerEventHandler
);
return () => {
pointerEventTarget.removeEventListener(
UPDATE_POINTER_EVENT,
updatePointerEventHandler
);
};
}, [updatePointerEventHandler, pointerEventTargetRef]);
return { ...context, chartRef };
}