Stacked Bars

by ramnathv

HTML

<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//rawgit.com/gka/d3-jetpack/master/d3-jetpack.js"></script>
<script src="//rawgit.com/kristw/75b61f9beeab9b530612/raw/389e984e4041117a9185cf6edad9f6b85a38097a/d3kit.min.js"></script>
<script src="//rawgit.com/DarkMarmot/kodama/master/kodama.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="//cdn.rawgit.com/ramnathv/a5a3199538f86817ec1b/raw/96dde67abbf386b571d62dc366f15dc057085092/visutils.js"></script>
<div class="container-fluid" id="main">
    <div class="row">
        <div class="col-xs-12 col-md-3">
          <div id="chart"></div>
          <div class="btn-group" role="group" aria-label="...">
          <button class="btn btn-default active g1" data-option='stack'>
              Stack
          </button> 
          <button class="btn btn-default g2" data-option='stack'>
             Dodge
          </button>
               <button class="btn btn-default g1" data-option='separate'>
              Separate
          </button>
            </div>
        </div>
    </div>
</div>

CSS

.btn-group{
  display: 'block';
}

CoffeeScript

alphabet = (i) -> String.fromCharCode(i + 65)
make_data = (N) ->
  d3.range(N).map (i) -> 
    x: alphabet(i), y1: (i + 1), y2: (i + 1)*1.5, y3: (i + 1)*2
    
mydata = make_data(5)

d1 = ['y1', 'y2', 'y3'].map (k) ->
  mydata.map (d) ->
    {x: d.x, y: d[k]}
    

stackedBarConstructor = (skeleton) ->
  layers = skeleton.getLayerOrganizer()
  S =
    x: d3.scale.ordinal()
    y: d3.scale.linear()
    c: d3.scale.category20()
    
  A = 
    x: (d) -> d.x
    y: (d) -> d.y
    y0: (d) -> d.y0
  layers.create(['bars'])
  visualize = ->
    data = skeleton.data()
    opts = skeleton.options()
    H = skeleton.getInnerHeight()
    W = skeleton.getInnerWidth()
    
    S.x.rangeRoundBands([0, W], 0.05)
      .domain(d3.range(5).map(alphabet))
    S.y.range([H, 0])
      .domain([0, 40])
 
    rows = layers.get('bars').selectAll('.row')
      .data(data)
    rows.enter().append('g.row')
      .style
        fill: (d, i) -> S.c(i)
        stroke: 'whitesmoke'
        
    yAccessor = 
      stack: (i) -> (d) -> S.y(A.y(d) + A.y0(d))
      separate: (i) -> (d) -> S.y(A.y(d)) - 100*i
        
    rects = rows.selectAll('rect.bar')
      .data(Object)
    rects.enter().append('rect.bar')
    rects
      .attr
        x: (d) -> S.x A.x(d)
        width: S.x.rangeBand()
        y: (d) -> S.y(A.y(d) + A.y0(d))
        height: (d) -> -S.y(A.y(d) + A.y0(d)) + S.y(A.y0(d))
     
    d3.selectAll('.g1').on 'click', ->
       d3.selectAll('.btn').classed('active', false)
       opt = d3.select(@)
         .classed('active', true)
         .attr('data-option')
       #rows = d3.selectAll('g.row')
       ###
       rows.selectAll('rect.bar')
         .transition()
         .attr
            y: (d, i) -> yAccessor[opt](i)
         .transition()
         .attr
            x: (d) -> S.x A.x(d)
            width: S.x.rangeBand()
       ###
       rows.each (d, i) ->
         d3.select(@).selectAll('rect.bar')
          .transition()
          #.delay((d, i) -> i/5*750)
          .attr
...