recharts
Version:
React charts
125 lines (119 loc) • 5.08 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.externalEventsMiddleware = exports.externalEventAction = void 0;
var _toolkit = require("@reduxjs/toolkit");
var _tooltipSelectors = require("./selectors/tooltipSelectors");
var _createEventProxy = require("../util/createEventProxy");
var externalEventAction = exports.externalEventAction = (0, _toolkit.createAction)('externalEvent');
var externalEventsMiddleware = exports.externalEventsMiddleware = (0, _toolkit.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();
var timeoutIdMap = new Map();
var latestEventMap = new Map();
externalEventsMiddleware.startListening({
actionCreator: externalEventAction,
effect: (action, listenerApi) => {
var {
handler,
reactEvent
} = action.payload;
if (handler == null) {
return;
}
var eventType = reactEvent.type;
var eventProxy = (0, _createEventProxy.createEventProxy)(reactEvent);
latestEventMap.set(eventType, {
handler,
reactEvent: eventProxy
});
// Cancel any pending execution for this event type
var existingRafId = rafIdMap.get(eventType);
if (existingRafId !== undefined) {
cancelAnimationFrame(existingRafId);
rafIdMap.delete(eventType);
}
var state = listenerApi.getState();
var {
throttleDelay,
throttledEvents
} = state.eventSettings;
/*
* reactEvent.type gives us the event type as a string, e.g., 'click', 'mousemove', etc.
* which is the same as the names used in throttledEvents array
* but that array is strictly typed as ReadonlyArray<keyof GlobalEventHandlersEventMap> | 'all' | undefined
* so that we can have relevant autocomplete and type checking elsewhere.
* This makes TypeScript panic because it refuses to call .includes() on ReadonlyArray<keyof GlobalEventHandlersEventMap>
* with a string argument.
* To satisfy TypeScript, we need to explicitly typecast throttledEvents here.
*/
var eventListAsString = throttledEvents;
// Check if this event type should be throttled
// throttledEvents can be 'all' or an array of event names
var isThrottled = eventListAsString === 'all' || (eventListAsString === null || eventListAsString === void 0 ? void 0 : eventListAsString.includes(eventType));
var existingTimeoutId = timeoutIdMap.get(eventType);
if (existingTimeoutId !== undefined && (typeof throttleDelay !== 'number' || !isThrottled)) {
clearTimeout(existingTimeoutId);
timeoutIdMap.delete(eventType);
}
var callback = () => {
var latestAction = latestEventMap.get(eventType);
try {
if (!latestAction) {
// This happens if the event was consumed by the leading edge and no new event came in
return;
}
var {
handler: latestHandler,
reactEvent: latestEvent
} = latestAction;
var currentState = listenerApi.getState();
var nextState = {
activeCoordinate: (0, _tooltipSelectors.selectActiveTooltipCoordinate)(currentState),
activeDataKey: (0, _tooltipSelectors.selectActiveTooltipDataKey)(currentState),
activeIndex: (0, _tooltipSelectors.selectActiveTooltipIndex)(currentState),
activeLabel: (0, _tooltipSelectors.selectActiveLabel)(currentState),
activeTooltipIndex: (0, _tooltipSelectors.selectActiveTooltipIndex)(currentState),
isTooltipActive: (0, _tooltipSelectors.selectIsTooltipActive)(currentState)
};
if (latestHandler) {
latestHandler(nextState, latestEvent);
}
} finally {
rafIdMap.delete(eventType);
timeoutIdMap.delete(eventType);
latestEventMap.delete(eventType);
}
};
if (!isThrottled) {
// Execute immediately
callback();
return;
}
if (throttleDelay === 'raf') {
var rafId = requestAnimationFrame(callback);
rafIdMap.set(eventType, rafId);
} else if (typeof throttleDelay === 'number') {
if (!timeoutIdMap.has(eventType)) {
/*
* Leading edge execution - execute immediately on the first event
* and then start the cooldown period to throttle subsequent events.
*/
callback();
// Start cooldown
var timeoutId = setTimeout(callback, throttleDelay);
timeoutIdMap.set(eventType, timeoutId);
}
} else {
// Should not happen based on type, but fallback to immediate
callback();
}
}
});