UNPKG

@mui/x-charts

Version:

The community edition of MUI X Charts components.

229 lines (218 loc) 9.78 kB
"use strict"; 'use client'; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.useChartPolarAxis = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _warning = require("@mui/x-internals/warning"); var _useSelector = require("../../../store/useSelector"); var _useChartDimensions = require("../../corePlugins/useChartDimensions/useChartDimensions.selectors"); var _defaultizeAxis = require("./defaultizeAxis"); var _useChartInteraction = require("../useChartInteraction"); var _useChartPolarAxis = require("./useChartPolarAxis.selectors"); var _getSVGPoint = require("../../../getSVGPoint"); var _coordinateTransformation = require("./coordinateTransformation"); var _getAxisIndex = require("./getAxisIndex"); var _useChartSeries = require("../../corePlugins/useChartSeries"); const useChartPolarAxis = ({ params, store, seriesConfig, svgRef, instance }) => { const { rotationAxis, radiusAxis, dataset } = params; if (process.env.NODE_ENV !== 'production') { const ids = [...(rotationAxis ?? []), ...(radiusAxis ?? [])].filter(axis => axis.id).map(axis => axis.id); const duplicates = new Set(ids.filter((id, index) => ids.indexOf(id) !== index)); if (duplicates.size > 0) { (0, _warning.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 = (0, _useSelector.useSelector)(store, _useChartDimensions.selectorChartDrawingArea); const processedSeries = (0, _useSelector.useSelector)(store, _useChartSeries.selectorChartSeriesProcessed); const center = (0, _useSelector.useSelector)(store, _useChartPolarAxis.selectorChartPolarCenter); const isInteractionEnabled = (0, _useSelector.useSelector)(store, _useChartInteraction.selectorChartsInteractionIsInitialized); const { axis: rotationAxisWithScale, axisIds: rotationAxisIds } = (0, _useSelector.useSelector)(store, _useChartPolarAxis.selectorChartRotationAxis); const { axis: radiusAxisWithScale, axisIds: radiusAxisIds } = (0, _useSelector.useSelector)(store, _useChartPolarAxis.selectorChartRadiusAxis); // The effect do not track any value defined synchronously during the 1st render by hooks called after `useChartPolarAxis` // 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 => (0, _extends2.default)({}, prev, { polarAxis: (0, _extends2.default)({}, prev.polarAxis, { rotation: (0, _defaultizeAxis.defaultizeAxis)(rotationAxis, dataset, 'rotation'), radius: (0, _defaultizeAxis.defaultizeAxis)(radiusAxis, dataset, 'radius') }) })); }, [seriesConfig, drawingArea, rotationAxis, radiusAxis, dataset, store]); const svg2rotation = React.useMemo(() => (0, _coordinateTransformation.generateSvg2rotation)({ cx: center.cx, cy: center.cy }), [center.cx, center.cy]); const svg2polar = React.useMemo(() => (0, _coordinateTransformation.generateSvg2polar)({ cx: center.cx, cy: center.cy }), [center.cx, center.cy]); const polar2svg = React.useMemo(() => (0, _coordinateTransformation.generatePolar2svg)({ cx: center.cx, cy: center.cy }), [center.cx, center.cy]); const usedRotationAxisId = rotationAxisIds[0]; const usedRadiusAxisId = radiusAxisIds[0]; // Use a ref to avoid rerendering on every mousemove event. const mousePosition = React.useRef({ isInChart: false }); React.useEffect(() => { const element = svgRef.current; if (!isInteractionEnabled || element === null || params.disableAxisListener) { return () => {}; } // Clean the interaction when the mouse leaves the chart. const moveEndHandler = instance.addInteractionListener('moveEnd', event => { if (!event.detail.activeGestures.pan) { mousePosition.current.isInChart = false; instance.cleanInteraction(); } }); const panEndHandler = instance.addInteractionListener('panEnd', event => { if (!event.detail.activeGestures.move) { mousePosition.current.isInChart = false; instance.cleanInteraction(); } }); const pressEndHandler = instance.addInteractionListener('quickPressEnd', event => { if (!event.detail.activeGestures.move && !event.detail.activeGestures.pan) { mousePosition.current.isInChart = false; instance.cleanInteraction(); } }); const gestureHandler = event => { const srcEvent = event.detail.srcEvent; // On touch, we want to allow user to interact with the entire svg area in // order to better display the tooltip. if (event.detail.srcEvent.pointerType === 'touch') { const svgRect = element.getBoundingClientRect(); if (srcEvent.clientX < svgRect.left || srcEvent.clientX > svgRect.right || srcEvent.clientY < svgRect.top || srcEvent.clientY > svgRect.bottom) { mousePosition.current.isInChart = false; instance.cleanInteraction(); return; } const svgPoint = (0, _getSVGPoint.getSVGPoint)(element, srcEvent); mousePosition.current.isInChart = true; instance.setPointerCoordinate(svgPoint); return; } // On mouse, we want to restrict the interaction to the drawing area and radar circle. const svgPoint = (0, _getSVGPoint.getSVGPoint)(element, srcEvent); // Test if it's in the drawing area if (!instance.isPointInside(svgPoint.x, svgPoint.y, event.detail.target)) { if (mousePosition.current.isInChart) { instance?.cleanInteraction(); mousePosition.current.isInChart = false; } return; } // Test if it's in the radar circle const radiusSquare = (center.cx - svgPoint.x) ** 2 + (center.cy - svgPoint.y) ** 2; const maxRadius = radiusAxisWithScale[usedRadiusAxisId].scale.range()[1]; if (radiusSquare > maxRadius ** 2) { if (mousePosition.current.isInChart) { instance?.cleanInteraction(); mousePosition.current.isInChart = false; } return; } mousePosition.current.isInChart = true; instance.setPointerCoordinate?.(svgPoint); }; const moveHandler = instance.addInteractionListener('move', gestureHandler); const panHandler = instance.addInteractionListener('pan', gestureHandler); const pressHandler = instance.addInteractionListener('quickPress', gestureHandler); return () => { moveHandler.cleanup(); moveEndHandler.cleanup(); panHandler.cleanup(); panEndHandler.cleanup(); pressHandler.cleanup(); pressEndHandler.cleanup(); }; }, [svgRef, store, center, radiusAxisWithScale, usedRadiusAxisId, rotationAxisWithScale, usedRotationAxisId, instance, params.disableAxisListener, isInteractionEnabled, svg2rotation]); React.useEffect(() => { const element = svgRef.current; const onAxisClick = params.onAxisClick; if (element === null || !onAxisClick) { return () => {}; } const axisClickHandler = instance.addInteractionListener('tap', event => { let dataIndex = null; let isRotationAxis = false; const svgPoint = (0, _getSVGPoint.getSVGPoint)(element, event.detail.srcEvent); const rotation = (0, _coordinateTransformation.generateSvg2rotation)(center)(svgPoint.x, svgPoint.y); const rotationIndex = (0, _getAxisIndex.getAxisIndex)(rotationAxisWithScale[usedRotationAxisId], rotation); isRotationAxis = rotationIndex !== -1; dataIndex = isRotationAxis ? rotationIndex : null; // radius index is not yet implemented. const USED_AXIS_ID = isRotationAxis ? usedRotationAxisId : usedRadiusAxisId; if (dataIndex == null || dataIndex === -1) { return; } // The .data exist because otherwise the dataIndex would be null or -1. const axisValue = (isRotationAxis ? rotationAxisWithScale : radiusAxisWithScale)[USED_AXIS_ID].data[dataIndex]; const seriesValues = {}; Object.keys(processedSeries).filter(seriesType => seriesType === 'radar').forEach(seriesType => { processedSeries[seriesType]?.seriesOrder.forEach(seriesId => { const seriesItem = processedSeries[seriesType].series[seriesId]; seriesValues[seriesId] = seriesItem.data[dataIndex]; }); }); onAxisClick(event.detail.srcEvent, { dataIndex, axisValue, seriesValues }); }); return () => { axisClickHandler.cleanup(); }; }, [center, instance, params.onAxisClick, processedSeries, radiusAxisWithScale, rotationAxisWithScale, svgRef, usedRadiusAxisId, usedRotationAxisId]); return { instance: { svg2polar, svg2rotation, polar2svg } }; }; exports.useChartPolarAxis = useChartPolarAxis; useChartPolarAxis.params = { rotationAxis: true, radiusAxis: true, dataset: true, disableAxisListener: true, onAxisClick: true }; useChartPolarAxis.getInitialState = params => ({ polarAxis: { rotation: (0, _defaultizeAxis.defaultizeAxis)(params.rotationAxis, params.dataset, 'rotation'), radius: (0, _defaultizeAxis.defaultizeAxis)(params.radiusAxis, params.dataset, 'radius') } });