@mui/x-charts
Version:
The community edition of MUI X Charts components.
229 lines (218 loc) • 9.78 kB
JavaScript
'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')
}
});
;