UNPKG

@mui/x-charts

Version:

The community edition of MUI X Charts components.

168 lines (165 loc) 6.73 kB
'use client'; import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import { warnOnce } from '@mui/x-internals/warning'; import { rainbowSurgePalette } from "../../../../colorPalettes/index.js"; import { useSelector } from "../../../store/useSelector.js"; import { selectorChartDrawingArea } from "../../corePlugins/useChartDimensions/useChartDimensions.selectors.js"; import { selectorChartSeriesProcessed } from "../../corePlugins/useChartSeries/useChartSeries.selectors.js"; import { defaultizeXAxis, defaultizeYAxis } from "./defaultizeAxis.js"; import { selectorChartXAxis, selectorChartYAxis } from "./useChartCartesianAxisRendering.selectors.js"; import { getAxisIndex } from "./getAxisValue.js"; import { getSVGPoint } from "../../../getSVGPoint.js"; import { selectorChartsInteractionIsInitialized } from "../useChartInteraction/index.js"; export const useChartCartesianAxis = ({ params, store, seriesConfig, svgRef, instance }) => { const { xAxis, yAxis, dataset } = params; if (process.env.NODE_ENV !== 'production') { const ids = [...(xAxis ?? []), ...(yAxis ?? [])].filter(axis => axis.id).map(axis => axis.id); const duplicates = new Set(ids.filter((id, index) => ids.indexOf(id) !== index)); if (duplicates.size > 0) { warnOnce([`MUI X Charts: The following axis ids are duplicated: ${Array.from(duplicates).join(', ')}.`, `Please make sure that each axis has a unique id.`].join('\n'), 'error'); } } const drawingArea = useSelector(store, selectorChartDrawingArea); const processedSeries = useSelector(store, selectorChartSeriesProcessed); const isInteractionEnabled = useSelector(store, selectorChartsInteractionIsInitialized); const { axis: xAxisWithScale, axisIds: xAxisIds } = useSelector(store, selectorChartXAxis); const { axis: yAxisWithScale, axisIds: yAxisIds } = useSelector(store, selectorChartYAxis); // The effect do not track any value defined synchronously during the 1st render by hooks called after `useChartCartesianAxis` // As a consequence, the state generated by the 1st run of this useEffect will always be equal to the initialization one const isFirstRender = React.useRef(true); React.useEffect(() => { if (isFirstRender.current) { isFirstRender.current = false; return; } store.update(prev => _extends({}, prev, { cartesianAxis: _extends({}, prev.cartesianAxis, { x: defaultizeXAxis(xAxis, dataset), y: defaultizeYAxis(yAxis, dataset) }) })); }, [seriesConfig, drawingArea, xAxis, yAxis, dataset, store]); const usedXAxis = xAxisIds[0]; const usedYAxis = yAxisIds[0]; React.useEffect(() => { const element = svgRef.current; if (!isInteractionEnabled || element === null || params.disableAxisListener) { return () => {}; } const handleOut = () => { instance.cleanInteraction?.(); }; const handleMove = event => { const target = 'targetTouches' in event ? event.targetTouches[0] : event; const svgPoint = getSVGPoint(element, target); if (!instance.isPointInside(svgPoint.x, svgPoint.y, event.target)) { instance.cleanInteraction?.(); return; } instance.setPointerCoordinate?.(svgPoint); }; const handleDown = event => { const target = event.currentTarget; if (!target) { return; } if ('hasPointerCapture' in target && target.hasPointerCapture(event.pointerId)) { target.releasePointerCapture(event.pointerId); } }; element.addEventListener('pointerdown', handleDown); element.addEventListener('pointermove', handleMove); element.addEventListener('pointercancel', handleOut); element.addEventListener('pointerleave', handleOut); return () => { element.removeEventListener('pointerdown', handleDown); element.removeEventListener('pointermove', handleMove); element.removeEventListener('pointercancel', handleOut); element.removeEventListener('pointerleave', handleOut); }; }, [svgRef, store, xAxisWithScale, usedXAxis, yAxisWithScale, usedYAxis, instance, params.disableAxisListener, isInteractionEnabled]); React.useEffect(() => { const element = svgRef.current; const onAxisClick = params.onAxisClick; if (element === null || !onAxisClick) { return () => {}; } const handleMouseClick = event => { event.preventDefault(); let dataIndex = null; let isXAxis = false; const svgPoint = getSVGPoint(element, event); const xIndex = getAxisIndex(xAxisWithScale[usedXAxis], svgPoint.x); isXAxis = xIndex !== -1; dataIndex = isXAxis ? xIndex : getAxisIndex(yAxisWithScale[usedYAxis], svgPoint.y); const USED_AXIS_ID = isXAxis ? xAxisIds[0] : yAxisIds[0]; if (dataIndex == null || dataIndex === -1) { return; } // The .data exist because otherwise the dataIndex would be null or -1. const axisValue = (isXAxis ? xAxisWithScale : yAxisWithScale)[USED_AXIS_ID].data[dataIndex]; const seriesValues = {}; Object.keys(processedSeries).filter(seriesType => ['bar', 'line'].includes(seriesType)).forEach(seriesType => { processedSeries[seriesType]?.seriesOrder.forEach(seriesId => { const seriesItem = processedSeries[seriesType].series[seriesId]; const providedXAxisId = seriesItem.xAxisId; const providedYAxisId = seriesItem.yAxisId; const axisKey = isXAxis ? providedXAxisId : providedYAxisId; if (axisKey === undefined || axisKey === USED_AXIS_ID) { seriesValues[seriesId] = seriesItem.data[dataIndex]; } }); }); onAxisClick(event, { dataIndex, axisValue, seriesValues }); }; element.addEventListener('click', handleMouseClick); return () => { element.removeEventListener('click', handleMouseClick); }; }, [params.onAxisClick, processedSeries, svgRef, xAxisWithScale, xAxisIds, yAxisWithScale, yAxisIds, usedXAxis, usedYAxis]); return {}; }; useChartCartesianAxis.params = { xAxis: true, yAxis: true, dataset: true, onAxisClick: true, disableAxisListener: true }; useChartCartesianAxis.getDefaultizedParams = ({ params }) => { return _extends({}, params, { colors: params.colors ?? rainbowSurgePalette, theme: params.theme ?? 'light', defaultizedXAxis: defaultizeXAxis(params.xAxis, params.dataset), defaultizedYAxis: defaultizeYAxis(params.yAxis, params.dataset) }); }; useChartCartesianAxis.getInitialState = params => ({ cartesianAxis: { x: params.defaultizedXAxis, y: params.defaultizedYAxis } });