D3 Stack Layout Experiments

by ramnathv

HTML

<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//rawgit.com/jrideout/melt.js/master/melt.js"></script>
<svg></svg>
<button id="update">Dodge</button>
<button id="update2">Stack</button>

CoffeeScript

dataset = [
  { apples: 5, oranges: 10, grapes: 22, id: 1 },
  { apples: 4, oranges: 12, grapes: 28, id: 2 },
  { apples: 2, oranges: 19, grapes: 32, id: 3 },
  { apples: 7, oranges: 23, grapes: 35, id: 4 },
  { apples: 23, oranges: 17, grapes: 43, id: 5}
];

data_m = melt(dataset, ["id"], varName = "x", valName = "y")

data_2 = d3.nest()
  .key((d) -> d.x)
  .map(data_m)
    
data_2 = d3.values(data_2)

stack = d3.layout.stack()
 
data_3 = stack(data_2)

console.log JSON.stringify(d3.merge(data_2))

width = 600
height = 400
margin = {left: 20, right: 20, bottom: 20, top: 20}
svg = d3.select("svg")
  .attr("width", width + margin.left + margin.bottom)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(#{margin.left}, #{margin.top})")
    
S =
  x: d3.scale.ordinal().rangeRoundBands([0, width], 0)
  y: d3.scale.linear().range([height, 0])
    
# FIXME: make domains data dependent
# S.x.domain(d3.range(5))
S.x.domain(d3.range(5))
S.y.domain([0, 90])

S.c = d3.scale.category20()
   .domain(["apples", "oranges", "grapes"])

A = 
  x: (d) -> d._id
  

rectAttrs = 
  x: (d) -> S.x A.x d
  y: (d) -> S.y(d.y + d.y0)
  width: (d) -> S.x.rangeBand()
  height: (d) -> S.y(d.y0) - S.y(d.y + d.y0)
  stroke: "black"
  fill: (d) -> S.c(d.x)


data_4 = d3.merge(data_2)
data_4.sort((a, b) -> 
   d3.ascending(a._id, b._id) or
   d3.ascending(a.x, b.x)
)
 
rect = svg.selectAll("rect")
  .data(data_4).enter()
  .append("rect")
  .attr(rectAttrs)
    
rectAttrs2 = 
  x: (d, i) -> S.x i
  y: (d) -> S.y(d.y)
  width: S.x.rangeBand()
  height: (d) -> S.y(0) - S.y(d.y)
  fill: (d) -> S.c(d.x)
    
d3.select("#update").on "click", ->
  S.x.domain(d3.range(15))
  rectAttrs2.width = S.x.rangeBand()
  rect.data(data_4)
    .transition()
    .delay((d, i) -> Math.floor(i/3)/5*750)
    .attr
      x: (d, i) -> S.x i
      width: S.x.rangeBand()
    #.transition().duration(750)
    .attr
      height: (d) -> S.y(0) - S.y(d.y)
      y: (d) ->...