I’ve been struggling with this issue for days now and cannot find a solution to update the nodes properly.
Since I’m using threejs to render the graph I couldn’t find enough info on the web on how to properly achieve this.
On initial render everything works as expected. The problem is when I add new nodes with the update
function.
Newly added nodes are disconnected from their parents and the created links seem to lack coordinates and forces.
In the example below I am adding a new node with id: test
.
This is what I’ve tried so far:
let root = d3
.stratify()
.id((d) => d.id)
.parentId((d) => d.linkedTo)(data)
let nodes = root.descendants()
let links = root.links()
simulation = d3
.forceSimulation(nodes)
.force('charge', d3.forceManyBody().strength(-1000))
.force('center', d3.forceCenter(0, 0))
.force('collide', d3.forceCollide().radius(50).strength(0.9))
.on('tick', ticked)
simulation.force(
'link',
d3
.forceLink(links)
.id((d) => {
return d.data._id
})
.distance(10)
.strength(0.9)
)
// Render nodes and links three scene
links.forEach(renderLink)
nodes.forEach(renderNode)
function update(newData, oldData) {
simulation.stop()
const newRoot = d3
.stratify()
.id((d) => d.id)
.parentId((d) => d.linkedTo)(newData)
const newNodes = newRoot.descendants()
const newLinks = newRoot.links()
// Find nodes to remove and remove them
const nodesToRemove = nodes.filter((node) => !newNodes.some((newNode) => newNode.id === node.id))
// remove nodes from the three scene
removeNodes(nodesToRemove)
// Find links to remove and remove them
const linksToRemove = links.filter(
(link) =>
!newLinks.some(
(newLink) => newLink.source.id === link.source.id && newLink.target.id === link.target.id
)
)
// remove links from the three scene
removeLinks(linksToRemove)
// Find new nodes
const nodesToAdd = newNodes.filter((newNode) => !nodes.some((node) => node.id === newNode.id))
nodes = [...nodes, ...nodesToAdd]
// Find links to add and add them
const linksToAdd = newLinks.filter(
(newLink) =>
!links.some((link) => {
const sourceMathces = link.source.id === newLink.source.id
const targetMathces = link.target.id === newLink.target.id
return sourceMathces && targetMathces
})
)
links = [...links, ...linksToAdd]
simulation.nodes(nodes).force('link').links(links)
simulation.alpha(0.5).restart()
}
Thank you!