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

如何处理重复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:35:33