From a135b7e0a693e7caa99c9027c5fda528c07e4383 Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Thu, 15 Aug 2024 14:28:00 +0200 Subject: [PATCH 1/2] Fix isPointInside --- .../x-charts/src/ChartsXAxis/ChartsXAxis.tsx | 7 ++-- .../x-charts/src/ChartsYAxis/ChartsYAxis.tsx | 4 +-- .../x-charts/src/context/DrawingProvider.tsx | 33 ++++++++++++++----- packages/x-charts/src/hooks/useAxisEvents.ts | 2 +- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx index b3e47a0dcff9..dad073f7bdc5 100644 --- a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx +++ b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx @@ -134,7 +134,7 @@ function ChartsXAxis(inProps: ChartsXAxisProps) { const theme = useTheme(); const classes = useUtilityClasses({ ...defaultizedProps, theme }); - const { left, top, width, height } = useDrawingArea(); + const { left, top, width, height, isPointInside } = useDrawingArea(); const tickSize = disableTicks ? 4 : tickSizeProp; @@ -217,9 +217,8 @@ function ChartsXAxis(inProps: ChartsXAxisProps) { const xTickLabel = labelOffset ?? 0; const yTickLabel = positionSign * (tickSize + 3); - const showTick = offset >= left - 1 && offset <= left + width + 1; - const showTickLabel = - offset + xTickLabel >= left - 1 && offset + xTickLabel <= left + width + 1; + const showTick = isPointInside({ x: offset }, { direction: 'x' }); + const showTickLabel = isPointInside({ x: offset + xTickLabel }, { direction: 'x' }); return ( {!disableTicks && showTick && ( diff --git a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx index 55c2ac3e08af..d8c416cb15c0 100644 --- a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx +++ b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx @@ -81,7 +81,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { const classes = useUtilityClasses({ ...defaultizedProps, theme }); - const { left, top, width, height } = useDrawingArea(); + const { left, top, width, height, isPointInside } = useDrawingArea(); const tickSize = disableTicks ? 4 : tickSizeProp; @@ -171,7 +171,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { const skipLabel = typeof tickLabelInterval === 'function' && !tickLabelInterval?.(value, index); - const showLabel = offset >= top - 1 && offset <= height + top + 1; + const showLabel = isPointInside({ y: offset }, { direction: 'y' }); if (!showLabel) { return null; diff --git a/packages/x-charts/src/context/DrawingProvider.tsx b/packages/x-charts/src/context/DrawingProvider.tsx index 26dee3c5a414..5cc72d830125 100644 --- a/packages/x-charts/src/context/DrawingProvider.tsx +++ b/packages/x-charts/src/context/DrawingProvider.tsx @@ -42,10 +42,18 @@ export type DrawingArea = { * @param {Object} point The point to check. * @param {number} point.x The x coordinate of the point. * @param {number} point.y The y coordinate of the point. - * @param {Element} targetElement The target element if relevant. + * @param {Object} options The options of the check. + * @param {Element} [options.targetElement] The element to check if it is allowed to overflow the drawing area. + * @param {'x' | 'y' | 'xy'} [options.direction] The direction to check. * @returns {boolean} `true` if the point is inside the drawing area, `false` otherwise. */ - isPointInside: (point: { x: number; y: number }, targetElement?: Element) => boolean; + isPointInside: ( + point: { x?: number; y?: number }, + options?: { + targetElement?: Element; + direction?: 'x' | 'y' | 'xy'; + }, + ) => boolean; }; export const DrawingContext = React.createContext< @@ -87,17 +95,24 @@ export function DrawingProvider(props: DrawingProviderProps) { const chartId = useId(); const isPointInside = React.useCallback( - ({ x, y }, targetElement) => { + ({ x = 0, y = 0 }, { targetElement, direction } = {}) => { // For element allowed to overflow, wrapping them in make them fully part of the drawing area. if (targetElement && targetElement.closest('[data-drawing-container]')) { return true; } - return ( - x >= drawingArea.left && - x <= drawingArea.left + drawingArea.width && - y >= drawingArea.top && - y <= drawingArea.top + drawingArea.height - ); + + const isInsideX = x >= drawingArea.left - 1 && x <= drawingArea.left + drawingArea.width; + const isInsideY = y >= drawingArea.top - 1 && y <= drawingArea.top + drawingArea.height; + + if (direction === 'x') { + return isInsideX; + } + + if (direction === 'y') { + return isInsideY; + } + + return isInsideX && isInsideY; }, [drawingArea], ); diff --git a/packages/x-charts/src/hooks/useAxisEvents.ts b/packages/x-charts/src/hooks/useAxisEvents.ts index f20d26f76dcc..83994d170929 100644 --- a/packages/x-charts/src/hooks/useAxisEvents.ts +++ b/packages/x-charts/src/hooks/useAxisEvents.ts @@ -109,7 +109,7 @@ export const useAxisEvents = (disableAxisListener: boolean) => { mousePosition.current.x = svgPoint.x; mousePosition.current.y = svgPoint.y; - if (!drawingArea.isPointInside(svgPoint, event.target as SVGElement)) { + if (!drawingArea.isPointInside(svgPoint, { targetElement: event.target as SVGElement })) { if (mousePosition.current.isInChart) { dispatch({ type: 'exitChart' }); mousePosition.current.isInChart = false; From 37bc0d7b851200445c1a2699d26663e829e3749c Mon Sep 17 00:00:00 2001 From: Jose Quintas Date: Mon, 19 Aug 2024 11:26:27 +0200 Subject: [PATCH 2/2] feedback --- packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx | 4 ++-- packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx | 2 +- packages/x-charts/src/context/DrawingProvider.tsx | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx index dad073f7bdc5..c4929c9d9459 100644 --- a/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx +++ b/packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx @@ -217,8 +217,8 @@ function ChartsXAxis(inProps: ChartsXAxisProps) { const xTickLabel = labelOffset ?? 0; const yTickLabel = positionSign * (tickSize + 3); - const showTick = isPointInside({ x: offset }, { direction: 'x' }); - const showTickLabel = isPointInside({ x: offset + xTickLabel }, { direction: 'x' }); + const showTick = isPointInside({ x: offset, y: -1 }, { direction: 'x' }); + const showTickLabel = isPointInside({ x: offset + xTickLabel, y: -1 }, { direction: 'x' }); return ( {!disableTicks && showTick && ( diff --git a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx index d8c416cb15c0..281ce8d1b3d2 100644 --- a/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx +++ b/packages/x-charts/src/ChartsYAxis/ChartsYAxis.tsx @@ -171,7 +171,7 @@ function ChartsYAxis(inProps: ChartsYAxisProps) { const skipLabel = typeof tickLabelInterval === 'function' && !tickLabelInterval?.(value, index); - const showLabel = isPointInside({ y: offset }, { direction: 'y' }); + const showLabel = isPointInside({ x: -1, y: offset }, { direction: 'y' }); if (!showLabel) { return null; diff --git a/packages/x-charts/src/context/DrawingProvider.tsx b/packages/x-charts/src/context/DrawingProvider.tsx index 5cc72d830125..cf851ba3b350 100644 --- a/packages/x-charts/src/context/DrawingProvider.tsx +++ b/packages/x-charts/src/context/DrawingProvider.tsx @@ -44,14 +44,14 @@ export type DrawingArea = { * @param {number} point.y The y coordinate of the point. * @param {Object} options The options of the check. * @param {Element} [options.targetElement] The element to check if it is allowed to overflow the drawing area. - * @param {'x' | 'y' | 'xy'} [options.direction] The direction to check. + * @param {'x' | 'y'} [options.direction] The direction to check. * @returns {boolean} `true` if the point is inside the drawing area, `false` otherwise. */ isPointInside: ( - point: { x?: number; y?: number }, + point: { x: number; y: number }, options?: { targetElement?: Element; - direction?: 'x' | 'y' | 'xy'; + direction?: 'x' | 'y'; }, ) => boolean; }; @@ -95,20 +95,20 @@ export function DrawingProvider(props: DrawingProviderProps) { const chartId = useId(); const isPointInside = React.useCallback( - ({ x = 0, y = 0 }, { targetElement, direction } = {}) => { + ({ x, y }, options) => { // For element allowed to overflow, wrapping them in make them fully part of the drawing area. - if (targetElement && targetElement.closest('[data-drawing-container]')) { + if (options?.targetElement && options?.targetElement.closest('[data-drawing-container]')) { return true; } const isInsideX = x >= drawingArea.left - 1 && x <= drawingArea.left + drawingArea.width; const isInsideY = y >= drawingArea.top - 1 && y <= drawingArea.top + drawingArea.height; - if (direction === 'x') { + if (options?.direction === 'x') { return isInsideX; } - if (direction === 'y') { + if (options?.direction === 'y') { return isInsideY; }