/* 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/. */ // Test the drag and zooming behavior "use strict"; const CanvasUtils = require("resource://devtools/client/memory/components/tree-map/canvas-utils.js"); const DragZoom = require("resource://devtools/client/memory/components/tree-map/drag-zoom.js"); const TEST_URL = "data:text/html,"; const PIXEL_SCROLL_MODE = 0; const PIXEL_DELTA = 10; const MAX_RAF_LOOP = 1000; this.test = makeMemoryTest(TEST_URL, async function ({ panel }) { const panelWin = panel.panelWin; const panelDoc = panelWin.document; const div = panelDoc.createElement("div"); Object.assign(div.style, { width: "100px", height: "200px", position: "absolute", left: 0, top: 0, }); const rafMock = createRAFMock(); panelDoc.body.appendChild(div); const canvases = new CanvasUtils(div, 0); const dragZoom = new DragZoom(canvases.container, 0, rafMock.raf); const style = canvases.container.style; info("Check initial state of dragZoom"); { is(dragZoom.zoom, 0, "Zooming starts at 0"); is(dragZoom.smoothZoom, 0, "Smoothed zooming starts at 0"); is(rafMock.timesCalled, 0, "No RAFs have been queued"); is( style.transform, "translate(0px) scale(1)", "No transforms have been done." ); canvases.container.dispatchEvent( new WheelEvent("wheel", { deltaY: -PIXEL_DELTA, deltaMode: PIXEL_SCROLL_MODE, }) ); is( style.transform, "translate(0px) scale(1.05)", "The div has been slightly scaled." ); is( dragZoom.zoom, PIXEL_DELTA * dragZoom.ZOOM_SPEED, "The zoom was increased" ); ok( floatEquality(dragZoom.smoothZoom, 0.05), "The smooth zoom is between the initial value and the target" ); is(rafMock.timesCalled, 1, "A RAF has been queued"); } info("RAF will eventually stop once the smooth values approach the target"); { let i; let lastCallCount; for (i = 0; i < MAX_RAF_LOOP; i++) { if (lastCallCount === rafMock.timesCalled) { break; } lastCallCount = rafMock.timesCalled; rafMock.nextFrame(); } is( style.transform, "translate(0px) scale(1.1)", "The scale has been fully applied" ); is( dragZoom.zoom, dragZoom.smoothZoom, "The smooth and target zoom values match" ); isnot(MAX_RAF_LOOP, i, "The RAF loop correctly stopped"); } info("Dragging correctly translates the div"); { div.dispatchEvent( new MouseEvent("mousemove", { clientX: 10, clientY: 10, }) ); div.dispatchEvent(new MouseEvent("mousedown")); div.dispatchEvent( new MouseEvent("mousemove", { clientX: 20, clientY: 20, }) ); div.dispatchEvent(new MouseEvent("mouseup")); is( style.transform, "translate(2.5px, 5px) scale(1.1)", "The style is correctly translated" ); ok( floatEquality(dragZoom.translateX, 5), "Translate X moved by some pixel amount" ); ok( floatEquality(dragZoom.translateY, 10), "Translate Y moved by some pixel amount" ); } info("Zooming centers around the mouse"); { canvases.container.dispatchEvent( new WheelEvent("wheel", { deltaY: -PIXEL_DELTA, deltaMode: PIXEL_SCROLL_MODE, }) ); // Run through the RAF loop to zoom in towards that value. let lastCallCount; for (let i = 0; i < MAX_RAF_LOOP; i++) { if (lastCallCount === rafMock.timesCalled) { break; } lastCallCount = rafMock.timesCalled; rafMock.nextFrame(); } is( style.transform, "translate(8.18182px, 18.1818px) scale(1.2)", "Zooming affects the translation to keep the mouse centered" ); ok( floatEquality(dragZoom.translateX, 8.181818181818185), "Translate X was affected by the mouse position" ); ok( floatEquality(dragZoom.translateY, 18.18181818181817), "Translate Y was affected by the mouse position" ); is(dragZoom.zoom, 0.2, "Zooming starts at 0"); } dragZoom.destroy(); info("Scroll isn't tracked after destruction"); { const previousZoom = dragZoom.zoom; const previousSmoothZoom = dragZoom.smoothZoom; canvases.container.dispatchEvent( new WheelEvent("wheel", { deltaY: -PIXEL_DELTA, deltaMode: PIXEL_SCROLL_MODE, }) ); is(dragZoom.zoom, previousZoom, "The zoom stayed the same"); is( dragZoom.smoothZoom, previousSmoothZoom, "The smooth zoom stayed the same" ); } info("Translation isn't tracked after destruction"); { const initialX = dragZoom.translateX; const initialY = dragZoom.translateY; div.dispatchEvent(new MouseEvent("mousedown")); div.dispatchEvent(new MouseEvent("mousemove"), { clientX: 40, clientY: 40, }); div.dispatchEvent(new MouseEvent("mouseup")); is(dragZoom.translateX, initialX, "The translationX didn't change"); is(dragZoom.translateY, initialY, "The translationY didn't change"); } panelDoc.body.removeChild(div); });