OSDN Git Service

f22672fd695e6509b6193dc5305bfc3abbfb98dc
[pettanr/clientJs.git] / 0.6.x / js / 20_ui / 05_XUI_Gesture.js
1 var XUI_GestureUtils = {\r
2                 /**\r
3                  * get the center of all the touches\r
4                  * @param   {Array}     touches\r
5                  * @returns {Object}    center\r
6                  */\r
7                 getCenter : function( touches ){\r
8                         var i = 0,\r
9                                 l = touches.length,\r
10                                 x, y, minX, minY, maxX, maxY;\r
11 \r
12                         switch( l ){\r
13                                 case 0 :\r
14                                         return {};\r
15                                 case 1 :\r
16                                         return {\r
17                                                 pageX : touches[ 0 ].pageX,\r
18                                                 pageY : touches[ 0 ].pageY\r
19                                         };\r
20                                 case 2 :\r
21                                         return {\r
22                                                 pageX : ( touches[ 0 ].pageX + touches[ 1 ].pageX ) / 2,\r
23                                                 pageY : ( touches[ 0 ].pageY + touches[ 1 ].pageY ) / 2\r
24                                         };\r
25                         };\r
26                         minX = minY = 1 / 0;\r
27                         maxX = maxY = - 1 / 0;\r
28                         for( ; i < l; ++i ){\r
29                                 x    = touches[ i ].pageX;\r
30                                 minX = x < minX ? x : minX;\r
31                                 maxX = maxX < x ? x : maxX;\r
32                                 y    = touches[ i ].pageY;\r
33                                 minY = y < minY ? y : minY;\r
34                                 maxY = maxY < y ? y : maxY;\r
35                         };\r
36                         return {\r
37                                 pageX : ( minX + maxX ) / 2 | 0,\r
38                                 pageY : ( minY + maxY ) / 2 | 0\r
39                         };\r
40                 },\r
41 \r
42                 /**\r
43                  * calculate the velocity between two points\r
44                  * @param   {Number}    deltaTime\r
45                  * @param   {Number}    deltaX\r
46                  * @param   {Number}    deltaY\r
47                  * @returns {Object}    velocity\r
48                  */\r
49                 getVelocity : function( deltaTime, deltaX, deltaY ) {\r
50                         return {\r
51                                 x : Math.abs( deltaX / deltaTime ) || 0,\r
52                                 y : Math.abs( deltaY / deltaTime ) || 0\r
53                         };\r
54                 },\r
55 \r
56                 /**\r
57                  * calculate the angle between two coordinates\r
58                  * @param   {Touch}     touch1\r
59                  * @param   {Touch}     touch2\r
60                  * @returns {Number}    angle\r
61                  */\r
62                 getAngle : function( touch1, touch2 ){\r
63                         var y = touch2.pageY - touch1.pageY,\r
64                                 x = touch2.pageX - touch1.pageX;\r
65                         return Math.atan2( y, x ) * 180 / Math.PI;\r
66                 },\r
67 \r
68                 /**\r
69                  * angle to direction define\r
70                  * @param   {Touch}     touch1\r
71                  * @param   {Touch}     touch2\r
72                  * @returns {String}    direction constant, like 'left'\r
73                  */\r
74                 getDirection : function( touch1, touch2 ){\r
75                         var x = touch1.pageX - touch2.pageX,\r
76                                 y = touch1.pageY - touch2.pageY;\r
77                         return Math.abs( y ) <= Math.abs( x ) ?\r
78                                 ( x > 0 ? 'left' : 'right' ) :\r
79                                 ( y > 0 ? 'up'   : 'down' );\r
80                 },\r
81 \r
82                 /**\r
83                  * calculate the distance between two touches\r
84                  * @param   {Touch}     touch1\r
85                  * @param   {Touch}     touch2\r
86                  * @returns {Number}    distance\r
87                  */\r
88                 getDistance : function( touch1, touch2 ){\r
89                         var x = touch2.pageX - touch1.pageX,\r
90                                 y = touch2.pageY - touch1.pageY;\r
91                         return Math.sqrt( ( x * x ) + ( y * y ) );\r
92                 },\r
93 \r
94                 /**\r
95                  * calculate the scale factor between two touchLists (fingers)\r
96                  * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out\r
97                  * @param   {Array}     start\r
98                  * @param   {Array}     end\r
99                  * @returns {Number}    scale\r
100                  */\r
101                 getScale : function( start, end ){\r
102                         // need two fingers...\r
103                         return ( 2 <= start.length && 2 <= end.length ) ?\r
104                                 XUI_GestureUtils.getDistance( end[ 0 ], end[ 1 ] ) / XUI_GestureUtils.getDistance( start[ 0 ], start[ 1 ] ) :\r
105                                 1;\r
106                 },\r
107 \r
108                 /**\r
109                  * calculate the rotation degrees between two touchLists (fingers)\r
110                  * @param   {Array}     start\r
111                  * @param   {Array}     end\r
112                  * @returns {Number}    rotation\r
113                  */\r
114                 getRotation : function getRotation( start, end ){\r
115                         // need two fingers\r
116                         return ( 2 <= start.length && 2 <= end.length ) ?\r
117                                 XUI_GestureUtils.getAngle( end[ 1 ], end[ 0 ] ) - XUI_GestureUtils.getAngle( start[ 1 ], start[ 0 ] ) :\r
118                                 0;\r
119                 },\r
120 \r
121                 /**\r
122                  * boolean if the direction is vertical\r
123                  * @param    {String}    direction\r
124                  * @returns  {Boolean}   is_vertical\r
125                  */\r
126                 isVertical : function isVertical( direction ){\r
127                         return direction === 'up' || direction === 'down';\r
128                 }\r
129         };\r
130 \r
131 var XUI_Gesture_POINTERS = {},\r
132         XUI_Gesture_CAPTURED = {},\r
133         XUI_Gesture_DEFAULTS = {};\r
134 \r
135 \r
136 function XUI_Gesture_trigger( uinode, type, hammerEvent ){\r
137         if( !uinode.gestureTypes[ type ] ) return X_CALLBACK_NONE;\r
138         hammerEvent = X_Object_copy( hammerEvent );\r
139         hammerEvent.type = type;\r
140         return uinode[ 'dispatch' ]( hammerEvent ) || X_CALLBACK_NONE;\r
141 };\r
142 \r
143 function XUI_$UINodeBase_listen( type, arg1, arg2, arg3 ){\r
144         var events, gestures, i, g;\r
145         \r
146         if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){\r
147                 if( this.phase < 3 ){\r
148                         if( !( events = this.reserveEvents ) ) this.reserveEvents = events = [];\r
149                         events[ events.length ] = [ type, arg1, arg2, arg3 ];\r
150                         return this;\r
151                 };\r
152                 \r
153                 if( this[ 'listening' ]( type, arg1, arg2, arg3 ) ){\r
154                         return this;\r
155                 };\r
156                 \r
157                 if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){\r
158                         gestures = XUI_Gesture_LIST;\r
159                         for( i = gestures.length; i; ){\r
160                                 g = gestures[ --i ];\r
161                                 if( g.startID <= type && type <= g.endID ){\r
162                                         if( !this.gestureActivated ){\r
163                                                 this.gestureOptions   = XUI_Gesture_DEFAULTS; //X_Object_override( X_Object_copy( XUI_Gesture_DEFAULTS ), opt_options );\r
164                                                 this.gestureActivated = {};\r
165                                                 this.gestureTypes     = {};\r
166                                                 this.gestureTriggered = {};\r
167                                                 this.gestureCanceled  = {};\r
168                                         };\r
169                                         if( X_Object_isEmpty( this.gestureActivated ) ){\r
170                                                 this[ 'listen' ]( XUI_Event._POINTER_DOWN, this, XUI_Gesture_handleEvent );\r
171                                         };\r
172                                         this.gestureActivated[ g.name ] = this.gestureTypes[ type ] = true;\r
173                                         break;\r
174                                 };\r
175                         };\r
176                 } else\r
177                         if( XUI_EVENT_COUNTER[ type ] ){\r
178                                 ++XUI_EVENT_COUNTER[ type ];\r
179                         } else {\r
180                                 XUI_EVENT_COUNTER[ type ] = 1;                          \r
181                                 XUI_xnodeIneraction[ 'listen' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay );\r
182                         };\r
183         };\r
184         \r
185         return X_EventDispatcher_listen.apply( this, arguments );\r
186 };\r
187 \r
188 function XUI_$UINodeBase_unlisten( type, arg1, arg2, arg3 ){\r
189         var events, i, ev, gestures, active, g, f;\r
190         \r
191         if( XUI_Event._START_POINTER <= type && type <= XUI_Event._END_POINTER ){\r
192                 if( this.phase < 3 ){\r
193                         if( !( events = this.reserveEvents ) ) return this;\r
194                         for( i = events.length; i; ){\r
195                                 ev = events[ --i ];\r
196                                 if( ev[ 0 ] === type && ev[ 1 ] === arg1 && ev[ 2 ] === arg2 && ev[ 3 ] === arg3 ){\r
197                                         events.split( i, 1 );\r
198                                         return this;\r
199                                 };\r
200                         }; \r
201                         return this;\r
202                 };\r
203 \r
204                 if( !this[ 'listening' ]( type, arg1, arg2, arg3 ) ){\r
205                         return this;\r
206                 };\r
207                 \r
208                 if( XUI_Event._START_XUI_EVENT < type && type < XUI_Event._END_XUI_EVENT ){\r
209                         if( active = this.gestureActivated ){\r
210                                 gestures = XUI_Gesture_LIST;\r
211                                 for( i = gestures.length ; i; ){\r
212                                         g = gestures[ --i ];\r
213                                         if( g.startID <= type && type <= g.endID ){\r
214                                                 if( active[ g.name ] ){\r
215                                                         if( this.gestureTypes[ type ] ) delete this.gestureTypes[ type ];\r
216                                                         for( i = g.startID; i <= g.endID; ++i ){\r
217                                                                 if( this.gestureTypes[ i ] ){\r
218                                                                         f = true;\r
219                                                                         break;\r
220                                                                 };\r
221                                                         };\r
222                                                         if( !f ){\r
223                                                                 delete active[ g.name ];\r
224                                                                 \r
225                                                                 if( X_Object_isEmpty( active ) ){\r
226                                                                         this[ 'unlisten' ]( XUI_Event._POINTER_DOWN, this, XUI_Gesture_handleEvent );\r
227                                                                         //delete this.gestureTriggered;\r
228                                                                         //delete this.gestureCanceled;\r
229                                                                         //delete this.gestureTypes;\r
230                                                                         //delete this.gestureActivated;\r
231                                                                 };\r
232                                                         };\r
233                                                 };\r
234                                                 break;\r
235                                         };\r
236                                 };                                              \r
237                         };\r
238                 } else {\r
239                         if( XUI_EVENT_COUNTER[ type ] === 1 ){\r
240                                 XUI_xnodeIneraction[ 'unlisten' ]( XUI_Event.IdToName[ type ], X_UI_eventRellay );\r
241                                 XUI_EVENT_COUNTER[ type ] = 0;\r
242                         } else\r
243                         if( XUI_EVENT_COUNTER[ type ] ){\r
244                                 --XUI_EVENT_COUNTER[ type ];\r
245                         };\r
246                 };\r
247         };\r
248 \r
249         return X_EventDispatcher_unlisten.apply( this, arguments );\r
250 };\r
251 \r
252 function XUI_Gesture_handleEvent( e ){\r
253                 var gestures   = XUI_Gesture_LIST,\r
254                         type       = e.type,\r
255                         uid        = e[ 'pointerId' ],\r
256                         isStart    = type === XUI_Event._POINTER_DOWN,\r
257                         isEnd      = type === XUI_Event._POINTER_UP || type === XUI_Event._POINTER_CANCEL || type === XUI_Event.POINTER_OUT,\r
258                         hammer     = this,\r
259                         isMouse    = e.pointerType === 'mouse',\r
260                         touches    = [], \r
261                         numTouches = 0,// count the total touches on the screen\r
262                         i, p, l, j, captured, ret, activated, gesture, startEv,\r
263                         deltaTime, deltaX, deltaY, velocity, center, startCenter;\r
264 \r
265                 if( !isStart && !hammer.gestureStartEvent ) return;\r
266 \r
267 if( type === XUI_Event.POINTER_OUT ) console.log( 'gestureCanceled ...' + e.button )\r
268 \r
269                 if( isEnd ){\r
270                         if( XUI_Gesture_POINTERS[ uid ] ){\r
271                                 delete XUI_Gesture_POINTERS[ uid ];\r
272                                 if( XUI_Gesture_CAPTURED[ uid ] ) delete XUI_Gesture_CAPTURED[ uid ];\r
273                         };\r
274                 } else {\r
275                         XUI_Gesture_POINTERS[ uid ] = e;\r
276                 };\r
277 \r
278                 // mousebutton must be down or a touch event\r
279                 if( ( isEnd || !isMouse || e.button === 0 ) ){\r
280                         numTouches = -1;\r
281 \r
282                         for( i in XUI_Gesture_POINTERS ){\r
283                                 if( p = XUI_Gesture_POINTERS[ i ] ){\r
284                                         // いずれかの hammer によって束縛されている場合、その束縛している hammer なら\r
285                                         captured = XUI_Gesture_CAPTURED[ p[ 'pointerId' ] ];\r
286                                         if( captured && captured !== hammer ){\r
287                                                 continue;\r
288                                         };\r
289                                         touches[ ++numTouches ] = p;\r
290                                 };\r
291                         };\r
292                         ++numTouches;\r
293 \r
294                         // if we are in a end event, but when we remove one touch and\r
295                         // we still have enough, set eventType to move\r
296                         if( !numTouches ){ // no touches, force the end event\r
297                                 isEnd = true;\r
298                         };\r
299 \r
300                         // because touchend has no touches, and we often want to use these in our gestures,\r
301                         // we send the last move event as our eventData in touchend\r
302                         ( isEnd && hammer.gestureLastMoveEvent ) ? ( e = hammer.gestureLastMoveEvent ) : ( hammer.gestureLastMoveEvent = e ); // store the last move event\r
303 \r
304                         hammerEvent = X_Object_copy( e );\r
305                         hammerEvent.touches = touches;\r
306 \r
307                         if( isStart && !hammer.gestureStartEvent ){\r
308                                 console.log( '=- add -=' );\r
309                                 // already busy with a Hammer.gesture detection on an element\r
310                                 hammer.gestureStartEvent = hammerEvent;\r
311                                 XUI_rootData[ 'listen' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent );                              \r
312                         };\r
313                         \r
314                         startEv = hammer.gestureStartEvent;\r
315                         \r
316 \r
317                         // if the touches change, set the new touches over the startEvent touches\r
318                         // this because touchevents don't have all the touches on touchstart, or the\r
319                         // user must place his fingers at the EXACT same time on the screen, which is not realistic\r
320                         // but, sometimes it happens that both fingers are touching at the EXACT same time\r
321                         if( startEv && ( numTouches !== startEv.touches.length || touches !== startEv.touches ) ){\r
322                                 // extend 1 level deep to get the touchlist with the touch objects\r
323                                 startEv.touches.length = i = 0;\r
324                                 j = -1;\r
325                                 for( ; i < numTouches; ++i ){\r
326                                         startEv.touches[ ++j ] = touches[ i ];\r
327                                 };\r
328                         };\r
329 \r
330                         deltaTime   = hammerEvent.timestamp  - startEv.timestamp;\r
331                         center      = XUI_GestureUtils.getCenter( touches );\r
332                         startCenter = startEv.center;\r
333                         deltaX      = startCenter ? ( center.pageX - startCenter.pageX ) : 0;\r
334                         deltaY      = startCenter ? ( center.pageY - startCenter.pageY ) : 0;\r
335                         velocity    = XUI_GestureUtils.getVelocity( deltaTime, deltaX, deltaY );\r
336 \r
337                         X_Object_override( hammerEvent, {\r
338                                 type       : isEnd ? XUI_Event._POINTER_UP : type,\r
339                                 \r
340                                 deltaTime  : deltaTime,\r
341 \r
342                                 deltaX     : deltaX,\r
343                                 deltaY     : deltaY,\r
344 \r
345                                 velocityX  : velocity.x,\r
346                                 velocityY  : velocity.y,\r
347 \r
348                                 center     : center,\r
349                                 distance   : startCenter ? XUI_GestureUtils.getDistance( startCenter, center ) : 0,\r
350                                 angle      : startCenter ? XUI_GestureUtils.getAngle( startCenter, center ) : 0,\r
351                                 direction  : startCenter ? XUI_GestureUtils.getDirection( startCenter, center ) : 0,\r
352 \r
353                                 scale      : XUI_GestureUtils.getScale( startEv.touches, touches ),\r
354                                 rotation   : XUI_GestureUtils.getRotation( startEv.touches, touches ),\r
355 \r
356                                 gestureStartEvent : startEv\r
357                         });\r
358 \r
359                         // store as previous event event\r
360                         hammer.gestureLastEvent = hammerEvent;\r
361                         activated = hammer.gestureActivated;\r
362                         console.log( '... ' );\r
363                         // call Hammer.gesture handlers\r
364                         for( i = 0, l = gestures.length; i < l; ++i ){\r
365                                 gesture = gestures[ i ];\r
366 \r
367                                 if( activated[ gesture.name ] && !hammer.gestureCanceled[ gesture.name ] ){\r
368                                         ( console.log( '... ' + i + ' ' + gesture.name ) );\r
369                                         // if a handler returns false, we stop with the detection\r
370                                         ( ret |= ( gesture.handler( hammerEvent, hammer ) || X_CALLBACK_NONE ) );\r
371                                 };\r
372 \r
373                                 if( ret & X_CALLBACK_CAPTURE_POINTER ){\r
374                                         for( i = touches.length; i; ){\r
375                                                 uid = touches[ --i ][ 'pointerId' ];\r
376                                                 XUI_Gesture_CAPTURED[ uid ] = hammer;\r
377                                                 //console.log( 'captured. ' + uid );\r
378                                         };\r
379                                         break;\r
380                                 } else\r
381                                 if( ret & X_CALLBACK_STOP_NOW ){\r
382                                         break;\r
383                                 };\r
384                         };\r
385                         //console.log( '----' );\r
386                 } else {\r
387                         \r
388                 };\r
389                 \r
390                 if( isEnd || ( ret & X_CALLBACK_RELEASE_POINTER ) ){\r
391                         for( i = touches.length; i; ){\r
392                                 uid = touches[ --i ][ 'pointerId' ];\r
393                                 if( XUI_Gesture_CAPTURED[ uid ] === hammer ){\r
394                                         console.log( 'released. ' + uid );\r
395                                         delete XUI_Gesture_CAPTURED[ uid ];\r
396                                 };\r
397                         };\r
398                 };\r
399 \r
400                 if( isEnd ){\r
401                         console.log( '=- clear -=' );\r
402                         XUI_rootData[ 'unlisten' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent );\r
403                         \r
404                         hammer.previous = {\r
405                                 gestureCurrentName   : hammer.gestureCurrentName,\r
406                                 gestureStartEvent    : hammer.gestureStartEvent,\r
407                                 gestureLastEvent     : hammer.gestureLastEvent,\r
408                                 gestureLastMoveEvent : hammer.gestureLastMoveEvent\r
409                         };\r
410                         \r
411                         X_Object_clear( hammer.gestureTriggered );\r
412                         X_Object_clear( hammer.gestureCanceled  );\r
413                         \r
414                         delete hammer.gestureCurrentName;\r
415                         delete hammer.gestureStartEvent;\r
416                         delete hammer.gestureLastEvent;\r
417                         delete hammer.gestureLastMoveEvent;\r
418                         \r
419                         ret |= X_CALLBACK_RELEASE_POINTER;\r
420                 };\r
421                 \r
422                 return ret;\r
423 };\r
424 \r
425 \r
426 \r
427 var XUI_Gesture_LIST = [\r
428         /**\r
429          * Touch\r
430          * Called as first, tells the user has touched the screen\r
431          * @events  touch\r
432          */\r
433         {\r
434                 name     : 'touch',\r
435                 index    : -Infinity,\r
436                 defaults : {\r
437                         // call preventDefault at touchstart, and makes the element blocking by\r
438                         // disabling the scrolling of the page, but it improves gestures like\r
439                         // transforming and dragging.\r
440                         // be careful with using this, it can be very annoying for users to be stuck\r
441                         // on the page\r
442                         prevent_default : false,\r
443 \r
444                         // disable mouse events, so only touch (or pen!) input triggers events\r
445                         prevent_mouseevents : false\r
446                 },\r
447                 handler : function( e, hammer ){\r
448                         if( hammer.gestureOptions.prevent_mouseevents && e[ 'pointerType' ] === 'mouse' ){\r
449                                 return X_CALLBACK_STOP_NOW;\r
450                         };\r
451 \r
452                         //hammer.gestureOptions.prevent_default && e.preventDefault();\r
453 \r
454                         return e.type === XUI_Event._POINTER_DOWN && XUI_Gesture_trigger( hammer, XUI_Event.TOUCH, e );\r
455                 }\r
456         },\r
457         \r
458         /**\r
459          * Transform\r
460          * User want to scale or rotate with 2 fingers\r
461          * @events  transform, transformstart, transformend, pinch, pinchin, pinchout, rotate\r
462          */\r
463         {\r
464                 name     : 'transform',\r
465                 index    : 45,\r
466                 startID  : XUI_Event.TRANSFORM,\r
467                 endID    : XUI_Event.ROTATE,\r
468                 defaults : {\r
469                         // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1\r
470                         transform_min_scale : 0.01,\r
471                         // rotation in degrees\r
472                         transform_min_rotation : 1,\r
473                         // prevent default browser behavior when two touches are on the screen\r
474                         // but it makes the element a blocking element\r
475                         // when you are using the transform gesture, it is a good practice to set this true\r
476                         transform_always_block : false\r
477                 },\r
478 \r
479                 handler : function( e, hammer ){\r
480                         var transform = this, ret = X_CALLBACK_NONE, scale_threshold, rotation_threshold;\r
481                         \r
482                         // current gesture isnt drag, but dragged is true\r
483                         // this means an other gesture is busy. now call dragend\r
484                         if( hammer.gestureCurrentName !== transform.name && hammer.gestureTriggered[ transform.name ] ){\r
485                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
486                                 delete hammer.gestureTriggered[ transform.name ];\r
487                                 return ret;\r
488                         };\r
489 \r
490                         // atleast multitouch\r
491                         if( e.touches.length < 2 ) return;\r
492 \r
493                         // prevent default when two fingers are on the screen\r
494                         //hammer.gestureOptions.transform_always_block && e.preventDefault();\r
495 \r
496                         switch( e.type ){\r
497                                 case XUI_Event._POINTER_DOWN :\r
498                                         //hammer.gestureTriggered[ transform.name ] = false;\r
499                                         break;\r
500 \r
501                                 case XUI_Event._POINTER_MOVE:\r
502                                         scale_threshold    = Math.abs( 1 - e.scale );\r
503                                         rotation_threshold = Math.abs( e.rotation );\r
504 \r
505                                         // when the distance we moved is too small we skip this gesture\r
506                                         // or we can be already in dragging\r
507                                         if( scale_threshold < hammer.gestureOptions.transform_min_scale && rotation_threshold < hammer.gestureOptions.transform_min_rotation ) return;\r
508 \r
509                                         // we are transforming!\r
510                                         hammer.gestureCurrentName = transform.name;\r
511 \r
512                                         // first time, trigger dragstart event\r
513                                         if( !hammer.gestureTriggered[ transform.name ] ){\r
514                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_START, e );\r
515                                                 if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
516                                                         hammer.gestureCanceled[ transform.name ] = true;\r
517                                                         break;\r
518                                                 };\r
519                                                 hammer.gestureTriggered[ transform.name ] = true;\r
520                                                 break;\r
521                                         };\r
522 \r
523                                         ret |= XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM, e );\r
524                                         // basic transform event\r
525 \r
526                                         // trigger rotate event\r
527                                         if( hammer.gestureOptions.transform_min_rotation < rotation_threshold ){\r
528                                                 ret |= XUI_Gesture_trigger( hammer, XUI_Event.ROTATE, e );\r
529                                         };\r
530                                         \r
531                                         // trigger pinch event\r
532                                         if( scale_threshold > hammer.gestureOptions.transform_min_scale ){\r
533                                                 ret |= XUI_Gesture_trigger( hammer, XUI_Event.PINCH, e );\r
534                                                 ret |= XUI_Gesture_trigger( hammer, e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e );\r
535                                         };\r
536                                         break;\r
537 \r
538                                 case XUI_Event.POINTER_OUT :\r
539                                 case XUI_Event._POINTER_CANCEL :\r
540                                 case XUI_Event._POINTER_UP :\r
541                                         // trigger dragend\r
542                                         ret = hammer.gestureTriggered[ transform.name ] && XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
543                                         hammer.gestureTriggered[ transform.name ] = false;\r
544                                         break;\r
545                         };\r
546                         return ret;\r
547                 }\r
548         },\r
549         \r
550         /**\r
551          * Drag\r
552          * Move with x fingers (default 1) around on the page. Blocking the scrolling when\r
553          * moving left and right is a good practice. When all the drag events are blocking\r
554          * you disable scrolling on that area.\r
555          * @events  drag, dragstart, dragend, drapleft, dragright, dragup, dragdown\r
556          */\r
557         {\r
558                 name     : 'drag',\r
559                 index    : 50,\r
560                 startID  : XUI_Event.DRAG,\r
561                 endID    : XUI_Event.DRAG_DOWN,\r
562                 \r
563                 defaults : {\r
564                         drag_min_distance : 10,\r
565                         // set 0 for unlimited, but this can conflict with transform\r
566                         drag_max_touches : 1,\r
567                         // prevent default browser behavior when dragging occurs\r
568                         // be careful with it, it makes the element a blocking element\r
569                         // when you are using the drag gesture, it is a good practice to set this true\r
570                         drag_block_horizontal : false,\r
571                         drag_block_vertical : false,\r
572                         // drag_lock_to_axis keeps the drag gesture on the axis that it started on,\r
573                         // It disallows vertical directions if the initial direction was horizontal, and vice versa.\r
574                         drag_lock_to_axis : false,\r
575                         // drag lock only kicks in when distance > drag_lock_min_distance\r
576                         // This way, locking occurs only when the distance has become large enough to reliably determine the direction\r
577                         drag_lock_min_distance : 25\r
578                 },\r
579 \r
580                 handler : function( e, hammer ){\r
581                         var drag = this, last_direction, ret;\r
582 \r
583                         // current gesture isnt drag, but dragged is true\r
584                         // this means an other gesture is busy. now call dragend\r
585                         if( hammer.gestureCurrentName !== drag.name && hammer.gestureTriggered[ drag.name ] ){\r
586                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e );\r
587                                 hammer.gestureTriggered[ drag.name ] = false;\r
588                                 return ret;\r
589                         };\r
590 \r
591                         // max touches\r
592                         if( 0 < hammer.gestureOptions.drag_max_touches && hammer.gestureOptions.drag_max_touches < e.touches.length ) return;\r
593                         \r
594                         switch( e.type ){\r
595                                 case XUI_Event._POINTER_DOWN :\r
596                                         hammer.gestureTriggered[ drag.name ] = false;\r
597                                         break;\r
598 \r
599                                 case XUI_Event._POINTER_MOVE :\r
600                                         // when the distance we moved is too small we skip this gesture\r
601                                         // or we can be already in dragging\r
602                                         if( e.distance < hammer.gestureOptions.drag_min_distance && hammer.gestureCurrentName !== drag.name ) return;\r
603 \r
604                                         // we are dragging!\r
605                                         hammer.gestureCurrentName = drag.name;\r
606 \r
607                                         // lock drag to axis?\r
608                                         if( hammer.gestureLastEvent.drag_locked_to_axis || ( hammer.gestureOptions.drag_lock_to_axis && hammer.gestureOptions.drag_lock_min_distance <= e.distance ) ){\r
609                                                 e.drag_locked_to_axis = true;\r
610                                         };\r
611                                         last_direction = hammer.gestureLastEvent.direction;\r
612                                         if( e.drag_locked_to_axis && last_direction !== e.direction ){\r
613                                                 // keep direction on the axis that the drag gesture started on\r
614                                                 e.direction = XUI_GestureUtils.isVertical( last_direction ) ?\r
615                                                         ( e.deltaY < 0 ? 'up'   : 'down' ) :\r
616                                                         ( e.deltaX < 0 ? 'left' : 'right' );\r
617                                         };\r
618 \r
619                                         ret = X_CALLBACK_NONE;\r
620 \r
621                                         // first time, trigger dragstart event\r
622                                         if( !hammer.gestureTriggered[ drag.name ] ){\r
623                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_START, e );\r
624                                                 //if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
625                                                 //      hammer.gestureCanceled[ drag.name ] = true;\r
626                                                 //      break;\r
627                                                 //};\r
628                                                 ret |= X_CALLBACK_CAPTURE_POINTER;\r
629                                                 console.log( '----- drag start ....' + e.type );\r
630                                                 hammer.gestureTriggered[ drag.name ] = true;\r
631                                                 break;\r
632                                         };\r
633 \r
634                                         //console.log( '----- drag ....' + e.type );\r
635                                         // trigger normal event\r
636                                         ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG, e ) | X_CALLBACK_CAPTURE_POINTER;\r
637 \r
638                                         // direction event, like dragdown\r
639                                         ret |= XUI_Gesture_trigger( hammer,\r
640                                                 e.direction === 'up' ?\r
641                                                         XUI_Event.DRAG_UP :\r
642                                                 e.direction === 'down' ?\r
643                                                         XUI_Event.DRAG_DOWN :\r
644                                                 e.direction === 'left' ?\r
645                                                         XUI_Event.DRAG_LEFT :\r
646                                                         XUI_Event.DRAG_RIGHT,\r
647                                                 e\r
648                                         );\r
649 \r
650                                         // block the browser events\r
651                                         /* (\r
652                                                 ( hammer.gestureOptions.drag_block_vertical   &&  XUI_GestureUtils.isVertical( e.direction ) ) ||\r
653                                                 ( hammer.gestureOptions.drag_block_horizontal && !XUI_GestureUtils.isVertical( e.direction ) )\r
654                                         ) && e.preventDefault(); */\r
655                                         break;\r
656 \r
657                                 case XUI_Event.POINTER_OUT :\r
658                                         console.log( 'cancel!!' );\r
659                                 case XUI_Event._POINTER_CANCEL :\r
660                                 case XUI_Event._POINTER_UP:\r
661                                         // trigger dragend\r
662                                         if( hammer.gestureTriggered[ drag.name ] ){\r
663                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e ) | X_CALLBACK_CAPTURE_POINTER;\r
664                                                 console.log( '----- drag end ....' + e.type );\r
665                                                 hammer.gestureTriggered[ drag.name ] = false;\r
666                                         };\r
667                                         break;\r
668                         };\r
669                         return ret;\r
670                 }\r
671         },\r
672 \r
673         /**\r
674          * Tap/DoubleTap\r
675          * Quick touch at a place or double at the same place\r
676          * @events  tap, doubletap\r
677          */\r
678         {\r
679                 name     : 'tap',\r
680                 index    : 100,\r
681                 startID  : XUI_Event.TAP,\r
682                 endID    : XUI_Event.DOUBLE_TAP,\r
683                 defaults : {\r
684                         tap_max_touchtime  : 250,\r
685                         tap_max_distance   : 3,\r
686                         tap_always         : true,\r
687                         doubletap_distance : 20,\r
688                         doubletap_interval : 300\r
689                 },\r
690                 handler : function( e, hammer ){\r
691                         // previous gesture, for the double tap since these are two different gesture detections\r
692                         var prev = hammer.previous;\r
693                         \r
694                         if( e.type === XUI_Event._POINTER_MOVE && hammer.gestureOptions.tap_max_distance < e.distance ){\r
695                                 hammer.gestureCanceled[ 'tap' ] = true;\r
696                         };\r
697                         if( e.type === XUI_Event._POINTER_UP ){\r
698                                 // when the touchtime is higher then the max touch time\r
699                                 // or when the moving distance is too much\r
700                                 if( hammer.gestureOptions.tap_max_touchtime < e.deltaTime || hammer.gestureOptions.tap_max_distance < e.distance ) return;\r
701 \r
702                                 // check if double tap\r
703                                 if( prev && prev.gestureCurrentName === 'tap' && ( e.timestamp - prev.gestureLastEvent.timestamp ) < hammer.gestureOptions.doubletap_interval && e.distance < hammer.gestureOptions.doubletap_distance ){\r
704                                         return XUI_Gesture_trigger( hammer, XUI_Event.DOUBLE_TAP, e );\r
705                                 } else\r
706                                 // do a single tap\r
707                                 if( hammer.gestureOptions.tap_always ){\r
708                                         hammer.gestureCurrentName = 'tap';\r
709                                         console.log( 'tap! ' + e.deltaTime + 'ms ' + e.type );\r
710                                         return XUI_Gesture_trigger( hammer, XUI_Event.TAP, e );\r
711                                 };\r
712                         };\r
713                 }\r
714         }\r
715 \r
716 ];\r
717 \r
718 (function( i, g ){\r
719         for( ; i; ){\r
720                 g = XUI_Gesture_LIST[ --i ];\r
721                 X_Object_override( XUI_Gesture_DEFAULTS, g.defaults );\r
722                 delete g.defaults;\r
723         };\r
724 })( XUI_Gesture_LIST.length );\r
725 \r