block by syntagmatic 2056294

Crazy Hive Plot

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Hive Plot Demo</title>

    <link rel="stylesheet" type="text/css" href="demo.css" />

    <script src='//mbostock.github.com/d3/d3.v2.js'></script>
    <script src='//code.jquery.com/jquery-1.7.1.min.js'></script>
    <script src='coffee-script.js'></script>
    <script type='text/coffeescript' src='lib.coffee'></script>
    <script type='text/coffeescript' src='main.coffee'></script>
  </head>

  <body>
    <ul>
      <h2><span id='account-name'></span></h2>
      <h1>Hive Plot</h1>
      <p>
        Not the best choice of parameters for data visualization. Based on this <a href="//bl.ocks.org/d/2035137/">Hive Plot Demo</a>
      </p>

      <div id='chart'></div>
    </ul>
  </body>
</html>

demo.css

/* demo.css */

body {
  margin:         5px auto;
}

#chart svg {
  border:         solid 1px #ccc;
}

path {
  fill:           none;
  stroke-width:   1;
}

h1 {
  font:           20px/20px "Helvetica Neue";
  margin:         0;
}

p {
  color:          #333;
  font:           12px/15px "Helvetica Neue";
}

lib.coffee

# lib.coffee

functions =

  draw_axis: (axis, svg) ->
  #
  # Draw a hive plot axis in the svg area.

    a_rad       = axis.angle * (Math.PI / 180.0)
    r_beg       = axis.r_beg
    r_end       = r_beg + axis.r_len

    [ height, width ] = [ svg.attr('height'), svg.attr('width') ]
    [ x_ctr,  y_ctr ] = [ height * 0.5,       width * 0.5       ]
    [ x_mul,  y_mul ] = [ Math.sin(a_rad),    Math.cos(a_rad)   ]

    axis.x_beg  = x_ctr + x_mul * r_beg
    axis.x_end  = x_ctr + x_mul * r_end
    axis.x_len  = axis.x_end - axis.x_beg
    axis.x_mul  = x_mul

    axis.y_beg  = y_ctr + y_mul * r_beg
    axis.y_end  = y_ctr + y_mul * r_end
    axis.y_len  = axis.y_end - axis.y_beg
    axis.y_mul  = y_mul

    a_func  = () -> "rotate(#{ -axis.angle } " +
                    "#{ axis.x_beg } #{ axis.y_beg })"

    axis_attrs =
      class:      'axis_rect'
      fill:       axis.color
      height:     axis.r_len
      transform:  a_func()
      stroke:     axis.color
      width:      2
      x:          axis.x_beg
      y:          axis.y_beg

    svg.append('rect')
      .call(set_attrs, axis_attrs)
      .append('title').text(axis.title)


  edge_dir: (axes, edge) ->
  #
  # Find the edge direction, given the axes hash and an edge

    edge_dir_h( axes[ edge[0] ].angle,
                axes[ edge[2] ].angle )


  edge_dir_h: (a_beg, a_end) ->
  #
  # Find the edge direction, given a pair (beginning, end) of angles.

    diff  = a_end - a_beg
    abs   = Math.abs(diff)
    tmp   = if diff < 0 then -1 else 1
    if abs < 180 then tmp else -tmp


  edge_path: (edge, axes, cp_off) ->
  #
  # Create an SVG path (between the relevant axes) for this edge.

    edge_dir    = edge[5]

    end_points  = (end_key) ->
    #
    # Calculate the edge's intersection and control points (ip, cp),
    # based on end_key.  cp is on the normal to the axis, near ip.

      if end_key == 'from' then [ dir, ndx ] = [  edge_dir, 0 ]
      else                      [ dir, ndx ] = [ -edge_dir, 2 ]

      name    = edge[ndx]
      start   = edge[ndx+1]
      axis    = axes[name]
      x_ip    = axis.x_beg + start * axis.x_len
      y_ip    = axis.y_beg + start * axis.y_len
      x_off   = cp_off * axis.y_mul
      y_off   = cp_off * axis.x_mul
      x_cp    = x_ip + x_off * dir
      y_cp    = y_ip - y_off * dir
      [ [ x_ip, y_ip ], [ x_cp, y_cp ] ]

    from  = end_points('from')
    to    = end_points('to').reverse()
    out   = from.concat(to)


  set_attrs: (object, hash) ->
  #
  # Set an object's attributes, based on a hash.

    object.attr(key, val) for key, val of hash


# Make functions global.

window[key] = val for key, val of functions

main.coffee

# main.coffee

do ->

  # Create the SVG area.

  svg = d3.select('#chart').append('svg:svg')
    .attr('width',  350)
    .attr('height', 350)

  # Create the axes.

  axes        = {}
  axes.foo    = { angle:  0,  color: '#666',    title: 'foo'   }
  axes.bar    = { angle: 120,  color: '#666',  title: 'bar' }
  axes.baz    = { angle: 240,  color: '#666',   title: 'baz'  }

  axis.r_beg  =  20 for name, axis of axes
  axis.r_len  = 100 for name, axis of axes

  draw_axis(axis, svg) for name, axis of axes

  # Create the splines.

  edges1 = (['foo', Math.random(), 
            'bar', Math.random(), 
            'rgba(0,0,0,0.05)'] for i in [1..300])
  edges2 = (['bar', Math.random(), 
            'baz', Math.sqrt(Math.random()), 
            'rgba(0,0,0,0.05)'] for i in [1..300])
  edges3 = (['baz', Math.sqrt(Math.random()), 
            'foo', Math.pow(Math.random(), 3),
            'rgba(0,0,0,0.05)'] for i in [1..300])

  edges = [].concat edges1, edges2, edges3

  # Figure out edge directions.

  edge.push( edge_dir(axes, edge) ) for edge in edges

  # Create some paths.

  cp_off  = 30  # control point offset, in pixels

  paths   = ( edge_path(edge, axes, cp_off) for edge in edges )

  df = d3.svg.line()
         .x( (d) -> d[0] )
         .y( (d) -> d[1] )
         .interpolate('cardinal')
         .tension(15)

  svg.selectAll('path.edge')
    .data(paths)
    .enter()
    .append('svg:path')
    .attr('d', df )
    .attr('stroke', (d,i) -> edges[i][4] )