求助:修复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
相关产品推荐
相关产品推荐

