UNPKG

@mui/x-charts

Version:

The community edition of MUI X Charts components.

167 lines (164 loc) 6.21 kB
import { createSelector, createSelectorMemoized, createSelectorMemoizedWithOptions } from '@mui/x-internals/store'; import { isDeepEqual } from '@mui/x-internals/isDeepEqual'; import { selectorChartXAxis, selectorChartYAxis } from "./useChartCartesianAxisRendering.selectors.mjs"; import { selectorChartsInteractionPointerX, selectorChartsInteractionPointerY } from "../useChartInteraction/index.mjs"; import { selectorChartsLastInteraction } from "../useChartInteraction/useChartInteraction.selectors.mjs"; import { selectorChartsKeyboardXAxisIndex, selectorChartsKeyboardYAxisIndex } from "../useChartKeyboardNavigation/useChartKeyboardNavigation.selectors.mjs"; import { getAxisIndex } from "./getAxisValue.mjs"; import { getValueToPositionMapper } from "../../../../hooks/getValueToPositionMapper.mjs"; import { selectorChartDrawingArea } from "../../corePlugins/useChartDimensions/useChartDimensions.selectors.mjs"; const selectorChartControlledCartesianAxisTooltip = state => state.controlledCartesianAxisTooltip; const EMPTY_ARRAY = []; function getKeyboardAxisTooltip(keyboardIndex, axes) { if (keyboardIndex === undefined) { return EMPTY_ARRAY; } const axis = axes.axis[keyboardIndex.axisId]; if (!axis?.triggerTooltip) { return EMPTY_ARRAY; } return [keyboardIndex]; } /** * Get x-axis ids and corresponding data index that should be display in the tooltip. */ export const selectorChartsInteractionTooltipXAxes = createSelectorMemoizedWithOptions({ memoizeOptions: { // Keep the same reference if array content is the same. // If possible, avoid this pattern by creating selectors that // uses string/number as arguments. resultEqualityCheck: isDeepEqual } })(selectorChartControlledCartesianAxisTooltip, selectorChartsInteractionPointerX, selectorChartXAxis, selectorChartsLastInteraction, selectorChartsKeyboardXAxisIndex, (controlledValues, value, axes, lastInteraction, keyboardIndex) => { if (controlledValues !== undefined) { if (controlledValues.length === 0) { return EMPTY_ARRAY; } const ids = new Set(axes.axisIds); const filteredArray = controlledValues.filter(({ axisId }) => ids.has(axisId)); return filteredArray.length === controlledValues.length ? controlledValues : filteredArray; } if (lastInteraction === 'keyboard') { return getKeyboardAxisTooltip(keyboardIndex, axes); } if (value === null) { return EMPTY_ARRAY; } return axes.axisIds.filter(id => axes.axis[id].triggerTooltip).map(axisId => ({ axisId, dataIndex: getAxisIndex(axes.axis[axisId], value) })).filter(({ dataIndex }) => dataIndex >= 0); }); /** * Get y-axis ids and corresponding data index that should be display in the tooltip. */ export const selectorChartsInteractionTooltipYAxes = createSelectorMemoizedWithOptions({ memoizeOptions: { // Keep the same reference if array content is the same. // If possible, avoid this pattern by creating selectors that // uses string/number as arguments. resultEqualityCheck: isDeepEqual } })(selectorChartControlledCartesianAxisTooltip, selectorChartsInteractionPointerY, selectorChartYAxis, selectorChartsLastInteraction, selectorChartsKeyboardYAxisIndex, (controlledValues, value, axes, lastInteraction, keyboardIndex) => { if (controlledValues !== undefined) { if (controlledValues.length === 0) { return EMPTY_ARRAY; } const ids = new Set(axes.axisIds); const filteredArray = controlledValues.filter(({ axisId }) => ids.has(axisId)); return filteredArray.length === controlledValues.length ? controlledValues : filteredArray; } if (lastInteraction === 'keyboard') { return getKeyboardAxisTooltip(keyboardIndex, axes); } if (value === null) { return EMPTY_ARRAY; } return axes.axisIds.filter(id => axes.axis[id].triggerTooltip).map(axisId => ({ axisId, dataIndex: getAxisIndex(axes.axis[axisId], value) })).filter(({ dataIndex }) => dataIndex >= 0); }); /** * Return `true` if the axis tooltip has something to display. */ export const selectorChartsInteractionAxisTooltip = createSelector(selectorChartsInteractionTooltipXAxes, selectorChartsInteractionTooltipYAxes, (xTooltip, yTooltip) => xTooltip.length > 0 || yTooltip.length > 0); function getCoordinatesFromAxis(identifier, axes) { const axis = axes.axis[identifier.axisId]; if (!axis) { return null; } const value = axis.data?.[identifier.dataIndex]; if (value == null) { return null; } const coordinate = getValueToPositionMapper(axis.scale)(value); if (coordinate === undefined) { return null; } return coordinate; } export const selectorChartsTooltipAxisPosition = createSelectorMemoized(selectorChartsInteractionTooltipXAxes, selectorChartsInteractionTooltipYAxes, selectorChartXAxis, selectorChartYAxis, selectorChartDrawingArea, function selectorChartsTooltipItemPosition(xAxesIdentifiers, yAxesIdentifiers, xAxes, yAxes, drawingArea, placement) { if (xAxesIdentifiers.length === 0 && yAxesIdentifiers.length === 0) { return null; } if (xAxesIdentifiers.length > 0) { const x = getCoordinatesFromAxis(xAxesIdentifiers[0], xAxes); if (x === null) { return null; } switch (placement) { case 'left': case 'right': return { x, y: drawingArea.top + drawingArea.height / 2 }; case 'bottom': return { x, y: drawingArea.top + drawingArea.height }; case 'top': default: return { x, y: drawingArea.top }; } } if (yAxesIdentifiers.length > 0) { const y = getCoordinatesFromAxis(yAxesIdentifiers[0], yAxes); if (y === null) { return null; } switch (placement) { case 'right': return { x: drawingArea.left + drawingArea.width / 2, y }; case 'bottom': case 'top': return { x: drawingArea.left + drawingArea.width / 2, y }; case 'left': default: return { x: drawingArea.left + drawingArea.width / 2, y }; } } return null; });