D3.js嵌套数据折线图鼠标悬停功能实现求助
问题根源
你的<path>元素绑定的是groupclusters中的分组对象(结构为{key: ..., values: [数据点数组]}),而非单个数据点,所以直接访问d.mtbname必然取不到值,导致tooltip显示undefined。
解决方案
下面提供两种可行的实现方式:
方案一:给数据点添加可交互圆点(简单直观)
在绘制折线后,为每个分组的单个数据点添加小圆点,直接绑定单条数据实现悬停:
// 初始化tooltip(如果还没做的话) var tooltip1 = d3.select("body").append("div") .style("position", "absolute") .style("opacity", 0) .style("background", "#fff") .style("border", "1px solid #ccc") .style("padding", "8px") .style("border-radius", "4px"); // 绘制折线(保留你原有代码) svg.append("path") .attr("fill", "none") .attr("stroke", '#a65628') .attr("stroke-width", 1) .attr("class", "line") .attr("d", function(d){ return d3.line() .x(function(d) { return x(d.mtbname); }) .y(function(d) { return y(+d.clustcenters); })(d.values); }); // 为每个数据点添加可悬停圆点 svg.selectAll(".dot") .data(function(d) { return d.values; }) // 绑定单个数据点 .enter() .append("circle") .attr("class", "dot") .attr("cx", function(d) { return x(d.mtbname); }) .attr("cy", function(d) { return y(+d.clustcenters); }) .attr("r", 3) .style("fill", "#a65628") .on('mouseover', function(d){ tooltip1.transition().duration(10) .style("opacity", 0.8) .style("left", `${d3.event.pageX + 20}px`) .style("top", `${d3.event.pageY - 35}px`); tooltip1.html(`<p>名称:${d.mtbname}</p><p>数值:${d.clustcenters}</p>`); }) .on('mouseout', function(){ tooltip1.transition().duration(100).style("opacity", 0); });
可以给圆点加CSS过渡效果优化体验:
.dot { transition: r 0.2s; } .dot:hover { r: 5; }
方案二:直接在折线上实现悬停(无圆点)
通过D3的bisector工具,根据鼠标位置计算对应的数据点:
// 初始化tooltip(如果还没做的话) var tooltip1 = d3.select("body").append("div") .style("position", "absolute") .style("opacity", 0) .style("background", "#fff") .style("border", "1px solid #ccc") .style("padding", "8px") .style("border-radius", "4px"); // 定义bisector,用于匹配x轴数据 var bisectIndex = d3.bisector(function(d) { return mtbsnameslist.indexOf(d.mtbname); }).left; // 绘制折线并绑定悬停事件 svg.append("path") .attr("fill", "none") .attr("stroke", '#a65628') .attr("stroke-width", 1) .attr("class", "line") .attr("d", function(d){ return d3.line() .x(function(d) { return x(d.mtbname); }) .y(function(d) { return y(+d.clustcenters); })(d.values); }) .on('mouseover', function(d) { // 获取鼠标在SVG内的x坐标 var mouseX = d3.mouse(this)[0]; // 转换为对应的x轴索引 var targetIndex = bisectIndex(mtbsnameslist, x.invert(mouseX)); // 找到对应的数据点 var targetPoint = d.values.find(item => item.mtbname === mtbsnameslist[targetIndex]); if (targetPoint) { tooltip1.transition().duration(10) .style("opacity", 0.8) .style("left", `${d3.event.pageX + 20}px`) .style("top", `${d3.event.pageY - 35}px`); tooltip1.html(`<p>名称:${targetPoint.mtbname}</p><p>数值:${targetPoint.clustcenters}</p>`); } }) .on('mouseout', function(){ tooltip1.transition().duration(100).style("opacity", 0); });
内容的提问来源于stack exchange,提问作者ktzan
相关产品推荐
相关产品推荐

