You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 00:45:03