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

为何d3.forceSimulation模拟结果不总是对称?

无摩擦油面漂浮磁铁模拟的对称疑问

我正在做一个无摩擦油面上漂浮磁铁的模拟:磁铁的作用力与其半径相关,会自由移动直至达到受力平衡状态。我原本认为这种平衡状态下,磁铁应该始终呈现对称排列,但用D3实现后,结果并不总是对称的——即使拖拽元素,它们也不会总是回到同一位置。

想确认:是我的对称理论本身错误?元素本就不该固定回到同一位置?还是力的构建逻辑存在问题?

模拟预期示意图

实现代码

JavaScript

// Source: https://bl.ocks.org/HarryStevens/f636199a46fc4b210fbca3b1dc4ef372

var radius = 160;
var positives = [27, 50, 20, 20];
var negatives = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10];

/* Änderungen der Konfiguration nur oberhalb dieser Zeile */

var width = 400,
  height = 400;

var myNodes = [];

for (let i = 0; i < positives.length; i++) {
  myNodes.push({
    charge: -positives[i]
  });
}

for (let i = 0; i < negatives.length; i++) {
  myNodes.push({
    charge: negatives[i]
  });
}

var nodePadding = 10;

var svg = d3.select("svg").attr("width", width).attr("height", height);

var simulation = d3
  .forceSimulation()
  .nodes(myNodes)
  .force(
    "forceX",
    d3
      .forceX()
      .strength(0.1)
      .x(width * 0.5)
  )
  .force(
    "forceY",
    d3
      .forceY()
      .strength(0.1)
      .y(height * 0.5)
  )
  .force(
    "center",
    d3
      .forceCenter()
      .x(width * 0.5)
      .y(height * 0.5)
  )
  .force(
    "charge",
    d3.forceManyBody().strength(function (d) {
      return -d.charge * 10;
    })
  )
  .force(
    "radial",
    d3.forceRadial(
      function (d) {
        return d.charge > 0 ? radius : 0;
      },
      width / 2,
      height / 2
    )
  )
  .force(
    "collide",
    d3.forceCollide().radius(function (d) {
      return Math.abs(d.charge) + nodePadding;
    })
  )
  .on("tick", function (d) {
    node
      .attr("cx", function (d) {
        return d.x;
      })
      .attr("cy", function (d) {
        return d.y;
      });
  });

svg
  .append("circle")
  .classed("radius", true)
  .attr("cx", width / 2)
  .attr("cy", height / 2)
  .attr("r", radius)
  .style("fill", "none")
  .style("stroke", "#bbb")
  .style("stroke-dasharray", 4);

var node = svg
  .selectAll(".node")
  .data(myNodes)
  .join("circle")
  .classed("node", true)
  .attr("r", function (d) {
    return Math.abs(d.charge);
  })
  .attr("fill", function (d) {
    return d.charge > 0 ? "#0000ff" : "#ff0000";
  })
  .attr("cx", function (d) {
    return d.x;
  })
  .attr("cy", function (d) {
    return d.y;
  });

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

distance = ([x1, y1], [x2, y2]) =>
  Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2));

function dragstarted(event, d) {
  if (!event.active) simulation.alphaTarget(0.03).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.03);
  d.fx = null;
  d.fy = null;
}

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div id="content">
  <svg width="400" height="400">
  </svg>
</div>

内容的提问来源于stack exchange,提问作者Vale

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:05:15