From 439b825ed30e10166b8431375e5468d71dc4eb6c Mon Sep 17 00:00:00 2001 From: Ian O'Connor <10924707+ianoc90@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:11:18 +0100 Subject: [PATCH] fix: fixes #1876 for stack bar tooltips --- .../series/private/BaseBarStack.tsx | 19 ++++++++++++++--- .../src/utils/findNearestStackDatum.ts | 13 ++++++++++-- .../test/utils/findNearestDatum.test.ts | 21 ++++++++++++++++--- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/packages/visx-xychart/src/components/series/private/BaseBarStack.tsx b/packages/visx-xychart/src/components/series/private/BaseBarStack.tsx index db159bc90..03215e062 100644 --- a/packages/visx-xychart/src/components/series/private/BaseBarStack.tsx +++ b/packages/visx-xychart/src/components/series/private/BaseBarStack.tsx @@ -91,9 +91,22 @@ function BaseBarStack< ( params: NearestDatumArgs>, ): NearestDatumReturnType => { - const childData = seriesChildren.find((child) => child.props.dataKey === params.dataKey) - ?.props?.data; - return childData ? findNearestStackDatum(params, childData, horizontal) : null; + const childSeries = seriesChildren.find((child) => child.props.dataKey === params.dataKey); + const childData = childSeries?.props?.data; + + const nearestDatum = childData + ? findNearestStackDatum( + params, + childData, + { + xAccessor: childSeries?.props?.xAccessor, + yAccessor: childSeries?.props?.yAccessor, + }, + horizontal, + ) + : null; + + return nearestDatum; }, [seriesChildren, horizontal], ); diff --git a/packages/visx-xychart/src/utils/findNearestStackDatum.ts b/packages/visx-xychart/src/utils/findNearestStackDatum.ts index cee2640fe..700f5586f 100644 --- a/packages/visx-xychart/src/utils/findNearestStackDatum.ts +++ b/packages/visx-xychart/src/utils/findNearestStackDatum.ts @@ -1,5 +1,6 @@ import { AxisScale } from '@visx/axis'; import { getFirstItem, getSecondItem } from '@visx/shape/lib/util/accessors'; +import { ScaleInput } from '@visx/scale'; import findNearestDatumY from './findNearestDatumY'; import findNearestDatumX from './findNearestDatumX'; import { BarStackDatum, NearestDatumArgs } from '../types'; @@ -17,11 +18,19 @@ export default function findNearestStackDatum< >( nearestDatumArgs: NearestDatumArgs>, seriesData: Datum[], + childAccessors: { + xAccessor: (d: Datum) => ScaleInput; + yAccessor: (d: Datum) => ScaleInput; + }, horizontal?: boolean, ) { const { xScale, yScale, point } = nearestDatumArgs; - const datum = (horizontal ? findNearestDatumY : findNearestDatumX)(nearestDatumArgs); - const seriesDatum = datum?.index == null ? null : seriesData[datum.index]; + const datum = (horizontal ? findNearestDatumY : findNearestDatumX)(nearestDatumArgs); // <-- might be something wrong with the datum.index here + const stack = datum?.datum.data.stack; + const seriesDatum = seriesData.find((d) => { + const { yAccessor, xAccessor } = childAccessors; + return (horizontal ? yAccessor : xAccessor)(d) === stack; + }); return datum && seriesDatum && point ? { diff --git a/packages/visx-xychart/test/utils/findNearestDatum.test.ts b/packages/visx-xychart/test/utils/findNearestDatum.test.ts index 029f1c452..d1b544d5d 100644 --- a/packages/visx-xychart/test/utils/findNearestDatum.test.ts +++ b/packages/visx-xychart/test/utils/findNearestDatum.test.ts @@ -1,6 +1,7 @@ import { AxisScale } from '@visx/axis'; import { scaleBand, scaleLinear } from '@visx/scale'; import { PositionScale } from '@visx/shape/lib/types'; +import { Point } from '@visx/point'; import findNearestDatumX from '../../src/utils/findNearestDatumX'; import findNearestDatumY from '../../src/utils/findNearestDatumY'; @@ -121,18 +122,32 @@ describe('findNearestStackDatum', () => { }); it('should find the nearest datum', () => { - const d1 = { yVal: '🍌' }; - const d2 = { yVal: '🚀' }; + const d1 = { xVal: 0, yVal: '0' }; + const d2 = { xVal: 8, yVal: '8' }; + + const stackData = [ + { xy: [0, 0], item: { '0': 0, stack: '0' } }, + { xy: [1, 1], item: { '8': 8, stack: '8' } }, + ].map(({ xy, item }) => { + const dataItem = [...xy]; + // @ts-ignore + dataItem.data = item; + return dataItem; + }); + expect( findNearestStackDatum( { ...params, + data: stackData, + point: new Point({ x: 0, y: 0 }), // type is not technically correct, but coerce for test } as unknown as NearestDatumArgs>, [d1, d2], + { xAccessor: ({ xVal }) => xVal, yAccessor: ({ yVal }) => yVal }, true, )!.datum, - ).toEqual(d2); // nearest datum index=1 + ).toEqual(d1); // nearest datum index=0 }); });