123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533 |
- /*jslint undef: true, browser: true, continue: true, eqeq: true, vars: true, forin: true, white: true, newcap: false, nomen: true, plusplus: true, maxerr: 50, indent: 4 */
- /**
- * jGestures: a jQuery plugin for gesture events
- * Copyright 2010-2011 Neue Digitale / Razorfish GmbH
- * Copyright 2011-2012, Razorfish GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @fileOverview
- * Razorfish GmbH javascript library: add touch events such as 'pinch',
- * 'rotate', 'swipe', 'tap' and 'orientationchange' on capable user agents.
- * For incapable devices there's a basic event substitution: a "tapone" event
- * can be triggered by "clicking", a "swipeone" by performing a swipe-ish
- * gesture using the mouse (buttondown - mousemove - buttonup).
- *
- * This is still a beta version, bugfixes and improvements appreciated.
- *
- * @author martin.krause@razorfish.de
- * @version 0.90-shake
- *
- * @requires
- * jQuery JavaScript Library v1.4.2 - http://jquery.com/
- * Copyright 2010, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * @example jQuery('#swipe').bind('swipeone',eventHandler);
- *
- * Notification on native events:
- * On every native touchstart, touchend, gesturestart and gestureend-event,
- * jgestures triggers a corresponding custom event
- * ('jGestures.touchstart', 'jGestures.touchend;start', 'jGestures.touchend;processed',
- * 'jGestures.gesturestart', 'jGestures.gestureend;start', 'jGestures.gestureend;processed') on the event-element.
- * The eventhandler's second argument represents the original touch event (yes: including all touchpoints).
- * Use this if you need very detailed control e.g. kinetic scrolling or implementing additional gestures.
- *
- * Every jGesture-eventhandler receives a custom object as second argument
- * containing the original event (originalEvent property) and processed
- * information (such as delta values and timesptamp).
- * Example:{
- * type: eventtype e.g. "swipe","pinch",
- * originalEvent: {DOM-Event},
- * // default: just one entry on the delta-array - the first touchpoint
- * // the first touchpoint is the reference point for every gesture,
- * // because moving touchpoints in various directions would result in
- * // a gesture.
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : [
- * {
- * lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)
- * lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)
- * moved: {Number}, // distance: relative to the original touchpoint
- * startX: {Number} , // relative to the original touchpoint
- * startY: {Number} ,// relative to the original touchpoint
- * } ],
- * // based on the first touchpoint
- * direction : { // relative to the last touchevent (e.g. touchmove!)
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * lastX : {Number}, // -1,0,+1 || null (orientationchange) // relative to the last touchevent (e.g. touchmove!)
- * lastY : {Number}, // -1,0,+1 || null (orientationchange)// relative to the last touchevent (e.g. touchmove!)
- * startX: {Number} , // relative to the original touchpoint
- * startY: {Number} ,// relative to the original touchpoint
- * },
- * rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original
- * scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint
- * };
- *
- * Available jGesture-events can be grouped into:
- *
- *
- * Device events:
- * The jGesture-Events in this group are triggered by the device.
- *
- * @event 'orientationchange'
- * The device is turned clockwise or counterclockwise. This event is triggered
- * by the device and might use an internal gyroscope.
- * obj.description:
- * orientationchange:landscape:clockwise:-90
- * orientationchange:portrait:default:0
- * orientationchange:landscape:counterclockwise|portrait:90
- * orientationchange:portrait:upsidedown:180
- *
- *
- * Move events:
- * The jGesture-Events in this group are triggered during the touch/gesture
- * execution whenever a touchpoint changes.
- * In contrast to touchend/gestureend-events which are triggered after
- * the touch/gesture has completed.
- *
- * @event 'pinch'
- * Is triggered during a pinch gesture (two fingers moving away from or
- * towards each other).
- * obj.description:
- * pinch:-1:close
- * pinch:+1:open
- *
- * @event 'rotate'
- * Is triggered during a rotation gesture (two fingers rotating clockwise
- * or counterclockwise).
- * obj.description:
- * rotate:-1:counterclockwise
- * rotate:+1:+clockwise
- *
- * @event 'swipemove'
- * Is triggered during a swipe move gesture (finger(s) being moved around
- * the device, e.g. dragging)
- * obj.description:
- * swipemove:1:left:down
- * swipemove:1:left:up
- * swipemove:1:left:steady
- * swipemove:1:right:down
- * swipemove:1:right:up
- * swipemove:1:right:steady
- * swipemove:2:left:down
- * swipemove:2:left:up
- * swipemove:2:left:steady
- * swipemove:2:right:down
- * swipemove:2:right:up
- * swipemove:2:right:steady
- * swipemove:2:left:down
- * swipemove:3:left:up
- * swipemove:3:left:steady
- * swipemove:3:right:down
- * swipemove:3:right:up
- * swipemove:3:right:steady
- * swipemove:3:left:down
- * swipemove:4:left:up
- * swipemove:4:left:steady
- * swipemove:4:right:down
- * swipemove:4:right:up
- * swipemove:4:right:steady
- *
- *
- * Toucheend events:
- * The jGesture-Events in this group are triggered after the touch/gesture
- * has completed.
- * In contrast to touchmove-events which are triggered during the touch/gesture
- * execution whenever a touchpoint changes.
- *
- * @event 'swipeone'
- * Is triggered after a swipe move gesture with one touchpoint (one finger
- * was moved around the device)
- * obj.description:
- * swipeone:1:left:down
- * swipeone:1:left:up
- * swipeone:1:left:steady
- * swipeone:1:right:down
- * swipeone:1:right:up
- * swipeone:1:right:steady
- *
- * @event 'swipetwo'
- * Is triggered after a swipe move gesture with two touchpoints (two fingers
- * were moved around the device)
- * obj.description:
- * swipetwo:2:left:down
- * swipetwo:2:left:up
- * swipetwo:2:left:steady
- * swipetwo:2:right:down
- * swipetwo:2:right:up
- * swipetwo:2:right:steady
- *
- * @event 'swipethree'
- * Is triggered after a swipe move gesture with three touchpoints (three
- * fingers were moved around the device)
- * obj.description:
- * swipethree:3:left:down
- * swipethree:3:left:up
- * swipethree:3:left:steady
- * swipethree:3:right:down
- * swipethree:3:right:up
- * swipethree:3:right:steady
- *
- * @event 'swipefour'
- * Is triggered after a swipe move gesture with four touchpoints (four
- * fingers were moved around the device)
- * obj.description:
- * swipefour:4:left:down
- * swipefour:4:left:up
- * swipefour:4:left:steady
- * swipefour:4:right:down
- * swipefour:4:right:up
- * swipefour:4:right:steady
- *
- *
- * @event 'swipeup'
- * Is triggered after an strict upwards swipe move gesture
- * obj.description:
- * swipe:1:steady:up
- * swipe:2:steady:up
- * swipe:3:steady:up
- * swipe:4:steady:up
- *
- * @event 'swiperightup'
- * Is triggered after a rightwards and upwards swipe move gesture
- * obj.description:
- * swipe:1:right:up
- * swipe:2:right:up
- * swipe:3:right:up
- * swipe:4:right:up
- *
- * @event 'swiperight'
- * Is triggered after a strict rightwards swipe move gesture
- * obj.description:
- * swipe:1:right:steady
- * swipe:2:right:steady
- * swipe:3:right:steady
- * swipe:4:right:steady
- *
- * @event 'swiperightdown'
- * Is triggered after a rightwards and downwards swipe move gesture
- * obj.description:
- * swipe:1:right:down
- * swipe:2:right:down
- * swipe:3:right:down
- * swipe:4:right:down
- *
- * @event 'swipedown'
- * Is triggered after a strict downwards swipe move gesture
- * obj.description:
- * swipe:1:steady:down
- * swipe:2:steady:down
- * swipe:3:steady:down
- * swipe:4:steady:down
- *
- * @event 'swipeleftdown'
- * Is triggered after a leftwards and downwards swipe move gesture
- * obj.description:
- * swipe:1:left:down
- * swipe:2:left:down
- * swipe:3:left:down
- * swipe:4:left:down
- *
- * @event 'swipeleft'
- * Is triggered after a strict leftwards swipe move gesture
- * obj.description:
- * swipe:1:left:steady
- * swipe:2:left:steady
- * swipe:3:left:steady
- * swipe:4:left:steady
- *
- * @event 'swipeleftup'
- * Is triggered after a leftwards and upwards swipe move gesture
- * obj.description:
- * swipe:1:left:up
- * swipe:2:left:up
- * swipe:3:left:up
- * swipe:4:left:up
- *
- * @event 'tapone'
- * Is triggered after a single (one finger) tap gesture
- * obj.description:
- * tapone
- *
- * @event 'taptwo'
- * Is triggered after a double (two finger) tap gesture
- * obj.description:
- * taptwo
- * *
- * @event 'tapthree'
- * Is triggered after a tripple (three finger) tap gesture
- * obj.description:
- * tapthree
- *
- *
- * Gestureend events:
- * A gesture is an interpretation of different touchpoints.
- * The jGesture-Events in this group are triggered when a gesture has finished
- * and the touchpoints are removed from the device.
- *
- * @event 'pinchopen'
- * Is triggered when a pinchopen gesture (two fingers moving away from each
- * other) occured and the touchpoints (fingers) are removed the device.
- * obj.description:
- * pinch:+1:open
- *
- * @event 'pinchclose'
- * Is triggered when a pinchclose gesture (two fingers moving towards each
- * other) occured and the touchpoints (fingers) are removed the device.
- * obj.description:
- * pinch:-1:close
- *
- * @event 'rotatecw'
- * Is triggered when a clockwise rotation gesture (two fingers rotating
- * clockwise) occured and the touchpoints (fingers) are removed the device.
- * obj.description:
- * rotate:+1:+clockwise
- *
- * @event 'rotateccw'
- * Is triggered when a counterclockwise rotation gesture (two fingers
- * rotating counterclockwise) occured and the touchpoints (fingers) are
- * removed the device.
- * obj.description:
- * rotate:-1:+counterclockwise
- *
- *
- * Motion events:
- * A "motion event" is an interpretation of changes in space, e.g. a "shaking motion"
- * consists of a specified number of acceleration changes in a given interval.
- * For understanding "directions", place your mobile device on a table with the bottom
- * (home button) close to you:
- * - x-axis: horizontal left / right
- * - y-axis: horizontal front / back (through the home button)
- * - z-axis: vertical through your device
- *
- * Note: Devicemotion / deviceorientation don't send custom event (such as: jGestures.touchstart).
- * Note: Devicemotion should be bound on the "window-element" - because the whole device moves
- *
- * @event 'shake'
- * Is triggered when a shaking motion is detected
- * obj.description:
- * shake:leftright:x-axisfrontback:y-axis:updown:z-axis
- *
- * @event 'shakefrontback'
- * Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly front-back movement.
- * obj.description:
- * shakefrontback:shakefrontback:y-axis
- *
- * @event 'shakeleftright'
- * Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly left-right movement.
- * Additional major movements are mentioned in the obj.description.
- * obj.description:
- * shakeleftright:leftright:x-axis
- *
- * @event 'shakeupdown'
- * Is triggered when a shaking motion is detected and the gesture can be interpreted as a mainly up-down movement.
- * Additional major movements are mentioned in the obj.description.
- * obj.description:
- * shake:shakeupdown:updown:z-axis
- *
- * @example
- * .bind( eventType, [ eventData ], handler(eventObject) )
- * jQuery('body').bind('tapone',function(){alert(arguments[1].description);})
- *
- */
- (function($) {
- /**
- * General thresholds.
- */
- // @TODO: move to $...defaults
- // @TODO: shake to defaults freeze etc
- // change of x deg in y ms
- $.jGestures = {};
- $.jGestures.defaults = {};
- $.jGestures.defaults.thresholdShake = {
- requiredShakes : 10,
- freezeShakes: 100,
- frontback : {
- sensitivity: 10
- },
- leftright : {
- sensitivity: 10
- },
- updown : {
- sensitivity: 10
- }
- };
- $.jGestures.defaults.thresholdPinchopen = 0.05;
- $.jGestures.defaults.thresholdPinchmove = 0.05;
- $.jGestures.defaults.thresholdPinch = 0.05;
- $.jGestures.defaults.thresholdPinchclose = 0.05;
- $.jGestures.defaults.thresholdRotatecw = 5; //deg
- $.jGestures.defaults.thresholdRotateccw = 5; // deg
- // a tap becomes a swipe if x/y values changes are above this threshold
- $.jGestures.defaults.thresholdMove = 20;
- $.jGestures.defaults.thresholdSwipe = 100;
- // get capable user agents
- $.jGestures.data = {};
- $.jGestures.data.capableDevicesInUserAgentString = ['iPad','iPhone','iPod','Mobile Safari']; // basic functionality such as swipe, pinch, rotate, tap should work on every mobile safari, e.g. GalaxyTab
- $.jGestures.data.hasGestures = (function () { var _i; for(_i = 0; _i < $.jGestures.data.capableDevicesInUserAgentString.length; _i++ ) { if (navigator.userAgent.indexOf($.jGestures.data.capableDevicesInUserAgentString[_i]) !== -1 ) {return true;} } return false; } )();
- $.hasGestures = $.jGestures.data.hasGestures;
- $.jGestures.events = {
- touchstart : 'jGestures.touchstart',
- touchendStart: 'jGestures.touchend;start',
- touchendProcessed: 'jGestures.touchend;processed',
- gesturestart: 'jGestures.gesturestart',
- gestureendStart: 'jGestures.gestureend;start',
- gestureendProcessed: 'jGestures.gestureend;processed'
- };
- jQuery
- .each({
- // "first domevent necessary"_"touch event+counter" : "exposed as"
- // event: orientationchange
- orientationchange_orientationchange01: "orientationchange",
- // event: gestures
- gestureend_pinchopen01: "pinchopen",
- gestureend_pinchclose01: "pinchclose",
- gestureend_rotatecw01 : 'rotatecw',
- gestureend_rotateccw01 : 'rotateccw',
- // move events
- gesturechange_pinch01: 'pinch',
- gesturechange_rotate01: 'rotate',
- touchstart_swipe13: 'swipemove',
- // event: touches
- touchstart_swipe01: "swipeone",
- touchstart_swipe02: "swipetwo",
- touchstart_swipe03: "swipethree",
- touchstart_swipe04: "swipefour",
- touchstart_swipe05: 'swipeup',
- touchstart_swipe06: 'swiperightup',
- touchstart_swipe07: 'swiperight',
- touchstart_swipe08: 'swiperightdown',
- touchstart_swipe09: 'swipedown',
- touchstart_swipe10: 'swipeleftdown',
- touchstart_swipe11: 'swipeleft',
- touchstart_swipe12: 'swipeleftup',
- touchstart_tap01: 'tapone',
- touchstart_tap02: 'taptwo',
- touchstart_tap03: 'tapthree',
- touchstart_tap04: 'tapfour',
- devicemotion_shake01: 'shake',
- devicemotion_shake02: 'shakefrontback',
- devicemotion_shake03: 'shakeleftright',
- devicemotion_shake04: 'shakeupdown'
- },
- /**
- * Add gesture events inside the jQuery.event.special namespace
- */
- function( sInternal_, sPublicFN_ ) {
- // add as funciton to jQuery.event.special.sPublicFN_
- jQuery.event.special[ sPublicFN_ ] = {
- /**
- * When the first event handler is bound, jQuery executes the setup function.
- * This plugin just uses one eventhandler per element, regardless of the number of bound events.
- * All Events are stored internally as properties on the dom-element using the $.data api.
- * The setup-function adds the eventlistener, acting as a proxy function for the internal events.
- * $.data.ojQueryGestures[_sDOMEvent ('tap') ] = {Boolean}
- * @return {Void}
- */
- setup: function () {
- // split the arguments to necessary controll arguements
- var _aSplit = sInternal_.split('_');
- var _sDOMEvent = _aSplit[0]; //
- // get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour
- var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);
- var _$element = jQuery(this);
- var _oDatajQueryGestures ;
- var oObj;
- // bind the event handler on the first $.bind() for a gestureend-event, set marker
- if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent]) {
- // setup pseudo event
- _oDatajQueryGestures = _$element.data('ojQueryGestures') || {};
- oObj = {};
- // marker for: domEvent being set on this element
- // e.g.: $.data.oGestureInternals['touchstart'] = true;
- // since they're grouped, i'm just marking the first one being added
- oObj[_sDOMEvent] = true;
- $.extend(true,_oDatajQueryGestures,oObj);
- _$element.data('ojQueryGestures' ,_oDatajQueryGestures);
- // add gesture events
- if($.hasGestures) {
- switch(_sGestureEvent) {
- // event: orientationchange
- case 'orientationchange':
- _$element.get(0).addEventListener('orientationchange', _onOrientationchange, false);
- break;
- // event:
- // - shake
- // - tilt
- case 'shake':
- case 'shakefrontback':
- case 'shakeleftright':
- case 'shakeupdown':
- case 'tilt':
- //$.hasGyroscope = true //!window.DeviceOrientationEvent;
- //_$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);
- //_$element.get(0).addEventListener('deviceorientation', _onDeviceorientation, false);
- _$element.get(0).addEventListener('devicemotion', _onDevicemotion, false);
- break;
- // event:
- // - touchstart
- // - touchmove
- // - touchend
- case 'tap':
- case 'swipe':
- case 'swipeup':
- case 'swiperightup':
- case 'swiperight':
- case 'swiperightdown':
- case 'swipedown':
- case 'swipeleftdown':
- case 'swipeleft':
- _$element.get(0).addEventListener('touchstart', _onTouchstart, false);
- break;
- // event: gestureend
- case 'pinchopen':
- case 'pinchclose' :
- case 'rotatecw' :
- case 'rotateccw' :
- _$element.get(0).addEventListener('gesturestart', _onGesturestart, false);
- _$element.get(0).addEventListener('gestureend', _onGestureend, false);
- break;
- // event: gesturechange
- case 'pinch':
- case 'rotate':
- _$element.get(0).addEventListener('gesturestart', _onGesturestart, false);
- _$element.get(0).addEventListener('gesturechange', _onGesturechange, false);
- break;
- }
- }
- // create substitute for gesture events
- else {
- switch(_sGestureEvent) {
- // event substitutes:
- // - touchstart: mousedown
- // - touchmove: none
- // - touchend: mouseup
- case 'tap':
- case 'swipe':
- // _$element.get(0).addEventListener('mousedown', _onTouchstart, false);
- _$element.bind('mousedown', _onTouchstart);
- break;
- // no substitution
- case 'orientationchange':
- case 'pinchopen':
- case 'pinchclose' :
- case 'rotatecw' :
- case 'rotateccw' :
- case 'pinch':
- case 'rotate':
- case 'shake':
- case 'tilt':
- break;
- }
- }
- }
- return false;
- },
- /**
- * For every $.bind(GESTURE) the add-function will be called.
- * Instead of binding an actual eventlister, the event is stored as $.data on the element.
- * The handler will be triggered using $.triggerHandler(GESTURE) if the internal
- * eventhandler (proxy being bound on setup()) detects a GESTURE event
- * @param {Object} event_ jQuery-Event-Object being passed by $.bind()
- * @return {Void}
- */
- add : function(event_) {
- // add pseudo event: properties on $.data
- var _$element = jQuery(this);
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // _oDatajQueryGestures[event_.type] = { 'originalType' : event_.type , 'threshold' : event_.data.threshold, 'preventDefault' : event_.data.preventDefault } ;
- _oDatajQueryGestures[event_.type] = { 'originalType' : event_.type } ;
- return false;
- },
- /**
- * For every $.unbind(GESTURE) the remove-function will be called.
- * Instead of removing the actual eventlister, the event is removed from $.data on the element.
- * @param {Object} event_ jQuery-Event-Object being passed by $.bind()
- * @return {Void}
- */
- remove : function(event_) {
- // remove pseudo event: properties on $.data
- var _$element = jQuery(this);
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- _oDatajQueryGestures[event_.type] = false;
- _$element.data('ojQueryGestures' ,_oDatajQueryGestures );
- return false;
- },
- /**
- * The last $.unbind()-call on the domElement triggers the teardown function
- * removing the eventlistener
- * @return {Void}
- */
- // @TODO: maybe rework teardown to work with event type?!
- teardown : function() {
- // split the arguments to necessary controll arguements
- var _aSplit = sInternal_.split('_');
- var _sDOMEvent = _aSplit[0]; //
- // get the associated gesture event and strip the counter: necessary for distinguisihng similliar events such as tapone-tapfour
- var _sGestureEvent = _aSplit[1].slice(0,_aSplit[1].length-2);
- var _$element = jQuery(this);
- var _oDatajQueryGestures;
- var oObj;
- // bind the event handler on the first $.bind() for a gestureend-event, set marker
- if (!_$element.data('ojQueryGestures') || !_$element.data('ojQueryGestures')[_sDOMEvent]) {
- // setup pseudo event
- _oDatajQueryGestures = _$element.data('ojQueryGestures') || {};
- oObj = {};
- // remove marker for: domEvent being set on this element
- oObj[_sDOMEvent] = false;
- $.extend(true,_oDatajQueryGestures,oObj);
- _$element.data('ojQueryGestures' ,_oDatajQueryGestures);
- // remove gesture events
- if($.hasGestures) {
- switch(_sGestureEvent) {
- // event: orientationchange
- case 'orientationchange':
- _$element.get(0).removeEventListener('orientationchange', _onOrientationchange, false);
- break;
- case 'shake':
- case 'shakefrontback':
- case 'shakeleftright':
- case 'shakeupdown':
- case 'tilt':
- _$element.get(0).removeEventListener('devicemotion', _onDevicemotion, false);
- break;
- // event :
- // - touchstart
- // - touchmove
- // - touchend
- case 'tap':
- case 'swipe':
- case 'swipeup':
- case 'swiperightup':
- case 'swiperight':
- case 'swiperightdown':
- case 'swipedown':
- case 'swipeleftdown':
- case 'swipeleft':
- case 'swipeleftup':
- _$element.get(0).removeEventListener('touchstart', _onTouchstart, false);
- _$element.get(0).removeEventListener('touchmove', _onTouchmove, false);
- _$element.get(0).removeEventListener('touchend', _onTouchend, false);
- break;
- // event: gestureend
- case 'pinchopen':
- case 'pinchclose' :
- case 'rotatecw' :
- case 'rotateccw' :
- _$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);
- _$element.get(0).removeEventListener('gestureend', _onGestureend, false);
- break;
- // event: gesturechange
- case 'pinch':
- case 'rotate':
- _$element.get(0).removeEventListener('gesturestart', _onGesturestart, false);
- _$element.get(0).removeEventListener('gesturechange', _onGesturechange, false);
- break;
- }
- }
- // remove substitute for gesture events
- else {
- switch(_sGestureEvent) {
- // event substitutes:
- // - touchstart: mousedown
- // - touchmove: none
- // - touchend: mouseup
- case 'tap':
- case 'swipe':
- // _$element.get(0).removeEventListener('mousedown', _onTouchstart, false);
- // _$element.get(0).removeEventListener('mousemove', _onTouchmove, false);
- // _$element.get(0).removeEventListener('mouseup', _onTouchend, false);
- _$element.unbind('mousedown', _onTouchstart);
- _$element.unbind('mousemove', _onTouchmove);
- _$element.unbind('mouseup', _onTouchend);
- break;
- // no substitution
- case 'orientationchange':
- case 'pinchopen':
- case 'pinchclose' :
- case 'rotatecw' :
- case 'rotateccw' :
- case 'pinch':
- case 'rotate':
- case 'shake':
- case 'tilt':
- break;
- }
- }
- }
- return false;
- }
- };
- });
- /**
- * Creates the object that ist passed as second argument to the $element.triggerHandler function.
- * This object contains detailed informations about the gesture event.
- * @param {Object} oOptions_ {type: {String}, touches: {String}, deltaY: {String},deltaX : {String}, startMove: {Object}, event:{DOM-Event}, timestamp:{String},vector: {Number}}
- * @example _createOptions (
- * {
- * type: 'swipemove',
- * touches: '1',
- * deltaY: _iDeltaY,
- * deltaX : _iDeltaX,
- * startMove: _oDatajQueryGestures.oStartTouch,
- * event:event_,
- * timestamp:_oEventData.timestamp,
- * vector: -1
- * }
- * );
- * @returns {Object}
- * {
- * type: eventtype e.g. "swipe","pinch",
- * originalEvent: {DOM-Event},
- * // default: just one entry on the delta-array - the first touchpoint
- * // the first touchpoint is the reference point for every gesture,
- * // because moving touchpoints in various directions would result in
- * // a gesture.
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : [
- * {
- * lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)
- * lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)
- * moved: {Number}, // distance: relative to the original touchpoint
- * startX: {Number} , // relative to the original touchpoint
- * startY: {Number} ,// relative to the original touchpoint
- * } ],
- * // based on the first touchpoint
- * direction : { // relative to the last touchevent (e.g. touchmove!)
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * startX: {Number} , //-1,0,+1 relative to the original touchpoint
- * startY: {Number} ,// -1,0,+1 relative to the original touchpoint
- * },
- * rotation: {Number} || null, // gestureonly: amount of rotation relative to the current position NOT the original
- * scale: {Number} || null, // gestureonly: amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint
- * };
- */
- function _createOptions(oOptions_) {
- // force properties
- oOptions_.startMove = (oOptions_.startMove) ? oOptions_.startMove : {startX: null,startY:null,timestamp:null} ;
- var _iNow = new Date().getTime();
- var _oDirection;
- var _oDelta;
- // calculate touch differences
- if (oOptions_.touches) {
- // store delta values
- _oDelta = [
- {
- lastX: oOptions_.deltaX ,
- lastY: oOptions_.deltaY,
- moved: null,
- startX: oOptions_.screenX - oOptions_.startMove.screenX ,
- startY: oOptions_.screenY - oOptions_.startMove.screenY
- }
- ];
- _oDirection = {
- vector: oOptions_.vector || null,
- orientation : window.orientation || null,
- lastX : ((_oDelta[0].lastX > 0) ? +1 : ( (_oDelta[0].lastX < 0) ? -1 : 0 ) ),
- lastY : ((_oDelta[0].lastY > 0) ? +1 : ( (_oDelta[0].lastY < 0) ? -1 : 0 ) ),
- startX : ((_oDelta[0].startX > 0) ? +1 : ( (_oDelta[0].startX < 0) ? -1 : 0 ) ),
- startY : ((_oDelta[0].startY > 0) ? +1 : ( (_oDelta[0].startY < 0) ? -1 : 0 ) )
- };
- // calculate distance traveled using the pythagorean theorem
- _oDelta[0].moved = Math.sqrt(Math.pow(Math.abs(_oDelta[0].startX), 2) + Math.pow(Math.abs(_oDelta[0].startY), 2));
- }
- return {
- type: oOptions_.type || null,
- originalEvent: oOptions_.event || null,
- delta : _oDelta || null,
- direction : _oDirection || { orientation : window.orientation || null, vector: oOptions_.vector || null},
- duration: (oOptions_.duration) ? oOptions_.duration : ( oOptions_.startMove.timestamp ) ? _iNow - oOptions_.timestamp : null,
- rotation: oOptions_.rotation || null,
- scale: oOptions_.scale || null,
- description : oOptions_.description || [
- oOptions_.type,
- ':',
- oOptions_.touches,
- ':',
- ((_oDelta[0].lastX != 0) ? ((_oDelta[0].lastX > 0) ? 'right' : 'left') : 'steady'),
- ':',
- ((_oDelta[0].lastY != 0) ? ( (_oDelta[0].lastY > 0) ? 'down' : 'up') :'steady')
- ].join('')
- };
- }
- /**
- * DOM-event handlers
- */
- /**
- * Handler: orientationchange
- * Triggers the bound orientationchange handler on the window element
- * The "orientationchange" handler will receive an object with additional information
- * about the event.
- * {
- * direction : {
- * orientation: {-90|0|90|180}
- * },
- * description : [
- * 'orientationchange:{landscape:clockwise:|portrait:default|landscape:counterclockwise|portrait:upsidedown}:{-90|0|90|180}' // e.g. 'orientation:landscape:clockwise:-90
- * }
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onOrientationchange(event_) {
- // window.orientation: -90,0,90,180
- var _aDict = ['landscape:clockwise:','portrait:default:','landscape:counterclockwise:','portrait:upsidedown:'];
- $(window).triggerHandler('orientationchange',
- {
- direction : {orientation: window.orientation},
- description : [
- 'orientationchange:',
- _aDict[( (window.orientation / 90) +1)],
- window.orientation
- ].join('')
- });
- }
- /**
- * Handler: devicemotion
- * Calculates "motion events" such as shake, tilt, wiggle by observing "changes in space"
- * For understanding "directions", place your mobile device on a table with the bottom
- * (home button) close to you:
- * - x-axis: horizontal left / right
- * - y-axis: horizontal front / back (through the home button)
- * - z-axis: vertical through your device
- * @param {DOM-Event} event_
- * @returns {Object}
- * {
- * type: eventtype e.g. "shake",
- * originalEvent: {DOM-Event},
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : null,
- * direction :{
- * vector: null,
- * orientation: -90,0,90,180 || null (window.orienntation)
- * }
- * rotation: {Number} , // amount of rotation relative to the current position NOT the original
- * scale: {Number} , // amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: duration of the motion
- * description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" || rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"
- * };
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onDevicemotion(event_) {
- var _sType;
- var _$element = jQuery(window);
- //var _bHasGyroscope = $.hasGyroscope;
- // skip custom notification: devicemotion is triggered every 0.05s regardlesse of any gesture
- // get options
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- var _oThreshold = $.jGestures.defaults.thresholdShake;
- // get last position or set initital values
- var _oLastDevicePosition = _oDatajQueryGestures.oDeviceMotionLastDevicePosition || {
- accelerationIncludingGravity : {
- x: 0,
- y: 0,
- z: 0
- },
- shake : {
- eventCount: 0,
- intervalsPassed: 0,
- intervalsFreeze: 0
- },
- shakeleftright : {
- eventCount: 0,
- intervalsPassed: 0,
- intervalsFreeze: 0
- },
- shakefrontback : {
- eventCount: 0,
- intervalsPassed: 0,
- intervalsFreeze: 0
- },
- shakeupdown : {
- eventCount: 0,
- intervalsPassed: 0,
- intervalsFreeze: 0
- }
- };
- // cache current values
- var _oCurrentDevicePosition = {
- accelerationIncludingGravity : {
- x: event_.accelerationIncludingGravity.x,
- y: event_.accelerationIncludingGravity.y,
- z: event_.accelerationIncludingGravity.z
- },
- shake: {
- eventCount: _oLastDevicePosition.shake.eventCount,
- intervalsPassed: _oLastDevicePosition.shake.intervalsPassed,
- intervalsFreeze: _oLastDevicePosition.shake.intervalsFreeze
- },
- shakeleftright: {
- eventCount: _oLastDevicePosition.shakeleftright.eventCount,
- intervalsPassed: _oLastDevicePosition.shakeleftright.intervalsPassed,
- intervalsFreeze: _oLastDevicePosition.shakeleftright.intervalsFreeze
- },
- shakefrontback: {
- eventCount: _oLastDevicePosition.shakefrontback.eventCount,
- intervalsPassed: _oLastDevicePosition.shakefrontback.intervalsPassed,
- intervalsFreeze: _oLastDevicePosition.shakefrontback.intervalsFreeze
- },
- shakeupdown: {
- eventCount: _oLastDevicePosition.shakeupdown.eventCount,
- intervalsPassed: _oLastDevicePosition.shakeupdown.intervalsPassed,
- intervalsFreeze: _oLastDevicePosition.shakeupdown.intervalsFreeze
- }
- };
- // options
- var _aType;
- var _aDescription;
- var _oObj;
- // trigger events for all bound pseudo events on this element
- for (_sType in _oDatajQueryGestures) {
- // get current pseudo event
- // trigger bound events on this element
- switch(_sType) {
- case 'shake':
- case 'shakeleftright':
- case 'shakefrontback':
- case 'shakeupdown':
- // options
- _aType = [];
- _aDescription = [];
- _aType.push(_sType);
- // freeze shake - prevent multiple shake events on one shaking motion (user won't stop shaking immediately)
- if (++_oCurrentDevicePosition[_sType].intervalsFreeze > _oThreshold.freezeShakes && _oCurrentDevicePosition[_sType].intervalsFreeze < (2*_oThreshold.freezeShakes) ) { break; }
- // set control values
- _oCurrentDevicePosition[_sType].intervalsFreeze = 0;
- _oCurrentDevicePosition[_sType].intervalsPassed++;
- // check for shaking motions: massive acceleration changes in every direction
- if ( ( _sType === 'shake' ||_sType === 'shakeleftright' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.x > _oThreshold.leftright.sensitivity || _oCurrentDevicePosition.accelerationIncludingGravity.x < (-1* _oThreshold.leftright.sensitivity) ) ) {
- _aType.push('leftright');
- _aType.push('x-axis');
- }
- if ( ( _sType === 'shake' ||_sType === 'shakefrontback' ) && (_oCurrentDevicePosition.accelerationIncludingGravity.y > _oThreshold.frontback.sensitivity || _oCurrentDevicePosition.accelerationIncludingGravity.y < (-1 * _oThreshold.frontback.sensitivity) ) ) {
- _aType.push('frontback');
- _aType.push('y-axis');
- }
- if ( ( _sType === 'shake' ||_sType === 'shakeupdown' ) && ( _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 > _oThreshold.updown.sensitivity || _oCurrentDevicePosition.accelerationIncludingGravity.z+9.81 < (-1 * _oThreshold.updown.sensitivity) ) ) {
- _aType.push('updown');
- _aType.push('z-axis');
- }
- // at least one successful shaking event
- if (_aType.length > 1) {
- // minimum number of shaking motions during the defined "time" (messured by events - device event interval: 0.05s)
- if (++_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) < _oThreshold.freezeShakes ) {
- // send event
- _$element.triggerHandler(_sType, _createOptions ({type: _sType, description: _aType.join(':'), event:event_,duration:_oCurrentDevicePosition[_sType].intervalsPassed*5 }) );
- // reset
- _oCurrentDevicePosition[_sType].eventCount = 0;
- _oCurrentDevicePosition[_sType].intervalsPassed = 0;
- // freeze shake
- _oCurrentDevicePosition[_sType].intervalsFreeze = _oThreshold.freezeShakes+1;
- }
- // too slow, reset
- else if (_oCurrentDevicePosition[_sType].eventCount == _oThreshold.requiredShakes && (_oCurrentDevicePosition[_sType].intervalsPassed) > _oThreshold.freezeShakes ) {
- _oCurrentDevicePosition[_sType].eventCount = 0 ;
- _oCurrentDevicePosition[_sType].intervalsPassed = 0;
- }
- }
- break;
- }
- // refresh pseudo events
- _oObj = {};
- _oObj.oDeviceMotionLastDevicePosition = _oCurrentDevicePosition;
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- }
- }
- /**
- * Handler: touchstart or mousedown
- * Setup pseudo-event by storing initial values such as :
- * screenX : {Number}
- * screenY : {Number}
- * timestamp: {Number}
- * on the pseudo gesture event and
- * sets up additional eventlisteners for handling touchmove events.
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onTouchstart(event_) {
- // ignore bubbled handlers
- // if ( event_.currentTarget !== event_.target ) { return; }
- var _$element = jQuery(event_.currentTarget);
- // var _$element = jQuery(event_.target);
- // trigger custom notification
- _$element.triggerHandler($.jGestures.events.touchstart,event_);
- // set the necessary touch events
- if($.hasGestures) {
- event_.currentTarget.addEventListener('touchmove', _onTouchmove, false);
- event_.currentTarget.addEventListener('touchend', _onTouchend, false);
- }
- // event substitution
- else {
- // event_.currentTarget.addEventListener('mousemove', _onTouchmove, false);
- // event_.currentTarget.addEventListener('mouseup', _onTouchend, false);
- _$element.bind('mousemove', _onTouchmove);
- _$element.bind('mouseup', _onTouchend);
- }
- // get stored pseudo event
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // var _oEventData = _oDatajQueryGestures[_sType];
- var _eventBase = (event_.touches) ? event_.touches[0] : event_;
- // store current values for calculating relative values (changes between touchmoveevents)
- var _oObj = {};
- _oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};
- _oObj.oStartTouch = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- }
- /**
- * Handler: touchmove or mousemove
- * Calculates the x/y changes since the last event,
- * compares it to $.jGestures.defaults.thresholdMove and triggers
- * an swipemove event if the distance exceed the
- * threshold.
- * Custom-event argument object:
- * {Object}
- * {
- * type: e.g. 'swipemove',
- * ¡Ö: {DOM-Event},
- * // default: just one entry on the delta-array - the first touchpoint
- * // the first touchpoint is the reference point for every gesture,
- * // because moving touchpoints in various directions would result in
- * // a gesture.
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : [
- * {
- * lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)
- * lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)
- * moved: {Number}, // distance: relative to the original touchpoint
- * startX: {Number} , // relative to the original touchpoint
- * startY: {Number} ,// relative to the original touchpoint
- * } ],
- * // based on the first touchpoint
- * direction : { // relative to the last touchevent (e.g. touchmove!)
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * startX: {Number} , //-1,0,+1 relative to the original touchpoint
- * startY: {Number} ,// -1,0,+1 relative to the original touchpoint
- * },
- * rotation: null, // gestureonly: amount of rotation relative to the current position NOT the original
- * scale: null, // gestureonly: amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint
- * };
- *
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onTouchmove(event_) {
- var _$element = jQuery(event_.currentTarget);
- // var _$element = jQuery(event_.target);
- // get stored pseudo event
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- var _bHasTouches = !!event_.touches;
- var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;
- var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;
- //relative to the last event
- var _oEventData = _oDatajQueryGestures.oLastSwipemove;
- var _iDeltaX = _iScreenX - _oEventData.screenX ;
- var _iDeltaY = _iScreenY - _oEventData.screenY;
- var _oDetails;
- // there's a swipemove set (not the first occurance), trigger event
- if (!!_oDatajQueryGestures.oLastSwipemove) {
- // check
- _oDetails = _createOptions({type: 'swipemove', touches: (_bHasTouches) ? event_.touches.length: '1', screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp:_oEventData.timestamp});
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- // store the new values
- var _oObj = {};
- var _eventBase = (event_.touches) ? event_.touches[0] : event_;
- _oObj.oLastSwipemove = { screenX : _eventBase.screenX, screenY : _eventBase.screenY, timestamp:new Date().getTime()};
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- }
- /**
- * Handler: touchend or mouseup
- * Removes the additional handlers (move/end)
- * Calculates the x/y changes since the touchstart event
- * not in relation to the last move event.
- * Triggers the
- * swipeone|swipetwo|swipethree|swipefour|
- * swipeup|swiperightup|swiperight|swiperightdown|swipedown|
- * swipeleftdown|swipeleft|swipeleftup|
- * tapone|taptwo|tapthree|tapfour
- * event.
- * {Object}
- * {
- * type: eventtype e.g. "swipeone","swipeleftdown",
- * originalEvent: {DOM-Event},
- * // default: just one entry on the delta-array - the first touchpoint
- * // the first touchpoint is the reference point for every gesture,
- * // because moving touchpoints in various directions would result in
- * // a gesture.
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : [
- * {
- * lastX:{Number} , // x-axis: relative to the last touchevent (e.g. touchmove!)
- * lastY:{Number}, // y-axis: relative to the last touchevent (e.g. touchmove!)
- * moved: {Number}, // distance: relative to the original touchpoint
- * startX: {Number} , // relative to the original touchpoint
- * startY: {Number} ,// relative to the original touchpoint
- * } ],
- * // based on the first touchpoint
- * direction : { // relative to the last touchevent (e.g. touchmove!)
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * lastX : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * lastY : {Number}, // -1,0,+1 relative to the last touchevent (e.g. touchmove!)
- * startX: {Number} , //-1,0,+1 relative to the original touchpoint
- * startY: {Number} ,// -1,0,+1 relative to the original touchpoint
- * },
- * rotation: null,
- * scale: null ,
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: {TYPE *}:{TOUCHES 1|2|3|4}:{X-AXIS 'right'|'left'|'steady'}:{Y-AXIS 'down'|'up'|'steady'} e.g. "swipe:1:left:steady" relative to the last touchpoint
- * };
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onTouchend(event_) {
- // ignore bubbled handlers
- // if ( event_.currentTarget !== event_.target ) { return; }
- var _$element = jQuery(event_.currentTarget);
- var _bHasTouches = !!event_.changedTouches;
- var _iTouches = (_bHasTouches) ? event_.changedTouches.length : '1';
- var _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;
- var _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;
- // trigger custom notification
- _$element.triggerHandler($.jGestures.events.touchendStart,event_);
- // var _$element = jQuery(event_.target);
- // remove events
- if($.hasGestures) {
- event_.currentTarget.removeEventListener('touchmove', _onTouchmove, false);
- event_.currentTarget.removeEventListener('touchend', _onTouchend, false);
- }
- // event substitution
- else {
- // event_.currentTarget.removeEventListener('mousemove', _onTouchmove, false);
- // event_.currentTarget.removeEventListener('mouseup', _onTouchend, false);
- _$element.unbind('mousemove', _onTouchmove);
- _$element.unbind('mouseup', _onTouchend);
- }
- // get all bound pseudo events
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // if the current change on the x/y position is above the defined threshold for moving an element set the moved flag
- // to distinguish between a moving gesture and a shaking finger trying to tap
- var _bHasMoved = (
- Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdMove ||
- Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdMove
- ) ? true : false;
- // if the current change on the x/y position is above the defined threshold for swiping set the moved flag
- // to indicate we're dealing with a swipe gesture
- var _bHasSwipeGesture = (
- Math.abs(_oDatajQueryGestures.oStartTouch.screenX - _iScreenX) > $.jGestures.defaults.thresholdSwipe ||
- Math.abs(_oDatajQueryGestures.oStartTouch.screenY - _iScreenY) > $.jGestures.defaults.thresholdSwipe
- ) ? true : false;
- var _sType;
- var _oEventData ;
- var _oDelta;
- // calculate distances in relation to the touchstart position not the last touchmove event!
- var _iDeltaX;
- var _iDeltaY;
- var _oDetails;
- var _aDict = ['zero','one','two','three','four'];
- // swipe marker
- var _bIsSwipe;
- // trigger events for all bound pseudo events on this element
- for (_sType in _oDatajQueryGestures) {
- // get current pseudo event
- _oEventData = _oDatajQueryGestures.oStartTouch;
- _oDelta = {};
- _iScreenX = (_bHasTouches) ? event_.changedTouches[0].screenX : event_.screenX;
- _iScreenY = (_bHasTouches) ? event_.changedTouches[0].screenY : event_.screenY;
- // calculate distances in relation to the touchstart position not the last touchmove event!
- _iDeltaX = _iScreenX - _oEventData.screenX ;
- _iDeltaY = _iScreenY - _oEventData.screenY;
- _oDetails = _createOptions({type: 'swipe', touches: _iTouches, screenY: _iScreenY,screenX:_iScreenX ,deltaY: _iDeltaY,deltaX : _iDeltaX, startMove:_oEventData, event:event_, timestamp: _oEventData.timestamp });
- // swipe marker
- _bIsSwipe = false;
- // trigger bound events on this element
- switch(_sType) {
- case 'swipeone':
- if( _bHasTouches === false && _iTouches == 1 && _bHasMoved === false){
- // trigger tapone!
- break;
- }
- if (_bHasTouches===false || ( _iTouches == 1 && _bHasMoved === true && _bHasSwipeGesture===true)) {
- _bIsSwipe = true;
- _oDetails.type = ['swipe',_aDict[_iTouches]].join('');
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- break;
- case 'swipetwo':
- if (( _bHasTouches && _iTouches== 2 && _bHasMoved === true && _bHasSwipeGesture===true)) {
- _bIsSwipe = true;
- _oDetails.type = ['swipe',_aDict[_iTouches]].join('');
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- break;
- case 'swipethree':
- if ( ( _bHasTouches && _iTouches == 3 && _bHasMoved === true && _bHasSwipeGesture===true)) {
- _bIsSwipe = true;
- _oDetails.type = ['swipe',_aDict[_iTouches]].join('');
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- break;
- case 'swipefour':
- if ( ( _bHasTouches && _iTouches == 4 && _bHasMoved === true && _bHasSwipeGesture===true)) {
- _bIsSwipe = true;
- _oDetails.type = ['swipe',_aDict[_iTouches]].join('');
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- break;
- case 'swipeup':
- case 'swiperightup':
- case 'swiperight':
- case 'swiperightdown':
- case 'swipedown':
- case 'swipeleftdown':
- case 'swipeleft':
- case 'swipeleftup':
- if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {
- _bIsSwipe = true;
- _oDetails.type = [
- 'swipe',
- ((_oDetails.delta[0].lastX != 0) ? ((_oDetails.delta[0].lastX > 0) ? 'right' : 'left') : ''),
- ((_oDetails.delta[0].lastY != 0) ? ((_oDetails.delta[0].lastY > 0) ? 'down' : 'up') :'')
- ].join('');
- _$element.triggerHandler(_oDetails.type, _oDetails);
- }
- break;
- case 'tapone':
- case 'taptwo':
- case 'tapthree':
- case 'tapfour':
- if (( /* _bHasTouches && */ _bHasMoved !== true && _bIsSwipe !==true) && (_aDict[_iTouches] ==_sType.slice(3)) ) {
- _oDetails.description = ['tap',_aDict[_iTouches]].join('');
- _oDetails.type = ['tap',_aDict[_iTouches]].join('');
- _$element.triggerHandler(_oDetails.type,_oDetails);
- }
- break;
- }
- // refresh pseudo events
- var _oObj = {};
- // _oObj[_sType] = false;
- // _oObj.hasTouchmoved = false;
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- }
- _$element.triggerHandler($.jGestures.events.touchendProcessed,event_);
- }
- /**
- * Handler: gesturestart
- * Setup pseudo-event by storing initial values such as :
- * timestamp: {Number}
- * on the pseudo gesture event
- * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onGesturestart(event_) {
- // ignore bubbled handlers
- // if ( event_.currentTarget !== event_.target ) { return; }
- var _$element = jQuery(event_.currentTarget);
- // var _$element = jQuery(event_.target);
- // trigger custom notification
- _$element.triggerHandler($.jGestures.events.gesturestart,event_);
- // get stored pseudo event
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // var _oEventData = _oDatajQueryGestures[_sType];
- // store current values for calculating relative values (changes between touchmoveevents)
- var _oObj = {};
- _oObj.oStartTouch = {timestamp:new Date().getTime()};
- _$element.data('ojQueryGestures',$.extend(true,_oDatajQueryGestures,_oObj));
- }
- /**
- * Handler: gesturechange
- * Read the event_.scale / event_.rotate values,
- * an triggers a pinch|rotate event if necessary.
- * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated
- * @returns {Object}
- * {
- * type: eventtype e.g. "pinch","rotate",
- * originalEvent: {DOM-Event},
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : null,
- * direction : {
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * },
- * rotation: {Number} , // amount of rotation relative to the current position NOT the original
- * scale: {Number} , // amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" || rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"
- * };
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onGesturechange(event_) {
- // ignore bubbled handlers
- // if ( event_.currentTarget !== event_.target ) { return; }
- var _$element = jQuery(event_.currentTarget);
- // var _$element = jQuery(event_.target);
- var _iDelta,_iDirection,_sDesc,_oDetails;
- // get all pseudo events
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // trigger events for all bound pseudo events on this element
- var _sType;
- for (_sType in _oDatajQueryGestures) {
- // trigger a specific bound event
- switch(_sType) {
- case 'pinch':
- _iDelta = event_.scale;
- if ( ( ( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose) ) || ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) ) {
- _iDirection = (_iDelta < 1 ) ? -1 : +1 ;
- _oDetails = _createOptions({type: 'pinch', scale: _iDelta, touches: null,startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['pinch:',_iDirection,':' , ( (_iDelta < 1 ) ? 'close' : 'open' )].join('') });
- _$element.triggerHandler(_oDetails.type, _oDetails);
- }
- break;
- case 'rotate':
- _iDelta = event_.rotation;
- if ( ( ( _iDelta < 1 ) && ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) || ( ( _iDelta > 1 ) && (_iDelta > $.jGestures.defaults.thresholdRotatecw) ) ) {
- _iDirection = (_iDelta < 1 ) ? -1 : +1 ;
- _oDetails = _createOptions({type: 'rotate', rotation: _iDelta, touches: null, startMove:_oDatajQueryGestures.oStartTouch, event:event_, timestamp: _oDatajQueryGestures.oStartTouch.timestamp, vector:_iDirection, description: ['rotate:',_iDirection,':' , ( (_iDelta < 1 ) ? 'counterclockwise' : 'clockwise' )].join('') });
- _$element.triggerHandler(_oDetails.type, _oDetails);
- }
- break;
- }
- }
- }
- /**
- * Handler: gestureend
- * Read the event_.scale / event_.rotate values,
- * compares it to $.jGestures.defaults.threshold* and triggers
- * a pinchclose|pinchclose|rotatecw|rotateccw event if the distance exceed the
- * Since the gesture-event doesn't supply event.touches no tuchpoints will be calculated
- * * Custom-event argument object:
- * @returns {Object}
- * {
- * type: eventtype e.g. "pinchclose","pinchopen", "rotatecw", "rotateccw",
- * originalEvent: {DOM-Event},
- * // delta and direction details are just provided for touch not for gesture / motion events
- * delta : null,
- * // based on the first touchpoint
- * direction : {
- * vector: {Number}, // -1|+1, indicates the direction if necessary(pinch/rotate)
- * orientation: {Number} // window.orientation: -90,0,90,180 || null (window.orienntation)
- * },
- * rotation: {Number} , // amount of rotation relative to the current position NOT the original
- * scale: {Number} , // amount of scaling relative to the current position NOT the original
- * duration: {Number}, // ms: relative to the original touchpoint
- * description : {String} // details as String: pinch:{'close'|'open'} e.g. "pinch:-1:close" || rotate:{'counterclockwise'|'clockwise'} e.g. "rotate:-1:counterclockwise"
- * };
- * @param {DOM-Event} event_
- * @return {Void}
- */
- function _onGestureend(event_) {
- // ignore bubbled handlers
- // if ( event_.currentTarget !== event_.target ) { return; }
- var _$element = jQuery(event_.currentTarget);
- // var _$element = jQuery(event_.target);
- // trigger custom notification
- _$element.triggerHandler($.jGestures.events.gestureendStart,event_);
- var _iDelta;
- var _oDatajQueryGestures = _$element.data('ojQueryGestures');
- // trigger handler for every bound event
- var _sType;
- for (_sType in _oDatajQueryGestures) {
- switch(_sType) {
- case 'pinchclose':
- _iDelta = event_.scale;
- if (( _iDelta < 1 ) && (_iDelta % 1) < (1 - $.jGestures.defaults.thresholdPinchclose)) {
- _$element.triggerHandler('pinchclose', _createOptions ({type: 'pinchclose', scale:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:-1:close' }) );
- }
- break;
- case 'pinchopen':
- _iDelta = event_.scale;
- if ( ( _iDelta > 1 ) && (_iDelta % 1) > ($.jGestures.defaults.thresholdPinchopen) ) {
- _$element.triggerHandler('pinchopen', _createOptions ({type: 'pinchopen', scale:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'pinch:+1:open'}) );
- }
- break;
- case 'rotatecw':
- _iDelta = event_.rotation;
- if ( ( _iDelta > 1 ) && (_iDelta > $.jGestures.defaults.thresholdRotatecw) ) {
- _$element.triggerHandler('rotatecw', _createOptions ({type: 'rotatecw', rotation:_iDelta, vector: +1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:+1:clockwise'}) );
- }
- break;
- case 'rotateccw':
- _iDelta = event_.rotation;
- if ( ( _iDelta < 1 ) && ( -1*(_iDelta) > $.jGestures.defaults.thresholdRotateccw ) ) {
- _$element.triggerHandler('rotateccw', _createOptions ({type: 'rotateccw', rotation:_iDelta, vector: -1, touches: null, startMove: _oDatajQueryGestures.oStartTouch, event:event_, timestamp:_oDatajQueryGestures.oStartTouch.timestamp,description: 'rotate:-1:counterclockwise'}) );
- }
- break;
- }
- }
- _$element.triggerHandler($.jGestures.events.gestureendProcessed,event_);
- }
- }
- )(jQuery);
|