Javascript 如何构造d3 v4 force布局中需要更新的嵌套节点?
我使用的是d3 v4,并希望执行此JSFIDLE中的嵌套选择(但在强制布局中,圆圈不是表格中的文本): 我不知道从哪里开始。我的数据如下[[“circle1”、“circle2”]、[“circle3”、“circle4”]、[“circle5”、“circle6”]、[“circle7”、“circle8”]。我希望每个迷你阵列都有一个圆圈,然后在force布局中,在圆圈的正上方添加圆圈。数据正在更改,因此我需要小型阵列的大数据集和每个小型阵列的退出-进入合并周期。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布局中
// 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只是想知道这是否回答了您原来的问题?是的。我让它工作了。谢谢你的帮助。如果我自己无法解决这个问题,我会把它当作另一个问题来问,但我想我会选择你的大脑,以防它很容易解决。因此,大圆和小圆实际上必须在单独的组中,因为小圆总是需要位于每个大圆的顶部,所以去掉了当前的大圆,并将其作为独立于小圆的单独节点。这很有效,小圆总是在大圆的顶部,除非小圆与大圆的左上象限重叠