使用 d3js 将子元素添加到力导向图中的特定节点
Adding child elements to specific nodes in a force-directed graph using d3js
我想根据节点类型向我的节点添加不同的子元素。因此该节点有一个名为 type
的属性。所有节点都应包含一个 g
元素和依赖的子元素。
我通过使用 D3s filter
功能尝试了这个,但是我被卡住了,因为我的代码不是每个节点只添加一次子元素,而是多次添加想要的子元素(与我有节点)。所以我想我在选择方面做错了。
我的图表的节点和 links 随着时间的推移而变化,所以我所做的是首先存储选择,当一个节点被添加到 self.nodes
我调用绘图函数(我将省略 link 代码)。
self.domNodes = this.svg.append('g').attr('class', 'nodes').selectAll('.node')
function draw() {
self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
self.domNodes.exit().remove()
// all nodes
self.domNodes.enter()
.append('g')
.attr('class', (node) => `node ${node.type}`)
.merge(self.domNodes)
// contributions
self.domNodes.filter((d) => d.type === 'contribution')
.append('circle')
.attr('r', 4)
.attr('fill', 'blue')
// persons
self.domNodes.filter((d) => d.type === 'person')
.append('other elements and attributes...')
self.simulation.nodes(self.nodes)
self.simulation.force('link').links(self.links)
self.simulation.alpha(1).restart()
}
有效的是,它确实区分了 person
和 contribution
并添加了我专门为此类型想要的元素,但它不只为每个 g
添加一个元素节点,但它会将这些(我拥有的节点数)的倍数添加到每个 g
节点中。如果我继续调用 draw 函数,它将在我的 g 元素上附加越来越多的圆圈。
<svg>
<g>
<g class="nodes">
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
<someotherthings></someotherthings>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
<someotherthings></someotherthings>
</g>
</g>
</g>
</svg>
我在这里做错了什么?我只希望 circle
和其他元素每个节点只附加一次。
<svg>
<g>
<g class="nodes">
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
</g>
</g>
</g>
</svg>
感谢任何帮助。
在 d3 wiki 上再次阅读 selection.data 后,我终于让它工作了。
我事先合并了我的笔记,所以我的选择包括输入和更新节点。我现在所做的是首先创建输入节点,然后对它们进行选择和过滤,然后再合并它们。
function draw() {
self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
self.domNodes.exit().remove()
// all nodes
const enterNodes = self.domNodes.enter()
.append('g')
.attr('class', (node) => `node ${node.type}`)
// contributions
enterNodes.filter((d) => d.type === 'contribution')
.append('circle')
.attr('r', 4)
.attr('fill', 'blue')
// persons
enterNodes.filter((d) => d.type === 'person')
.append('other elements and attributes...')
self.domNodes = self.domNodes.merge(enterNodes)
self.simulation.nodes(self.nodes)
self.simulation.force('link').links(self.links)
self.simulation.alpha(1).restart()
}
我想根据节点类型向我的节点添加不同的子元素。因此该节点有一个名为 type
的属性。所有节点都应包含一个 g
元素和依赖的子元素。
我通过使用 D3s filter
功能尝试了这个,但是我被卡住了,因为我的代码不是每个节点只添加一次子元素,而是多次添加想要的子元素(与我有节点)。所以我想我在选择方面做错了。
我的图表的节点和 links 随着时间的推移而变化,所以我所做的是首先存储选择,当一个节点被添加到 self.nodes
我调用绘图函数(我将省略 link 代码)。
self.domNodes = this.svg.append('g').attr('class', 'nodes').selectAll('.node')
function draw() {
self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
self.domNodes.exit().remove()
// all nodes
self.domNodes.enter()
.append('g')
.attr('class', (node) => `node ${node.type}`)
.merge(self.domNodes)
// contributions
self.domNodes.filter((d) => d.type === 'contribution')
.append('circle')
.attr('r', 4)
.attr('fill', 'blue')
// persons
self.domNodes.filter((d) => d.type === 'person')
.append('other elements and attributes...')
self.simulation.nodes(self.nodes)
self.simulation.force('link').links(self.links)
self.simulation.alpha(1).restart()
}
有效的是,它确实区分了 person
和 contribution
并添加了我专门为此类型想要的元素,但它不只为每个 g
添加一个元素节点,但它会将这些(我拥有的节点数)的倍数添加到每个 g
节点中。如果我继续调用 draw 函数,它将在我的 g 元素上附加越来越多的圆圈。
<svg>
<g>
<g class="nodes">
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
<circle r="4" fill="blue"></circle>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
<someotherthings></someotherthings>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
<someotherthings></someotherthings>
</g>
</g>
</g>
</svg>
我在这里做错了什么?我只希望 circle
和其他元素每个节点只附加一次。
<svg>
<g>
<g class="nodes">
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node contribution" transform="translate(466, 442)">
<circle r="4" fill="blue"></circle>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
</g>
<g class="node person" transform="translate(400, 200)">
<someotherthings></someotherthings>
</g>
</g>
</g>
</svg>
感谢任何帮助。
在 d3 wiki 上再次阅读 selection.data 后,我终于让它工作了。
我事先合并了我的笔记,所以我的选择包括输入和更新节点。我现在所做的是首先创建输入节点,然后对它们进行选择和过滤,然后再合并它们。
function draw() {
self.domNodes = self.domNodes.data(self.nodes, (node) => node.id)
self.domNodes.exit().remove()
// all nodes
const enterNodes = self.domNodes.enter()
.append('g')
.attr('class', (node) => `node ${node.type}`)
// contributions
enterNodes.filter((d) => d.type === 'contribution')
.append('circle')
.attr('r', 4)
.attr('fill', 'blue')
// persons
enterNodes.filter((d) => d.type === 'person')
.append('other elements and attributes...')
self.domNodes = self.domNodes.merge(enterNodes)
self.simulation.nodes(self.nodes)
self.simulation.force('link').links(self.links)
self.simulation.alpha(1).restart()
}