Chart.js点击数据点保持tooltip常开且支持多tooltip同时显示的适配问题
实现思路
- 为Chart实例自定义
persistentActivePoints数组,专门存储需要保持显示tooltip的数据点信息(包含数据集索引、数据点索引) - 通过插件的
afterEvent钩子监听图表点击事件:点击命中数据点时,检查该点是否已在持久化数组中,存在则移除(取消固定)、不存在则加入(固定tooltip),操作完成后触发图表重绘 - 通过插件的
afterDraw钩子,遍历持久化数组中的每一个数据点,基于全局tooltip配置生成对应Tooltip实例并渲染,保证固定的tooltip和默认hover tooltip样式完全一致 - 可选扩展:支持点击图表空白区域清空所有已固定的tooltip,可根据业务需求调整逻辑
适配Chart.js v3/v4版本的插件代码
const PersistentTooltipPlugin = { id: 'persistentTooltip', beforeInit: (chart) => { // 初始化持久化存储数组 chart.persistentActivePoints = []; }, afterEvent: (chart, args) => { const event = args.event; // 只处理点击事件 if (event.type !== 'click') return; // 获取点击位置命中的所有数据点 const points = chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true); if (points.length) { const targetPoint = points[0]; // 检查该点是否已经被固定 const existIndex = chart.persistentActivePoints.findIndex(p => p.datasetIndex === targetPoint.datasetIndex && p.index === targetPoint.index ); if (existIndex > -1) { // 已存在则移除(取消固定) chart.persistentActivePoints.splice(existIndex, 1); } else { // 不存在则加入(固定tooltip) chart.persistentActivePoints.push({ datasetIndex: targetPoint.datasetIndex, index: targetPoint.index }); } } else { // 点击空白区域,清空所有固定tooltip,不需要可注释这段 chart.persistentActivePoints = []; } // 触发重绘 chart.draw(); }, afterDraw: (chart) => { if (!chart.persistentActivePoints.length) return; // 继承全局tooltip配置 const tooltipOptions = chart.options.plugins.tooltip; if (!tooltipOptions.enabled) return; chart.persistentActivePoints.forEach(pointInfo => { // 构建tooltip需要的激活项 const active = [chart.getDatasetMeta(pointInfo.datasetIndex).data[pointInfo.index]]; // 生成tooltip实例 const tooltip = new Chart.Tooltip({ chart: chart, options: tooltipOptions }); // 更新并绘制tooltip const position = active[0].getProps(['x', 'y']); tooltip.setActiveElements(active, position); tooltip.update(); tooltip.draw(chart.ctx); }); } }; // 全局注册插件,也可以仅给单个图表注册 Chart.register(PersistentTooltipPlugin);
使用示例
const ctx = document.getElementById('myChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: ['1月', '2月', '3月', '4月', '5月', '6月'], datasets: [{ label: '销量A', data: [12, 19, 3, 5, 2, 3], borderColor: 'rgb(255, 99, 132)', tension: 0.1 }, { label: '销量B', data: [7, 11, 5, 8, 3, 7], borderColor: 'rgb(54, 162, 235)', tension: 0.1 }] }, options: { plugins: { // 正常配置tooltip样式即可,固定的tooltip会继承该配置 tooltip: { backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 10, boxPadding: 5 } } } });
注意事项
- 如果需要保留hover时的普通tooltip,无需额外配置,两者会同时存在
- 如果不需要点击空白清空所有固定tooltip,直接删除
afterEvent中点击无数据点时的清空逻辑即可 - 插件兼容Chart.js v3、v4全系列版本,无需额外依赖
内容的提问来源于stack exchange,提问作者Simen Stubsjøen
相关产品推荐
相关产品推荐

