如何处理重复SVG?实现mouseover/mouseout添加移除子SVG并恢复初始状态
问题描述
使用D3.js进行SVG绘图,初始状态下所有圆点为绿色。当鼠标悬停在任意圆点上时,希望将具有相同netName的圆点高亮显示为红色,但操作后无法恢复到全绿色状态,也无法再次高亮其他分组。当前代码如下:
// Parent svg svg.append('g') .selectAll("dot") .data(storage) .join("circle") .attr("cx", function (d) { return x(d.x); }) .attr("cy", function (d) { return y(d.y); }) .attr("r", .5) .style("fill", "green") .on("mouseover", function (e, d) { d3.select(this).transition() .duration(200) div.style("left", (e.pageX) + "px") .style("top", (e.pageY - 28) + "px"); console.log(e, d); div.transition() .duration(500) .style("opacity", 0); div.transition() .duration(200) .style("opacity", .9); div.html( 'X, Y: ' + d.x + ", "+ d.y + "<br>Pin: " + d.pinName + "<br>Net: " + d.netName); s_data = storage.filter(a => a.netName ===d.netName); // Child svg svg.append('g') .selectAll("dot") .data(s_data) .join("circle") .attr("cx", function (d) { return x(d.x); }) .attr("cy", function (d) { return y(d.y); }) .attr("r", .5) .style("fill", "red") }) .on('mouseout', function(d,i){ d3.select(this).transition() .duration('200') .style('fill', 'green'); })
问题核心:每次mouseover都会新增<g>元素绘制红色圆点,但mouseout时未移除该分组,导致红色圆点残留,无法回到全绿色初始状态。需要实现子SVG的添加与移除,解决重复SVG的问题。
解决方案
优化思路
- 复用高亮分组:提前创建一个专门用于高亮的
<g>元素,避免每次鼠标悬停都新增容器。 - 动态更新高亮内容:鼠标悬停时更新该分组的圆点数据,设置为红色;鼠标移出时清空该分组内的所有元素。
修改后的代码
// 提前创建专门用于高亮的g元素,添加唯一类名方便选择 const highlightGroup = svg.append('g').attr('class', 'highlight-group'); // Parent svg svg.append('g') .selectAll("circle") .data(storage) .join("circle") .attr("cx", d => x(d.x)) .attr("cy", d => y(d.y)) .attr("r", .5) .style("fill", "green") .on("mouseover", function (e, d) { // 保留tooltip逻辑 div.style("left", `${e.pageX}px`) .style("top", `${e.pageY - 28}px`); div.transition() .duration(500) .style("opacity", 0) .transition() .duration(200) .style("opacity", .9); div.html(` X, Y: ${d.x}, ${d.y} <br>Pin: ${d.pinName} <br>Net: ${d.netName} `); // 筛选同netName的数据 const s_data = storage.filter(a => a.netName === d.netName); // 更新高亮分组的圆点:清空旧数据,加入新数据并设为红色 highlightGroup.selectAll("circle") .data(s_data) .join("circle") .attr("cx", d => x(d.x)) .attr("cy", d => y(d.y)) .attr("r", .5) .style("fill", "red"); }) .on('mouseout', function() { // 移除高亮分组内的所有圆点,恢复初始状态 highlightGroup.selectAll("circle").remove(); });
关键改进点
- 单一高亮容器:仅创建一次
highlight-group,彻底避免重复添加<g>元素。 - 精准状态恢复:鼠标移出时直接清空高亮容器内的所有圆点,确保界面回到全绿色初始状态。
- 简化代码逻辑:合并tooltip的过渡链式调用,让代码更简洁易维护。
内容的提问来源于stack exchange,提问作者Sourav B M
相关产品推荐
相关产品推荐

