Start adding tests for the interaction model. Create the beginning of a
authorRobert Konigsberg <konigsberg@google.com>
Fri, 13 May 2011 15:18:09 +0000 (11:18 -0400)
committerRobert Konigsberg <konigsberg@google.com>
Fri, 13 May 2011 15:18:09 +0000 (11:18 -0400)
solution for getting clickCallbacks when the interaction model is
rewritten.

There's lots about this change I dislike (the method naming for one.)

Still pending is the lack of maintaining lastx and selPoints.

auto_tests/misc/local.html
auto_tests/tests/DygraphOps.js
auto_tests/tests/interaction_model.js [new file with mode: 0644]
auto_tests/tests/range_tests.js
dygraph.js

index 046a11e..32814be 100644 (file)
@@ -24,6 +24,7 @@
   <script type="text/javascript" src="../tests/range_tests.js"></script>
   <script type="text/javascript" src="../tests/axis_labels.js"></script>
   <script type="text/javascript" src="../tests/multi_csv.js"></script>
+  <script type="text/javascript" src="../tests/interaction_model.js"></script>
 </head>
 <body>
   <div id='graph'></div>
index 072d992..ad67b2a 100644 (file)
@@ -90,12 +90,9 @@ DygraphOps.dispatchDoubleClick = function(g, custom) {
   g.canvas_.dispatchEvent(event);
 };
 
-DygraphOps.dispatchMouseDown = function(g, x, y, custom) {
-  var px = Dygraph.findPosX(g.canvas_);
-  var py = Dygraph.findPosY(g.canvas_);
-
-  var pageX = px + g.toDomXCoord(x);
-  var pageY = py + g.toDomYCoord(y);
+DygraphOps.dispatchMouseDown_Point = function(g, x, y, custom) {
+  var pageX = Dygraph.findPosX(g.canvas_) + x;
+  var pageY = Dygraph.findPosY(g.canvas_) + y;
 
   var opts = {
     type : 'mousedown',
@@ -108,14 +105,11 @@ DygraphOps.dispatchMouseDown = function(g, x, y, custom) {
 
   var event = DygraphOps.createEvent_(opts, custom);
   g.canvas_.dispatchEvent(event);
-};
-
-DygraphOps.dispatchMouseMove = function(g, x, y, custom) {
-  var px = Dygraph.findPosX(g.canvas_);
-  var py = Dygraph.findPosY(g.canvas_);
+}
 
-  var pageX = px + g.toDomXCoord(x);
-  var pageY = py + g.toDomYCoord(y);
+DygraphOps.dispatchMouseMove_Point = function(g, x, y, custom) {
+  var pageX = Dygraph.findPosX(g.canvas_) + x;
+  var pageY = Dygraph.findPosY(g.canvas_) + y;
 
   var opts = {
     type : 'mousemove',
@@ -129,12 +123,9 @@ DygraphOps.dispatchMouseMove = function(g, x, y, custom) {
   g.canvas_.dispatchEvent(event);
 };
 
-DygraphOps.dispatchMouseUp = function(g, x, y, custom) {
-  var px = Dygraph.findPosX(g.canvas_);
-  var py = Dygraph.findPosY(g.canvas_);
-
-  var pageX = px + g.toDomXCoord(x);
-  var pageY = py + g.toDomYCoord(y);
+DygraphOps.dispatchMouseUp_Point = function(g, x, y, custom) {
+  var pageX = Dygraph.findPosX(g.canvas_) + x;
+  var pageY = Dygraph.findPosY(g.canvas_) + y;
 
   var opts = {
     type : 'mouseup',
@@ -147,3 +138,28 @@ DygraphOps.dispatchMouseUp = function(g, x, y, custom) {
   var event = DygraphOps.createEvent_(opts, custom);
   g.canvas_.dispatchEvent(event);
 };
+
+DygraphOps.dispatchMouseDown = function(g, x, y, custom) {
+  DygraphOps.dispatchMouseDown_Point(
+      g,
+      g.toDomXCoord(x),
+      g.toDomYCoord(y),
+      custom);
+};
+
+DygraphOps.dispatchMouseMove = function(g, x, y, custom) {
+  DygraphOps.dispatchMouseMove_Point(
+      g,
+      g.toDomXCoord(x),
+      g.toDomYCoord(y),
+      custom);
+};
+
+DygraphOps.dispatchMouseUp = function(g, x, y, custom) {
+  DygraphOps.dispatchMouseUp_Point(
+      g,
+      g.toDomXCoord(x),
+      g.toDomYCoord(y),
+      custom);
+};
+
diff --git a/auto_tests/tests/interaction_model.js b/auto_tests/tests/interaction_model.js
new file mode 100644 (file)
index 0000000..6249731
--- /dev/null
@@ -0,0 +1,128 @@
+/** 
+ * @fileoverview Test cases for the interaction model.
+ *
+ * @author konigsberg@google.com (Robert Konigsbrg)
+ */
+var InteractionModelTestCase = TestCase("interaction-model");
+
+InteractionModelTestCase.prototype.setUp = function() {
+  document.body.innerHTML = "<div id='graph'></div>";
+};
+
+InteractionModelTestCase.prototype.tearDown = function() {
+};
+
+function getXLabels() {
+  var x_labels = document.getElementsByClassName("dygraph-axis-label-x");
+  var ary = [];
+  for (var i = 0; i < x_labels.length; i++) {
+    ary.push(x_labels[i].innerHTML);
+  }
+  return ary;
+}
+
+InteractionModelTestCase.prototype.pan = function(g, xRange, yRange) {
+  var originalXRange = g.xAxisRange();
+  var originalYRange = g.yAxisRange(0);
+
+  DygraphOps.dispatchMouseDown(g, xRange[0], yRange[0]);
+  DygraphOps.dispatchMouseMove(g, xRange[1], yRange[0]); // this is really necessary.
+  DygraphOps.dispatchMouseUp(g, xRange[1], yRange[0]);
+
+  assertEqualsDelta(xRange, g.xAxisRange(), 0.2);
+  // assertEqualsDelta(originalYRange, g.yAxisRange(0), 0.2); // Not true, it's something in the middle.
+
+  var midX = (xRange[1] - xRange[0]) / 2;
+  DygraphOps.dispatchMouseDown(g, midX, yRange[0]);
+  DygraphOps.dispatchMouseMove(g, midX, yRange[1]); // this is really necessary.
+  DygraphOps.dispatchMouseUp(g, midX, yRange[1]);
+
+  assertEqualsDelta(xRange, g.xAxisRange(), 0.2);
+  assertEqualsDelta(yRange, g.yAxisRange(0), 0.2);
+}
+
+/**
+ * This tests that when changing the interaction model so pan is used instead
+ * of zoom as the default behavior, a standard click method is still called.
+ */
+InteractionModelTestCase.prototype.testClickCallbackIsCalled = function() {
+  var clicked;
+
+  var clickCallback = function(event, x) {
+    clicked = x;
+  };
+
+  var data = "X,Y\n" +
+      "20,-1\n" +
+      "21,0\n" +
+      "22,1\n" +
+      "23,0\n"
+  ;
+
+  var graph = document.getElementById("graph");
+  var g = new Dygraph(graph, data,
+      {
+        width: 100,
+        height : 100,
+        clickCallback : clickCallback
+      });
+
+  DygraphOps.dispatchMouseDown_Point(g, 10, 10);
+  DygraphOps.dispatchMouseMove_Point(g, 10, 10);
+  DygraphOps.dispatchMouseUp_Point(g, 10, 10);
+
+  assertEquals(20, clicked);
+};
+
+/**
+ * This tests that when changing the interaction model so pan is used instead
+ * of zoom as the default behavior, a standard click method is still called.
+ */
+InteractionModelTestCase.prototype.testClickCallbackIsCalledOnCustomPan = function() {
+  var clicked;
+
+  var clickCallback = function(event, x) {
+    clicked = x;
+  };
+
+  var data = "X,Y\n" +
+      "20,-1\n" +
+      "21,0\n" +
+      "22,1\n" +
+      "23,0\n"
+  ;
+
+  function customDown(event, g, context) {
+    context.initializeMouseDown(event, g, context);
+    Dygraph.startPan(event, g, context);
+  }
+
+  function customMove(event, g, context) {
+    Dygraph.movePan(event, g, context);
+  }
+
+  function customUp(event, g, context) {
+    Dygraph.endPan(event, g, context);
+  }
+
+  var opts = {
+    width: 100,
+    height : 100,
+    clickCallback : clickCallback,
+    interactionModel : {
+      'mousedown' : customDown,
+      'mousemove' : customMove,
+      'mouseup' : customUp,
+    }
+  };
+
+  var graph = document.getElementById("graph");
+  var g = new Dygraph(graph, data, opts);
+
+  DygraphOps.dispatchMouseDown_Point(g, 10, 10);
+  DygraphOps.dispatchMouseMove_Point(g, 10, 10);
+  DygraphOps.dispatchMouseUp_Point(g, 10, 10);
+
+  assertEquals(20, clicked);
+};
+
index 561ceeb..036fc1b 100644 (file)
@@ -84,7 +84,6 @@ RangeTestCase.prototype.zoom = function(g, xRange, yRange) {
   var originalXRange = g.xAxisRange();
   var originalYRange = g.yAxisRange(0);
 
-  // Editing e.shiftKey post construction doesn't work for Firefox. Damn.
   DygraphOps.dispatchMouseDown(g, xRange[0], yRange[0]);
   DygraphOps.dispatchMouseMove(g, xRange[1], yRange[0]); // this is really necessary.
   DygraphOps.dispatchMouseUp(g, xRange[1], yRange[0]);
index 2e8a38e..61e8e49 100644 (file)
@@ -1254,6 +1254,16 @@ Dygraph.Interaction.endPan = function(event, g, context) {
   context.valueRange = null;
   context.boundedDates = null;
   context.boundedValues = null;
+
+  var dragEndX = g.dragGetX_(event, context);
+  var dragEndY = g.dragGetY_(event, context);
+  var regionWidth = Math.abs(context.dragEndX - context.dragStartX);
+  var regionHeight = Math.abs(context.dragEndY - context.dragStartY);
+
+  if (regionWidth < 2 && regionHeight < 2 &&
+      g.lastx_ != undefined && g.lastx_ != -1) {
+    Dygraph.Interaction.treatMouseOpAsClick(g);
+  }
 };
 
 /**
@@ -1311,6 +1321,33 @@ Dygraph.Interaction.moveZoom = function(event, g, context) {
   context.prevDragDirection = context.dragDirection;
 };
 
+Dygraph.Interaction.treatMouseOpAsClick = function(g) {
+  // TODO(danvk): pass along more info about the points, e.g. 'x'
+  if (g.attr_('clickCallback') != null) {
+    g.attr_('clickCallback')(event, g.lastx_, g.selPoints_);
+  }
+  if (g.attr_('pointClickCallback')) {
+    // check if the click was on a particular point.
+    var closestIdx = -1;
+    var closestDistance = 0;
+    for (var i = 0; i < g.selPoints_.length; i++) {
+      var p = g.selPoints_[i];
+      var distance = Math.pow(p.canvasx - context.dragEndX, 2) +
+                     Math.pow(p.canvasy - context.dragEndY, 2);
+      if (closestIdx == -1 || distance < closestDistance) {
+        closestDistance = distance;
+        closestIdx = i;
+      }
+    }
+
+    // Allow any click within two pixels of the dot.
+    var radius = g.attr_('highlightCircleSize') + 2;
+    if (closestDistance <= 5 * 5) {
+      g.attr_('pointClickCallback')(event, g.selPoints_[closestIdx]);
+    }
+  }
+}
+
 /**
  * Called in response to an interaction model operation that
  * responds to an event that performs a zoom based on previously defined
@@ -1326,7 +1363,6 @@ Dygraph.Interaction.moveZoom = function(event, g, context) {
  * dragStartX/dragStartY/etc. properties). This function modifies the context.
  */
 Dygraph.Interaction.endZoom = function(event, g, context) {
-  // TODO(konigsberg): Refactor or rename this fn -- it deals with clicks, too.
   context.isZooming = false;
   context.dragEndX = g.dragGetX_(event, context);
   context.dragEndY = g.dragGetY_(event, context);
@@ -1335,30 +1371,7 @@ Dygraph.Interaction.endZoom = function(event, g, context) {
 
   if (regionWidth < 2 && regionHeight < 2 &&
       g.lastx_ != undefined && g.lastx_ != -1) {
-    // TODO(danvk): pass along more info about the points, e.g. 'x'
-    if (g.attr_('clickCallback') != null) {
-      g.attr_('clickCallback')(event, g.lastx_, g.selPoints_);
-    }
-    if (g.attr_('pointClickCallback')) {
-      // check if the click was on a particular point.
-      var closestIdx = -1;
-      var closestDistance = 0;
-      for (var i = 0; i < g.selPoints_.length; i++) {
-        var p = g.selPoints_[i];
-        var distance = Math.pow(p.canvasx - context.dragEndX, 2) +
-                       Math.pow(p.canvasy - context.dragEndY, 2);
-        if (closestIdx == -1 || distance < closestDistance) {
-          closestDistance = distance;
-          closestIdx = i;
-        }
-      }
-
-      // Allow any click within two pixels of the dot.
-      var radius = g.attr_('highlightCircleSize') + 2;
-      if (closestDistance <= 5 * 5) {
-        g.attr_('pointClickCallback')(event, g.selPoints_[closestIdx]);
-      }
-    }
+    Dygraph.Interaction.treatMouseOpAsClick(g);
   }
 
   if (regionWidth >= 10 && context.dragDirection == Dygraph.HORIZONTAL) {