Forked from this mbostock block.
Added force-directed edge-bundling from this implementation: d3.forceBundle.
--
This simple force-directed graph shows character co-occurence in Les Misérables. A physical simulation of charged particles and springs places related characters in closer proximity, while unrelated characters are farther apart. Layout algorithm inspired by Tim Dwyer and Thomas Jakobsen. Data based on character coappearence in Victor Hugo's Les Misérables, compiled by Donald Knuth.
Compare this display to a force layout with curved links, a force layout with fisheye distortion and a matrix diagram.
xxxxxxxxxx
<meta charset="utf-8">
<style>
.links path {
stroke: #999;
stroke-opacity: 0.3;
fill: none;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/upphiminn/d3.forcebundle/2b406b8567fcad0a6c2922c84cd4bceb0c374bc5/d3-forceedgebundling.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var color = d3.scaleOrdinal(d3.schemeCategory20);
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) { return d.id; }))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2));
d3.json("miserables.json", function(error, graph) {
if (error) throw error;
var links = svg.append("g")
.attr("class", "links");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 5)
.attr("fill", function(d) { return color(d.group); })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
node.append("title")
.text(function(d) { return d.id; });
var d3line = d3.line()
.x(function(d){return d.x;})
.y(function(d){return d.y;});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
//Run FDEB on all the links
var fbundling = d3.ForceEdgeBundling()
.nodes(simulation.nodes())
.edges(simulation.force('link').links().map(function(edge) {
return {
source: simulation.nodes().indexOf(edge.source),
target: simulation.nodes().indexOf(edge.target)
}
}));
var link = links.selectAll('path')
.data(fbundling());
link.exit().remove();
link.merge(link.enter().append('path'))
.attr('d', d3line);
}
});
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
</script>
Updated missing url https://cdn.rawgit.com/upphiminn/d3.ForceBundle/2b406b8567fcad0a6c2922c84cd4bceb0c374bc5/d3-ForceEdgeBundling.js to https://cdn.jsdelivr.net/gh/upphiminn/d3.forcebundle/2b406b8567fcad0a6c2922c84cd4bceb0c374bc5/d3-forceedgebundling.js
https://d3js.org/d3.v4.min.js
https://cdn.rawgit.com/upphiminn/d3.ForceBundle/2b406b8567fcad0a6c2922c84cd4bceb0c374bc5/d3-ForceEdgeBundling.js