// Original idea source below. // [Multi-Foci Force Layout](https://bl.ocks.org/mbostock/1021841) // [D3 Force Layout API](https://github.com/mbostock/d3/wiki/Force-Layout) // load data set d3.json('zadjacency_dataset.json', function(error, raw) { var dataset = new Dataset(raw); // boundaries var margin = { top: 75, right: 120, bottom: 20, left: 120 }; var width = 1000 - margin.right - margin.left; var height = 850 - margin.top - margin.bottom; // prepare force layout using mostly default settings var force = d3.layout.force() .nodes(dataset.nodes) .links(dataset.links) .size([ width, height ]) .linkStrength(0.1) .friction(0.9) .charge(-200) .linkDistance(100) .gravity(0.1) .theta(0.8) .alpha(0.1) .on('tick', update) .start(); // prepare svg element var svg = d3.select('body') .append('svg') .attr('width', width + margin.right + margin.left) .attr('height', height + margin.top + margin.bottom) .append('g') .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); var links = svg.selectAll('.link') .data(dataset.links) .enter() .append('line') .style('stroke', 'gray'); var labels = svg.selectAll('.labels') .data(dataset.nodes) .enter() .append('text') .attr('class', 'state-label') .attr('transform', function(d) { return 'translate(' + d.x + ',' + d.y + ')'; }) .attr('style', 'font-family: arial, sans-serif;' + 'font-size: 20px;' + 'fill: blue;' + 'font-weight: bold;'); // nodes automatically update position values from force layout var nodes = svg.selectAll('.node') .data(dataset.nodes) .enter() .append('circle') .attr('class', '.node') .attr('cx', function(d) { return d.x; }) .attr('xy', function(d) { return d.y; }) .attr('r', function(d) { return 10; }) .style('fill', 'red') .style('stroke', 'black') // allow interactive dragging .call(force.drag) .on('mouseover', function(d) { d.showLabel = true; }) .on('mouseout', function(d) { d.showLabel = false; }); function update(e) { nodes.attr('cx', function(d) { return d.x; }) .attr('cy', function(d) { return d.y; }); links.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; }); labels.attr('transform', function(d) { return 'translate(' + (d.x + 10) + ',' + (d.y - 10) + ')'; }) } var loop = d3.timer(function() { labels.text(function(d) { if (d.showLabel) { return d.name; } return ''; }); }); });