Javascript 如何构造d3 v4 force布局中需要更新的嵌套节点?

Javascript 如何构造d3 v4 force布局中需要更新的嵌套节点?,javascript,d3.js,Javascript,D3.js,我使用的是d3 v4,并希望执行此JSFIDLE中的嵌套选择(但在强制布局中,圆圈不是表格中的文本): 我不知道从哪里开始。我的数据如下[[“circle1”、“circle2”]、[“circle3”、“circle4”]、[“circle5”、“circle6”]、[“circle7”、“circle8”]。我希望每个迷你阵列都有一个圆圈,然后在force布局中,在圆圈的正上方添加圆圈。数据正在更改,因此我需要小型阵列的大数据集和每个小型阵列的退出-进入合并周期。d3 v4 force布局中

我使用的是d3 v4,并希望执行此JSFIDLE中的嵌套选择(但在强制布局中,圆圈不是表格中的文本):

我不知道从哪里开始。我的数据如下[[“circle1”、“circle2”]、[“circle3”、“circle4”]、[“circle5”、“circle6”]、[“circle7”、“circle8”]。我希望每个迷你阵列都有一个圆圈,然后在force布局中,在圆圈的正上方添加圆圈。数据正在更改,因此我需要小型阵列的大数据集和每个小型阵列的退出-进入合并周期。d3 v4 force布局中是否有嵌套选择的示例?我应该从哪里开始呢

这是我目前拥有的,但是这根本没有附加小的红色圆圈,而且更新似乎不起作用

// Create circle nodes
this.circleNode = this.d3Graph.selectAll("circle")

// Call our restartD3 function
this.restartD3();


// Function that restarts D3 and replace nodes with new this.users array (needed in when  add or remove a node)
restartD3() {

  // Circles
this.circleNode = this.circleNode.data(this.users);

 this.circleNode.exit().remove();

//maybe append a group here not circles
  this.rowenter = this.circleNode
  .enter()
    .append("circle")
    .attr("class", "circlenodes")
    .attr("r", 50)
    .attr("fill", "green")



  this.cell = this.circleNode.merge(this.rowenter)
  .selectAll(".circlenodes").data(function(d){
    return d.m;});

     this.cell.exit().remove();

    this.cell.enter().append("circle")
    .attr("class", "smallnodes")
    .attr("r", function(d){
      return 10
  })
  .attr("fill", "red")


  this.force.nodes(this.users);


}

更新:使用正确的嵌套联接的更好解决方案

因此,这让我思考得更多-我并不特别喜欢这种方法,
innerRender
必须进行大量连接,而不是一个大连接。感觉可以改进。因此,
selection.data
函数也可以使用我以前没有实现过的函数。(如果你还没有看到这一页,建议阅读)

所以我修改了我的示例-这是渲染函数。我还添加了一些过渡,以便在视觉上更容易看到发生了什么

render = (data) => {
const join = d3
    .select(".container")
    .selectAll("g")
    .data(data);

// Remove old groups
join
    .exit()
    .transition()
    .duration(500)
    .attr("transform", "scale(0)")
    .remove();

// Create the new groups
const groups = join
    .enter()
    .append("g");

// Add in the new circles
groups.append("circle")
    .attr("r", 0)
    .style("fill", "steelblue")
    .transition()
    .duration(500)
    .attr("r", RADIUS);

// Merge the new groups with the existing groups
// and apply an appropriate translation
const innerJoin = groups
    .merge(join)
    .attr("transform", d => `translate(${d.x},${d.y})`)
    .selectAll("circle.inner")
    .data(d => d);

// Remove old small circles
innerJoin
    .exit()
    .transition()
    .duration(500)
    .attr("r", 0);

 const newCircles = innerJoin
     .enter()
     .append("circle")
     .attr("class", "inner")
     .attr("r", 0)
     .style("fill", "orange")
     .attr("cy", -RADIUS - 5);

 newCircles
    .transition()
    .duration(500)
    .attr("r", 5);

 newCircles.merge(join)
     .attr("cx", (d, i) => 2 * i * 5);
}
请参阅完整示例


我建议将其分解为单独的函数。从外部零件的常规
d3.forceSimulation
开始-处理外部阵列上的连接和施加的力。下面是一个如何进行渲染的示例

render = (data) => {
    const join = d3
        .select(".container")
        .selectAll("g")
        .data(data);

    // Remove old
    join.exit().remove();

    // Create the new groups
    const groups = join.enter().append("g");
    groups.append("circle")
        .attr("r", RADIUS)
        .style("fill", "steelblue");

    // Merge the new groups with the existing groups
    // and apply an appropriate translation
    groups.merge(join)
        .attr("transform", d => `translate(${d.x},${d.y})`)
        .each(function(d) {
            renderInner(this, d);
        });
}
注意对
renderiner
的调用吗?这就是我要处理嵌套的地方,保持它的简单,所以实际上你们只是把它当作另一个渲染

renderInner = (element, data) => {
    const join = d3
        .select(element)
        .selectAll("circle.inner")
        .data(data);

     join.exit().remove();
     join.enter()
         .append("circle")
         .attr("r", 5)
         .style("fill", "orange")
         .attr("cy", -RADIUS - 5)
         .merge(join)
         .attr("cx", (d, i) => 2 * i * 5);
};
这里有一个例子,我放在一起充分说明。如果您愿意,可以很容易地映射出要输入
forceSimulation
上的
节点
函数的
内部
项,以便它们也在力中发挥作用


下面是一个完全有效的示例:

这里有两个问题:如何为嵌套数据设置输入/退出/更新选择,以及如何使用它创建强制布局。这对我来说太宽泛了(可能对许多其他人来说也是如此)。我建议你保留问题的第一部分,去掉力的部分(也因为你没有说节点应该如何链接)。这种结构非常有效。非常感谢。然而,我有一个问题:超过20个大小圆圈的性能很差。在我的模拟中,这些圆不断地移动,添加的圆越多,它就变得越不稳定。我假设这是因为渲染每秒被调用60次onTic。我想知道有什么办法可以改进吗?也许只有在添加或减去一个节点时才调用整个渲染函数,并且有一个基本的定位函数,可以将圆移动60 fps。事实上,你所建议的正是我应该怎么做的-我只是尝试在时间短时演示连接。在每个
上粘贴一个类,并在一个勾号函数中选择它们,只需更新它们的转换即可。@PurplePanda所以我更新了这个答案-我不太高兴,遇到了一个重要的发现。我还在最新的示例代码中修改了那个勾号。@PurplePanda只是想知道这是否回答了您原来的问题?是的。我让它工作了。谢谢你的帮助。如果我自己无法解决这个问题,我会把它当作另一个问题来问,但我想我会选择你的大脑,以防它很容易解决。因此,大圆和小圆实际上必须在单独的组中,因为小圆总是需要位于每个大圆的顶部,所以去掉了当前的大圆,并将其作为独立于小圆的单独节点。这很有效,小圆总是在大圆的顶部,除非小圆与大圆的左上象限重叠