@mui/x-charts
Version:
The community edition of the charts components (MUI X).
174 lines (172 loc) • 7.05 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ChartsVoronoiHandler = ChartsVoronoiHandler;
var React = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _d3Delaunay = require("d3-delaunay");
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _InteractionProvider = require("../context/InteractionProvider");
var _CartesianContextProvider = require("../context/CartesianContextProvider");
var _DrawingProvider = require("../context/DrawingProvider");
var _SeriesContextProvider = require("../context/SeriesContextProvider");
var _useScale = require("../hooks/useScale");
var _utils = require("../internals/utils");
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function ChartsVoronoiHandler(props) {
const {
voronoiMaxRadius
} = props;
const svgRef = React.useContext(_DrawingProvider.SVGContext);
const {
width,
height,
top,
left
} = React.useContext(_DrawingProvider.DrawingContext);
const {
xAxis,
yAxis,
xAxisIds,
yAxisIds
} = React.useContext(_CartesianContextProvider.CartesianContext);
const {
dispatch
} = React.useContext(_InteractionProvider.InteractionContext);
const {
series,
seriesOrder
} = React.useContext(_SeriesContextProvider.SeriesContext).scatter ?? {};
const voronoiRef = React.useRef({});
const defaultXAxisId = xAxisIds[0];
const defaultYAxisId = yAxisIds[0];
(0, _useEnhancedEffect.default)(() => {
dispatch({
type: 'updateVoronoiUsage',
useVoronoiInteraction: true
});
return () => {
dispatch({
type: 'updateVoronoiUsage',
useVoronoiInteraction: false
});
};
}, [dispatch]);
(0, _useEnhancedEffect.default)(() => {
if (seriesOrder === undefined || series === undefined) {
// If there is no scatter chart series
return;
}
voronoiRef.current = {};
let points = [];
seriesOrder.forEach(seriesId => {
const {
data,
xAxisKey,
yAxisKey
} = series[seriesId];
const xScale = xAxis[xAxisKey ?? defaultXAxisId].scale;
const yScale = yAxis[yAxisKey ?? defaultYAxisId].scale;
const getXPosition = (0, _useScale.getValueToPositionMapper)(xScale);
const getYPosition = (0, _useScale.getValueToPositionMapper)(yScale);
const seriesPoints = data.flatMap(({
x,
y
}) => [getXPosition(x), getYPosition(y)]);
voronoiRef.current[seriesId] = {
startIndex: points.length,
endIndex: points.length + seriesPoints.length
};
points = points.concat(seriesPoints);
});
voronoiRef.current.delauney = new _d3Delaunay.Delaunay(points);
}, [defaultXAxisId, defaultYAxisId, series, seriesOrder, xAxis, yAxis]);
React.useEffect(() => {
const element = svgRef.current;
if (element === null) {
return undefined;
}
const handleMouseOut = () => {
dispatch({
type: 'exitChart'
});
};
// TODO: A perf optimisation of voronoi could be to use the last point as the intial point for the next search.
const handleMouseMove = event => {
// Get mouse coordinate in global SVG space
const svgPoint = (0, _utils.getSVGPoint)(svgRef.current, event);
const outsideX = svgPoint.x < left || svgPoint.x > left + width;
const outsideY = svgPoint.y < top || svgPoint.y > top + height;
if (outsideX || outsideY) {
dispatch({
type: 'exitChart'
});
return;
}
if (!voronoiRef.current.delauney) {
return;
}
const closestPointIndex = voronoiRef.current.delauney?.find(svgPoint.x, svgPoint.y);
if (closestPointIndex !== undefined) {
const seriesId = Object.keys(voronoiRef.current).find(id => {
if (id === 'delauney') {
return false;
}
return 2 * closestPointIndex >= voronoiRef.current[id].startIndex && 2 * closestPointIndex < voronoiRef.current[id].endIndex;
});
if (seriesId === undefined) {
return;
}
const dataIndex = (2 * closestPointIndex - voronoiRef.current[seriesId].startIndex) / 2;
if (voronoiMaxRadius !== undefined) {
const pointX = voronoiRef.current.delauney.points[2 * closestPointIndex];
const pointY = voronoiRef.current.delauney.points[2 * closestPointIndex + 1];
const dist2 = (pointX - svgPoint.x) ** 2 + (pointY - svgPoint.y) ** 2;
if (dist2 > voronoiMaxRadius ** 2) {
// The closest point is too far to be considered.
dispatch({
type: 'leaveItem',
data: {
type: 'scatter',
seriesId,
dataIndex
}
});
return;
}
}
dispatch({
type: 'enterItem',
data: {
type: 'scatter',
seriesId,
dataIndex
}
});
}
};
element.addEventListener('mouseout', handleMouseOut);
element.addEventListener('mousemove', handleMouseMove);
return () => {
element.removeEventListener('mouseout', handleMouseOut);
element.removeEventListener('mousemove', handleMouseMove);
};
}, [svgRef, dispatch, left, width, top, height, yAxis, xAxis, voronoiMaxRadius]);
return /*#__PURE__*/(0, _jsxRuntime.jsx)("g", {}); // Workaround to fix docs scripts
}
process.env.NODE_ENV !== "production" ? ChartsVoronoiHandler.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "yarn proptypes" |
// ----------------------------------------------------------------------
/**
* Defines the maximal distance between a scatter point and the pointer that triggers the interaction.
* If `undefined`, the radius is assumed to be infinite.
* @default undefined
*/
voronoiMaxRadius: _propTypes.default.number
} : void 0;
;