d3.js - d3 v4 强制作用于动态添加的节点

标签 d3.js

我正在尝试将节点一个一个地添加到 d3 力模拟(在版本 4 中!),但有些节点在创建后似乎并没有被模拟演化。


目前模拟分配一个节点,然后调用一个函数 addNode 两次添加两个节点。每一个都被添加到模拟中,呈现一个圆圈和一条线,并添加一个光标事件,一个接一个。

(从技术上讲,第一个和第二个节点是同时完成的,因为第一个节点仅在第二个调用 addNode 时设置)

然后,当单击一个节点时,应创建一个连接到光标下的节点的新节点。然后,该节点应该像任何其他节点一样在模拟的力量下进化。


但是,虽然一两个节点似乎创建得很好,但后来的节点似乎并没有在模拟下进化。特别是应该在节点之间保持一定空间的多体力似乎不起作用。


我的直觉是,对于模拟的 ticked 函数,节点是在不合时宜的时间添加的(早期的问题是通过添加一些 simulation.stop 和 simulation.restart 命令来解决的,只要新节点被添加)但理论上模拟每当添加新主体时都应暂停。

这是在 d3 v4 中动态添加节点的正确实现,还是力的问题只是突出了一个损坏的方法? This之前的回答帮助我意识到我需要合并新条目,但力似乎在那里工作正常。

var w = 250;
var h = 250;

var svg = d3.select("body").append("svg");

svg.attr('width', w)
  .attr('height', h);

// ensures links sit beneath nodes  
svg.append("g").attr("id", "lnks")
svg.append("g").attr("id", "nds")

function new_node(id) {
  this.id = id;
  this.x = w / 2;
  this.y = h / 2;
}

function new_link(source, target) {
  this.source = source;
  this.target = target;
}

var nodes = [];
var links = [];

var node;

var circles;

var link;

var simulation = d3.forceSimulation()
  .force("link", d3.forceLink().distance(80).id(function(d) {
    return d.id;
  }))
  .force("charge", d3.forceManyBody().strength(-1000))
  .force("xPos", d3.forceX(w / 2))
  .force("yPos", d3.forceY(h / 2))
  .on('tick', ticked);

simulation.stop();

var newNode = new new_node(0);
nodes.push(newNode);

for (var i = 1; i < 3; i++) {
  if (i == 3) continue;
  addNode(0, i)
}

function addNode(rootId, newId) {

  var newNode = new new_node(newId);
  nodes.push(newNode);
  var newLink = new new_link(rootId, newId);
  links.push(newLink);

  //adds newest link and draws it
  link = svg.select("#lnks").selectAll(".link")
    .data(links)
  var linkEnter = link
    .enter().append("line")
    .attr("class", "link");
  link = linkEnter.merge(link);

  //adds newest node  
  node = svg.select("#nds").selectAll(".node")
    .data(nodes)
  var nodeEnter = node
    .enter().append("g")
    .attr("class", "node");

  //draws circle on newest node  
  var circlesEnter = nodeEnter.append('circle')

  node = nodeEnter.merge(node);
  circles = d3.selectAll('circle');

  simulation.stop();

  simulation.nodes(nodes);

  simulation.force("link")
    .links(links);

  restartSim();
}

//starts up the simulation and sets up the way the leaves react to interaction
function restartSim() {
  simulation.restart();

  circles.on('click', function(d, i) {
    addNode(i, nodes.length)
  })
}

function ticked() {
  link
    .attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  node.attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });
}
.link {
  stroke: #bbb;
}
.node circle {
  pointer-events: all;
  fill: black;
  stroke-width: 0px;
  r: 20px
}
h1 {
  color: white;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

代码也在 codepen 上: http://codepen.io/zpenoyre/pen/kkxBRW?editors=0010

最佳答案

力模拟顾名思义就是对粒子相互作用的模拟。 Alpha 用于通过在每次迭代时衰减来帮助收敛系统。力乘以 alpha,因此在每次迭代中力都会变弱,直到 alpha 在模拟停止时达到非常低的值。来自 d3 文档:

simulation.restart() <>

Restarts the simulation’s internal timer and returns the simulation. In conjunction with simulation.alphaTarget or simulation.alpha, this method can be used to “reheat” the simulation during interaction, such as when dragging a node, or to resume the simulation after temporarily pausing it with simulation.stop.

当你添加一个节点时,模拟已经停止,所以,你需要用 alpha 1“重新加热”模拟。

  simulation.force("link")
    .links(links);

  simulation.alpha(1); // <---- reheat;

  restartSim();

这是更新后的代码笔: http://codepen.io/anon/pen/amqrWq?editors=0010

关于d3.js - d3 v4 强制作用于动态添加的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39843310/

相关文章:

javascript - 使用给定 ID 访问特定路径元素

javascript - d3.js svg 将符号保存到 Canvas 浏览器输出 <base href ="/">

javascript - 如何在 d3.js 中将单栏制作为 3d 效果?

javascript - 在 d3 中的树节点上调用运算符

javascript - 如何使用d3过渡使圆圈一个接一个出现?

javascript - 使用 D3 javascript 库,svg 上的圆圈无法正确补间

javascript - map 中浏览器的最大 svg 元素数

d3.js - D3 : How to create slow transition of circle radii for nodes in force directed graphs?

javascript - 定位由 d3.js 创建的 div

javascript - 如何使用 d3js 实现联合图