Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/__tests__/line-series.visual.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,26 @@ test.describe('Line series', () => {
const component = await mount(<ChartTestStory data={lineTwoYAxisData} />);
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(<ChartTestStory data={data} />);
component.hover();
await expect(component.locator('svg')).toHaveScreenshot();
});
});
47 changes: 29 additions & 18 deletions src/utils/chart/get-closest-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,36 +41,47 @@ export type ShapePoint = {
series: ChartSeries;
};

function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) {
const sorted = sort(points, (p) => p.x);
const closestXIndex = bisector<ShapePoint, number>((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);
closestYIndex = sortedY[sortedYIndex]?.index ?? -1;
}
}

return closestYIndex;
}

function getClosestPointsByXValue(x: number, y: number, points: ShapePoint[]) {
const sorted = sort(points, (p) => p.x);
const closestXIndex = bisector<ShapePoint, number>((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,
Expand Down
Loading