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

D3v3气泡图升级至D3v4:力导向与加载动画修复需求

搞定D3v3到D3v4气泡图的力导向修复+点击涟漪效果

嘿,我帮你梳理下怎么把v3的气泡图升级到v4,同时解决力导向失效的问题,还要加上点击的涟漪效果。D3v4把力布局完全重写了,API变化特别大,这就是为啥原来的力导向不好使的原因,咱们一步步来:

一、先把力导向布局给救回来

D3v3的d3.layout.force()在v4里变成了d3.forceSimulation(),而且力的配置方式完全不一样了,咱们替换一下:

  1. 初始化力模拟
    把原来v3的force初始化换成v4的simulation,还要把节点数据传进去,同时添加必要的力(电荷力、中心力、碰撞力,气泡图必须加碰撞力防止重叠):

    // 保存原始电荷强度,后面点击效果要用
    const originalCharge = -50;
    // 创建力模拟
    const simulation = d3.forceSimulation(nodes)
      .force("charge", d3.forceManyBody().strength(originalCharge)) // 电荷力,控制节点间的吸引/排斥
      .force("center", d3.forceCenter(width/2, height/2)) // 让节点保持在画布中心
      .force("collide", d3.forceCollide(d => d.radius * scale + 5)); // 碰撞力,防止气泡重叠
    
  2. 监听tick事件更新节点位置
    v3的force会自动更新节点位置,但v4需要你手动在tick事件里更新circle的cx和cy:

    simulation.on("tick", () => {
      nodes.attr("cx", d => d.x)
           .attr("cy", d => d.y);
    });
    
  3. 替换拖拽功能
    v3的.call(force.drag())在v4里换成d3.drag(),还要写三个拖拽事件函数来控制simulation的状态:

    function dragstarted(event, d) {
      if (!event.active) simulation.alphaTarget(0.3).restart();
      d.fx = d.x;
      d.fy = d.y;
    }
    
    function dragged(event, d) {
      d.fx = event.x;
      d.fy = event.y;
    }
    
    function dragended(event, d) {
      if (!event.active) simulation.alphaTarget(0);
      d.fx = null;
      d.fy = null;
    }
    

    然后在enter的circle上绑定拖拽:

    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    

二、保留初始加载的缩放动画

原来的enter/update/exit逻辑在v4里基本能用,稍微调整一下,确保动画和力模拟不冲突:

// Enter
const nodesEnter = nodes.enter()
  .append("circle")
  .attr("class", "node")
  .attr("cx", d => d.x)
  .attr("cy", d => d.y)
  .attr("r", 10) // 初始小尺寸
  .style("fill", (d,i) => color(i))
  .call(d3.drag() // 绑定拖拽
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended))
  .on("click", handleBubbleClick); // 绑定点击事件,后面讲

// Update
nodesEnter.merge(nodes)
  .transition()
  .delay(300)
  .duration(1000)
  .attr("r", d => d.radius * scale);

// Exit
nodes.exit()
  .transition()
  .duration(250)
  .attr("r", 1)
  .remove();

三、添加点击气泡的涟漪式互斥/吸引效果

咱们实现点击某个气泡时,临时修改电荷力的强度,让所有节点产生涟漪式的排斥,然后再恢复原状:

  1. 定义点击事件处理函数
    function handleBubbleClick() {
      // 临时把电荷改成强排斥(正数是排斥,负数是吸引)
      simulation.force("charge").strength(100);
      // 重启simulation,让新的力生效
      simulation.alpha(0.3).restart();
      // 1秒后恢复原始电荷强度
      setTimeout(() => {
        simulation.force("charge").strength(originalCharge);
        simulation.alpha(0.3).restart();
      }, 1000);
    }
    
    你可以调整100和1000这两个数值,来控制排斥强度和恢复时间,要是想要吸引效果,就把100改成负数比如-200。

最后整合起来的关键点

  • D3v4的力模拟是声明式的,需要手动添加各种力,并且通过tick事件更新节点位置
  • 拖拽功能需要手动控制simulation的alpha(模拟的活跃度),不然拖拽后节点不会回到自然状态
  • 点击效果通过动态修改电荷力的强度,结合重启simulation来触发涟漪效果

内容的提问来源于stack exchange,提问作者The Old County

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 20:48:11