Reputation: 489
I'm working on a basic javascript D3 graph class that I could use to quickly start projects. Currently adding links and nodes works correctly but there's something I'm clearly not understanding with some underlying concepts.
Here's what I'm currently doing to remove a node.
this.nodesRef = this.svg.select(".nodes").selectAll(".node");
//...
removeNode (iNodeId)
{
let indexToRemove = this.nodesData.map(node => node.id).indexOf(iNodeId);
this.nodesData.splice(indexToRemove,1);
this.nodesRef.data(this.nodesData,d => d.id).exit().remove();
};
There is clearly something wrong with how I handle the nodesRef
selection and the nodesData
array. When removeNode()
occurs, it looks ok but the selections still contains the removed node, and when I'm adding another node later, the added node does not appear, a node is stuck, and some other issues..
I need to figure out how to properly update the selection and the data after the removal, but I'm honestly lost in the enter/exit/update lingo.
UPDATE:
I added the updateSimulation()
that was missing from the removeNode()
function, but there is still the issue that after the removal, the 6th node is unresponsive in itself but it is controlled by the 5th node.
removeNode (iNodeId)
{
// Remove from data
let indexToRemove = this.nodesData.map(node => node.id).indexOf(iNodeId);
this.nodesData.splice(indexToRemove,1);
this.nodesRef.data(this.nodesData,d => d.id).exit().remove();
this.updateSimulation();
};
updateSimulation ()
{
this.simulation.nodes(this.nodesData);
this.simulation.force("link").links(this.linksData);
this.simulation.alphaDecay(0.05).alpha(1).restart();
}
What I find strange is that after the exit().remove()
, the removed node is kept in the selection. I tried to update nodesRef
by doing something like
this.nodesRef = this.nodesRef.data(this.nodesData,d => d.id)
.enter()
./* defining nodes stuff*/
.merge(this.nodesRef);
but it brings me to the same result. I still think I'm not understanding correctly how to manage selections.
EDIT : removed ancient CodePen link
Upvotes: 2
Views: 227
Reputation: 489
I finally got it to work!
This page was really helpful to understand selections. Basically I did not understand in the first place that append() would return a new selection and not only adding stuff to the variable containing the previous selection.
This page brought to light the author's way of updating a graph. Using this pattern made a lot of things simpler. The general idea is to splice, pop, push, do stuff to the nodes and links data arrays and then to update the selection this way:
// Update the data, remove obsolete elements, add and merge new elements
nodesSelection = nodesSelection.data(nodesData, d => d.id);
nodesSelection.exit().remove();
nodesSelection = nodesSelection.enter()./* setup node shape*/.merge(nodesSelection);
// Repeat pattern for links
// ...
// Update simulation resources and "reheat" the graph
simulation.nodes(nodesData);
simulation.force("link",d3.forceLink(linksData).id( d => d.id));
simulation.alpha(1).restart();
There are still some things I need to figure out with the links update, Mike's example updates the simulation links just by doing simulation.force("link").links(links);
but that's not working out for me so far. Probably something with the link object properties.
But this is good enough for now, time to play : current Graph class here
Upvotes: 1