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

D3.js如何结合过渡动画与鼠标事件?柱状图Tooltip失效求助

D3.js柱状图Tooltip失效问题修复

问题描述

我尝试创建一个支持数据切换的柱状图,并添加鼠标悬停Tooltip功能,但Tooltip无法正常工作。原因是鼠标事件绑定前调用了过渡动画,导致事件绑定失效。即使拆分调用,要么功能仍失效,要么破坏了合并过渡效果。当前代码如下:

let u = this.svg.selectAll("rect")
        .data(data);

    u.enter()
        .append("rect") // Add a new rect for each new elements
        .merge(u)
        .transition() // and apply changes to all of them
        .duration(1000)
        .attr("x", (d: any) => { return this.x(d.date); })
        .attr("y", (d: any) => { return this.y(d.value); })
        .attr("width", this.x.bandwidth())
        .attr("height", (d: any) => { return this.height - this.y(d.value); })
        u.on('mouseover', (event: any, d: any) => {
            d3.select('#tooltip').transition().duration(200).style('opacity', 1);
            d3.select('#tooltip').html(`Dividend: <span>${d.value}</span>`)
                .style('left', `${event.x}px`)
                .style('opacity', `1`)
                .style('top', `${(event.y - 28)}px`);
          }).on('mousemove', (event: any, d: any) =>
            d3.select('#tooltip')
            .style('left', `${event.x}px`)
            .style('top', `${(event.y - 28)}px`
          )).on('mouseout', () => d3.select('#tooltip').transition().duration(200).style('opacity', 0));

修复方案

问题核心是你将鼠标事件绑定到了过渡对象上,而非DOM元素本身。D3的transition()方法会返回临时的过渡对象,而非原DOM选择器,因此后续的on()并没有把事件绑定到矩形元素上。正确做法是拆分事件绑定与过渡动画的链式调用:

  1. 先对合并后的DOM元素绑定鼠标事件
  2. 再单独对这些元素执行过渡动画

修改后的代码:

let u = this.svg.selectAll("rect")
        .data(data);

// 处理新元素并合并选择器
const bars = u.enter()
        .append("rect")
        .merge(u);

// 先绑定鼠标事件到DOM元素
bars.on('mouseover', (event: any, d: any) => {
    d3.select('#tooltip').transition().duration(200).style('opacity', 1);
    d3.select('#tooltip').html(`Dividend: <span>${d.value}</span>`)
        .style('left', `${event.x}px`)
        .style('top', `${event.y - 28}px`);
}).on('mousemove', (event: any, d: any) => {
    d3.select('#tooltip')
        .style('left', `${event.x}px`)
        .style('top', `${event.y - 28}px`);
}).on('mouseout', () => {
    d3.select('#tooltip').transition().duration(200).style('opacity', 0);
});

// 再执行过渡动画
bars.transition()
    .duration(1000)
    .attr("x", (d: any) => this.x(d.date))
    .attr("y", (d: any) => this.y(d.value))
    .attr("width", this.x.bandwidth())
    .attr("height", (d: any) => this.height - this.y(d.value));

关键改动说明

  • 将merge(u)的结果保存为变量bars,直接对这个DOM选择器绑定事件,确保事件附着在真实的矩形元素上
  • 把过渡动画与事件绑定拆分为两个独立的链式调用,避免过渡对象干扰事件绑定
  • 保持了原有的合并逻辑,新元素和旧元素都会绑定事件并执行过渡动画

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 21:57:32