tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

canvas-utils.js (3846B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /**
      8 * Create 2 canvases and contexts for drawing onto, 1 main canvas, and 1 zoom
      9 * canvas. The main canvas dimensions match the parent div, but the CSS can be
     10 * transformed to be zoomed and dragged around (potentially creating a blurry
     11 * canvas once zoomed in). The zoom canvas is a zoomed in section that matches
     12 * the parent div's dimensions and is kept in place through CSS. A zoomed in
     13 * view of the visualization is drawn onto this canvas, providing a crisp zoomed
     14 * in view of the tree map.
     15 */
     16 const { debounce } = require("resource://devtools/shared/debounce.js");
     17 const EventEmitter = require("resource://devtools/shared/event-emitter.js");
     18 
     19 const HTML_NS = "http://www.w3.org/1999/xhtml";
     20 const FULLSCREEN_STYLE = {
     21  width: "100%",
     22  height: "100%",
     23  position: "absolute",
     24 };
     25 
     26 /**
     27 * Create the canvases, resize handlers, and return references to them all
     28 */
     29 class Canvases extends EventEmitter {
     30  /**
     31   *
     32   * @param  {HTMLDivElement} parentEl
     33   * @param  {number} debounceRate
     34   */
     35  constructor(parentEl, debounceRate) {
     36    super();
     37 
     38    this.container = createContainingDiv(parentEl);
     39 
     40    // This canvas contains all of the treemap
     41    this.main = createCanvas(this.container, "main");
     42    // This canvas contains only the zoomed in portion, overlaying the main canvas
     43    this.zoom = createCanvas(this.container, "zoom");
     44 
     45    this.removeHandlers = handleResizes(this, debounceRate);
     46  }
     47  /**
     48   * Remove the handlers and elements
     49   *
     50   * @return {type}  description
     51   */
     52  destroy() {
     53    this.removeHandlers();
     54    this.container.removeChild(this.main.canvas);
     55    this.container.removeChild(this.zoom.canvas);
     56  }
     57 }
     58 
     59 module.exports = Canvases;
     60 
     61 /**
     62 * Create the containing div
     63 *
     64 * @param  {HTMLDivElement} parentEl
     65 * @return {HTMLDivElement}
     66 */
     67 function createContainingDiv(parentEl) {
     68  const div = parentEl.ownerDocument.createElementNS(HTML_NS, "div");
     69  Object.assign(div.style, FULLSCREEN_STYLE);
     70  parentEl.appendChild(div);
     71  return div;
     72 }
     73 
     74 /**
     75 * Create a canvas and context
     76 *
     77 * @param  {HTMLDivElement} container
     78 * @param  {string} className
     79 * @return {object} { canvas, ctx }
     80 */
     81 function createCanvas(container, className) {
     82  const window = container.ownerDocument.defaultView;
     83  const canvas = container.ownerDocument.createElementNS(HTML_NS, "canvas");
     84  container.appendChild(canvas);
     85  canvas.width = container.offsetWidth * window.devicePixelRatio;
     86  canvas.height = container.offsetHeight * window.devicePixelRatio;
     87  canvas.className = className;
     88 
     89  Object.assign(canvas.style, FULLSCREEN_STYLE, {
     90    pointerEvents: "none",
     91  });
     92 
     93  const ctx = canvas.getContext("2d");
     94 
     95  return { canvas, ctx };
     96 }
     97 
     98 /**
     99 * Resize the canvases' resolutions, and fires out the onResize callback
    100 *
    101 * @param  {HTMLDivElement} container
    102 * @param  {object} canvases
    103 * @param  {number} debounceRate
    104 */
    105 function handleResizes(canvases, debounceRate) {
    106  const { container, main, zoom } = canvases;
    107  const window = container.ownerDocument.defaultView;
    108 
    109  function resize() {
    110    const width = container.offsetWidth * window.devicePixelRatio;
    111    const height = container.offsetHeight * window.devicePixelRatio;
    112 
    113    main.canvas.width = width;
    114    main.canvas.height = height;
    115    zoom.canvas.width = width;
    116    zoom.canvas.height = height;
    117 
    118    canvases.emit("resize");
    119  }
    120 
    121  // Tests may not need debouncing
    122  const debouncedResize =
    123    debounceRate > 0 ? debounce(resize, debounceRate) : resize;
    124 
    125  window.addEventListener("resize", debouncedResize);
    126  resize();
    127 
    128  return function removeResizeHandlers() {
    129    window.removeEventListener("resize", debouncedResize);
    130  };
    131 }