let n_rows = 20,
    n_cols = 20,
    cells = d3.cross(d3.range(n_rows), d3.range(n_cols), (row, col) => {
        return {"row": row, "col": col, "datum": Math.random()};
    });

// static and scroll-able plots
createPlot("static", cells);
createPlot("trans", cells);

// scroll event listener 
d3.select("#scroll_overlay")
  .on("wheel", translatePlot);

function createPlot(plot_type, data) {
    addGrid(plot_type);
    addCells(plot_type, data);
}

function addGrid(plot_type) {
    d3.select("#plot_" + plot_type)
      .append("div")
      .attr("class", "grid")
      .attr("id", "grid_" + plot_type);
}

function addCells(plot_type, data) {
    d3.select("#grid_" + plot_type)
      .selectAll("div")
      .data(data)
      .enter()
      .append("div")
      .attr("class", "cell")
      .style("left", cell => (cell.col * 17) + "px")
      .style("top", cell => (cell.row * 17) + "px")
      .style("background", cell => {
          if (plot_type == "static") {
              return cell.datum < 0.10 ? d3.interpolateViridis(Math.random()) : "lightgrey"; 
          } else {
              return cell.datum > 0.90 ? d3.interpolateViridis(Math.random()) : "lightgrey"; 
          } 
      });
}

function translatePlot() {

    // prevent default scrolling of browser window 
    d3.event.preventDefault();     

    let wheel_delta = d3.event.wheelDelta,
        coords_re = /-?\d+/g,
        ty = d3.select("#plot_trans")
               .style("transform")
               .match(coords_re)
               .pop(),     // last value is y translation; ref[1]
        plot_y_pos = ty - wheel_delta;

    // only scroll plot upwards from initial position and to a limited dist.
    if (plot_y_pos < 50 && plot_y_pos >= -250) {
        d3.select("#plot_trans")
          .style("transform", "translate(100px, " + plot_y_pos + "px)");
    }
}

// REFERENCES 
// [1] https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix