I'm using D3's forced layout graph to plot the data.
update
function using setInterval
with new data, the force layout graph nodes start from a random position. How can I fix this?console
prints the correct data. How can I solve this too?Here is the jsfiddle: https://jsfiddle.net/mootqvs1/
(Please avoid asking about different issues in the same question, specially when they are not related. Here I'll explain your problem #2, which is specific to your code. Your problem #1 is a general problem and has been already addressed in several questions/answers here at S.O.)
The problem with the update function is that you're using the indices as keys. However, the indices are the same for those different datasets!
Therefore, change this...
if (!node.id) node.id = ++i;
... for something that assigns unique ids for the nodes. The obvious choice is using their names:
if (!node.id) node.id = node.name;
However, even that won't work, because some nodes have the same name... so, we can mix the approaches:
if (!node.id) node.id = node.name + (++i);
Have in mind that this is just an example. The best solution is finding some property (or combination of properties) which are always unique and the same for each node.
Here is your code with that change only:
var width = 680,
height = 380,
root;
var data1 = {
"name": "RootNode",
"children": [{
"name": "B1",
"children": [{
"name": "D1"
}, {
"name": "D2"
}, {
"name": "D3"
}]
}, {
"name": "B2",
"children": [{
"name": "D1"
}, {
"name": "D2"
}, {
"name": "D3"
}, {
"name": "D4"
}]
}, {
"name": "B3",
"children": [{
"name": "D1"
}, {
"name": "D2"
}, {
"name": "D3"
}, {
"name": "D4"
}, {
"name": "D5"
}]
}, {
"name": "B4",
"children": [{
"name": "D1"
}, {
"name": "D2"
}, {
"name": "D3"
}, {
"name": "D4"
}]
}, {
"name": "B5",
"children": [{
"name": "D1"
}]
}]
};
var data2 = {
"name": "Root",
"children": [{
"name": "Box1",
"children": [{
"name": "device1"
}, {
"name": "device2"
}, {
"name": "device3"
}]
}, {
"name": "Box2",
"children": [{
"name": "device1"
}, {
"name": "device2"
}, {
"name": "device3"
}, {
"name": "device4"
}]
}, {
"name": "Box3",
"children": [{
"name": "device1"
}, {
"name": "device2"
}, {
"name": "device3"
}, {
"name": "device4"
}, {
"name": "device5"
}]
}, {
"name": "Box4",
"children": [{
"name": "device1"
}, {
"name": "device2"
}, {
"name": "device3"
}, {
"name": "device4"
}]
}, {
"name": "Box5",
"children": [{
"name": "device1"
}]
}]
};
var force = d3.layout.force()
.linkDistance(80)
.charge(-120)
.gravity(.05)
.size([width, height])
.on("tick", tick);
var svg = d3.select(".network-graph").append("svg")
.attr("width", width)
.attr("height", height);
var link = svg.selectAll(".link"),
node = svg.selectAll(".node");
root = data1;
update();
setInterval(function() {
root = data2;
update();
}, 5000);
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.start();
// Update links.
link = link.data(links, function(d) {
return d.target.id;
});
link.exit().remove();
link.enter().insert("line", ".node")
.attr("class", "link");
// Update nodes.
node = node.data(nodes, function(d) {
return d.id;
});
node.exit().remove();
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.on("click", click)
.call(force.drag);
nodeEnter.append("circle")
.attr("r", function(d) {
return 15 || 4.5;
});
nodeEnter.append("text")
.attr("dy", ".35em")
.text(function(d) {
return d.name;
});
node.select("circle")
.style("fill", color);
}
function tick() {
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 + ")";
});
}
function color(d) {
return d._children ? "#3182bd" // collapsed package
: d.children ? "#c6dbef" // expanded package
: "#fd8d3c"; // leaf node
}
// Toggle children on click.
function click(d) {
if (d3.event.defaultPrevented) return; // ignore drag
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update();
}
// Returns a list of all nodes under the root.
function flatten(root) {
var nodes = [],
i = 0;
function recurse(node) {
if (node.children) node.children.forEach(recurse);
if (!node.id) node.id = node.name + (++i);
nodes.push(node);
}
recurse(root);
return nodes;
}
.node circle {
cursor: pointer;
stroke: #3182bd;
stroke-width: 1.5px;
}
.node text {
font: 10px sans-serif;
pointer-events: none;
text-anchor: middle;
}
line.link {
fill: none;
stroke: #9ecae1;
stroke-width: 1.5px;
}
<script src="https://d3js.org/d3.v3.min.js"></script>
<div class="network-graph"></div>