Misc range selector cleanup.
authorPaul Felix <paul.eric.felix@gmail.com>
Thu, 29 Mar 2012 21:24:03 +0000 (17:24 -0400)
committerDan Vanderkam <danvk@google.com>
Thu, 29 Mar 2012 21:24:03 +0000 (17:24 -0400)
dygraph-range-selector.js

index 9ae04d0..6cc184e 100644 (file)
@@ -19,6 +19,8 @@ var DygraphRangeSelector = function(dygraph) {
   this.isIE_ = /MSIE/.test(navigator.userAgent) && !window.opera;
   this.isUsingExcanvas_ = dygraph.isUsingExcanvas_;
   this.dygraph_ = dygraph;
+  this.hasTouchInterface_ = typeof(TouchEvent) != 'undefined';
+  this.isMobileDevice_ =  Math.min(screen.width, screen.height) < 480;
   this.createCanvases_();
   if (this.isUsingExcanvas_) {
     this.createIEPanOverlay_();
@@ -135,15 +137,16 @@ DygraphRangeSelector.prototype.createZoomHandles_ = function() {
   img.style.zIndex = 10;
   img.style.visibility = 'hidden'; // Initially hidden so they don't show up in the wrong place.
   img.style.cursor = 'col-resize';
+
   if (/MSIE 7/.test(navigator.userAgent)) { // IE7 doesn't support embedded src data.
-      img.width = 7;
-      img.height = 14;
-      img.style.backgroundColor = 'white';
-      img.style.border = '1px solid #333333'; // Just show box in IE7.
+    img.width = 7;
+    img.height = 14;
+    img.style.backgroundColor = 'white';
+    img.style.border = '1px solid #333333'; // Just show box in IE7.
   } else {
-      img.width = 9;
-      img.height = 16;
-      img.src = 'data:image/png;base64,' +
+    img.width = 9;
+    img.height = 16;
+    img.src = 'data:image/png;base64,' +
 'iVBORw0KGgoAAAANSUhEUgAAAAkAAAAQCAYAAADESFVDAAAAAXNSR0IArs4c6QAAAAZiS0dEANAA' +
 'zwDP4Z7KegAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAAd0SU1FB9sHGw0cMqdt1UwAAAAZdEVYdENv' +
 'bW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAaElEQVQoz+3SsRFAQBCF4Z9WJM8KCDVwownl' +
@@ -151,6 +154,15 @@ DygraphRangeSelector.prototype.createZoomHandles_ = function() {
 'qSTDH32I1pQA2Pb9sZecAxc5r3IAb21d6878xsAAAAAASUVORK5CYII=';
   }
 
+  var minScreenDim = Math.min(screen.width, screen.height);
+  if (minScreenDim < 480) {
+    img.width *= 3;
+    img.height *= 3;
+  } else if (minScreenDim < 768) {
+    img.width *= 2;
+    img.height *= 2;
+  }
+
   this.leftZoomHandle_ = img;
   this.rightZoomHandle_ = img.cloneNode(false);
 };
@@ -166,12 +178,16 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
   var handle = null;
   var isZooming = false;
   var isPanning = false;
+  var dynamic = !this.isMobileDevice_ && !this.isUsingExcanvas_;
 
   // functions, defined below.  Defining them this way (rather than with
   // "function foo() {...}" makes JSHint happy.
   var toXDataWindow, onZoomStart, onZoom, onZoomEnd, doZoom, isMouseInPanZone,
       onPanStart, onPan, onPanEnd, doPan, onCanvasMouseMove;
 
+  // Touch event functions
+  var onZoomHandleTouchEvent, onCanvasTouchEvent, addTouchEvents;
+
   toXDataWindow = function(zoomHandleStatus) {
     var xDataLimits = self.dygraph_.xAxisExtremes();
     var fact = (xDataLimits[1] - xDataLimits[0])/self.canvasRect_.w;
@@ -215,7 +231,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     self.drawInteractiveLayer_();
 
     // Zoom on the fly (if not using excanvas).
-    if (!self.isUsingExcanvas_) {
+    if (dynamic) {
       doZoom();
     }
   };
@@ -230,7 +246,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     self.fgcanvas_.style.cursor = 'default';
 
     // If using excanvas, Zoom now.
-    if (self.isUsingExcanvas_) {
+    if (!dynamic) {
       doZoom();
     }
   };
@@ -254,15 +270,11 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     if (self.isUsingExcanvas_) {
         return e.srcElement == self.iePanOverlay_;
     } else {
-      // Getting clientX directly from the event is not accurate enough :(
-      var clientX;
-      if (e.offsetX != undefined) {
-        clientX = self.canvasRect_.x + e.offsetX;
-      } else {
-        clientX = e.clientX;
-      }
-      var zoomHandleStatus = self.getZoomHandleStatus_();
-      return (clientX > zoomHandleStatus.leftHandlePos && clientX < zoomHandleStatus.rightHandlePos);
+      var rect = self.leftZoomHandle_.getBoundingClientRect();
+      var leftHandleClientX = rect.left + rect.width/2;
+      rect = self.rightZoomHandle_.getBoundingClientRect();
+      var rightHandleClientX = rect.left + rect.width/2;
+      return (e.clientX > leftHandleClientX && e.clientX < rightHandleClientX);
     }
   };
 
@@ -309,7 +321,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     self.drawInteractiveLayer_();
 
     // Do pan on the fly (if not using excanvas).
-    if (!self.isUsingExcanvas_) {
+    if (dynamic) {
       doPan();
     }
   };
@@ -322,7 +334,7 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     Dygraph.removeEvent(topElem, 'mousemove', onPan);
     Dygraph.removeEvent(topElem, 'mouseup', onPanEnd);
     // If using excanvas, do pan now.
-    if (self.isUsingExcanvas_) {
+    if (!dynamic) {
       doPan();
     }
   };
@@ -347,6 +359,35 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     }
   };
 
+  onZoomHandleTouchEvent = function(e) {
+    e.preventDefault();
+    if (e.type == 'touchstart') {
+      onZoomStart(e.targetTouches[0]);
+    } else if (e.type == 'touchmove') {
+      onZoom(e.targetTouches[0]);
+    } else {
+      onZoomEnd(e);
+    }
+  };
+
+  onCanvasTouchEvent = function(e) {
+    e.preventDefault();
+    if (e.type == 'touchstart') {
+      onPanStart(e.targetTouches[0]);
+    } else if (e.type == 'touchmove') {
+      onPan(e.targetTouches[0]);
+    } else {
+      onPanEnd(e);
+    }
+  };
+
+  addTouchEvents = function(elem, fn) {
+      var types = ['touchstart', 'touchend', 'touchmove', 'touchcancel'];
+      for (var i = 0; i < types.length; i++) {
+        Dygraph.addEvent(elem, types[i], fn);
+      }
+  };
+
   this.dygraph_.attrs_.interactionModel =
       Dygraph.Interaction.dragIsPanInteractionModel;
   this.dygraph_.attrs_.panEdgeFraction = 0.0001;
@@ -361,6 +402,13 @@ DygraphRangeSelector.prototype.initInteraction_ = function() {
     Dygraph.addEvent(this.fgcanvas_, 'mousedown', onPanStart);
     Dygraph.addEvent(this.fgcanvas_, 'mousemove', onCanvasMouseMove);
   }
+
+  // Touch events
+  if (this.hasTouchInterface_) {
+    addTouchEvents(this.leftZoomHandle_, onZoomHandleTouchEvent);
+    addTouchEvents(this.rightZoomHandle_, onZoomHandleTouchEvent);
+    addTouchEvents(this.fgcanvas_, onCanvasTouchEvent);
+  }
 };
 
 /**
@@ -454,14 +502,14 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() {
   var combinedSeries = [];
   var sum;
   var count;
-  var yVal, y;
   var mutipleValues;
   var i, j, k;
+  var xVal, yVal;
 
   // Find out if data has multiple values per datapoint.
   // Go to first data point that actually has values (see http://code.google.com/p/dygraphs/issues/detail?id=246)
   for (i = 0; i < data.length; i++) {
-    if (data[i].length > 1 && data[i][1] != null) {
+    if (data[i].length > 1 && data[i][1] !== null) {
       mutipleValues = typeof data[i][1] != 'number';
       if (mutipleValues) {
         sum = [];
@@ -477,7 +525,7 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() {
 
   for (i = 0; i < data.length; i++) {
     var dataPoint = data[i];
-    var xVal = dataPoint[0];
+    xVal = dataPoint[0];
 
     if (mutipleValues) {
       for (k = 0; k < sum.length; k++) {
@@ -489,6 +537,7 @@ DygraphRangeSelector.prototype.computeCombinedSeriesAndLimits_ = function() {
 
     for (j = 1; j < dataPoint.length; j++) {
       if (this.dygraph_.visibility()[j-1]) {
+        var y;
         if (mutipleValues) {
           for (k = 0; k < sum.length; k++) {
             y = dataPoint[j][k];