<!DOCTYPE html>
<html>

  <head>
    <link rel="stylesheet" href="style.css">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="script.js"></script>    
  </head>

  <body>
    <h1>D3.js - <a href="http://bl.ocks.org/mbostock/3048450">Histogram example</a> extended to show Multiple Histograms  with pre-computed histogram bins from JSON data</h1>
  </body>

</html>
// Get pre-computed histogram data
d3.json("data.json", function(json) {
  
  var maxBin = 40;
  var binInc = 10;

  // transform data that is already binned into data
  // that is better for use in D3
  // we want to create something like this:
  // [
  //  { "x": 0,  "y": 30000 },
  //  { "x": 10, "y": 80000 },
  //  ...
  // ]
  // 
  for( var i = 0; i < json.length; i++) {
    
    // use the name of the group to initialize the array
    var group = json[i].name;
    var data = [];
    
    // we have a max bin for our histogram, must ensure
    // that any bins > maximum bin are rolled into the 
    // last bin that we have
    var binCounts = {};
    for( var j = 0; j < json[i].data.length; j++) {
      var xValue = json[i].data[j].bin;
      // bin cannot exceed the maximum bin
      xValue = ( xValue > maxBin ? maxBin : xValue);
      var yValue = json[i].data[j].count;
      
      if(binCounts[xValue] === undefined) {
        binCounts[xValue] = 0;
      }
      binCounts[xValue] += yValue;
    }
    
    // add the bin counts in
    for( var bin in binCounts) {
      data.push({"x": bin, "y": binCounts[bin]});
    }
    
    // add the histogram
    createHistogram(data, maxBin, binInc, group.toUpperCase())
  }
  
});

var createHistogram = function(data, maxBin, binInc, title) {

  // A formatter for counts.
  var formatCount = d3.format(",.0f");
  var totalWidth = 480;
  var totalHeight = 240;
  var margin = {top: 40, right: 60, bottom: 50, left: 70},
      width = totalWidth - margin.left - margin.right,
      height = totalHeight - margin.top - margin.bottom;
  
  var binArray = [];
  for (var i = 0; i <= maxBin + binInc; i += binInc) {
    binArray.push(i);
  }
  var binTicks = [];
  for (var i = 0; i < maxBin + binInc; i += binInc) {
    binTicks.push(i);
  }
  
  var x = d3.scale.linear()
      .domain([0, maxBin + binInc])
      .range([0, width]);
  var binWidth = parseFloat(width / (binArray.length - 1)) - 1;
  
  var y = d3.scale.linear()
      .domain([0, d3.max(data, function(d) { return d.y; })])
      .range([height, 0]);
  
  var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")
      .tickValues(binTicks);
      
  var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left");
  
  var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  
  var bar = svg.selectAll(".bar")
      .data(data)
      .enter()
      .append("rect")
      .attr("class", "bar")
      .attr("x", function(d) { return x(d.x); })
      .attr("width", binWidth)
      .attr("y", function(d) { return y(d.y); })
      .attr("height", function(d) { return height - y(d.y); })
      .on("mouseover", function(d) {
        var barWidth = parseFloat(d3.select(this).attr("width"));
        var xPosition = parseFloat(d3.select(this).attr("x")) + (barWidth / 2);
        var yPosition = parseFloat(d3.select(this).attr("y")) - 10;
        
        svg.append("text")
          .attr("id", "tooltip")
          .attr("x", xPosition)
          .attr("y", yPosition)
          .attr("text-anchor", "middle")
          .text(d.y);
      })
      .on("mouseout", function(d) {
        d3.select('#tooltip').remove();
      });
  
  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
      
  svg.append("g")
      .attr("class", "y axis")
      //.attr("transform", "translate(0," + height + ")")
      .call(yAxis);
      
  // Add axis labels
  svg.append("text")
      .attr("class", "x label")
      .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom - 15) + ")")
      //.attr("dy", "1em")
      .attr("text-anchor", "middle")
      .text("Time (minutes)");
      
  svg.append("text")
      .attr("class", "y label")
      .attr("transform", "rotate(-90)")
      .attr("y", 0 - margin.left)
      .attr("x", 0 - (height / 2))
      .attr("dy", "1em")
      .attr("text-anchor", "middle")
      .text("Count");
      
  // Add title to chart
  svg.append("text")
      .attr("class", "title")
      .attr("transform", "translate(" + (width / 2) + " ," + (-20) + ")")
      //.attr("dy", "1em")
      .attr("text-anchor", "middle")
      .text(title);  
};

body {
  font: 10px sans-serif;
}

.bar {
  fill: steelblue;
  shape-rendering: crispEdges;
}

.bar text {
  fill: #000;
}

.axis path, .axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.title {
  font-size: 14px;
}
[
  {
    "name": "A",
    "data":[
      {
        "bin": 0,
        "count": 30000
      },
      {
        "bin": 10,
        "count": 80000
      },
      {
        "bin": 20,
        "count": 180000
      },
      {
        "bin": 30,
        "count": 40000
      },
      {
        "bin": 40,
        "count": 40000
      },
      {
        "bin": 50,
        "count": 40000
      }
    ]
  },
  {
    "name": "B",
    "data":[
      {
        "bin": 0,
        "count": 90000
      },
      {
        "bin": 10,
        "count": 80000
      },
      {
        "bin": 20,
        "count": 10000
      },
      {
        "bin": 30,
        "count": 140000
      },
      {
        "bin": 40,
        "count": 140000
      },
      {
        "bin": 50,
        "count": 80000
      }
    ]
  },
  {
    "name": "C",
    "data":[
      {
        "bin": 0,
        "count": 10000
      },
      {
        "bin": 10,
        "count": 20000
      },
      {
        "bin": 20,
        "count": 120000
      },
      {
        "bin": 30,
        "count": 150000
      },
      {
        "bin": 40,
        "count": 130000
      },
      {
        "bin": 50,
        "count": 70000
      }
    ]
  }  
]