/*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);