I'd like to add different child elements to my nodes depending on the node type. Therefore the node has an attribute called type
. All nodes should consist of a g
element with the dependent child elements.
I tried this by using D3s filter
functionality but i'm stuck as my code doesn't add the child elements only once per node, but adds the wanted child elements multiple times (the same amount as i have nodes). So i guess i'm doing something wrong with the selection.
The nodes and links of my graph change over time, so what i did is to store the selection first and when a node gets added to self.nodes
i call the draw function (I'll leave out the link code).
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()
}
What works is, that it does differentiate between person
and contribution
and adds the elements i want specifically for this type, but it doesn't add only one per g
node, but it adds a multiple of those (the number of nodes i have) into every g
node. If i keep calling the draw function it will append more and more circles to my g elements.
<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>
What am i doing wrong here? I only want the circle
and other elements only append once per node.
<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>
Any help is appreciated.
After reading selection.data on the d3 wiki again, i finally got it working.
I merged my notes beforehand, so my selection included the enter and update nodes. What i did now was first to create the enter nodes, then do the selections and filters on them and merge them afterwards.
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()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With