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

React中Chart.js设置intersect:false时自定义Tooltip交互异常

React + Chart.js 自定义Tooltip交互异常修复

问题根因

该异常和基础交互配置无关,核心是几个问题叠加导致:

  • 自定义Tooltip是浮在canvas上层的DOM元素,默认会拦截所有鼠标事件,导致Chart.js无法接收到canvas上的鼠标移动信号,直接将tooltip opacity置为0。原生Tooltip是canvas内部绘制的图形,不存在DOM遮挡问题,所以交互正常。
  • 交互模式mode: 'nearest'和axis: 'x'的组合逻辑不符合「同X轴位置触发Tooltip」的需求,会导致取激活点的逻辑不稳定。
  • 垂直虚线插件依赖tooltip._active私有数组取坐标,鲁棒性差,当激活点匹配异常时就无法正常绘制。
  • React组件内Tooltip渲染存在变量引用错误,直接使用未定义的visible/top/left等变量,会导致渲染异常。

修复步骤

1. 给自定义Tooltip添加事件穿透属性

这是最核心的修复,给Tooltip对应的CSS类添加pointer-events: none,让鼠标事件直接穿透Tooltip层落到canvas上,从根源解决DOM遮挡事件的问题:

.tooltip {
  /* 保留原有定位、样式配置 */
  pointer-events: none;
}

2. 调整交互配置匹配X轴对齐逻辑

将交互模式改为index,适配「鼠标在任意X轴位置都触发对应列Tooltip」的需求,移除不必要的配置项:

interaction: {
  intersect: false,
  mode: 'index',
  axis: 'x',
},

3. 重写垂直虚线插件逻辑

不再依赖_active私有属性取坐标,直接从tooltip实例上获取对齐的X坐标,从Y轴顶部画到底部,逻辑更稳定:

export const plugins = [{
  beforeDatasetsDraw: chart => {
    const { tooltip, ctx, scales } = chart;
    if (tooltip.opacity === 0) return;

    // 直接取Tooltip对齐的X坐标,无需从激活点中提取
    const x = tooltip.caretX;
    const topY = scales.y.top;
    const bottomY = scales.y.bottom;

    ctx.save();
    ctx.beginPath();
    ctx.moveTo(x, topY);
    ctx.lineTo(x, bottomY);
    ctx.lineWidth = 1;
    ctx.strokeStyle = '#718086';
    ctx.setLineDash([4, 2]);
    ctx.stroke();
    ctx.restore();
  },
}];

4. 修复React组件的渲染逻辑

补全容器定位配置,修正状态变量的引用方式,避免渲染报错:

const NotificationStatisticsChart = ({ statistics }) => {
  const [tooltipData, setTooltipData] = useState({
    top: 0,
    left: 0,
    label: '',
    data: null,
    visible: false,
  });
  const data = useMemo(() => createDataObjectForChart(statistics), [statistics]);
  const options = useMemo(() => createOptions(statistics, setTooltipData), [statistics]);

  return (
    {/* 外层容器必须加相对定位,作为Tooltip绝对定位的父级参照 */}
    <div className={styles.chart} style={{ position: 'relative' }}>
      <Line options={options} data={data} plugins={plugins} />
      {tooltipData.visible ? (
        <div 
          className={styles.tooltip} 
          style={{ 
            position: 'absolute',
            top: tooltipData.top, 
            left: tooltipData.left 
          }}
        >
         <div className={styles.date}>{tooltipData.label}</div>
         {tooltipData.data?.map(item => (
            <div key={item.type} className={styles.amount}>
              <span>{item.total}</span>
              <span className={styles.count}>{item.delta}</span>
              <span>{item.type}</span>
            </div>
         ))}
        </div>
       ) : null}
    </div>
  );
};

完成以上修改后,鼠标在图表任意位置悬停都能正常触发Tooltip和垂直虚线,不会再出现折线上方区域无响应的问题。


内容的提问来源于stack exchange,提问作者Roman Telyatnik

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:09:13