block by emeeks e0d32d1d39c6cd045bd2

Ch. 10, Fig. 5 - D3.js in Action

Full Screen

This is the code for Chapter 10, Figure 5 from D3.js in Action showing how a layout like d3.layout.grid() can be used to create different graphical elements, in this case SVG rect elements instead of SVG circles as in earlier examples.

index.html

<html>
<head>
  <title>D3 in Action Chapter 10 - Example 3</title>
  <meta charset="utf-8" />
<script src="//d3js.org/colorbrewer.v1.min.js" type="text/JavaScript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
</head>
<style>
  svg {
    height: 500px;
    width: 500px;
    border: 1px solid gray;
  }
</style>
<body>
  <div id="viz">
  <svg></svg>
</div>
</body>
  <footer>
    
<script>
  
  d3.json("tweets.json", function(error, data) {
      makeAGrid(data);
    })
  
  function makeAGrid(data) {
    var grid = d3.layout.grid();
    grid.size([400,400]);
    var griddedData = grid(data.tweets);

    d3.select("svg")
    .append("g")
    .attr("transform", "translate(50,50)")
    .selectAll("circle").data(griddedData)
    .enter()
    .append("rect")
    .attr("x", function(d) {return d.x - (d.width / 2)})
    .attr("y", function(d) {return d.y - (d.height / 2)})
    .attr("width", function(d) {return d.width})
    .attr("height", function(d) {return d.height})
    .style("fill", "pink")
    
    var fakeTweets = []
    for (x = 0;x<12;x++) {
      var tweet = {id: x, content: "Fake Tweet #" + x};
      fakeTweets.push(tweet);
    }
      var doubledArray = data.tweets.concat(fakeTweets);
    
      var newGriddedData = grid(doubledArray);

    d3.select("g").selectAll("rect").data(newGriddedData)    
    .enter()
    .append("rect")
    .attr("x", 0)
    .attr("y", 0)
    .style("fill", "darkred");

    d3.select("g").selectAll("rect")
    .transition()
    .duration(1000)
    .attr("x", function(d) {return d.x - (d.width / 2)})
    .attr("y", function(d) {return d.y - (d.height / 2)})
    .attr("width", function(d) {return d.width})
    .attr("height", function(d) {return d.height})
    .each("end", resizeGrid1)
    
    function resizeGrid1() {
      grid.size([200,200])
      grid(doubledArray)
      
      d3.select("g").selectAll("rect")
        .transition()
        .duration(1000)
    .attr("x", function(d) {return d.x - (d.width / 2)})
    .attr("y", function(d) {return d.y - (d.height / 2)})
    .attr("width", function(d) {return d.width})
    .attr("height", function(d) {return d.height})
    .each("end", resizeGrid2)
    }
    
    function resizeGrid2() {
      grid.size([200,400])
      grid(doubledArray)
      
      d3.select("g").selectAll("rect")
        .transition()
        .duration(1000)
    .attr("x", function(d) {return d.x - (d.width / 2)})
    .attr("y", function(d) {return d.y - (d.height / 2)})
    .attr("width", function(d) {return d.width})
    .attr("height", function(d) {return d.height})
    }

  }
  
  d3.layout.grid = function() {
  var gridSize = [10,10];
  var gridCellWidth;
  var gridCellHeight;
  var gridXScale = d3.scale.linear();
  var gridYScale = d3.scale.linear();

    function processGrid(data) {

      var rows = Math.ceil(Math.sqrt(data.length));
      var columns = Math.ceil(Math.sqrt(data.length));
      gridCellWidth = gridSize[0] / columns;
      gridCellHeight = gridSize[1] / rows;

      gridXScale.domain([1,columns]).range([0,gridSize[0]]);
      gridYScale.domain([1,rows]).range([0,gridSize[1]]);

      var x = 0;

        for (i = 1; i <= rows; i++) { 
          for (j = 1; j <= columns; j++) {
            if (data[x]) {
              data[x].x = gridXScale(j);
              data[x].y = gridYScale(i);
              data[x].height = gridCellHeight;
              data[x].width = gridCellWidth;
              x++;
            }
            else {
              break;
            }
          }
        }
      
      return data;
    }
    
    processGrid.size = function(newSize) {
      	if (!arguments.length) return gridSize;

        gridSize = newSize;
        return this;
    }

    return processGrid;
  }
</script>
  </footer>

</html>

tweets.json

{
"tweets": [
{"user": "Al", "content": "I really love seafood.", "timestamp": " Mon Dec 23 2013 21:30 GMT-0800 (PST)", "retweets": ["Raj","Pris","Roy"], "favorites": ["Sam"]},
{"user": "Al", "content": "I take that back, this doesn't taste so good.", "timestamp": "Mon Dec 23 2013 21:55 GMT-0800 (PST)", "retweets": ["Roy"], "favorites": []},
{"user": "Al", "content": "From now on, I'm only eating cheese sandwiches.", "timestamp": "Mon Dec 23 2013 22:22 GMT-0800 (PST)", "retweets": [], "favorites": ["Roy","Sam"]},
{"user": "Roy", "content": "Great workout!", "timestamp": " Mon Dec 23 2013 7:20 GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Spectacular oatmeal!", "timestamp": " Mon Dec 23 2013 7:23 GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Amazing traffic!", "timestamp": " Mon Dec 23 2013 7:47  GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Just got a ticket for texting and driving!", "timestamp": " Mon Dec 23 2013 8:05 GMT-0800 (PST)", "retweets": [], "favorites": ["Sam", "Sally", "Pris"]},
{"user": "Pris", "content": "Going to have some boiled eggs.", "timestamp": " Mon Dec 23 2013 18:23 GMT-0800 (PST)", "retweets": [], "favorites": ["Sally"]},
{"user": "Pris", "content": "Maybe practice some gymnastics.", "timestamp": " Mon Dec 23 2013 19:47  GMT-0800 (PST)", "retweets": [], "favorites": ["Sally"]},
{"user": "Sam", "content": "@Roy Let's get lunch", "timestamp": " Mon Dec 23 2013 11:05 GMT-0800 (PST)", "retweets": ["Pris"], "favorites": ["Sally", "Pris"]}
]
}