source: Dev/trunk/src/client/dojox/geo/openlayers/TouchInteractionSupport.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 7.2 KB
Line 
1define([
2        "dojo/_base/declare",
3        "dojo/_base/connect",
4        "dojo/_base/html",
5        "dojo/_base/lang",
6        "dojo/_base/event",
7        "dojo/_base/window"
8], function(declare, connect, html, lang, event, win){
9
10        return declare("dojox.geo.openlayers.TouchInteractionSupport", null, {
11                // summary:
12                //              class to handle touch interactions on a OpenLayers.Map widget
13                // tags:
14                //              private
15
16                _map: null,
17                _centerTouchLocation: null,
18                _touchMoveListener: null,
19                _touchEndListener: null,
20                _initialFingerSpacing: null,
21                _initialScale: null,
22                _tapCount: null,
23                _tapThreshold: null,
24                _lastTap: null,
25
26                constructor: function(map){
27                        // summary:
28                        //              Constructs a new TouchInteractionSupport instance
29                        // map: OpenLayers.Map
30                        //              the Map widget this class provides touch navigation for.
31                        this._map = map;
32                        this._centerTouchLocation = new OpenLayers.LonLat(0, 0);
33
34                        var div = this._map.div;
35
36                        // install touch listeners
37                        connect.connect(div, "touchstart", this, this._touchStartHandler);
38                        connect.connect(div, "touchmove", this, this._touchMoveHandler);
39                        connect.connect(div, "touchend", this, this._touchEndHandler);
40
41                        this._tapCount = 0;
42                        this._lastTap = {
43                                x: 0,
44                                y: 0
45                        };
46                        this._tapThreshold = 100; // square distance in pixels
47
48                },
49
50                _getTouchBarycenter: function(touchEvent){
51                        // summary:
52                        //              returns the midpoint of the two first fingers (or the first finger location if only one)
53                        // touchEvent: TouchEvent
54                        //              a touch event
55                        // returns:
56                        //              the midpoint as an {x,y} object.
57                        // tags:
58                        //              private
59                        var touches = touchEvent.touches;
60                        var firstTouch = touches[0];
61                        var secondTouch = null;
62                        if(touches.length > 1){
63                                secondTouch = touches[1];
64                        }else{
65                                secondTouch = touches[0];
66                        }
67
68                        var marginBox = html.marginBox(this._map.div);
69
70                        var middleX = (firstTouch.pageX + secondTouch.pageX) / 2.0 - marginBox.l;
71                        var middleY = (firstTouch.pageY + secondTouch.pageY) / 2.0 - marginBox.t;
72
73                        return {
74                                x: middleX,
75                                y: middleY
76                        }; // Object
77
78                },
79
80                _getFingerSpacing: function(touchEvent){
81                        // summary:
82                        //              computes the distance between the first two fingers
83                        // touchEvent: Event
84                        //              a touch event
85                        // returns: float
86                        //              a distance. -1 if less that 2 fingers
87                        // tags:
88                        //              private
89                        var touches = touchEvent.touches;
90                        var spacing = -1;
91                        if(touches.length >= 2){
92                                var dx = (touches[1].pageX - touches[0].pageX);
93                                var dy = (touches[1].pageY - touches[0].pageY);
94                                spacing = Math.sqrt(dx * dx + dy * dy);
95                        }
96                        return spacing;
97                },
98
99                _isDoubleTap: function(touchEvent){
100                        // summary:
101                        //              checks whether the specified touchStart event is a double tap
102                        //              (i.e. follows closely a previous touchStart at approximately the same location)
103                        // touchEvent: TouchEvent
104                        //              a touch event
105                        // returns: boolean
106                        //              true if this event is considered a double tap
107                        // tags:
108                        //              private
109                        var isDoubleTap = false;
110                        var touches = touchEvent.touches;
111                        if((this._tapCount > 0) && touches.length == 1){
112                                // test distance from last tap
113                                var dx = (touches[0].pageX - this._lastTap.x);
114                                var dy = (touches[0].pageY - this._lastTap.y);
115                                var distance = dx * dx + dy * dy;
116                                if(distance < this._tapThreshold){
117                                        isDoubleTap = true;
118                                }else{
119                                        this._tapCount = 0;
120                                }
121                        }
122                        this._tapCount++;
123                        this._lastTap.x = touches[0].pageX;
124                        this._lastTap.y = touches[0].pageY;
125                        setTimeout(lang.hitch(this, function(){
126                                this._tapCount = 0;
127                        }), 300);
128
129                        return isDoubleTap;
130                },
131
132                _doubleTapHandler: function(touchEvent){
133                        // summary:
134                        //              action performed on the map when a double tap was triggered
135                        // touchEvent: TouchEvent
136                        //              a touch event
137                        // tags:
138                        //              private
139
140                        // perform a basic 2x zoom on touch
141                        var touches = touchEvent.touches;
142                        var marginBox = html.marginBox(this._map.div);
143                        var offX = touches[0].pageX - marginBox.l;
144                        var offY = touches[0].pageY - marginBox.t;
145                        // clicked map point before zooming
146                        var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(offX, offY));
147                        // zoom increment power
148                        this._map.setCenter(new OpenLayers.LonLat(mapPoint.lon, mapPoint.lat), this._map.getZoom() + 1);
149                },
150
151                _touchStartHandler: function(touchEvent){
152                        // summary:
153                        //              action performed on the map when a touch start was triggered
154                        // touchEvent: Event
155                        //              a touch event
156                        // tags:
157                        //              private
158                        event.stop(touchEvent);
159
160                        // test double tap
161                        if(this._isDoubleTap(touchEvent)){
162                                this._doubleTapHandler(touchEvent);
163                                return;
164                        }
165
166                        // compute map midpoint between fingers         
167                        var middlePoint = this._getTouchBarycenter(touchEvent);
168
169                        this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
170
171                        // store initial finger spacing to compute zoom later
172                        this._initialFingerSpacing = this._getFingerSpacing(touchEvent);
173
174                        // store initial map scale
175                        this._initialScale = this._map.getScale();
176
177                        // install touch move and up listeners (if not done by other fingers before)
178                        if(!this._touchMoveListener){
179                                this._touchMoveListener = connect.connect(win.global, "touchmove", this, this._touchMoveHandler);
180                        }
181                        if(!this._touchEndListener){
182                                this._touchEndListener = connect.connect(win.global, "touchend", this, this._touchEndHandler);
183                        }
184                },
185
186                _touchEndHandler: function(touchEvent){
187                        // summary:
188                        //              action performed on the map when a touch end was triggered
189                        // touchEvent: Event
190                        //              a touch event
191                        // tags:
192                        //              private
193                        event.stop(touchEvent);
194
195                        var touches = touchEvent.touches;
196
197                        if(touches.length == 0){
198                                // disconnect listeners only when all fingers are up
199                                if(this._touchMoveListener){
200                                        connect.disconnect(this._touchMoveListener);
201                                        this._touchMoveListener = null;
202                                }
203                                if(this._touchEndListener){
204                                        connect.disconnect(this._touchEndListener);
205                                        this._touchEndListener = null;
206                                }
207                        }else{
208                                // recompute touch center
209                                var middlePoint = this._getTouchBarycenter(touchEvent);
210
211                                this._centerTouchLocation = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
212                        }
213                },
214
215                _touchMoveHandler: function(touchEvent){
216                        // summary:
217                        //              action performed on the map when a touch move was triggered
218                        // touchEvent: Event
219                        //              a touch event
220                        // tags:
221                        //              private
222
223                        // prevent browser interaction
224                        event.stop(touchEvent);
225
226                        var middlePoint = this._getTouchBarycenter(touchEvent);
227
228                        // compute map offset
229                        var mapPoint = this._map.getLonLatFromPixel(new OpenLayers.Pixel(middlePoint.x, middlePoint.y));
230                        var mapOffsetLon = mapPoint.lon - this._centerTouchLocation.lon;
231                        var mapOffsetLat = mapPoint.lat - this._centerTouchLocation.lat;
232
233                        // compute scale factor
234                        var scaleFactor = 1;
235                        var touches = touchEvent.touches;
236                        if(touches.length >= 2){
237                                var fingerSpacing = this._getFingerSpacing(touchEvent);
238                                scaleFactor = fingerSpacing / this._initialFingerSpacing;
239                                // weird openlayer bug: setting several times the same scale value lead to visual zoom...
240                                this._map.zoomToScale(this._initialScale / scaleFactor);
241                        }
242
243                        // adjust map center on barycenter
244                        var currentMapCenter = this._map.getCenter();
245                        this._map.setCenter(new OpenLayers.LonLat(currentMapCenter.lon - mapOffsetLon, currentMapCenter.lat
246                                                                                                                                                                                                                                                                                                                                                        - mapOffsetLat));
247
248                }
249        });
250});
Note: See TracBrowser for help on using the repository browser.