Reputation: 619
My goal is to start the layout with all the nodes collapsed, on click they expand. The issue here is that text labels create duplicates on mouseover. They also create duplicates on the top left of the screen.
I've reduced the json to a minimal amount for testing, which is below the block of code.
What am I doing wrong?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Force-Directed Graph</title>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style type="text/css">
circle.node {
cursor: pointer;
stroke: #3182bd;
stroke-width: 1.5px;
}
line.link {
fill: none;
stroke: #9ecae1;
stroke-width: 1.5px;
}
</style>
</head>
<body>
<div id="chart"></div>
<script type="text/javascript">
var w = 960,
h = 500,
node,
link,
root,
t;
var force = d3.layout.force()
.on("tick", tick)
.size([w, h]);
var vis = d3.select("#chart").append("svg:svg")
.attr("width", w)
.attr("height", h);
d3.json("test.json", function(json) {
root = json;
update();
function toggleAll(d) {
if (d.children) {
d.children.forEach(toggleAll);
toggle(d);
}
}
// Initialize the display to show a few nodes.
root.children.forEach(toggleAll);
update(root);
});
function update() {
var nodes = flatten(root),
links = d3.layout.tree().links(nodes);
// Restart the force layout.
force
.nodes(nodes)
.links(links)
.charge(-1000)
.linkDistance(100)
.friction(0.5)
.start();
// Update the links…
link = vis.selectAll("line.link")
.data(links, function(d) { return d.target.id; });
// Enter any new links.
link.enter().insert("svg:line", ".node")
.attr("class", "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; });
// Exit any old links.
link.exit().remove();
// Update the nodes…
node = vis.selectAll("circle.node")
.data(nodes, function(d) { return d.id; })
.style("fill", color);
// Enter any new nodes.
node.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", "15")
.style("fill", color)
.on("mouseover", mouseover)
.call(force.drag);
// Exit any old nodes.
node.exit().remove();
t = vis.selectAll("t.node")
.data(nodes, function(d) { return d.id; })
.style("fill", color);
// Enter any new nodes.
t.enter().append("svg:text")
.attr("class", "t-node")
.attr("dx", "25px")
.attr("y", 0)
.text("test");
// .call(force.drag);
// Exit any old nodes.
t.exit().remove();
}
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
t.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
// t.attr("transform", function(d) {
// return "translate(" + d.x + "," + d.y + ")"; } )
}
// Color leaf nodes orange, and packages white or blue.
function color(d) {
return d._children ? "#3182bd" : d.children ? "#c6dbef" : "#fd8d3c";
}
// Toggle children on click.
function mouseover(d) {
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 = ++i;
nodes.push(node);
}
recurse(root);
return nodes;
}
function toggle(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
}
</script>
</body>
</html>
{
"name": "Test",
"children": [
{
"name": "cat 1",
"children": [
{"name": "subcat 1-a", "size": 1082},
{"name": "subcat 1-b", "size": 1082}
]
},
{
"name": "cat 2",
"children": [
{"name": "subcat 2-a", "size": 1082}
]
}
]
}
Upvotes: 1
Views: 1492
Reputation: 55688
At the risk of stealing @Lars' answer, vis.selectAll("t.node")
looks like it needs to be vis.selectAll(".t-node")
. If you don't use a selector in selectAll
that matches the nodes you append in the .enter()
selection, you'll get duplicate nodes every time it runs.
Upvotes: 2