Skip to content

Commit 3945c7b

Browse files
committed
Make chart point links clickable
1 parent a8c8082 commit 3945c7b

5 files changed

Lines changed: 51 additions & 13 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## unreleased
44

5-
- Chart data points can now include a `link`, which is shown as a clickable link in the point's tooltip.
5+
- **Beta:** Chart data points can now include a `link`. The link is shown in an interactive tooltip, and clicking the data point itself also follows it. Interactive tooltips depend on [upstream ApexCharts support](https://github.com/apexcharts/apexcharts.js/issues/4469).
66

77
## v0.46.2
88

‎examples/official-site/sqlpage/migrations/01_documentation.sql‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S
688688
('label', 'An alias for parameter "x". On a row that draws a reference line, the text to display next to the line.', 'TEXT', FALSE, TRUE),
689689
('value', 'An alias for parameter "y"', 'REAL', FALSE, TRUE),
690690
('series', 'If multiple series are represented and share the same y-axis, this parameter can be used to distinguish between them.', 'TEXT', FALSE, TRUE),
691-
('link', 'Adds a clickable link to this point in its tooltip.', 'URL', FALSE, TRUE),
691+
('link', 'Beta: makes this data point clickable and adds the same link to its tooltip. Interactive tooltips depend on ApexCharts issue #4469.', 'URL', FALSE, TRUE),
692692
('yline', 'Draws a reference line across the chart at this value of the y axis instead of plotting a point, to show a limit such as a quota or an alarm threshold. Not drawn if it falls outside of the axis, so set ymax when the limit is above the data.', 'REAL', FALSE, TRUE),
693693
('yline_end', 'Makes the yline a band instead of a line, reaching to this value.', 'REAL', FALSE, TRUE),
694694
('xline', 'Draws a reference line across the chart at this position of the x axis instead of plotting a point, to mark an event such as a deployment. A date or a timestamp when time is set, otherwise one of the x values.', 'TEXT', FALSE, TRUE),
@@ -790,7 +790,7 @@ The `color` property sets the color of each series separately, in order.
790790
{ "series": "PostgreSQL", "x": "2010", "y": 65},{ "series": "SQLite", "x": "2010", "y": 62},{ "series": "MySQL", "x": "2010", "y": 83},
791791
{ "series": "PostgreSQL", "x": "2020", "y": 73},{ "series": "SQLite", "x": "2020", "y": 38},{ "series": "MySQL", "x": "2020", "y": 87}
792792
]')),
793-
('chart', 'A timeline displaying events with a start and an end date. A data row can include a `link` to make it available as a clickable action in the tooltip.',
793+
('chart', 'A timeline displaying events with a start and an end date. A data row can include a beta `link` to make both the bar and its tooltip clickable; see [ApexCharts issue #4469](https://github.com/apexcharts/apexcharts.js/issues/4469).',
794794
json('[
795795
{"component":"chart", "title": "Project Timeline", "type": "rangeBar", "time": true, "color": ["teal", "cyan"], "labels": true, "xmin": "2021-12-28", "xmax": "2022-01-04" },
796796
{"series": "Phase 1", "label": "Operations", "value": ["2021-12-29", "2022-01-02"], "link": "/examples/chart.sql?phase=1"},

‎sqlpage/apexcharts.js‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ sqlpage_chart = (() => {
258258
chart_type === "rangeBar" || (chart_type === "bar" && !!data.horizontal);
259259
const value_axis = inverted ? "x" : "y";
260260
const category_axis = inverted ? "y" : "x";
261+
const has_point_links = points.some((point) => point[5]);
261262
const options = {
262263
annotations: {
263264
[`${value_axis}axis`]: reference_lines(
@@ -289,6 +290,12 @@ sqlpage_chart = (() => {
289290
zoom: {
290291
enabled: false,
291292
},
293+
events: {
294+
dataPointSelection: (_event, _chart, args) => {
295+
const link = pointLink(args, points);
296+
if (link) window.location.assign(link);
297+
},
298+
},
292299
},
293300
theme: {
294301
mode: isDarkTheme ? "dark" : "light",
@@ -361,7 +368,7 @@ sqlpage_chart = (() => {
361368
},
362369
tooltip: {
363370
fillSeriesColor: false,
364-
custom: points.some((point) => point[5])
371+
custom: has_point_links
365372
? (args) => chartTooltip(args, points)
366373
: chart_type === "bubble" || chart_type === "scatter"
367374
? bubbleTooltip
@@ -413,7 +420,7 @@ sqlpage_chart = (() => {
413420
const point = has_series_data
414421
? series.data[dataPointIndex]
415422
: { y: raw_point?.[2], z: raw_point?.[4] };
416-
const link = has_series_data ? point?.link : raw_point?.[5];
423+
const link = pointLink({ seriesIndex, dataPointIndex, w }, raw_points);
417424

418425
const tooltip = document.createElement("div");
419426
tooltip.className = "apexcharts-tooltip-text";
@@ -452,6 +459,13 @@ sqlpage_chart = (() => {
452459
return tooltip.outerHTML;
453460
}
454461

462+
function pointLink({ seriesIndex, dataPointIndex, w }, raw_points) {
463+
const series = w.config.series[seriesIndex];
464+
return Array.isArray(series?.data)
465+
? series.data[dataPointIndex]?.link
466+
: raw_points[seriesIndex]?.[5];
467+
}
468+
455469
function bubbleTooltip(args) {
456470
return chartTooltip(args, []);
457471
}

‎sqlpage/sqlpage.css‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,28 @@ code {
6464
color: inherit;
6565
}
6666

67-
.apexcharts-tooltip:has(a) {
67+
.apexcharts-tooltip.apexcharts-active:has(a) {
68+
isolation: isolate;
6869
pointer-events: auto;
6970
}
7071

72+
.apexcharts-tooltip.apexcharts-active:has(a)::before {
73+
content: "";
74+
position: absolute;
75+
inset: -12px;
76+
z-index: -1;
77+
}
78+
7179
.apexcharts-tooltip a {
7280
color: currentColor;
7381
text-decoration: underline;
7482
}
7583

84+
.apexcharts-canvas:has(.apexcharts-tooltip.apexcharts-active a)
85+
.apexcharts-svg {
86+
cursor: pointer;
87+
}
88+
7689
/** table **/
7790
.table-freeze-headers thead {
7891
position: sticky;

‎tests/end-to-end/fixtures/chart/test.ts‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,14 @@ test("shows an interactive data point link in a rangeBar tooltip", async ({
385385
"pointer-events",
386386
"auto",
387387
);
388+
await expect(
389+
page.locator("#test-chart .apexcharts-rangebar-area").first(),
390+
).toHaveCSS("cursor", "pointer");
391+
await page.locator("#test-chart .apexcharts-rangebar-area").nth(1).hover();
392+
await expect(
393+
page.locator("#test-chart .apexcharts-rangebar-area").nth(1),
394+
).not.toHaveCSS("cursor", "pointer");
395+
await page.locator("#test-chart .apexcharts-rangebar-area").first().hover();
388396
const colors = await link.evaluate((anchor) => {
389397
const tooltip = anchor.closest(".apexcharts-tooltip");
390398
if (!tooltip) throw new Error("Link has no tooltip");
@@ -394,13 +402,16 @@ test("shows an interactive data point link in a rangeBar tooltip", async ({
394402
};
395403
});
396404
expect(colors.link).toBe(colors.tooltip);
397-
await link.hover();
398-
await expect(link).toBeVisible();
399-
await page.locator("#test-chart .apexcharts-rangebar-area").nth(1).hover();
400-
await expect(page.locator("#test-chart .apexcharts-tooltip a")).toHaveCount(
401-
0,
402-
);
403-
await page.locator("#test-chart .apexcharts-rangebar-area").first().hover();
405+
for (let attempt = 0; attempt < 10; attempt++) {
406+
await link.hover();
407+
await expect(link).toBeVisible();
408+
await page.locator("#test-chart .apexcharts-rangebar-area").nth(1).hover();
409+
await expect(page.locator("#test-chart .apexcharts-tooltip a")).toHaveCount(
410+
0,
411+
);
412+
await page.locator("#test-chart .apexcharts-rangebar-area").first().hover();
413+
await expect(link).toBeVisible();
414+
}
404415
await link.click();
405416
await expect(page).toHaveURL(/workpackage_edit/);
406417
});

0 commit comments

Comments
 (0)