Bug 1263397 - The tree map should zoom at centering around the mouse pointer. r=fitzgen
authorGreg Tatum <tatum.creative@gmail.com>
Thu, 14 Apr 2016 07:17:00 +0200
changeset 293778 dece9231ef6cfdd1d34074da3af8925530bfec5f
parent 293777 f60bd9567a058bf0d4d5b35f0d53a46eba0aa500
child 293779 d4cd977c44f0eaa7d7a6ec2f77481950e33833c6
push id18808
push usercbook@mozilla.com
push dateWed, 20 Apr 2016 03:57:38 +0000
treeherderfx-team@d4cd977c44f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfitzgen
bugs1263397
milestone48.0a1
Bug 1263397 - The tree map should zoom at centering around the mouse pointer. r=fitzgen
devtools/client/memory/components/tree-map/drag-zoom.js
devtools/client/memory/test/browser/browser_memory_tree_map-02.js
devtools/client/memory/test/browser/head.js
--- a/devtools/client/memory/components/tree-map/drag-zoom.js
+++ b/devtools/client/memory/components/tree-map/drag-zoom.js
@@ -248,35 +248,35 @@ function setScrollHandlers(container, dr
     let deltaWidth = dragZoom.zoomedWidth - prevZoomedWidth;
     let deltaHeight = dragZoom.zoomedHeight - prevZoomedHeight;
 
     let mouseOffsetX = dragZoom.mouseX - container.offsetWidth / 2
     let mouseOffsetY = dragZoom.mouseY - container.offsetHeight / 2
 
     // The ratio of where the center of the mouse is in regards to the total
     // zoomed width/height
-    let ratioZoomX = (dragZoom.zoomedWidth / 2 + mouseOffsetX - dragZoom.translateX)
-      / dragZoom.zoomedWidth;
-    let ratioZoomY = (dragZoom.zoomedHeight / 2 + mouseOffsetY - dragZoom.translateY)
-      / dragZoom.zoomedHeight;
+    let ratioZoomX = (prevZoomedWidth / 2 + mouseOffsetX - dragZoom.translateX)
+      / prevZoomedWidth;
+    let ratioZoomY = (prevZoomedHeight / 2 + mouseOffsetY - dragZoom.translateY)
+      / prevZoomedHeight;
 
     // Distribute the change in width and height based on the above ratio
     dragZoom.translateX -= lerp(-deltaWidth / 2, deltaWidth / 2, ratioZoomX);
     dragZoom.translateY -= lerp(-deltaHeight / 2, deltaHeight / 2, ratioZoomY);
 
     // Keep the canvas in range of the container
     keepInView(container, dragZoom);
     emitChanged();
     update();
   }
 
-  window.addEventListener("wheel", handleWheel, false);
+  container.addEventListener("wheel", handleWheel, false);
 
   return function removeListener() {
-    window.removeEventListener("wheel", handleWheel, false);
+    container.removeEventListener("wheel", handleWheel, false);
   };
 }
 
 /**
  * Account for the various mouse wheel event types, per pixel or per line
  *
  * @param  {WheelEvent} event
  * @param  {Window} window
--- a/devtools/client/memory/test/browser/browser_memory_tree_map-02.js
+++ b/devtools/client/memory/test/browser/browser_memory_tree_map-02.js
@@ -28,47 +28,53 @@ this.test = makeMemoryTest(TEST_URL, fun
   });
 
   let rafMock = createRAFMock();
 
   panelDoc.body.appendChild(div);
 
   let canvases = new CanvasUtils(div, 0);
   let dragZoom = new DragZoom(canvases.container, 0, rafMock.raf);
+  let 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, 0px) scale(1)",
+       "No transforms have been done.");
 
-    panelWin.dispatchEvent(new WheelEvent("wheel", {
+    canvases.container.dispatchEvent(new WheelEvent("wheel", {
       deltaY: -PIXEL_DELTA,
       deltaMode: PIXEL_SCROLL_MODE
     }));
 
+    is(style.transform, "translate(0px, 0px) scale(1.05)",
+       "The div has been slightly scaled.");
     is(dragZoom.zoom, PIXEL_DELTA * dragZoom.ZOOM_SPEED,
       "The zoom was increased");
-    ok(dragZoom.smoothZoom < dragZoom.zoom && dragZoom.smoothZoom > 0,
+    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, 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");
   {
@@ -80,30 +86,56 @@ this.test = makeMemoryTest(TEST_URL, fun
     }));
     div.dispatchEvent(new MouseEvent("mousedown"));
     div.dispatchEvent(new MouseEvent("mousemove", {
       clientX: 20,
       clientY: 20,
     }));
     div.dispatchEvent(new MouseEvent("mouseup"));
 
-    ok(dragZoom.translateX - initialX > 0,
+    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(dragZoom.translateY - initialY > 0,
+    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");
   {
     let previousZoom = dragZoom.zoom;
     let previousSmoothZoom = dragZoom.smoothZoom;
 
-    panelWin.dispatchEvent(new WheelEvent("wheel", {
+    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");
--- a/devtools/client/memory/test/browser/head.js
+++ b/devtools/client/memory/test/browser/head.js
@@ -221,8 +221,24 @@ function createRAFMock() {
   };
 
   mock.raf = function(fn) {
     mock.timesCalled++;
     queuedFns.push(fn);
   };
   return mock;
 }
+
+/**
+ * Test to see if two floats are equivalent.
+ *
+ * @param {Float} a
+ * @param {Float} b
+ * @return {Boolean}
+ */
+function floatEquality(a, b) {
+  const EPSILON = 0.00000000001;
+  const equals = Math.abs(a - b) < EPSILON;
+  if (!equals) {
+    info(`${a} not equal to ${b}`);
+  }
+  return equals;
+}