Source: PlotGlass.js

import DrawRegion from "DrawRegion";
import Stats from "Stats";
import cfg from "Config"
export default PlotGlass;

/**
 * @constructor
 * @description
 *
 * This class creates a webGl context which is transparent to mouse clicks, sizes and positions it to cover the entire
 * browser window. The webGl context is referred to as "glass", and it's position is fixed - it does not scroll with the
 * document.
 *
 */
function PlotGlass(){

  /** List of DOM elements to render within */
  this._plots = [];
  this._running = false;
  this._stats = new Stats();
}

PlotGlass.prototype = {
  /**
   * Add a plot to render.
   * @param element   Dom element to serve as the bounds for rendering
   * @param plot  PlotGlass DrawRegion to render on the element bounds
   */
  add : function(plot) {

    this._plots.push(plot);

    let parent = plot.element.parentElement;
    while (parent) {
      /** @todo dedupe events */
      parent.addEventListener("scroll", this.scroll.bind(this));
      parent = parent.parentElement;
    }

    this.resize();
  },

  start : function() {

    /* Place a canvas over the whole screen */
    this.canvas = document.createElement("canvas");
    Object.assign(this.canvas.style, {
      position: "fixed",
      top: "0px",
      left: "0px",
      bottom: "0px",
      right: "0px",
      zIndex: "1000",
      pointerEvents: "none",
    });
    document.body.append(this.canvas);

    let resizeTimeout = null;
    window.addEventListener("scroll", this.scroll.bind(this));
    window.addEventListener("resize", ()=>{
      this.resize();
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(this.resize.bind(this), 300);
    });

    let gl = this.gl = this.canvas.getContext("webgl", {
      preserveDrawingBuffer: false
    });
    gl.enable(gl.SCISSOR_TEST);
    gl.clearColor.apply(gl, cfg.CLEAR_COLOR);
    gl.clearDepth(1.0);
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

    this.resize();
    this._stats.startFpsInterval(5);
    this._running = true;
    window.requestAnimationFrame(this._render.bind(this));
  },

  resize: function() {

    if (!this.canvas) {
      /* ignore resize events before canvas is loaded */
      return;
    }

    Object.assign(this.canvas.style, {
      width: `${window.innerWidth}px`,
      height: `${window.innerHeight}px`,
    });

    this.canvas.width = window.innerWidth;
    this.canvas.height = window.innerHeight;

    for (let i = 0; i < this._plots.length; i++ ) {
      let plot = this._plots[i];
      for (let j = 0; j < plot._resizeList.length; j++) {
        plot._resizeList[j].resize();
      }
    }
  },

  scroll: function() {
    for (let i = 0; i < this._plots.length; i++ ) {
      let plot = this._plots[i];
      for (let j = 0; j < plot._scrollList.length; j++) {
        plot._scrollList[j].scroll();
      }
    }
  },

  _render : function() {

    for (let i = 0; i < this._plots.length; i++ ) {
      let plot = this._plots[i];
      for (let j = 0; j < plot._drawList.length; j++) {
        plot._drawList[j].draw(this.gl);
      }
    }

    if (this._running) {
      window.requestAnimationFrame(this._render.bind(this));
    }

    this._stats.recordFrame();

  },

  /**
   * Clear the entire screen.
   */
  _clearScreen : function() {
    this.gl.disable(this.gl.SCISSOR_TEST);
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
    this.gl.enable(this.gl.SCISSOR_TEST);
  }
};