block by HarryStevens 81e7699d43b2373ba805e23c5eafa21e

Grid Generator

Full Screen

Make a grid of n cells. Uses my handy data2grid library.

index.html

<!DOCTYPE html>
<html>
<head>
  <style>
  body {
    margin: 0 auto;
    display: table;
    font-family: "Helvetica Neue", sans-serif;
  }
  button {
    margin: auto;
    display: table;
    margin-bottom: 10px;
  }
  rect.selected {
    stroke: #000;
    stroke-width: 2px;
  }
  .axis .domain {
    display: none;
  }
  .axis .tick text.selected {
    font-weight: bold;
    font-size: 1.2em;
    fill: #47ff63;
  }
  .axis .tick line.selected {
	  stroke: #47ff63;	
  }
  .tip {
    position: absolute;
    font-size: .8em;
    text-align: center;
    text-shadow: -1px -1px 1px #ffffff, -1px 0px 1px #ffffff, -1px 1px 1px #ffffff, 0px -1px 1px #ffffff, 0px 1px 1px #ffffff, 1px -1px 1px #ffffff, 1px 0px 1px #ffffff, 1px 1px 1px #ffffff;
  }
  </style>
</head>
<body>
  <button id="new">New grid</button>
  <div id="grid"></div>
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://unpkg.com/jeezy@1.11.2/lib/jeezy.min.js"></script>
  <script src="https://unpkg.com/data2grid@1.0.0/build/data2grid.min.js"></script>
  <script>
  d3.select("body").append("div").attr("class", "tip").style("display", "none");

  var first_time = true;

  var margin = {top: 20, bottom: 1, left: 20, right: 1};

  var dim = d3.min([window.innerWidth * .9, window.innerHeight * .9]);

  var width = dim - margin.left - margin.right, height = dim - margin.top - margin.bottom;

  var svg = d3.select("#grid").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 padding = .1;

  var x = d3.scaleBand()
    .range([0, width])
    .paddingInner(padding);

  var y = d3.scaleBand()
    .range([0, height])
    .paddingInner(padding);

  var x_axis = d3.axisTop(y);
  var y_axis = d3.axisLeft(x);

  svg.append("g")
      .attr("class", "x axis")
      .call(x_axis);

  svg.append("g")
      .attr("class", "y axis")
      .call(y_axis);

  function generateData(){
    var data = [];

    ["steelblue", "tomato", "lightgrey"].forEach(function(color){
      for (var i = 0; i < (first_time ? 147 : jz.num.randBetween(10, 3000)); i++){
        data.push({color: color});
      }
    });

    data.forEach(function(d, i){
      d.id = i;
      return d;
    });

    if (first_time) first_time = false;
    return data;
  }

  draw(generateData());

  d3.select("button").on("click", function(){
    draw(generateData());
  });

  function draw(data){

    var grid = data2grid.grid(data);
    var rows = d3.max(grid, function(d){ return d.row; });
    
    x.domain(d3.range(1, rows + 1));
    y.domain(d3.range(1, rows + 1));

    d3.select(".x.axis").transition().call(x_axis);
    d3.select(".y.axis").transition().call(y_axis)

    var square = svg.selectAll("rect")
        .data(grid, function(d){ return d.id; });

    square.exit()
      .transition()
        .style("opacity", 1e-6)
        .remove();

    square
      .transition()
        .attr("x", function(d){ return x(d.column); })
        .attr("y", function(d){ return y(d.row); })
        .attr("width", x.bandwidth())
        .attr("height", y.bandwidth())
        .style("fill", function(d){ return d.color; });

    square.enter().append("rect")
        .attr("x", function(d){ return x(d.column); })
        .attr("y", function(d){ return y(d.row); })
        .attr("width", x.bandwidth())
        .attr("height", y.bandwidth())
        .style("fill", function(d){ return d.color; })
        .style("opacity", 1e-6)
      .transition()
        .style("opacity", 1)

    d3.selectAll("rect")
      .on("mouseover", function(d){
        
        d3.select(this).classed("selected", true);

        d3.select(".tip")
            .style("display", "block")
            .html("Row: " + d.row + "<br />Column: " + d.column);

        var row_pos = y(d.row);
        var col_pos = x(d.column);
        var tip_pos = d3.select(".tip").node().getBoundingClientRect();
        var tip_width = tip_pos.width;
        var tip_height = tip_pos.height;
        var grid_pos = d3.select("#grid").node().getBoundingClientRect();
        var grid_left = grid_pos.left;
        var grid_top = grid_pos.top;

        var left = grid_left + col_pos + margin.left + (x.bandwidth() / 2) - (tip_width / 2);
        var top = grid_top + row_pos + margin.top - tip_height - 5;

        d3.select(".tip")
            .style("left", left + "px")
            .style("top", top + "px");

        d3.select(".x.axis .tick:nth-of-type(" + d.column + ") text").classed("selected", true);
        d3.select(".y.axis .tick:nth-of-type(" + d.row + ") text").classed("selected", true);
        d3.select(".x.axis .tick:nth-of-type(" + d.column + ") line").classed("selected", true);
        d3.select(".y.axis .tick:nth-of-type(" + d.row + ") line").classed("selected", true);

      })
      .on("mouseout", function(){
        d3.selectAll("rect").classed("selected", false);
        d3.select(".tip").style("display", "none");
        d3.selectAll(".axis .tick text").classed("selected", false);
        d3.selectAll(".axis .tick line").classed("selected", false);
      });

  }
  </script>

</body>
</html>