D3NodeExamplesWithLabelsAndFishEye
A D3 force directed layout where the nodes are not allowed overlap and with labels on the circles
by Simon Raper
HTML
<script src="http://bost.ocks.org/mike/fisheye/fisheye.js?0.0.3"></script>
<script type="application/json" id="mis">
{
"nodes": [{
"name": "Myriel",
"group": 1
}, {
"name": "Napoleon",
"group": 1
}, {
"name": "Mlle.Baptistine",
"group": 1
}, {
"name": "Mme.Magloire",
"group": 1
}, {
"name": "CountessdeLo",
"group": 1
}, {
"name": "Geborand",
"group": 1
}, {
"name": "Champtercier",
"group": 1
}, {
"name": "Cravatte",
"group": 1
}, {
"name": "Count",
"group": 1
}, {
"name": "OldMan",
"group": 1
}, {
"name": "Labarre",
"group": 2
}, {
"name": "Valjean",
"group": 2
}, {
"name": "Marguerite",
"group": 3
}, {
"name": "Mme.deR",
"group": 2
}, {
"name": "Isabeau",
"group": 2
}, {
"name": "Gervais",
"group": 2
}, {
"name": "Tholomyes",
"group": 3
}, {
"name": "Listolier",
"group": 3
}, {
"name": "Fameuil",
"group": 3
}, {
"name": "Blacheville",
"group": 3
}, {
"name": "Favourite",
"group": 3
}, {
"name": "Dahlia",
"group": 3
}, {
"name": "Zephine",
"group": 3
}, {
"name": "Fantine",
"group": 3
}, {
"name": "Mme.Thenardier",
"group": 4
}, {
"name": "Thenardier",
...
CSS
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.node text {
pointer-events: none;
font: 5px helvetica;
text-shadow:none;
}
.link {
stroke: #999;
stroke-opacity: .3;
}
JavaScript
var width = 1300,
height = 1300,
debug=0;
var padding = 1, // separation between same-color circles
clusterPadding = 1, // separation between different-color circles
radius=20,
maxRadius = 20;
var color = d3.scale.category20();
var fisheye = d3.fisheye.circular()
.radius(120);
var force = d3.layout.force()
.charge(-400)
.linkDistance(200)
.size([width, height]);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var stuff = document.getElementById('mis').innerHTML;
graph = JSON.parse(stuff);
force.nodes(graph.nodes) //Creates the graph data structure out of the json data
.links(graph.links)
.start();
//Create all the line svgs but without locations yet <line class="link" style="stroke-width: 1px;"></line>
var link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function (d) {
return Math.sqrt(d.value);
});
//Do the same with the circles for the nodes - no
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", radius)
.style("fill", function (d) {
return color(d.group);
})
node.append("text")
.attr("dx", -9)
.attr("dy", ".35em")
.attr("stroke", "black")
.text(function(d) { return d.name });
//Now we are giving the SVGs co-ordinates - looks like the force layout is generating the co-ordinates which this code is using to up date the attributes of the SVG elements
svg.on("mousemove", function() {
fisheye.focus(d3.mouse(this));
d3.selectAll("circle").each(function(d) { d.fisheye = fisheye(d); })
.attr("cx", function(d) { return d.fisheye.x; })
.attr("cy", function(d) { return d.fisheye.y; })
.attr("r", function(d) { return d.fisheye.z * radius; });
//link.attr("x1", function(d) {...