UNPKG

recharts

Version:
56 lines (54 loc) 2.47 kB
import { createAction, createListenerMiddleware } from '@reduxjs/toolkit'; import { selectActiveLabel, selectActiveTooltipCoordinate, selectActiveTooltipDataKey, selectActiveTooltipIndex, selectIsTooltipActive } from './selectors/tooltipSelectors'; export var externalEventAction = createAction('externalEvent'); export var externalEventsMiddleware = createListenerMiddleware(); /* * We need a Map keyed by event type because this middleware handles MULTIPLE different event types * (click, mouseenter, mouseleave, mousedown, mouseup, contextmenu, dblclick, touchstart, touchmove, touchend) * from the same DOM element. Different event types should NOT cancel each other's animation frames. * For example, a click event and a mousemove event can happen in quick succession and both should be processed. * This is different from mouseMoveMiddleware which only handles one event type and uses a single rafId. */ var rafIdMap = new Map(); externalEventsMiddleware.startListening({ actionCreator: externalEventAction, effect: (action, listenerApi) => { var { handler, reactEvent } = action.payload; if (handler == null) { return; } reactEvent.persist(); var eventType = reactEvent.type; // Cancel any pending animation frame for this event type var existingRafId = rafIdMap.get(eventType); if (existingRafId !== undefined) { cancelAnimationFrame(existingRafId); } var rafId = requestAnimationFrame(() => { try { /* * Here it is important that we get the latest state inside the animation frame callback, * not from the outer scope, because there may have been other actions dispatched * between the time the event was fired and the animation frame callback is executed. * One of those actions is the one that actually sets the active tooltip state! */ var state = listenerApi.getState(); var nextState = { activeCoordinate: selectActiveTooltipCoordinate(state), activeDataKey: selectActiveTooltipDataKey(state), activeIndex: selectActiveTooltipIndex(state), activeLabel: selectActiveLabel(state), activeTooltipIndex: selectActiveTooltipIndex(state), isTooltipActive: selectIsTooltipActive(state) }; handler(nextState, reactEvent); } finally { rafIdMap.delete(eventType); } }); rafIdMap.set(eventType, rafId); } });