Skip to content

Commit edbe1a9

Browse files
committed
fix: update tooltip tests continuing the fix for #3439
1 parent eaaa752 commit edbe1a9

2 files changed

Lines changed: 92 additions & 38 deletions

File tree

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
/**
2-
* Line chart with `tooltip.shared: true` — clicking a marker should
3-
* report the series the user clicked, not always series 0.
2+
* Line chart with `tooltip.shared: true` — click events must report the
3+
* series the user actually clicked, not always series 0.
44
*
5-
* Background: a previous fix for #3439 (zoomed-bar shared tooltip)
6-
* skipped Y in closestInMultiArray whenever allSeriesHasEqualX was true.
7-
* That made every line-chart series tie at distance 0, so series 0
8-
* always won → markerClick always reported series 0 regardless of which
9-
* line the user clicked. The fix narrows the Y-skip to bar charts only;
10-
* line/area charts now use full Euclidean distance to identify the
11-
* actually-hovered series.
5+
* Two distinct bugs converge here:
6+
* 1. The fix for #3439 (zoomed-bar shared tooltip) made
7+
* closestInMultiArray skip Y whenever allSeriesHasEqualX was true.
8+
* That tied every line series at distance X = 0, so series 0 always
9+
* won. The Y-skip is now narrowed to bar charts only.
10+
* 2. Even before #3439, closestInMultiArray measured distance to each
11+
* series's *markers* rather than its *line segments*. Clicks landing
12+
* between two markers picked whichever series's marker was closest
13+
* to that empty space — often the wrong line. For line/area charts
14+
* we now project the cursor onto each segment, which makes clicks
15+
* on the line itself report the line under the cursor.
1216
*
13-
* Uses real `page.mouse.click` because synthetic dispatchEvent on a
14-
* marker would bypass the foreignObject overlay and silently mask the
15-
* bug. Marker click coordinates are taken from the marker's bounding
16-
* rect, so the click lands exactly on the series's marker.
17+
* Real `page.mouse.click` is used throughout — synthetic dispatchEvent
18+
* on a marker bypasses the foreignObject hover overlay and would
19+
* silently mask the bug.
1720
*/
1821

1922
import { test, expect } from '../fixtures/base.js'
2023

21-
test('Shared tooltip — markerClick reports the clicked series', async ({
22-
page,
23-
loadChart,
24-
}) => {
24+
async function loadDemo(page, loadChart) {
2525
await loadChart('line', 'shared-tooltip-click')
2626
await page.evaluate(() => {
2727
window.__events = []
@@ -42,23 +42,75 @@ test('Shared tooltip — markerClick reports the clicked series', async ({
4242
() => window.chart.w.globals.animationEnded === true,
4343
{ timeout: 5_000 },
4444
)
45+
}
4546

46-
// Use point 4 (May): 49, 70, 33, 55, 57 — values are spread enough that
47-
// each series's marker is unambiguously hit by clicking its own center.
48-
for (let s = 0; s < 5; s++) {
49-
const { x, y } = await page.evaluate((si) => {
50-
const m = document.querySelector(
51-
`.apexcharts-marker[index="${si}"][rel="4"]`,
52-
)
53-
const r = m.getBoundingClientRect()
54-
return { x: r.left + r.width / 2, y: r.top + r.height / 2 }
55-
}, s)
56-
await page.evaluate(() => (window.__events = []))
57-
await page.mouse.click(x, y)
58-
await page.waitForTimeout(80)
59-
const events = await page.evaluate(() => window.__events)
60-
expect(events[0], `no markerClick fired for series ${s}`).toBeTruthy()
61-
expect(events[0].seriesIndex).toBe(s)
62-
expect(events[0].dataPointIndex).toBe(4)
63-
}
47+
async function clickAt(page, x, y) {
48+
await page.evaluate(() => (window.__events = []))
49+
await page.mouse.click(x, y)
50+
await page.waitForTimeout(80)
51+
return page.evaluate(() => window.__events)
52+
}
53+
54+
test.describe('Shared tooltip — click reports correct series', () => {
55+
test('clicking each series marker reports that series index', async ({
56+
page,
57+
loadChart,
58+
}) => {
59+
await loadDemo(page, loadChart)
60+
61+
// Point 4 (May): 49, 70, 33, 55, 57 — values are spread enough that
62+
// each series's marker is unambiguously hit by clicking its own center.
63+
for (let s = 0; s < 5; s++) {
64+
const { x, y } = await page.evaluate((si) => {
65+
const m = document.querySelector(
66+
`.apexcharts-marker[index="${si}"][rel="4"]`,
67+
)
68+
const r = m.getBoundingClientRect()
69+
return { x: r.left + r.width / 2, y: r.top + r.height / 2 }
70+
}, s)
71+
const events = await clickAt(page, x, y)
72+
expect(events[0], `no markerClick fired for series ${s}`).toBeTruthy()
73+
expect(events[0].seriesIndex).toBe(s)
74+
expect(events[0].dataPointIndex).toBe(4)
75+
}
76+
})
77+
78+
test('clicking on a line between markers reports the clicked line', async ({
79+
page,
80+
loadChart,
81+
}) => {
82+
await loadDemo(page, loadChart)
83+
// Hide markers so the click coordinates fall on the line itself —
84+
// mirrors the original user report where clicks landed on the colored
85+
// line segment, not on a data point.
86+
await page.evaluate(() =>
87+
window.chart.updateOptions({ markers: { size: 0 } }),
88+
)
89+
await page.waitForFunction(
90+
() => window.chart.w.globals.animationEnded === true,
91+
{ timeout: 5_000 },
92+
)
93+
94+
// Click midway between data points 3 and 4 of each series. Series 3
95+
// is the historically tricky one: its midpoint sits very close to
96+
// series 0's marker, so a marker-distance algorithm would
97+
// misidentify it as series 0.
98+
for (let s = 0; s < 5; s++) {
99+
const pos = await page.evaluate((si) => {
100+
const gl = window.chart.w.globals
101+
const svg = document.querySelector('.apexcharts-svg')
102+
const rect = svg.getBoundingClientRect()
103+
const x =
104+
gl.translateX +
105+
(gl.seriesXvalues[si][3] + gl.seriesXvalues[si][4]) / 2
106+
const y =
107+
gl.translateY +
108+
(gl.seriesYvalues[si][3] + gl.seriesYvalues[si][4]) / 2
109+
return { x: rect.left + x, y: rect.top + y }
110+
}, s)
111+
const events = await clickAt(page, pos.x, pos.y)
112+
expect(events[0], `no markerClick fired for line ${s}`).toBeTruthy()
113+
expect(events[0].seriesIndex).toBe(s)
114+
}
115+
})
64116
})

tests/unit/tooltip.spec.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,16 +277,18 @@ describe('Tooltip.Utils', () => {
277277
w.globals.allSeriesHasEqualX = false
278278
const utils = new TooltipUtils(ttCtx)
279279

280+
// Two near-horizontal segments at y ≈ 105 (series 0) and y ≈ 155
281+
// (series 1). Hover at (32, 155) lies almost on series 1's segment
282+
// and far above series 0's.
280283
const Xarrays = [
281284
[10, 50],
282285
[30, 70],
283286
]
284287
const Yarrays = [
285-
[100, 200],
286-
[150, 250],
288+
[100, 110],
289+
[150, 160],
287290
]
288291

289-
// hoverX=32, hoverY=155 → closest to series 1, point 0 (30, 150)
290292
const result = utils.closestInMultiArray(32, 155, Xarrays, Yarrays)
291293
expect(result.index).toBe(1)
292294
expect(result.j).toBe(0)

0 commit comments

Comments
 (0)