Skip to content

Commit 3321456

Browse files
authored
fix: tooltip closest data for line series (#77)
1 parent 7194de6 commit 3321456

File tree

2 files changed

+51
-18
lines changed

2 files changed

+51
-18
lines changed

src/__tests__/line-series.visual.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,26 @@ test.describe('Line series', () => {
5050
const component = await mount(<ChartTestStory data={lineTwoYAxisData} />);
5151
await expect(component.locator('svg')).toHaveScreenshot();
5252
});
53+
54+
// TODO: take a screenshot and unskip the test
55+
test.skip('Vertical line tooltip', async ({mount}) => {
56+
const data = {
57+
series: {
58+
data: [
59+
{
60+
type: 'line',
61+
name: 'Line series',
62+
data: [
63+
{x: 10, y: 10},
64+
{x: 10, y: 50},
65+
],
66+
},
67+
],
68+
},
69+
} as ChartData;
70+
71+
const component = await mount(<ChartTestStory data={data} />);
72+
component.hover();
73+
await expect(component.locator('svg')).toHaveScreenshot();
74+
});
5375
});

src/utils/chart/get-closest-data.ts

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,47 @@ export type ShapePoint = {
4141
series: ChartSeries;
4242
};
4343

44-
function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) {
45-
const sorted = sort(points, (p) => p.x);
46-
const closestXIndex = bisector<ShapePoint, number>((p) => p.x).center(sorted, x);
47-
if (closestXIndex === -1) {
48-
return [];
49-
}
50-
51-
const closestX = sorted[closestXIndex].x;
52-
const closestPoints = sort(
53-
points.filter((p) => p.x === closestX),
54-
(p) => p.y0,
55-
);
56-
44+
function getClosestYIndex(items: ShapePoint[], y: number) {
5745
let closestYIndex = -1;
58-
if (y < closestPoints[0]?.y0) {
46+
if (y < items[0]?.y0) {
5947
closestYIndex = 0;
60-
} else if (y > closestPoints[closestPoints.length - 1]?.y1) {
61-
closestYIndex = closestPoints.length - 1;
48+
} else if (y > items[items.length - 1]?.y1) {
49+
closestYIndex = items.length - 1;
6250
} else {
63-
closestYIndex = closestPoints.findIndex((p) => y > p.y0 && y < p.y1);
51+
closestYIndex = items.findIndex((p) => y > p.y0 && y < p.y1);
6452
if (closestYIndex === -1) {
6553
const sortedY = sort(
66-
closestPoints.map((p, index) => ({index, y: p.y1 + (p.y0 - p.y1) / 2})),
54+
items.map((p, index) => ({index, y: p.y1 + (p.y0 - p.y1) / 2})),
6755
(p) => p.y,
6856
);
6957
const sortedYIndex = bisector<{y: number}, number>((p) => p.y).center(sortedY, y);
7058
closestYIndex = sortedY[sortedYIndex]?.index ?? -1;
7159
}
7260
}
7361

62+
return closestYIndex;
63+
}
64+
65+
function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) {
66+
const sorted = sort(points, (p) => p.x);
67+
const closestXIndex = bisector<ShapePoint, number>((p) => p.x).center(sorted, x);
68+
if (closestXIndex === -1) {
69+
return [];
70+
}
71+
72+
const closestX = sorted[closestXIndex].x;
73+
const filtered = points.filter((p) => p.x === closestX);
74+
75+
const groupedBySeries = Object.values(groupBy(filtered, (p) => get(p.series, 'id'))).map(
76+
(items) => {
77+
const sortedByY = sort(items, (p) => p.y0);
78+
const index = getClosestYIndex(sortedByY, y);
79+
return sortedByY[index === -1 ? 0 : index];
80+
},
81+
);
82+
83+
const closestPoints = sort(groupedBySeries, (p) => p.y0);
84+
const closestYIndex = getClosestYIndex(closestPoints, y);
7485
return closestPoints.map((p, i) => ({
7586
data: p.data,
7687
series: p.series,

0 commit comments

Comments
 (0)