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

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: 0;
}

#show-length {
  position: absolute;
  top: 10px;
  left: 10px;
}

.links {
  fill: none;
  stroke: #000;
}

.link-extensions {
  fill: none;
  stroke: #000;
  stroke-opacity: .25;
}

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

.link--active {
  stroke: #000 !important;
  stroke-width: 1.5px;
}

.link-extension--active {
  stroke-opacity: .6;
}

.label--active {
  font-weight: bold;
}

</style>
<label id="show-length">
  <input type="checkbox"> Show branch length
</label>

<!-- Copyright 2011 Jason Davies https://github.com/jasondavies/newick.js -->
<script>function parseNewick(a){for(var e=[],r={},s=a.split(/\s*(;|\(|\)|,|:)\s*/),t=0;t<s.length;t++){var n=s[t];switch(n){case"(":var c={};r.branchset=[c],e.push(r),r=c;break;case",":var c={};e[e.length-1].branchset.push(c),r=c;break;case")":r=e.pop();break;case":":break;default:var h=s[t-1];")"==h||"("==h||","==h?r.name=n:":"==h&&(r.length=parseFloat(n))}}return r}</script>

<!-- Copyright 2015 Mike Bostock http://d3js.org -->
<script src="//d3js.org/d3.v3.min.js"></script>
<script>

var outerRadius = 960 / 2,
    innerRadius = outerRadius - 170;

var color = d3.scale.category10()
    .domain(["Bacteria", "Eukaryota", "Archaea"]);

var cluster = d3.layout.cluster()
    .size([360, innerRadius])
    .children(function(d) { return d.branchset; })
    .value(function(d) { return 1; })
    .sort(function(a, b) { return (a.value - b.value) || d3.ascending(a.length, b.length); })
    .separation(function(a, b) { return 1; });

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

var legend = svg.append("g")
    .attr("class", "legend")
  .selectAll("g")
    .data(color.domain())
  .enter().append("g")
    .attr("transform", function(d, i) { return "translate(" + (outerRadius * 2 - 10) + "," + (i * 20 + 10) + ")"; });

legend.append("rect")
    .attr("x", -18)
    .attr("width", 18)
    .attr("height", 18)
    .style("fill", color);

legend.append("text")
    .attr("x", -24)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "end")
    .text(function(d) { return d; });

var chart = svg.append("g")
    .attr("transform", "translate(" + outerRadius + "," + outerRadius + ")");

d3.text("life.txt", function(error, life) {
  if (error) throw error;

  var root = parseNewick(life),
      nodes = cluster.nodes(root),
      links = cluster.links(nodes),
      input = d3.select("#show-length input").on("change", changed),
      timeout = setTimeout(function() { input.property("checked", true).each(changed); }, 2000);

  setRadius(root, root.length = 0, innerRadius / maxLength(root));
  setColor(root);

  var linkExtension = chart.append("g")
      .attr("class", "link-extensions")
    .selectAll("path")
      .data(links.filter(function(d) { return !d.target.children; }))
    .enter().append("path")
      .each(function(d) { d.target.linkExtensionNode = this; })
      .attr("d", function(d) { return step(d.target.x, d.target.y, d.target.x, innerRadius); });

  var link = chart.append("g")
      .attr("class", "links")
    .selectAll("path")
      .data(links)
    .enter().append("path")
      .each(function(d) { d.target.linkNode = this; })
      .attr("d", function(d) { return step(d.source.x, d.source.y, d.target.x, d.target.y) })
      .style("stroke", function(d) { return d.target.color; });

  chart.append("g")
      .attr("class", "labels")
    .selectAll("text")
      .data(nodes.filter(function(d) { return !d.children; }))
    .enter().append("text")
      .attr("dy", ".31em")
      .attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (innerRadius + 4) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); })
      .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
      .text(function(d) { return d.name.replace(/_/g, " "); })
      .on("mouseover", mouseovered(true))
      .on("mouseout", mouseovered(false));

  function changed() {
    clearTimeout(timeout);
    var checked = this.checked;
    d3.transition().duration(750).each(function() {
      linkExtension.transition().attr("d", function(d) { return step(d.target.x, checked ? d.target.radius : d.target.y, d.target.x, innerRadius); });
      link.transition().attr("d", function(d) { return step(d.source.x, checked ? d.source.radius : d.source.y, d.target.x, checked ? d.target.radius : d.target.y) });
    });
  }

  function mouseovered(active) {
    return function(d) {
      d3.select(this).classed("label--active", active);
      d3.select(d.linkExtensionNode).classed("link-extension--active", active).each(moveToFront);
      do d3.select(d.linkNode).classed("link--active", active).each(moveToFront); while (d = d.parent);
    };
  }

  function moveToFront() {
    this.parentNode.appendChild(this);
  }
});

// Compute the maximum cumulative length of any node in the tree.
function maxLength(d) {
  return d.length + (d.children ? d3.max(d.children, maxLength) : 0);
}

// Set the radius of each node by recursively summing and scaling the distance from the root.
function setRadius(d, y0, k) {
  d.radius = (y0 += d.length) * k;
  if (d.children) d.children.forEach(function(d) { setRadius(d, y0, k); });
}

// Set the color of each node by recursively inheriting.
function setColor(d) {
  d.color = color.domain().indexOf(d.name) >= 0 ? color(d.name) : d.parent ? d.parent.color : null;
  if (d.children) d.children.forEach(setColor);
}

// Like d3.svg.diagonal.radial, but with square corners.
function step(startAngle, startRadius, endAngle, endRadius) {
  var c0 = Math.cos(startAngle = (startAngle - 90) / 180 * Math.PI),
      s0 = Math.sin(startAngle),
      c1 = Math.cos(endAngle = (endAngle - 90) / 180 * Math.PI),
      s1 = Math.sin(endAngle);
  return "M" + startRadius * c0 + "," + startRadius * s0
      + (endAngle === startAngle ? "" : "A" + startRadius + "," + startRadius + " 0 0 " + (endAngle > startAngle ? 1 : 0) + " " + startRadius * c1 + "," + startRadius * s1)
      + "L" + endRadius * c1 + "," + endRadius * s1;
}

d3.select(self.frameElement).style("height", outerRadius * 2 + "px");

</script>