Ulises
Ulises

Reputation: 13419

How to add links dynamically to a D3 Tree

I'm trying to add links dynamically to a tree in order to create new relationships. My intent is to develop a flow diagram, more than a tree.

The code seems to work fine at first but then, after showing a bootstrap popover on one of the nodes, my new links disappear. I'm thinking that the tree is being "re-painted" and my makeshift links don't get included.

Here is how it looks "by default": enter image description here

Here is how it looks with my new links: enter image description here

After some looping I get the Ids of the nodes that should be connected, then I get a reference to those nodes and finally concat those pairs to the output of tree.links. Here is the code

//Create links
var newLinkPairs = getNodeReferencesForLinks(nodes, newLinksIds);
//Add new pair to the links based on the removed duplicates
var linkPairs = tree.links(nodes).concat(newLinkPairs);

var linkEnter = g.selectAll(".node-link")
.data(linkPairs)
.enter();

linkEnter
.insert("path", "g")
.attr("class", "node-link")
.attr("d", (function(d, i){return createConnector(nodeHeight, nodeWidth)})())
.attr("marker-end", "url(#source-target-marker)");

These are the auxiliary functions:

function createConnector(nodeHeight, nodeWidth) {
    return d3.svg.diagonal()
    .source(function(d) {
        return {
            y: d.source.y + nodeWidth,
            x: ((d.source.height - nodeHeight) /2) + d.source.x}; })
            .target(function(d) {
                return {
                    y: d.target.y,
                    x: ((d.target.height - nodeHeight) /2) + d.target.x}; })
                    .projection(function(d) { return [d.y, d.x]; });    
}

function getNodeReferencesForLinks(nodes, newLinksIds){
    var newLinkPairs =[];

    _.each(newLinksIds, function(p){
        var s = _.findWhere(nodes, {id: p.source});
        var t = _.findWhere(nodes, {id: p.target});

        newLinkPairs.push({source:s,target:t});
        // console.log(s.tasks.join(',') + ' -> ' + t.tasks.join(','));
    });

    return newLinkPairs;
}

Is there a better way to do this?

Upvotes: 0

Views: 1285

Answers (1)

Ulises
Ulises

Reputation: 13419

The code above actually works as it is supposed to. The links were disappearing because the function that created the graph was being called whenever the popover displayed.

The underlying problem here was mutation. The function that created the graph was modifying the original structure so consecutive calls failed to create the new links.

Bottom line: Mutation is evil.

Upvotes: 1

Related Questions