diff --git a/src/__tests__/line-series.visual.test.tsx b/src/__tests__/line-series.visual.test.tsx index 048bb7ac0..bc25de195 100644 --- a/src/__tests__/line-series.visual.test.tsx +++ b/src/__tests__/line-series.visual.test.tsx @@ -50,4 +50,26 @@ test.describe('Line series', () => { const component = await mount(); await expect(component.locator('svg')).toHaveScreenshot(); }); + + // TODO: take a screenshot and unskip the test + test.skip('Vertical line tooltip', async ({mount}) => { + const data = { + series: { + data: [ + { + type: 'line', + name: 'Line series', + data: [ + {x: 10, y: 10}, + {x: 10, y: 50}, + ], + }, + ], + }, + } as ChartData; + + const component = await mount(); + component.hover(); + await expect(component.locator('svg')).toHaveScreenshot(); + }); }); diff --git a/src/utils/chart/get-closest-data.ts b/src/utils/chart/get-closest-data.ts index 4df09504b..8cd6709a5 100644 --- a/src/utils/chart/get-closest-data.ts +++ b/src/utils/chart/get-closest-data.ts @@ -41,29 +41,17 @@ export type ShapePoint = { series: ChartSeries; }; -function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) { - const sorted = sort(points, (p) => p.x); - const closestXIndex = bisector((p) => p.x).center(sorted, x); - if (closestXIndex === -1) { - return []; - } - - const closestX = sorted[closestXIndex].x; - const closestPoints = sort( - points.filter((p) => p.x === closestX), - (p) => p.y0, - ); - +function getClosestYIndex(items: ShapePoint[], y: number) { let closestYIndex = -1; - if (y < closestPoints[0]?.y0) { + if (y < items[0]?.y0) { closestYIndex = 0; - } else if (y > closestPoints[closestPoints.length - 1]?.y1) { - closestYIndex = closestPoints.length - 1; + } else if (y > items[items.length - 1]?.y1) { + closestYIndex = items.length - 1; } else { - closestYIndex = closestPoints.findIndex((p) => y > p.y0 && y < p.y1); + closestYIndex = items.findIndex((p) => y > p.y0 && y < p.y1); if (closestYIndex === -1) { const sortedY = sort( - closestPoints.map((p, index) => ({index, y: p.y1 + (p.y0 - p.y1) / 2})), + items.map((p, index) => ({index, y: p.y1 + (p.y0 - p.y1) / 2})), (p) => p.y, ); const sortedYIndex = bisector<{y: number}, number>((p) => p.y).center(sortedY, y); @@ -71,6 +59,29 @@ function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) { } } + return closestYIndex; +} + +function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) { + const sorted = sort(points, (p) => p.x); + const closestXIndex = bisector((p) => p.x).center(sorted, x); + if (closestXIndex === -1) { + return []; + } + + const closestX = sorted[closestXIndex].x; + const filtered = points.filter((p) => p.x === closestX); + + const groupedBySeries = Object.values(groupBy(filtered, (p) => get(p.series, 'id'))).map( + (items) => { + const sortedByY = sort(items, (p) => p.y0); + const index = getClosestYIndex(sortedByY, y); + return sortedByY[index === -1 ? 0 : index]; + }, + ); + + const closestPoints = sort(groupedBySeries, (p) => p.y0); + const closestYIndex = getClosestYIndex(closestPoints, y); return closestPoints.map((p, i) => ({ data: p.data, series: p.series,