@mui/x-charts
Version:
The community edition of MUI X Charts components.
216 lines (213 loc) • 7.9 kB
JavaScript
"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.useChartClosestPoint = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var React = _interopRequireWildcard(require("react"));
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
var _getSVGPoint = require("../../../getSVGPoint");
var _useChartCartesianAxis = require("../useChartCartesianAxis");
var _useChartSeries = require("../../corePlugins/useChartSeries/useChartSeries.selectors");
var _findClosestPoints = require("./findClosestPoints");
const useChartClosestPoint = ({
svgRef,
params,
store,
instance
}) => {
const {
disableVoronoi,
voronoiMaxRadius,
onItemClick
} = params;
const {
axis: xAxis,
axisIds: xAxisIds
} = store.use(_useChartCartesianAxis.selectorChartXAxis);
const {
axis: yAxis,
axisIds: yAxisIds
} = store.use(_useChartCartesianAxis.selectorChartYAxis);
const zoomIsInteracting = store.use(_useChartCartesianAxis.selectorChartZoomIsInteracting);
const {
series,
seriesOrder
} = store.use(_useChartSeries.selectorChartSeriesProcessed)?.scatter ?? {};
const flatbushMap = store.use(zoomIsInteracting ? _useChartCartesianAxis.selectorChartSeriesEmptyFlatbushMap : _useChartCartesianAxis.selectorChartSeriesFlatbushMap);
const defaultXAxisId = xAxisIds[0];
const defaultYAxisId = yAxisIds[0];
(0, _useEnhancedEffect.default)(() => {
store.set('voronoi', {
isVoronoiEnabled: !disableVoronoi
});
}, [store, disableVoronoi]);
React.useEffect(() => {
if (svgRef.current === null || disableVoronoi) {
return undefined;
}
const element = svgRef.current;
function getClosestPoint(event) {
// Get mouse coordinate in global SVG space
const svgPoint = (0, _getSVGPoint.getSVGPoint)(element, event);
if (!instance.isPointInside(svgPoint.x, svgPoint.y)) {
return 'outside-chart';
}
let closestPoint = undefined;
for (const seriesId of seriesOrder ?? []) {
const aSeries = (series ?? {})[seriesId];
const flatbush = flatbushMap.get(seriesId);
if (!flatbush) {
continue;
}
const xAxisId = aSeries.xAxisId ?? defaultXAxisId;
const yAxisId = aSeries.yAxisId ?? defaultYAxisId;
const xAxisZoom = (0, _useChartCartesianAxis.selectorChartAxisZoomData)(store.state, xAxisId);
const yAxisZoom = (0, _useChartCartesianAxis.selectorChartAxisZoomData)(store.state, yAxisId);
const maxRadius = voronoiMaxRadius === 'item' ? aSeries.markerSize : voronoiMaxRadius;
const xZoomStart = (xAxisZoom?.start ?? 0) / 100;
const xZoomEnd = (xAxisZoom?.end ?? 100) / 100;
const yZoomStart = (yAxisZoom?.start ?? 0) / 100;
const yZoomEnd = (yAxisZoom?.end ?? 100) / 100;
const xScale = xAxis[xAxisId].scale;
const yScale = yAxis[yAxisId].scale;
const closestPointIndex = (0, _findClosestPoints.findClosestPoints)(flatbush, aSeries.data, xScale, yScale, xZoomStart, xZoomEnd, yZoomStart, yZoomEnd, svgPoint.x, svgPoint.y, maxRadius)[0];
if (closestPointIndex === undefined) {
continue;
}
const point = aSeries.data[closestPointIndex];
const scaledX = xScale(point.x);
const scaledY = yScale(point.y);
const distSq = (scaledX - svgPoint.x) ** 2 + (scaledY - svgPoint.y) ** 2;
if (closestPoint === undefined || distSq < closestPoint.distanceSq) {
closestPoint = {
dataIndex: closestPointIndex,
seriesId,
distanceSq: distSq
};
}
}
if (closestPoint === undefined) {
return 'no-point-found';
}
return {
seriesId: closestPoint.seriesId,
dataIndex: closestPoint.dataIndex
};
}
// Clean the interaction when the mouse leaves the chart.
const moveEndHandler = instance.addInteractionListener('moveEnd', event => {
if (!event.detail.activeGestures.pan) {
instance.cleanInteraction?.();
instance.clearHighlight?.();
instance.removeTooltipItem?.();
}
});
const panEndHandler = instance.addInteractionListener('panEnd', event => {
if (!event.detail.activeGestures.move) {
instance.cleanInteraction?.();
instance.clearHighlight?.();
instance.removeTooltipItem?.();
}
});
const pressEndHandler = instance.addInteractionListener('quickPressEnd', event => {
if (!event.detail.activeGestures.move && !event.detail.activeGestures.pan) {
instance.cleanInteraction?.();
instance.clearHighlight?.();
instance.removeTooltipItem?.();
}
});
const gestureHandler = event => {
const closestPoint = getClosestPoint(event.detail.srcEvent);
if (closestPoint === 'outside-chart') {
instance.cleanInteraction?.();
instance.clearHighlight?.();
instance.removeTooltipItem?.();
return;
}
if (closestPoint === 'outside-voronoi-max-radius' || closestPoint === 'no-point-found') {
instance.removeTooltipItem?.();
instance.clearHighlight?.();
instance.removeTooltipItem?.();
return;
}
const {
seriesId,
dataIndex
} = closestPoint;
instance.setTooltipItem?.({
type: 'scatter',
seriesId,
dataIndex
});
instance.setLastUpdateSource?.('pointer');
instance.setHighlight?.({
seriesId,
dataIndex
});
};
const tapHandler = instance.addInteractionListener('tap', event => {
const closestPoint = getClosestPoint(event.detail.srcEvent);
if (typeof closestPoint !== 'string' && onItemClick) {
const {
seriesId,
dataIndex
} = closestPoint;
onItemClick(event.detail.srcEvent, {
type: 'scatter',
seriesId,
dataIndex
});
}
});
const moveHandler = instance.addInteractionListener('move', gestureHandler);
const panHandler = instance.addInteractionListener('pan', gestureHandler);
const pressHandler = instance.addInteractionListener('quickPress', gestureHandler);
return () => {
tapHandler.cleanup();
moveHandler.cleanup();
moveEndHandler.cleanup();
panHandler.cleanup();
panEndHandler.cleanup();
pressHandler.cleanup();
pressEndHandler.cleanup();
};
}, [svgRef, yAxis, xAxis, voronoiMaxRadius, onItemClick, disableVoronoi, instance, seriesOrder, series, flatbushMap, defaultXAxisId, defaultYAxisId, store]);
// Instance implementation
const enableVoronoiCallback = (0, _useEventCallback.default)(() => {
store.set('voronoi', {
isVoronoiEnabled: true
});
});
const disableVoronoiCallback = (0, _useEventCallback.default)(() => {
store.set('voronoi', {
isVoronoiEnabled: false
});
});
return {
instance: {
enableVoronoi: enableVoronoiCallback,
disableVoronoi: disableVoronoiCallback
}
};
};
exports.useChartClosestPoint = useChartClosestPoint;
useChartClosestPoint.getDefaultizedParams = ({
params
}) => (0, _extends2.default)({}, params, {
disableVoronoi: params.disableVoronoi ?? !params.series.some(item => item.type === 'scatter')
});
useChartClosestPoint.getInitialState = params => ({
voronoi: {
isVoronoiEnabled: !params.disableVoronoi
}
});
useChartClosestPoint.params = {
disableVoronoi: true,
voronoiMaxRadius: true,
onItemClick: true
};