Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I am loading json from database and creating a json file which loads fine. Now I don't know which steps to take for making the nodes responsive in a Force-Directed Graph. I need to remove and add new nodes and their links.

force.nodes(json.nodes)
    .links(json.links)
    .start();

initNodes(json);

How can I make this more dynamic or update it without resetting the whole visualization?

I have seen this question a couple of times not being answered so I hope someone can post and give a guide.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
279 views
Welcome To Ask or Share your Answers For Others

1 Answer

Adding nodes/links to my D3 force graph was very confusing until I better understood the way I was adding the initial set of nodes.

Assuming a <g> is what you'd like to use for your nodes:

// Select the element where you'd like to create the force layout
var el = d3.select("#svg");

// This should not select anything
el.selectAll("g")

// Because it's being compared to the data in force.nodes() 
    .data(force.nodes())

// Calling `.enter()` below returns the difference in nodes between 
// the current selection and force.nodes(). At this point, there are
// no nodes in the selection, so `.enter()` should return 
// all of the nodes in force.nodes()
    .enter()

// Create the nodes
    .append("g")
    .attr("id", d.name)
    .classed("manipulateYourNewNode", true);

Now let's make that function that will add a node to the layout once the graph has been initialized!

newNodeData is an object with the data you'd like to use for your new node. connectToMe is a string containing the unique id of a node you'd like to connect your new node to.

function createNode (newNodeData, connectToMe) {
    force.nodes().push(newNodeData);
    el.selectAll("g")
       .data(force.nodes(), function(datum, index) { return index })

The function given as the optional second argument in .data() is run once for each node in the selection and again for each node in force.nodes(), matching them up based on the returned value. If no function is supplied, a fallback function is invoked, which returns the index (as above).

However, there's most likely going to be a dispute between the index of your new selection (I believe the order is random) and the order in force.nodes(). Instead you'll most likely need the function to return a property that is unique to each node.

This time, .enter() will only return the node you're trying to add as newData because no key was found for it by the second argument of .data().

       .enter()
       .insert("g", "#svg")
       .attr("id", d.name)
       .classed("manipulatYourNewNode", true);

    createLink(connectToMe, newNodeData.name);

    force.start();
}

The function createLink (defined below) creates a link between your new node and your node of choice.

Additionally, the d3js API states that force.start() should be called after updating the layout.

Note: Calling force.stop() at the very beginning of my function was a huge help for me when I was first trying to figure out how to add nodes and links to my graph.

function createLink (from, to) {
    var source = d3.select( "g#" + from ).datum(),
        target = d3.select( "g#" + to ).datum(),
        newLink = {
            source: source,
            target: target,
            value: 1
        };
    force.links().push(newLink);

The code below works under the assumptions that:

  1. #links is the wrapper element that contains all of your link elements
  2. Your links are represented as <line> elements:

    d3.select("#links")
        .selectAll("line")
        .data(force.links())
        .enter()
        .append("line");
    

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...