Skip to content Skip to sidebar Skip to footer

D3 Dynamic Network Slow When Adding Nodes Realtime

I am struggling to work out why my codepen is slow when I stream the nodes and links real-time. In the codepen, I have simulated the real-time stuff by having links1 and nodes1 arr

Solution 1:

Minor change to fix a major issue.

Here's a screenshot which will clearly explain the slowdown of adding the nodes,links (and this was just by the initial reset click, IMAGINE the number of nodes it'd add in real time when the number of nodes would increase):

enter image description here

To fix this, you'll have to change the node enter selection (which is incorrect now). Here's the new node enter selection:

node = node.data(nodes);

var nodeEnter = node.enter().insert("g").attr("class", "node")
   .call(force.drag);

nodeEnter
 .append("image")
 ...

nodeEnter
 .append('text')
 ...

Note the difference, I'm not appending image and text on every call.

Here's the code snippet:

#nodeConsole {
  width: 80%;
  height: 1px;
  font-family: courier new;
  padding: 1px;
  border: 3px solid gray;
  margin-top: 1px;
  overflow: auto;
}

#linkedNodes {
  width: 80%;
  font-family: courier new;
  padding: 10px;
}

#srcNodes {
  width: 40%;
  font-family: courier new;
  padding: 8px;
}

#targetNodes {
  width: 40%;
  font-family: courier new;
  padding: 8px;
}

rect {
  fill: none;
  pointer-events: all;
}

.node {
  fill: #000;
}

.cursor {
  fill: none;
  stroke: brown;
  pointer-events: none;
}

.link {
  stroke: #999;
}
.node text {
  pointer-events: none;
  font: 10px sans-serif;
}

path.link {
  fill: none;
  stroke: #666;
  stroke-width: 1.5px;
}
<scriptsrc="https://d3js.org/d3.v3.min.js"></script><buttonid="ref"onclick="refresh()">refresh </button><buttonid="reset"onclick="reset()">reset </button><script>var links1 = [{"source":"ctfa","target":"tfa"},
 {"source":"cea","target":"tea"},
 {"source":"ctfe","target":"tfe"},
 {"source":"ctee","target":"tee"},
 {"source":"ctfu","target":"tfu"},
 {"source":"cteu","target":"teu"},
 {"source":"rfa","target":"tfa"},
 {"source":"rea","target":"tea"},
 {"source":"rfe","target":"tfe"},
 {"source":"ree","target":"tee"},
 {"source":"rfu","target":"tfu"},
 {"source":"reu","target":"teu"},
 {"source":"r1fa","target":"rfa"},
 {"source":"r1fa","target":"gfa"},
 {"source":"r1fa","target":"ggf"},
 {"source":"r1ea","target":"rea"},
 {"source":"r1ea","target":"gea"},
 {"source":"r1ea","target":"gge"},
 {"source":"r1fe","target":"rfe"},
 {"source":"r1fe","target":"gfe"},
 {"source":"r1fe","target":"ggf"},
 {"source":"r1ee","target":"ree"},
 {"source":"r1ee","target":"gee"},
 {"source":"r1ee","target":"gge"},
 {"source":"r1fu","target":"rfu"},
 {"source":"r1fu","target":"gfu"},
 {"source":"r1fu","target":"ggf"},
 {"source":"r1eu","target":"reu"},
 {"source":"r1eu","target":"geu"},
 {"source":"r1eu","target":"gge"},
 {"source":"hh1fa","target":"ggf"},
 {"source":"hh1ea","target":"gge"},
 {"source":"hh1fe","target":"ggf"},
 {"source":"hh1ee","target":"gge"},
 {"source":"hh1fu","target":"ggf"},
 {"source":"hh1eu","target":"gge"},
 {"source":"dbfa","target":"gfa"},
 {"source":"dbea","target":"gea"},
 {"source":"dbfe","target":"gfe"},
 {"source":"dbee","target":"gee"},
 {"source":"dbfu","target":"gfu"},
 {"source":"dbeu","target":"geu"},
 {"source":"hflse","target":"tee"},
 {"source":"hfnyse","target":"teu"},
 {"source":"hfnse","target":"teu"},
 {"source":"hfret","target":"tfu"},
 {"source":"hfebs","target":"tfe"},
 {"source":"hfint","target":"tfu"},
 {"source":"c1e","target":"ctee"},
 {"source":"c1e","target":"gge"},
 {"source":"c2e","target":"ctee"},
 {"source":"c3e","target":"cteu"},
 {"source":"c4e","target":"cteu"},
 {"source":"c5e","target":"ggf"},
 {"source":"d1e","target":"ctee"},
 {"source":"c1f","target":"ctfe"},
 {"source":"c2f","target":"ctfe"},
 {"source":"c3f","target":"ggf"},
 {"source":"c4f","target":"gge"},
 {"source":"c5f","target":"ctfa"},
 {"source":"d1f","target":"ctfe"}];

var nodes1 = [{"id":"tfa"},
 {"id":"tea"},
 {"id":"tfe"},
 {"id":"tee"},
 {"id":"tfu"},
 {"id":"teu"},
 {"id":"ctfa"},
 {"id":"cea"},
 {"id":"ctfe"},
 {"id":"ctee"},
 {"id":"ctfu"},
 {"id":"cteu"},
 {"id":"rfa"},
 {"id":"rea"},
 {"id":"rfe"},
 {"id":"ree"},
 {"id":"rfu"},
 {"id":"reu"},
 {"id":"r1fa"},
 {"id":"r1ea"},
 {"id":"r1fe"},
 {"id":"r1ee"},
 {"id":"r1fu"},
 {"id":"r1eu"},
 {"id":"hh1fa"},
 {"id":"hh1ea"},
 {"id":"hh1fe"},
 {"id":"hh1ee"},
 {"id":"hh1fu"},
 {"id":"hh1eu"},
 {"id":"dbfa"},
 {"id":"dbea"},
 {"id":"dbfe"},
 {"id":"dbee"},
 {"id":"dbfu"},
 {"id":"dbeu"},
 {"id":"gfa"},
 {"id":"gea"},
 {"id":"gfe"},
 {"id":"gee"},
 {"id":"gfu"},
 {"id":"geu"},
 {"id":"gge"},
 {"id":"ggf"},
 {"id":"hflse"},
 {"id":"hfnyse"},
 {"id":"hfnse"},
 {"id":"hfret"},
 {"id":"hfebs"},
 {"id":"hfint"},
 {"id":"c1e"},
 {"id":"c2e"},
 {"id":"c3e"},
 {"id":"c4e"},
 {"id":"c5e"},
 {"id":"d1e"},
 {"id":"c1f"},
 {"id":"c2f"},
 {"id":"c3f"},
 {"id":"c4f"},
 {"id":"c5f"},
 {"id":"d1f"}];
    //refresh();functionreset() {
        nodes1.forEach(function(d){ add_prc(d)  });
        links1.forEach(function(d){ add_con(d)  });
    }
 
    functionadd_prc(newNode) {
        //console.log(newNode);addNodeCanvas(newNode.id,newNode.grp);
    }

    functionadd_con(newConnection) {
        //console.log(newConnection);addLinkCanvas( newConnection.source,newConnection.target);  
    }

    //setInterval(refresh, 15000);functionaddNodeCanvas(nodeName,g) {
        var node = {        x: 900,    y: 900,        id: nodeName,    grp:g  };
        var n = nodes.push(node);
       // console.log(node);refresh();
    }
    
    functionaddLinkCanvas(idSrc, idTarget) {
        if (idSrc != idTarget) {
            var s = {},        t = {};
            nodes.forEach(function(curNode) {
                if (typeof curNode.id != "undefined") {
                    if (curNode.id == idSrc) {          s = curNode;        }
                    if (curNode.id == idTarget) {          t = curNode;        }
                }
            });

            //console.log( { s,t});
            links.push({     source: s,      target: t    });
        };
        refresh();
    }

  var width = 960,
  height = 500;

var fill = d3.scale.category20();

var links = [{ source:  "FH", target: "TP" }];
var nodes = [
    { id: "FH", x: 100, y: 110 },
    { id: "TP", x: 200, y: 110 },
    { id: "GW", x: 200, y: 110 },
    { id: "DB", x: 100, y: 110 }
  ]

var map = {}
nodes.forEach(function(d,i){
  map[d.id] = i;
})

links.forEach(function(d) {
  d.source = map[d.source];
  d.target = map[d.target];
})

var force = d3.layout
  .force()
  .size([width, height])
  .nodes(nodes) .links(links)
  .linkDistance(50)
  .charge(-50)
  .on("tick", tick);

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", height);

// build the arrow.var arrows = svg
  .append("svg:defs")
  .selectAll("marker")
  .data(["arrow"]) // Different link/path types can be defined here
  .enter()
  .append("svg:marker") // This section adds in the arrows
  .attr("id", String)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", -1.5)
  .attr("markerWidth", 6)
  .attr("markerHeight", 6)
  .attr("orient", "auto")
  .append("svg:path")
  .attr("d", "M0,-5L10,0L0,5");


svg
  .append("rect")
  .attr("width", width)
  .attr("height", height);

var nodes = force.nodes(),
  links = force.links(),
  node = svg.selectAll(".node"),
  link = svg.selectAll(".link");


functiontick() {
  link.attr("x1", function(d) {
      return d.source.x;
    })
    .attr("y1", function(d) {
      return d.source.y;
    })
    .attr("x2", function(d) {
      return d.target.x;
    })
    .attr("y2", function(d) {
      return d.target.y;
    });

  node.attr("transform", function(d) {
    return"translate(" + d.x + "," + d.y + ")";
  });
}


 functionrefresh(){
  
  node = node.data(nodes);
  
  var nodeEnter = node.enter().insert("g")
  	.attr("class", "node")
    .call(force.drag);
  
  nodeEnter
    .append("image")
    .attr("xlink:href", "https://github.com/favicon.ico")
    .attr("x", -8)
    .attr("y", -8)
    .attr("width", 16)
    .attr("height", 16);
  nodeEnter
    .append("text")
    .attr("dx", 12)
    .attr("dy", ".35em")
    .text(function(d) {
      return d.id;
    });
  node.exit().remove();

  link = link.data(links);
  link
    .enter()
    .insert("line", ".node")
    .attr("class", "link");
  link.exit().remove();

  force.start();
}


    </script>

And here's a JSFIDDLE (I'm a jsfiddle fan).

And I see that you moved from a canvas to SVG. Anyway, hope this helps.

Post a Comment for "D3 Dynamic Network Slow When Adding Nodes Realtime"