block by pjsier 34f5428db1e75d5390f6ab78fcd0454e

Force-Directed States v4

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

path {
  fill: #ddd;
  fill-opacity: .8;
  stroke: #fff;
  stroke-width: 1.5px;
}

line {
  stroke: #999;
}

</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>
<script>
// Mike Bostock's bl.ock updated for D3 v4 https://bl.ocks.org/mbostock/1073373
var width = 960,
    height = 700;

var path = d3.geoPath();

var simulation = d3.forceSimulation();

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

d3.json("https://d3js.org/us-10m.v1.json", function(error, us) {
  if (error) throw error;

  var states = topojson.feature(us, us.objects.states),
      nodes = [],
      links = [];

  states.features.forEach(function(d, i) {
    if (d.id === "02" || d.id === "15" || d.id === "72") return; // lower 48
    var centroid = path.centroid(d);
    if (centroid.some(isNaN)) return;
    centroid.x = centroid[0];
    centroid.y = centroid[1];
    centroid.feature = d;
    nodes.push(centroid);
  });

  d3.voronoi().links(nodes).forEach(function(link) {
    var dx = link.source.x - link.target.x,
        dy = link.source.y - link.target.y;
    link.distance = Math.sqrt(dx * dx + dy * dy);
    links.push(link);
  });

  var link = svg.selectAll("line")
      .data(links)
    .enter().append("line")
      .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; });

  var node = svg.selectAll("g")
      .data(nodes)
    .enter().append("g")
      .attr("transform", function(d) { return "translate(" + -d.x + "," + -d.y + ")"; })
      .call(d3.drag()
              .on("start", dragstarted)
              .on("drag", dragged)
              .on("end", dragended))
    .append("path")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
      .attr("d", function(d) { return path(d.feature); });

  usCentroid = [d3.mean(nodes, function(d) { return d.x; }), 
                d3.mean(nodes, function(d) { return d.y; })];
                
  simulation.nodes(nodes)
    .force("charge", d3.forceManyBody().strength(-5))
    .force("link", d3.forceLink(links).distance(function(d) { return d.distance; }))
    .force("center", d3.forceCenter(usCentroid[0], usCentroid[1]))
    .on("tick", ticked);

  function ticked() {
    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 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>