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

求助:修复D3.js v4中第二个图表tooltip位置偏移问题

解决D3.js v4中第二个图表Tooltip位置偏移的问题

我一眼就看出问题出在Tooltip的定位逻辑上——你现在用的d3.event.pageX和d3.event.pageY是基于整个文档页面的坐标,第一个图表在页面顶部,所以位置看起来正常,但第二个图表本身已经处于页面下方,直接用这两个值的话,Tooltip就会“跟着”页面级的Y坐标跑,自然就跑到页面底部去了。

解决方案:基于图表容器计算Tooltip位置

我们需要获取鼠标相对于当前图表容器的局部坐标,再结合容器在页面中的偏移量来定位Tooltip,这样不管图表在页面哪个位置,Tooltip都能准确显示在鼠标附近。

这里提供两种可行的修改方式:

方式1:利用getBoundingClientRect()计算

修改柱状图的mousemove事件处理函数:

.on("mousemove", function(n) {
  // 获取当前柱状图元素相对于视口的位置
  const rect = this.getBoundingClientRect();
  // 计算鼠标相对于当前元素的偏移(加上微调值让Tooltip不挡住鼠标)
  const tooltipX = rect.left + window.scrollX + d3.event.clientX - rect.left + 10;
  const tooltipY = rect.top + window.scrollY + d3.event.clientY - rect.top - 20;
  
  tooltip
    .style("opacity", 1)
    .style("left", tooltipX + "px")
    .style("top", tooltipY + "px")
    .style("display", "inline-block")
    .html("<span>Hola</span>")
})

方式2:使用d3.mouse()获取局部坐标

d3.mouse(this)可以直接返回鼠标相对于当前元素的[x,y]坐标,再结合容器的页面偏移量:

.on("mousemove", function(n) {
  // 获取鼠标相对于当前柱状图的局部坐标
  const [mouseX, mouseY] = d3.mouse(this);
  // 获取图表容器的页面位置
  const containerRect = d3.select(container).node().getBoundingClientRect();
  
  tooltip
    .style("opacity", 1)
    .style("left", (containerRect.left + window.scrollX + mouseX + 10) + "px")
    .style("top", (containerRect.top + window.scrollY + mouseY - 20) + "px")
    .style("display", "inline-block")
    .html("<span>Hola</span>")
})

修改后的完整JS代码

(function() {
  var mrg = { t:10, r:20, b:30, l:20 };
  var data = [
    { id: 1, amount: 6 },
    { id: 2, amount: 5 },
    { id: 3, amount: 2 },
    { id: 4, amount: 8 }
  ];

  function loadChart(container) {
    var width = 400 - mrg.l - mrg.r;
    var height = 300 - mrg.t - mrg.b;
    var color = d3.scaleOrdinal(d3.schemeCategory10);

    var tooltip = d3.select(container).append("div")
      .attr("class", "tooltipx")
      .style("opacity", 0);

    var x = d3.scaleBand().range([0, width]).padding(0.1);
    var y = d3.scaleLinear().range([height, 0]);

    x.domain([1, 2, 3, 4]);
    y.domain([0, 10]);

    var svg = d3.select(container).append("svg")
      .attr("width", width + mrg.l + mrg.r)
      .attr("height", height + mrg.t + mrg.b)
      .append("g")
      .attr("transform", "translate(" + mrg.l + "," + mrg.t + ")");

    svg.selectAll(".bar")
      .data(data)
      .enter()
      .append("rect")
      .attr("class", "bar")
      .attr("x", function(n) { return x(n.id); })
      .attr("y", function(n) { return y(n.amount); })
      .attr("width", x.bandwidth())
      .attr("height", function(n) { return height - y(n.amount); })
      .attr("fill", function(n, i) { return color(i); })
      .on("mousemove", function(n) {
        const rect = this.getBoundingClientRect();
        const tooltipX = rect.left + window.scrollX + d3.event.clientX - rect.left + 10;
        const tooltipY = rect.top + window.scrollY + d3.event.clientY - rect.top - 20;
        
        tooltip
          .style("opacity", 1)
          .style("left", tooltipX + "px")
          .style("top", tooltipY + "px")
          .style("display", "inline-block")
          .html("<span>Hola</span>")
      })
      .on("mouseout", function(n) {
        tooltip.style("opacity", 0);
      });

    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    svg.append("g").call(d3.axisLeft(y));
  }

  function init() {
    loadChart("#chart1");
    loadChart("#chart2");
  }

  init();
}());

这样修改后,两个图表的Tooltip都会准确显示在对应的柱状图上方啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:14:12