Fix zooming in interaction.js so it focuses on the point where the mouse cursor is.
authorRobert Konigsberg <konigsberg@google.com>
Thu, 23 Dec 2010 06:19:29 +0000 (22:19 -0800)
committerRobert Konigsberg <konigsberg@google.com>
Thu, 23 Dec 2010 06:19:29 +0000 (22:19 -0800)
tests/interaction.js

index ab5d5f5..3e72c78 100644 (file)
         }
       }
 
+      // Take the offset of a mouse event on the dygraph canvas and
+      // convert it to a pair of percentages from the bottom left. 
+      // (Not top left, bottom is where the lower value is.)
+      function offsetToPercentage(g, offsetX, offsetY) {
+        // This is calculating the pixel offset of the leftmost date.
+        var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
+        var yar0 = g.yAxisRange(0);
+
+        // This is calculating the pixel of the higest value. (Top pixel)
+        var yOffset = g.toDomCoords(null, yar0[1])[1];
+
+        // x y w and h are relative to the corner of the drawing area,
+        // so that the upper corner of the drawing area is (0, 0).
+        var x = offsetX - xOffset;
+        var y = offsetY - yOffset;
+
+        // This is computing the rightmost pixel, effectively defining the
+        // width.
+        var w = g.toDomCoords(g.xAxisRange()[1], null)[0] - xOffset;
+
+        // This is computing the lowest pixel, effectively defining the height.
+        var h = g.toDomCoords(null, yar0[0])[1] - yOffset;
+
+        // Percentage from the left.
+        var xPct = w == 0 ? 0 : (x / w);
+        // Percentage from the top.
+        var yPct = h == 0 ? 0 : (y / h);
+
+        // The (1-) part below changes it from "% distance down from the top"
+        // to "% distance up from the bottom".
+        return [xPct, (1-yPct)];
+      }
+
       function dblClickV3(event, g, context) {
+        // Reducing by 20% makes it 80% the original size, which means
+        // to restore to original size it must grow by 25%
+        var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
+        var xPct = percentages[0];
+        var yPct = percentages[1];
+
         if (event.ctrlKey) {
-          zoom(g, -(1/8));
+          zoom(g, -.25, xPct, yPct);
         } else {
-          zoom(g, +.1);
+          zoom(g, +.2, xPct, yPct);
         }
       }
 
       function scrollV3(event, g, context) {
         var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
         // For me the normalized value shows 0.075 for one click. If I took
-        // that verbatim, it would be a 7.5%. I think I'm gonna take 1/10 of that.
-        // (double for left and right side)
-        var percentage = normal / 100;
+        // that verbatim, it would be a 7.5%.
+        var percentage = normal / 50;
+
+        var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
+        var xPct = percentages[0];
+        var yPct = percentages[1];
 
-        zoom(g, percentage);
+        zoom(g, percentage, xPct, yPct);
         Dygraph.cancelEvent(event);
       }
 
-      function zoom(g, percentage) {
-        // Adjusts [x, y] toward each other by percentage%
-        function adjustAxis(axis, percentage) {
+      // Adjusts [x, y] toward each other by zoomInPercentage%
+      // Split it so the left/bottom axis gets xBias/yBias of that change and
+      // tight/top gets (1-xBias)/(1-yBias) of that change.
+      //
+      // If a bias is missing it splits it down the middle.
+      function zoom(g, zoomInPercentage, xBias, yBias) {
+        xBias = xBias || 0.5;
+        yBias = yBias || 0.5;
+        function adjustAxis(axis, zoomInPercentage, bias) {
           var delta = axis[1] - axis[0];
-          var increment = delta * percentage;
-          return [ axis[0] + increment, axis[1] - increment ];
+          var increment = delta * zoomInPercentage;
+          var foo = [increment * bias, increment * (1-bias)];
+          return [ axis[0] + foo[0], axis[1] - foo[1] ];
         }
         var yAxes = g.yAxisRanges();
         var newYAxes = [];
         for (var i = 0; i < yAxes.length; i++) {
-          newYAxes[i] = adjustAxis(yAxes[i], percentage);
+          newYAxes[i] = adjustAxis(yAxes[i], zoomInPercentage, yBias);
         }
 
         g.updateOptions({
-          dateWindow: adjustAxis(g.xAxisRange(), percentage),
+          dateWindow: adjustAxis(g.xAxisRange(), zoomInPercentage, xBias),
           valueRange: newYAxes[0]
           });
       }