summaryrefslogtreecommitdiff
path: root/js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js')
-rw-r--r--js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js248
1 files changed, 248 insertions, 0 deletions
diff --git a/js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js b/js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js
new file mode 100644
index 0000000..0ea58f6
--- /dev/null
+++ b/js/dojo-1.7.2/dojox/geo/openlayers/TouchInteractionSupport.js
@@ -0,0 +1,248 @@
+//>>built
+define("dojox/geo/openlayers/TouchInteractionSupport", ["dojo/_base/kernel",
+ "dojo/_base/declare",
+ "dojo/_base/connect",
+ "dojo/_base/html",
+ "dojo/_base/lang",
+ "dojo/_base/event",
+ "dojo/_base/window"], function(dojo, declare, connect, html, lang, event, window){
+
+ return declare("dojox.geo.openlayers.TouchInteractionSupport", null, {
+ // summary:
+ // class to handle touch interactions on a OpenLayers.Map widget
+ // tags:
+ // private
+
+ _map : null,
+ _centerTouchLocation : null,
+ _touchMoveListener : null,
+ _touchEndListener : null,
+ _initialFingerSpacing : null,
+ _initialScale : null,
+ _tapCount : null,
+ _tapThreshold : null,
+ _lastTap : null,
+
+ constructor : function(/* OpenLayers.Map */map){
+ // summary:
+ // Constructs a new TouchInteractionSupport instance
+ // map: OpenLayers.Map
+ // the Map widget this class provides touch navigation for.
+ this._map = map;
+ this._centerTouchLocation = new OpenLayers.LonLat(0, 0);
+
+ var div = this._map.div;
+
+ // install touch listeners
+ connect.connect(div, "touchstart", this, this._touchStartHandler);
+ connect.connect(div, "touchmove", this, this._touchMoveHandler);
+ connect.connect(div, "touchend", this, this._touchEndHandler);
+
+ this._tapCount = 0;
+ this._lastTap = {
+ x : 0,
+ y : 0
+ };
+ this._tapThreshold = 100; // square distance in pixels
+
+ },
+
+ _getTouchBarycenter : function(touchEvent){
+ // summary:
+ // returns the midpoint of the two first fingers (or the first finger location if only one)
+ // touchEvent: Event
+ // a touch event
+ // returns: dojox.gfx.Point
+ // the midpoint
+ // tags:
+ // private
+ var touches = touchEvent.touches;
+ var firstTouch = touches[0];
+ var secondTouch = null;
+ if (touches.length > 1) {
+ secondTouch = touches[1];
+ } else {
+ secondTouch = touches[0];
+ }
+
+ var marginBox = html.marginBox(this._map.div);
+
+ var middleX = (firstTouch.pageX + secondTouch.pageX) / 2.0 - marginBox.l;
+ var middleY = (firstTouch.pageY + secondTouch.pageY) / 2.0 - marginBox.t;
+
+ return {
+ x : middleX,
+ y : middleY
+ };
+
+ },
+
+ _getFingerSpacing : function(touchEvent){
+ // summary:
+ // computes the distance between the first two fingers
+ // touchEvent: Event
+ // a touch event
+ // returns: float
+ // a distance. -1 if less that 2 fingers
+ // tags:
+ // private
+ var touches = touchEvent.touches;
+ var spacing = -1;
+ if (touches.length >= 2) {
+ var dx = (touches[1].pageX - touches[0].pageX);
+ var dy = (touches[1].pageY - touches[0].pageY);
+ spacing = Math.sqrt(dx * dx + dy * dy);
+ }
+ return spacing;
+ },
+
+ _isDoubleTap : function(touchEvent){
+ // summary:
+ // checks whether the specified touchStart event is a double tap
+ // (i.e. follows closely a previous touchStart at approximately the same location)
+ // touchEvent: Event
+ // a touch event
+ // returns: boolean
+ // true if this event is considered a double tap
+ // tags:
+ // private
+ var isDoubleTap = false;
+ var touches = touchEvent.touches;
+ if ((this._tapCount > 0) && touches.length == 1) {
+ // test distance from last tap
+ var dx = (touches[0].pageX - this._lastTap.x);
+ var dy = (touches[0].pageY - this._lastTap.y);
+ var distance = dx * dx + dy * dy;
+ if (distance < this._tapThreshold) {
+ isDoubleTap = true;
+ } else {
+ this._tapCount = 0;
+ }
+ }
+ this._tapCount++;
+ this._lastTap.x = touches[0].pageX;
+ this._lastTap.y = touches[0].pageY;
+ setTimeout(lang.hitch(this, function(){
+ this._tapCount = 0;
+ }), 300);
+
+ return isDoubleTap;
+ },
+
+ _doubleTapHandler : function(touchEvent){
+ // summary:
+ // action performed on the map when a double tap was triggered
+ // touchEvent: Event
+ // a touch event
+ // tags:
+ // private
+ // perform a basic 2x zoom on touch
+ var touches = touchEvent.touches;
+ var marginBox = html.marginBox(this._map.div);
+ var offX = touches[0].pageX - marginBox.l;
+ var offY = touches[0].pageY - marginBox.t;
+ // clicked map point before zooming
+ var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(offX, offY));
+ // zoom increment power
+ this._map.setCenter(new OpenLayers.LonLat(mapPoint.lon, mapPoint.lat), this._map.getZoom() + 1);
+ },
+
+ _touchStartHandler : function(touchEvent){
+ // summary:
+ // action performed on the map when a touch start was triggered
+ // touchEvent: Event
+ // a touch event
+ // tags:
+ // private
+ event.stop(touchEvent);
+
+ // test double tap
+ if (this._isDoubleTap(touchEvent)) {
+ this._doubleTapHandler(touchEvent);
+ return;
+ }
+
+ // compute map midpoint between fingers
+ var middlePoint = this._getTouchBarycenter(touchEvent);
+
+ this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
+
+ // store initial finger spacing to compute zoom later
+ this._initialFingerSpacing = this._getFingerSpacing(touchEvent);
+
+ // store initial map scale
+ this._initialScale = this._map.getScale();
+
+ // install touch move and up listeners (if not done by other fingers before)
+ if (!this._touchMoveListener)
+ this._touchMoveListener = connect.connect(window.global, "touchmove", this, this._touchMoveHandler);
+ if (!this._touchEndListener)
+ this._touchEndListener = connect.connect(window.global, "touchend", this, this._touchEndHandler);
+
+ },
+
+ _touchEndHandler : function(touchEvent){
+ // summary:
+ // action performed on the map when a touch end was triggered
+ // touchEvent: Event
+ // a touch event
+ // tags:
+ // private
+ event.stop(touchEvent);
+
+ var touches = touchEvent.touches;
+
+ if (touches.length == 0) {
+ // disconnect listeners only when all fingers are up
+ if (this._touchMoveListener) {
+ connect.disconnect(this._touchMoveListener);
+ this._touchMoveListener = null;
+ }
+ if (this._touchEndListener) {
+ connect.disconnect(this._touchEndListener);
+ this._touchEndListener = null;
+ }
+ } else {
+ // recompute touch center
+ var middlePoint = this._getTouchBarycenter(touchEvent);
+
+ this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
+ }
+ },
+
+ _touchMoveHandler : function(touchEvent){
+ // summary:
+ // action performed on the map when a touch move was triggered
+ // touchEvent: Event
+ // a touch event
+ // tags:
+ // private
+
+ // prevent browser interaction
+ event.stop(touchEvent);
+
+ var middlePoint = this._getTouchBarycenter(touchEvent);
+
+ // compute map offset
+ var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
+ var mapOffsetLon = mapPoint.lon - this._centerTouchLocation.lon;
+ var mapOffsetLat = mapPoint.lat - this._centerTouchLocation.lat;
+
+ // compute scale factor
+ var scaleFactor = 1;
+ var touches = touchEvent.touches;
+ if (touches.length >= 2) {
+ var fingerSpacing = this._getFingerSpacing(touchEvent);
+ scaleFactor = fingerSpacing / this._initialFingerSpacing;
+ // weird openlayer bug : setting several times the same scale value lead to visual zoom...
+ this._map.zoomToScale(this._initialScale / scaleFactor);
+ }
+
+ // adjust map center on barycenter
+ var currentMapCenter = this._map.getCenter();
+ this._map.setCenter(new OpenLayers.LonLat(currentMapCenter.lon - mapOffsetLon, currentMapCenter.lat
+ - mapOffsetLat));
+
+ }
+ });
+});