summaryrefslogtreecommitdiffstats
path: root/devtools/client/memory/components/tree-map/canvas-utils.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/memory/components/tree-map/canvas-utils.js')
-rw-r--r--devtools/client/memory/components/tree-map/canvas-utils.js134
1 files changed, 134 insertions, 0 deletions
diff --git a/devtools/client/memory/components/tree-map/canvas-utils.js b/devtools/client/memory/components/tree-map/canvas-utils.js
new file mode 100644
index 000000000..c7d67a0bf
--- /dev/null
+++ b/devtools/client/memory/components/tree-map/canvas-utils.js
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+/**
+ * Create 2 canvases and contexts for drawing onto, 1 main canvas, and 1 zoom
+ * canvas. The main canvas dimensions match the parent div, but the CSS can be
+ * transformed to be zoomed and dragged around (potentially creating a blurry
+ * canvas once zoomed in). The zoom canvas is a zoomed in section that matches
+ * the parent div's dimensions and is kept in place through CSS. A zoomed in
+ * view of the visualization is drawn onto this canvas, providing a crisp zoomed
+ * in view of the tree map.
+ */
+const { debounce } = require("sdk/lang/functional");
+const EventEmitter = require("devtools/shared/event-emitter");
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+const FULLSCREEN_STYLE = {
+ width: "100%",
+ height: "100%",
+ position: "absolute",
+};
+
+/**
+ * Create the canvases, resize handlers, and return references to them all
+ *
+ * @param {HTMLDivElement} parentEl
+ * @param {Number} debounceRate
+ * @return {Object}
+ */
+function Canvases(parentEl, debounceRate) {
+ EventEmitter.decorate(this);
+ this.container = createContainingDiv(parentEl);
+
+ // This canvas contains all of the treemap
+ this.main = createCanvas(this.container, "main");
+ // This canvas contains only the zoomed in portion, overlaying the main canvas
+ this.zoom = createCanvas(this.container, "zoom");
+
+ this.removeHandlers = handleResizes(this, debounceRate);
+}
+
+Canvases.prototype = {
+
+ /**
+ * Remove the handlers and elements
+ *
+ * @return {type} description
+ */
+ destroy : function () {
+ this.removeHandlers();
+ this.container.removeChild(this.main.canvas);
+ this.container.removeChild(this.zoom.canvas);
+ }
+};
+
+module.exports = Canvases;
+
+/**
+ * Create the containing div
+ *
+ * @param {HTMLDivElement} parentEl
+ * @return {HTMLDivElement}
+ */
+function createContainingDiv(parentEl) {
+ let div = parentEl.ownerDocument.createElementNS(HTML_NS, "div");
+ Object.assign(div.style, FULLSCREEN_STYLE);
+ parentEl.appendChild(div);
+ return div;
+}
+
+/**
+ * Create a canvas and context
+ *
+ * @param {HTMLDivElement} container
+ * @param {String} className
+ * @return {Object} { canvas, ctx }
+ */
+function createCanvas(container, className) {
+ let window = container.ownerDocument.defaultView;
+ let canvas = container.ownerDocument.createElementNS(HTML_NS, "canvas");
+ container.appendChild(canvas);
+ canvas.width = container.offsetWidth * window.devicePixelRatio;
+ canvas.height = container.offsetHeight * window.devicePixelRatio;
+ canvas.className = className;
+
+ Object.assign(canvas.style, FULLSCREEN_STYLE, {
+ pointerEvents: "none"
+ });
+
+ let ctx = canvas.getContext("2d");
+
+ return { canvas, ctx };
+}
+
+/**
+ * Resize the canvases' resolutions, and fires out the onResize callback
+ *
+ * @param {HTMLDivElement} container
+ * @param {Object} canvases
+ * @param {Number} debounceRate
+ */
+function handleResizes(canvases, debounceRate) {
+ let { container, main, zoom } = canvases;
+ let window = container.ownerDocument.defaultView;
+
+ function resize() {
+ let width = container.offsetWidth * window.devicePixelRatio;
+ let height = container.offsetHeight * window.devicePixelRatio;
+
+ main.canvas.width = width;
+ main.canvas.height = height;
+ zoom.canvas.width = width;
+ zoom.canvas.height = height;
+
+ canvases.emit("resize");
+ }
+
+ // Tests may not need debouncing
+ let debouncedResize = debounceRate > 0
+ ? debounce(resize, debounceRate)
+ : resize;
+
+ window.addEventListener("resize", debouncedResize, false);
+ resize();
+
+ return function removeResizeHandlers() {
+ window.removeEventListener("resize", debouncedResize, false);
+ };
+}