block by mbostock 5672200

Hierarchical Edge Bundling

Full Screen

A planar layout of hierarchical edge bundling, as opposed to the radial version. Not sure I would recommend this version; it feels less effective at bundling edges.

index.html

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

.node {
  font: 10px sans-serif;
}

.link {
  stroke: steelblue;
  stroke-opacity: .4;
  fill: none;
}

</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>

var margin = {top: 10, right: 140, bottom: 10, left: -400},
    width = 960 - margin.left - margin.right,
    height = 2400 - margin.top - margin.bottom;

var cluster = d3.layout.cluster()
    .size([height, width])
    .sort(function(a, b) { return d3.ascending(a.name, b.name); })
    .value(function(d) { return d.size; });

var bundle = d3.layout.bundle();

var line = d3.svg.line()
    .interpolate("bundle")
    .tension(.85)
    .x(function(d) { return d.y; })
    .y(function(d) { return d.x; });

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.json("readme-flare-imports.json", function(error, classes) {
  if (error) throw error;

  var nodes = cluster.nodes(packages.root(classes)),
      links = packages.imports(nodes);

  svg.selectAll(".link")
      .data(bundle(links))
    .enter().append("path")
      .attr("class", "link")
      .attr("d", line);

  svg.selectAll(".node")
      .data(nodes.filter(function(n) { return !n.children; }))
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
    .append("text")
      .attr("dx", 8)
      .attr("dy", ".31em")
      .text(function(d) { return d.key; });
});

d3.select(self.frameElement).style("height", height + margin.top + margin.bottom + "px");

var packages = {

  // Lazily construct the package hierarchy from class names.
  root: function(classes) {
    var map = {};

    function find(name, data) {
      var node = map[name], i;
      if (!node) {
        node = map[name] = data || {name: name, children: []};
        if (name.length) {
          node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
          node.parent.children.push(node);
          node.key = name.substring(i + 1);
        }
      }
      return node;
    }

    classes.forEach(function(d) {
      find(d.name, d);
    });

    return map[""];
  },

  // Return a list of imports for the given array of nodes.
  imports: function(nodes) {
    var map = {},
        imports = [];

    // Compute a map from name to node.
    nodes.forEach(function(d) {
      map[d.name] = d;
    });

    // For each import, construct a link from the source to target node.
    nodes.forEach(function(d) {
      if (d.imports) d.imports.forEach(function(i) {
        imports.push({source: map[d.name], target: map[i]});
      });
    });

    return imports;
  }
};

</script>