OSDN Git Service

Fix the bug of X.NodeAnime.
[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, hammerEvent, 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( isEnd ){\r
268                         if( XUI_Gesture_POINTERS[ uid ] ){\r
269                                 delete XUI_Gesture_POINTERS[ uid ];\r
270                                 if( XUI_Gesture_CAPTURED[ uid ] ) delete XUI_Gesture_CAPTURED[ uid ];\r
271                         };\r
272                 } else {\r
273                         XUI_Gesture_POINTERS[ uid ] = e;\r
274                 };\r
275 \r
276                 // mousebutton must be down or a touch event\r
277                 if( ( isEnd || !isMouse || e.button === 0 ) ){\r
278                         numTouches = -1;\r
279 \r
280                         for( i in XUI_Gesture_POINTERS ){\r
281                                 if( p = XUI_Gesture_POINTERS[ i ] ){\r
282                                         // いずれかの hammer によって束縛されている場合、その束縛している hammer なら\r
283                                         captured = XUI_Gesture_CAPTURED[ p[ 'pointerId' ] ];\r
284                                         if( captured && captured !== hammer ){\r
285                                                 continue;\r
286                                         };\r
287                                         touches[ ++numTouches ] = p;\r
288                                 };\r
289                         };\r
290                         ++numTouches;\r
291 \r
292                         // if we are in a end event, but when we remove one touch and\r
293                         // we still have enough, set eventType to move\r
294                         if( !numTouches ){ // no touches, force the end event\r
295                                 isEnd = true;\r
296                         };\r
297 \r
298                         // because touchend has no touches, and we often want to use these in our gestures,\r
299                         // we send the last move event as our eventData in touchend\r
300                         ( isEnd && hammer.gestureLastMoveEvent ) ? ( e = hammer.gestureLastMoveEvent ) : ( hammer.gestureLastMoveEvent = e ); // store the last move event\r
301 \r
302                         hammerEvent = X_Object_copy( e );\r
303                         hammerEvent.touches = touches;\r
304 \r
305                         if( isStart && !hammer.gestureStartEvent ){\r
306                                 //console.log( '=- add -=' );\r
307                                 // already busy with a Hammer.gesture detection on an element\r
308                                 hammer.gestureStartEvent = hammerEvent;\r
309                                 XUI_rootData[ 'listen' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent );                              \r
310                         };\r
311                         \r
312                         startEv = hammer.gestureStartEvent;\r
313                         \r
314 \r
315                         // if the touches change, set the new touches over the startEvent touches\r
316                         // this because touchevents don't have all the touches on touchstart, or the\r
317                         // user must place his fingers at the EXACT same time on the screen, which is not realistic\r
318                         // but, sometimes it happens that both fingers are touching at the EXACT same time\r
319                         if( startEv && ( numTouches !== startEv.touches.length || touches !== startEv.touches ) ){\r
320                                 // extend 1 level deep to get the touchlist with the touch objects\r
321                                 startEv.touches.length = i = 0;\r
322                                 j = -1;\r
323                                 for( ; i < numTouches; ++i ){\r
324                                         startEv.touches[ ++j ] = touches[ i ];\r
325                                 };\r
326                         };\r
327 \r
328                         deltaTime   = hammerEvent.timestamp  - startEv.timestamp;\r
329                         center      = XUI_GestureUtils.getCenter( touches );\r
330                         startCenter = startEv.center;\r
331                         deltaX      = startCenter ? ( center.pageX - startCenter.pageX ) : 0;\r
332                         deltaY      = startCenter ? ( center.pageY - startCenter.pageY ) : 0;\r
333                         velocity    = XUI_GestureUtils.getVelocity( deltaTime, deltaX, deltaY );\r
334 \r
335                         X_Object_override( hammerEvent, {\r
336                                 type       : isEnd ? XUI_Event._POINTER_UP : type,\r
337                                 \r
338                                 deltaTime  : deltaTime,\r
339 \r
340                                 deltaX     : deltaX,\r
341                                 deltaY     : deltaY,\r
342 \r
343                                 velocityX  : velocity.x,\r
344                                 velocityY  : velocity.y,\r
345 \r
346                                 center     : center,\r
347                                 distance   : startCenter ? XUI_GestureUtils.getDistance( startCenter, center ) : 0,\r
348                                 angle      : startCenter ? XUI_GestureUtils.getAngle( startCenter, center ) : 0,\r
349                                 direction  : startCenter ? XUI_GestureUtils.getDirection( startCenter, center ) : 0,\r
350 \r
351                                 scale      : XUI_GestureUtils.getScale( startEv.touches, touches ),\r
352                                 rotation   : XUI_GestureUtils.getRotation( startEv.touches, touches ),\r
353 \r
354                                 gestureStartEvent : startEv\r
355                         });\r
356 \r
357                         // store as previous event event\r
358                         hammer.gestureLastEvent = hammerEvent;\r
359                         activated = hammer.gestureActivated;\r
360                         //console.log( '... ' );\r
361                         // call Hammer.gesture handlers\r
362                         for( i = 0, l = gestures.length; i < l; ++i ){\r
363                                 gesture = gestures[ i ];\r
364 \r
365                                 if( activated[ gesture.name ] && !hammer.gestureCanceled[ gesture.name ] ){\r
366                                         //( console.log( '... ' + i + ' ' + gesture.name ) );\r
367                                         // if a handler returns false, we stop with the detection\r
368                                         ( ret |= ( gesture.handler( hammerEvent, hammer ) || X_CALLBACK_NONE ) );\r
369                                 };\r
370 \r
371                                 if( ret & X_CALLBACK_CAPTURE_POINTER ){\r
372                                         for( i = touches.length; i; ){\r
373                                                 uid = touches[ --i ][ 'pointerId' ];\r
374                                                 XUI_Gesture_CAPTURED[ uid ] = hammer;\r
375                                                 //console.log( 'captured. ' + uid );\r
376                                         };\r
377                                         break;\r
378                                 } else\r
379                                 if( ret & X_CALLBACK_STOP_NOW ){\r
380                                         break;\r
381                                 };\r
382                         };\r
383                         //console.log( '----' );\r
384                 } else {\r
385                         \r
386                 };\r
387                 \r
388                 if( isEnd || ( ret & X_CALLBACK_RELEASE_POINTER ) ){\r
389                         for( i = touches.length; i; ){\r
390                                 uid = touches[ --i ][ 'pointerId' ];\r
391                                 if( XUI_Gesture_CAPTURED[ uid ] === hammer ){\r
392                                         //console.log( 'released. ' + uid );\r
393                                         delete XUI_Gesture_CAPTURED[ uid ];\r
394                                 };\r
395                         };\r
396                 };\r
397 \r
398                 if( isEnd ){\r
399                         //console.log( '=- clear -=' );\r
400                         XUI_rootData[ 'unlisten' ]( [ XUI_Event._POINTER_MOVE, XUI_Event._POINTER_UP, XUI_Event._POINTER_CANCEL, XUI_Event.POINTER_OUT ], hammer, XUI_Gesture_handleEvent );\r
401                         \r
402                         hammer.previous = {\r
403                                 gestureCurrentName   : hammer.gestureCurrentName,\r
404                                 gestureStartEvent    : hammer.gestureStartEvent,\r
405                                 gestureLastEvent     : hammer.gestureLastEvent,\r
406                                 gestureLastMoveEvent : hammer.gestureLastMoveEvent\r
407                         };\r
408                         \r
409                         X_Object_clear( hammer.gestureTriggered );\r
410                         X_Object_clear( hammer.gestureCanceled  );\r
411                         \r
412                         delete hammer.gestureCurrentName;\r
413                         delete hammer.gestureStartEvent;\r
414                         delete hammer.gestureLastEvent;\r
415                         delete hammer.gestureLastMoveEvent;\r
416                         \r
417                         ret |= X_CALLBACK_RELEASE_POINTER;\r
418                 };\r
419                 \r
420                 return ret;\r
421 };\r
422 \r
423 \r
424 \r
425 var XUI_Gesture_LIST = [\r
426         /*\r
427          * Touch\r
428          * Called as first, tells the user has touched the screen\r
429          * @events  touch\r
430          */\r
431         {\r
432                 name     : 'touch',\r
433                 index    : -Infinity,\r
434                 defaults : {\r
435                         // call preventDefault at touchstart, and makes the element blocking by\r
436                         // disabling the scrolling of the page, but it improves gestures like\r
437                         // transforming and dragging.\r
438                         // be careful with using this, it can be very annoying for users to be stuck\r
439                         // on the page\r
440                         prevent_default : false,\r
441 \r
442                         // disable mouse events, so only touch (or pen!) input triggers events\r
443                         prevent_mouseevents : false\r
444                 },\r
445                 handler : function( e, hammer ){\r
446                         if( hammer.gestureOptions.prevent_mouseevents && e[ 'pointerType' ] === 'mouse' ){\r
447                                 return X_CALLBACK_STOP_NOW;\r
448                         };\r
449 \r
450                         //hammer.gestureOptions.prevent_default && e.preventDefault();\r
451 \r
452                         return e.type === XUI_Event._POINTER_DOWN && XUI_Gesture_trigger( hammer, XUI_Event.TOUCH, e );\r
453                 }\r
454         },\r
455         \r
456         /*\r
457          * Transform\r
458          * User want to scale or rotate with 2 fingers\r
459          * @events  transform, transformstart, transformend, pinch, pinchin, pinchout, rotate\r
460          */\r
461         {\r
462                 name     : 'transform',\r
463                 index    : 45,\r
464                 startID  : XUI_Event.TRANSFORM,\r
465                 endID    : XUI_Event.ROTATE,\r
466                 defaults : {\r
467                         // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1\r
468                         transform_min_scale : 0.01,\r
469                         // rotation in degrees\r
470                         transform_min_rotation : 1,\r
471                         // prevent default browser behavior when two touches are on the screen\r
472                         // but it makes the element a blocking element\r
473                         // when you are using the transform gesture, it is a good practice to set this true\r
474                         transform_always_block : false\r
475                 },\r
476 \r
477                 handler : function( e, hammer ){\r
478                         var transform = this, ret = X_CALLBACK_NONE, scale_threshold, rotation_threshold;\r
479                         \r
480                         // current gesture isnt drag, but dragged is true\r
481                         // this means an other gesture is busy. now call dragend\r
482                         if( hammer.gestureCurrentName !== transform.name && hammer.gestureTriggered[ transform.name ] ){\r
483                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
484                                 delete hammer.gestureTriggered[ transform.name ];\r
485                                 return ret;\r
486                         };\r
487 \r
488                         // atleast multitouch\r
489                         if( e.touches.length < 2 ) return;\r
490 \r
491                         // prevent default when two fingers are on the screen\r
492                         //hammer.gestureOptions.transform_always_block && e.preventDefault();\r
493 \r
494                         switch( e.type ){\r
495                                 case XUI_Event._POINTER_DOWN :\r
496                                         //hammer.gestureTriggered[ transform.name ] = false;\r
497                                         break;\r
498 \r
499                                 case XUI_Event._POINTER_MOVE:\r
500                                         scale_threshold    = Math.abs( 1 - e.scale );\r
501                                         rotation_threshold = Math.abs( e.rotation );\r
502 \r
503                                         // when the distance we moved is too small we skip this gesture\r
504                                         // or we can be already in dragging\r
505                                         if( scale_threshold < hammer.gestureOptions.transform_min_scale && rotation_threshold < hammer.gestureOptions.transform_min_rotation ) return;\r
506 \r
507                                         // we are transforming!\r
508                                         hammer.gestureCurrentName = transform.name;\r
509 \r
510                                         // first time, trigger dragstart event\r
511                                         if( !hammer.gestureTriggered[ transform.name ] ){\r
512                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_START, e );\r
513                                                 if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
514                                                         hammer.gestureCanceled[ transform.name ] = true;\r
515                                                         break;\r
516                                                 };\r
517                                                 hammer.gestureTriggered[ transform.name ] = true;\r
518                                                 break;\r
519                                         };\r
520 \r
521                                         ret |= XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM, e );\r
522                                         // basic transform event\r
523 \r
524                                         // trigger rotate event\r
525                                         if( hammer.gestureOptions.transform_min_rotation < rotation_threshold ){\r
526                                                 ret |= XUI_Gesture_trigger( hammer, XUI_Event.ROTATE, e );\r
527                                         };\r
528                                         \r
529                                         // trigger pinch event\r
530                                         if( scale_threshold > hammer.gestureOptions.transform_min_scale ){\r
531                                                 ret |= XUI_Gesture_trigger( hammer, XUI_Event.PINCH, e );\r
532                                                 ret |= XUI_Gesture_trigger( hammer, e.scale < 1 ? XUI_Event.PINCH_IN : XUI_Event.PINCH_OUT, e );\r
533                                         };\r
534                                         break;\r
535 \r
536                                 case XUI_Event.POINTER_OUT :\r
537                                 case XUI_Event._POINTER_CANCEL :\r
538                                 case XUI_Event._POINTER_UP :\r
539                                         // trigger dragend\r
540                                         ret = hammer.gestureTriggered[ transform.name ] && XUI_Gesture_trigger( hammer, XUI_Event.TRANSFORM_END, e );\r
541                                         hammer.gestureTriggered[ transform.name ] = false;\r
542                                         break;\r
543                         };\r
544                         return ret;\r
545                 }\r
546         },\r
547         \r
548         /*\r
549          * Drag\r
550          * Move with x fingers (default 1) around on the page. Blocking the scrolling when\r
551          * moving left and right is a good practice. When all the drag events are blocking\r
552          * you disable scrolling on that area.\r
553          * @events  drag, dragstart, dragend, drapleft, dragright, dragup, dragdown\r
554          */\r
555         {\r
556                 name     : 'drag',\r
557                 index    : 50,\r
558                 startID  : XUI_Event.DRAG,\r
559                 endID    : XUI_Event.DRAG_DOWN,\r
560                 \r
561                 defaults : {\r
562                         drag_min_distance : 10,\r
563                         // set 0 for unlimited, but this can conflict with transform\r
564                         drag_max_touches : 1,\r
565                         // prevent default browser behavior when dragging occurs\r
566                         // be careful with it, it makes the element a blocking element\r
567                         // when you are using the drag gesture, it is a good practice to set this true\r
568                         drag_block_horizontal : false,\r
569                         drag_block_vertical : false,\r
570                         // drag_lock_to_axis keeps the drag gesture on the axis that it started on,\r
571                         // It disallows vertical directions if the initial direction was horizontal, and vice versa.\r
572                         drag_lock_to_axis : false,\r
573                         // drag lock only kicks in when distance > drag_lock_min_distance\r
574                         // This way, locking occurs only when the distance has become large enough to reliably determine the direction\r
575                         drag_lock_min_distance : 25\r
576                 },\r
577 \r
578                 handler : function( e, hammer ){\r
579                         var drag = this, last_direction, ret;\r
580 \r
581                         // current gesture isnt drag, but dragged is true\r
582                         // this means an other gesture is busy. now call dragend\r
583                         if( hammer.gestureCurrentName !== drag.name && hammer.gestureTriggered[ drag.name ] ){\r
584                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e );\r
585                                 hammer.gestureTriggered[ drag.name ] = false;\r
586                                 return ret;\r
587                         };\r
588 \r
589                         // max touches\r
590                         if( 0 < hammer.gestureOptions.drag_max_touches && hammer.gestureOptions.drag_max_touches < e.touches.length ) return;\r
591                         \r
592                         switch( e.type ){\r
593                                 case XUI_Event._POINTER_DOWN :\r
594                                         hammer.gestureTriggered[ drag.name ] = false;\r
595                                         break;\r
596 \r
597                                 case XUI_Event._POINTER_MOVE :\r
598                                         // when the distance we moved is too small we skip this gesture\r
599                                         // or we can be already in dragging\r
600                                         if( e.distance < hammer.gestureOptions.drag_min_distance && hammer.gestureCurrentName !== drag.name ) return;\r
601 \r
602                                         // we are dragging!\r
603                                         hammer.gestureCurrentName = drag.name;\r
604 \r
605                                         // lock drag to axis?\r
606                                         if( hammer.gestureLastEvent.drag_locked_to_axis || ( hammer.gestureOptions.drag_lock_to_axis && hammer.gestureOptions.drag_lock_min_distance <= e.distance ) ){\r
607                                                 e.drag_locked_to_axis = true;\r
608                                         };\r
609                                         last_direction = hammer.gestureLastEvent.direction;\r
610                                         if( e.drag_locked_to_axis && last_direction !== e.direction ){\r
611                                                 // keep direction on the axis that the drag gesture started on\r
612                                                 e.direction = XUI_GestureUtils.isVertical( last_direction ) ?\r
613                                                         ( e.deltaY < 0 ? 'up'   : 'down' ) :\r
614                                                         ( e.deltaX < 0 ? 'left' : 'right' );\r
615                                         };\r
616 \r
617                                         ret = X_CALLBACK_NONE;\r
618 \r
619                                         // first time, trigger dragstart event\r
620                                         if( !hammer.gestureTriggered[ drag.name ] ){\r
621                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_START, e );\r
622                                                 //if( ret & X_CALLBACK_PREVENT_DEFAULT ){\r
623                                                 //      hammer.gestureCanceled[ drag.name ] = true;\r
624                                                 //      break;\r
625                                                 //};\r
626                                                 ret |= X_CALLBACK_CAPTURE_POINTER;\r
627                                                 //console.log( '----- drag start ....' + e.type );\r
628                                                 hammer.gestureTriggered[ drag.name ] = true;\r
629                                                 break;\r
630                                         };\r
631 \r
632                                         //console.log( '----- drag ....' + e.type );\r
633                                         // trigger normal event\r
634                                         ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG, e ) | X_CALLBACK_CAPTURE_POINTER;\r
635 \r
636                                         // direction event, like dragdown\r
637                                         ret |= XUI_Gesture_trigger( hammer,\r
638                                                 e.direction === 'up' ?\r
639                                                         XUI_Event.DRAG_UP :\r
640                                                 e.direction === 'down' ?\r
641                                                         XUI_Event.DRAG_DOWN :\r
642                                                 e.direction === 'left' ?\r
643                                                         XUI_Event.DRAG_LEFT :\r
644                                                         XUI_Event.DRAG_RIGHT,\r
645                                                 e\r
646                                         );\r
647 \r
648                                         // block the browser events\r
649                                         /* (\r
650                                                 ( hammer.gestureOptions.drag_block_vertical   &&  XUI_GestureUtils.isVertical( e.direction ) ) ||\r
651                                                 ( hammer.gestureOptions.drag_block_horizontal && !XUI_GestureUtils.isVertical( e.direction ) )\r
652                                         ) && e.preventDefault(); */\r
653                                         break;\r
654 \r
655                                 case XUI_Event.POINTER_OUT :\r
656                                         //console.log( 'cancel!!' );\r
657                                 case XUI_Event._POINTER_CANCEL :\r
658                                 case XUI_Event._POINTER_UP:\r
659                                         // trigger dragend\r
660                                         if( hammer.gestureTriggered[ drag.name ] ){\r
661                                                 ret = XUI_Gesture_trigger( hammer, XUI_Event.DRAG_END, e ) | X_CALLBACK_CAPTURE_POINTER;\r
662                                                 //console.log( '----- drag end ....' + e.type );\r
663                                                 hammer.gestureTriggered[ drag.name ] = false;\r
664                                         };\r
665                                         break;\r
666                         };\r
667                         return ret;\r
668                 }\r
669         },\r
670 \r
671         /*\r
672          * Tap/DoubleTap\r
673          * Quick touch at a place or double at the same place\r
674          * @events  tap, doubletap\r
675          */\r
676         {\r
677                 name     : 'tap',\r
678                 index    : 100,\r
679                 startID  : XUI_Event.TAP,\r
680                 endID    : XUI_Event.DOUBLE_TAP,\r
681                 defaults : {\r
682                         tap_max_touchtime  : 250,\r
683                         tap_max_distance   : 3,\r
684                         tap_always         : true,\r
685                         doubletap_distance : 20,\r
686                         doubletap_interval : 300\r
687                 },\r
688                 handler : function( e, hammer ){\r
689                         // previous gesture, for the double tap since these are two different gesture detections\r
690                         var prev = hammer.previous;\r
691                         \r
692                         if( e.type === XUI_Event._POINTER_MOVE && hammer.gestureOptions.tap_max_distance < e.distance ){\r
693                                 hammer.gestureCanceled[ 'tap' ] = true;\r
694                         };\r
695                         if( e.type === XUI_Event._POINTER_UP ){\r
696                                 // when the touchtime is higher then the max touch time\r
697                                 // or when the moving distance is too much\r
698                                 if( hammer.gestureOptions.tap_max_touchtime < e.deltaTime || hammer.gestureOptions.tap_max_distance < e.distance ) return;\r
699 \r
700                                 // check if double tap\r
701                                 if( prev && prev.gestureCurrentName === 'tap' && ( e.timestamp - prev.gestureLastEvent.timestamp ) < hammer.gestureOptions.doubletap_interval && e.distance < hammer.gestureOptions.doubletap_distance ){\r
702                                         return XUI_Gesture_trigger( hammer, XUI_Event.DOUBLE_TAP, e );\r
703                                 } else\r
704                                 // do a single tap\r
705                                 if( hammer.gestureOptions.tap_always ){\r
706                                         hammer.gestureCurrentName = 'tap';\r
707                                         //console.log( 'tap! ' + e.deltaTime + 'ms ' + e.type );\r
708                                         return XUI_Gesture_trigger( hammer, XUI_Event.TAP, e );\r
709                                 };\r
710                         };\r
711                 }\r
712         }\r
713 \r
714 ];\r
715 \r
716 (function( i, g ){\r
717         for( ; i; ){\r
718                 g = XUI_Gesture_LIST[ --i ];\r
719                 X_Object_override( XUI_Gesture_DEFAULTS, g.defaults );\r
720                 delete g.defaults;\r
721         };\r
722 })( XUI_Gesture_LIST.length );\r
723 \r