block by nitaku 5c05241a724bd559180a

Basic sunburst (flare)

Full Screen

A basic reference implementation for sunburst diagrams, representing the flare software package hierarchy (using d3.js, of course!).

index.js

(function() {
  var RADIUS, arc, height, partition, svg, vis, width, zoom, zoomable_layer;

  RADIUS = 250;

  partition = d3.layout.partition().sort(null).size([2 * Math.PI, RADIUS * RADIUS]).value(function(node) {
    return node.size;
  });

  arc = d3.svg.arc().startAngle(function(d) {
    return d.x;
  }).endAngle(function(d) {
    return d.x + d.dx;
  }).innerRadius(function(d) {
    return Math.sqrt(d.y);
  }).outerRadius(function(d) {
    return Math.sqrt(d.y + d.dy);
  });

  svg = d3.select('svg');

  width = svg.node().getBoundingClientRect().width;

  height = svg.node().getBoundingClientRect().height;

  svg.attr({
    viewBox: "" + (-width / 2) + " " + (-height / 2) + " " + width + " " + height
  });

  zoomable_layer = svg.append('g');

  zoom = d3.behavior.zoom().scaleExtent([1, 10]).on('zoom', function() {
    return zoomable_layer.attr({
      transform: "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")"
    });
  });

  svg.call(zoom);

  vis = zoomable_layer.append('g');

  d3.json('http://wafi.iit.cnr.it/webvis/tmp/flare.json', function(tree) {
    var enter_nodes, nodes;

    vis.datum(tree);
    nodes = vis.selectAll('.node').data(function(t) {
      return partition.nodes(t);
    });
    enter_nodes = nodes.enter().insert('path', 'path').attr({
      "class": 'node',
      d: arc
    });
    enter_nodes.append('title').text(function(node) {
      return node.name;
    });
    return vis.append('text').text(function(tree) {
      return tree.name;
    }).attr({
      "class": 'label',
      dy: '0.35em'
    });
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
	<head>
        <meta charset="utf-8">
        <meta name="description" content="Basic sunburst (flare)" />
        <title>Basic sunburst (flare)</title>
		<link type="text/css" href="index.css" rel="stylesheet"/>
        <script src="//d3js.org/d3.v3.min.js"></script>
	</head>
	<body>
        <svg height="500" width="960"></svg>
        <script src="index.js"></script>
	</body>
</html>

index.coffee

# layout, behaviors and scales
RADIUS = 250
partition = d3.layout.partition()
    .sort(null)
    .size([2 * Math.PI, RADIUS * RADIUS])
    .value((node) -> node.size)

arc = d3.svg.arc()
    .startAngle((d) -> d.x )
    .endAngle((d) -> d.x + d.dx )
    .innerRadius((d) -> Math.sqrt(d.y) )
    .outerRadius((d) -> Math.sqrt(d.y + d.dy) )
    
svg = d3.select('svg')
width = svg.node().getBoundingClientRect().width
height = svg.node().getBoundingClientRect().height

# translate the viewBox to have (0,0) at the center of the vis
svg
  .attr
    viewBox: "#{-width/2} #{-height/2} #{width} #{height}"
    
# append a group for zoomable content
zoomable_layer = svg.append('g')
 
# define a zoom behavior
zoom = d3.behavior.zoom()
  .scaleExtent([1,10]) # min-max zoom
  .on 'zoom', () ->
    # GEOMETRIC ZOOM
    zoomable_layer
      .attr
        transform: "translate(#{zoom.translate()})scale(#{zoom.scale()})"

# bind the zoom behavior to the main SVG
svg.call(zoom)

# group the visualization
vis = zoomable_layer.append('g')
    
d3.json 'http://wafi.iit.cnr.it/webvis/tmp/flare.json', (tree) ->
  vis.datum(tree)
  
  nodes = vis.selectAll('.node')
    .data((t) -> partition.nodes(t))
    
  enter_nodes = nodes.enter().insert('path','path')
    .attr
      class: 'node'
      d: arc
      
  enter_nodes.append('title')
    .text((node) -> node.name)
      
  vis.append('text')
    .text((tree) -> tree.name)
    .attr
      class: 'label'
      dy: '0.35em'
      

index.css

svg {
  background: white;
}
.node {
  vector-effect: non-scaling-stroke;
  fill: #AAB;
  stroke: white;
  stroke-width: 1;
}
.node:hover {
  fill: #889;
}
.label {
  pointer-events: none;
  fill: #444;
  text-anchor: middle;
  font-family: sans-serif;
  font-size: 28px;
  text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;
}