Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I recently tried to do the same thing, here is the solution I came up with. What I do is load a first batch of data with <code>links.php</code> and then update them with <code>newlinks.php</code>, both return a JSON with a list of objects with attributes <code>sender</code> and <code>receiver</code>. In this example newlinks returns a new sender each time and I set the receiver to be a randomly selected old node. </p> <pre><code>$.post("links.php", function(data) { // Functions as an "initializer", loads the first data // Then newlinks.php will add more data to this first batch (see below) var w = 1400, h = 1400; var svg = d3.select("#networkviz") .append("svg") .attr("width", w) .attr("height", h); var links = []; var nodes = []; var force = d3.layout.force() .nodes(nodes) .links(links) .size([w, h]) .linkDistance(50) .charge(-50) .on("tick", tick); svg.append("g").attr("class", "links"); svg.append("g").attr("class", "nodes"); var linkSVG = svg.select(".links").selectAll(".link"), nodeSVG = svg.select(".nodes").selectAll(".node"); handleData(data); update(); // This is the server call var interval = 5; // set the frequency of server calls (in seconds) setInterval(function() { var currentDate = new Date(); var beforeDate = new Date(currentDate.setSeconds(currentDate.getSeconds()-interval)); $.post("newlinks.php", {begin: beforeDate, end: new Date()}, function(newlinks) { // newlinks.php returns a JSON file with my new transactions (the one that happened between now and 5 seconds ago) if (newlinks.length != 0) { // If nothing happened, then I don't need to do anything, the graph will stay as it was // here I decide to add any new node and never remove any of the old ones // so eventually my graph will grow extra large, but that's up to you to decide what you want to do with your nodes newlinks = JSON.parse(newlinks); // Adds a node to a randomly selected node (completely useless, but a good example) var r = getRandomInt(0, nodes.length-1); newlinks[0].receiver = nodes[r].id; handleData(newlinks); update(); } }); }, interval*1000); function update() { // enter, update and exit force.start(); linkSVG = linkSVG.data(force.links(), function(d) { return d.source.id+"-"+d.target.id; }); linkSVG.enter().append("line").attr("class", "link").attr("stroke", "#ccc").attr("stroke-width", 2); linkSVG.exit().remove(); var r = d3.scale.sqrt().domain(d3.extent(force.nodes(), function(d) {return d.weight; })).range([5, 20]); var c = d3.scale.sqrt().domain(d3.extent(force.nodes(), function(d) {return d.weight; })).range([0, 270]); nodeSVG = nodeSVG.data(force.nodes(), function(d) { return d.id; }); nodeSVG.enter() .append("circle") .attr("class", "node") // Color of the nodes depends on their weight nodeSVG.attr("r", function(d) { return r(d.weight); }) .attr("fill", function(d) { return "hsl("+c(d.weight)+", 83%, 60%)"; }); nodeSVG.exit().remove(); } function handleData(data) { // This is where you create nodes and links from the data you receive // In my implementation I have a list of transactions with a sender and a receiver that I use as id // You'll have to customize that part depending on your data for (var i = 0, c = data.length; i&lt;c; i++) { var sender = {id: data[i].sender}; var receiver = {id: data[i].receiver}; sender = addNode(sender); receiver = addNode(receiver); addLink({source: sender, target: receiver}); } } // Checks whether node already exists in nodes or not function addNode(node) { var i = nodes.map(function(d) { return d.id; }).indexOf(node.id); if (i == -1) { nodes.push(node); return node; } else { return nodes[i]; } } // Checks whether link already exists in links or not function addLink(link) { if (links.map(function(d) { return d.source.id+"-"+d.target.id; }).indexOf(link.source.id+"-"+link.target.id) == -1 &amp;&amp; links.map(function(d) { return d.target.id+"-"+d.source.id; }).indexOf(link.source.id+"-"+link.target.id) == -1) links.push(link); } function tick() { linkSVG.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;}); nodeSVG.attr("cx", function(d) {return d.x}) .attr("cy", function(d) {return d.y}); } function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } }, "json"); </code></pre> <p>This is a very specific implementation so you should fill the holes where necessary depending on your server output. But I believe the D3 backbone is correct and what you are looking for :) Here is a JSFiddle to toy with it : <a href="http://jsfiddle.net/bTyh5/2/" rel="nofollow">http://jsfiddle.net/bTyh5/2/</a></p> <p><a href="http://bl.ocks.org/mbostock/1095795" rel="nofollow">This code</a> was really useful and inspired some of the parts introduced here.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload