UNPKG

@mui/x-charts

Version:

The community edition of MUI X Charts components.

67 lines (64 loc) 2.65 kB
'use client'; import * as React from 'react'; import { useSvgRef } from "../hooks/useSvgRef.js"; import { useChartContext } from "../context/ChartProvider/index.js"; import { getSVGPoint } from "../internals/getSVGPoint.js"; import { useStore } from "../internals/store/useStore.js"; import { selectorBarItemAtPosition } from "../internals/plugins/featurePlugins/useChartCartesianAxis/useChartCartesianAxisPosition.selectors.js"; /** * Hook that registers pointer event handlers for chart item clicking. * @param onItemClick Callback for item click events. */ export function useRegisterItemClickHandlers(onItemClick) { const { instance } = useChartContext(); const svgRef = useSvgRef(); const store = useStore(); React.useEffect(() => { const element = svgRef.current; if (!element || !onItemClick) { return undefined; } let lastPointerUp = null; const onClick = function onClick(event) { let point = event; /* The click event doesn't contain decimal values in clientX/Y, but the pointermove does. * This caused a problem when rendering many bars that were thinner than a pixel where the tooltip or the highlight * would refer to a different bar than the click since those rely on the pointermove event. * As a fix, we use the pointerup event to get the decimal values and check if the pointer up event was close enough * to the click event (1px difference in each direction); if so, then we can use the pointerup's clientX/Y; if not, * we default to the click event's clientX/Y. */ if (lastPointerUp) { if (Math.abs(event.clientX - lastPointerUp.clientX) <= 1 && Math.abs(event.clientY - lastPointerUp.clientY) <= 1) { point = { clientX: lastPointerUp.clientX, clientY: lastPointerUp.clientY }; } } lastPointerUp = null; const svgPoint = getSVGPoint(element, point); if (!instance.isPointInside(svgPoint.x, svgPoint.y)) { return; } const item = selectorBarItemAtPosition(store.state, svgPoint); if (item) { onItemClick(event, { type: 'bar', seriesId: item.seriesId, dataIndex: item.dataIndex }); } }; const onPointerUp = function onPointerUp(event) { lastPointerUp = event; }; element.addEventListener('click', onClick); element.addEventListener('pointerup', onPointerUp); return () => { element.removeEventListener('click', onClick); element.removeEventListener('pointerup', onPointerUp); }; }, [instance, onItemClick, store, svgRef]); }