// jQuery WipeTouch 1.2.0 // ------------------------------------------------------------------------ // // Developed and maintained by Igor Ramadas // http://aboutigor.com // http://devv.com // // USAGE // ------------------------------------------------------------------------ // // $(selector).wipetouch(config); // // The wipe events should expect the result object with the following properties: // speed - the wipe speed from 1 to 5 // x - how many pixels moved on the horizontal axis // y - how many pixels moved on the vertical axis // source - the element which triggered the wipe gesture // // EXAMPLE // $(document).wipetouch({ // allowDiagonal: true, // wipeLeft: function(result) { alert("Left on speed " + result.speed) }, // wipeTopLeft: function(result) { alert("Top left on speed " + result.speed) }, // wipeBottomLeft: function(result) { alert("Bottom left on speed " + result.speed) } // }); // // // More details at http://wipetouch.codeplex.com/ // // CHANGE LOG // ------------------------------------------------------------------------ // 1.2.0 // - New: wipeMove event, triggered while moving the mouse/finger. // - New: added "source" to the result object. // - Bug fix: sometimes vertical wipe events would not trigger correctly. // - Bug fix: improved tapToClick handler. // - General code refactoring. // - Windows Phone 7 is not supported, yet! Its behaviour is completely broken and would require some special tricks to make it work. Maybe in the future... // // 1.1.0 // - New: tapToClick, if true will identify taps and and trigger a click on the touched element. Default is false. // - Changed: events wipeBottom*** and wipeTop*** renamed to wipeDown*** and wipeUp***. // - Changed: better touch speed calculation (was always too fast before). // - Changed: speed will be an integer now (instead of float). // - Changed: better wipe detection (if Y movement is more than X, do a vertical wipe instead of horizontal). // - Bug fix: added preventDefault to touchStart and touchEnd internal events (this was missing). // - Other general tweaks to the code. // // The minified version of WipeTouch can be generated using Jasc: http://jasc.codeplex.com (function ($) { $.fn.wipetouch = function (settings) { // ------------------------------------------------------------------------ // PLUGIN SETTINGS // ------------------------------------------------------------------------ var config = { // Variables and options moveX: 40, // minimum amount of horizontal pixels to trigger a wipe event moveY: 40, // minimum amount of vertical pixels to trigger a wipe event tapToClick: false, // if user taps the screen it will fire a click event on the touched element preventDefault: true, // if true, prevents default events (click for example) allowDiagonal: false, // if false, will trigger horizontal and vertical movements so wipeUpLeft, wipeDownLeft, wipeUpRight, wipeDownRight are ignored // Wipe events wipeLeft: false, // called on wipe left gesture wipeRight: false, // called on wipe right gesture wipeUp: false, // called on wipe up gesture wipeDown: false, // called on wipe down gesture wipeUpLeft: false, // called on wipe top and left gesture wipeDownLeft: false, // called on wipe bottom and left gesture wipeUpRight: false, // called on wipe top and right gesture wipeDownRight: false, // called on wipe bottom and right gesture wipeMove: false, // triggered whenever touchMove acts // DEPRECATED EVENTS wipeTopLeft: false, // USE WIPEUPLEFT wipeBottomLeft: false, // USE WIPEDOWNLEFT wipeTopRight: false, // USE WIPEUPRIGHT wipeBottomRight: false // USE WIPEDOWNRIGHT }; if (settings) { $.extend(config, settings); } this.each(function () { // ------------------------------------------------------------------------ // INTERNAL VARIABLES // ------------------------------------------------------------------------ var startX; // where touch has started, left var startY; // where touch has started, top var startDate = false; // used to calculate timing and aprox. acceleration var curX; // keeps touch X position while moving on the screen var curY; // keeps touch Y position while moving on the screen var isMoving = false; // is user touching and moving? var touchedElement = false; // element which user has touched // These are for non-touch devices! var useMouseEvents = false; // force using the mouse events to simulate touch var clickEvent = false; // holds the click event of the target, when used hasn't clicked // ------------------------------------------------------------------------ // TOUCH EVENTS // ------------------------------------------------------------------------ // Called when user touches the screen. function onTouchStart(e) { var start = useMouseEvents || (e.originalEvent.touches && e.originalEvent.touches.length > 0); if (!isMoving && start) { if (config.preventDefault) { e.preventDefault(); } // Temporary fix for deprecated events, these will be removed on next version! if (config.allowDiagonal) { if (!config.wipeDownLeft) { config.wipeDownLeft = config.wipeBottomLeft; } if (!config.wipeDownRight) { config.wipeDownRight = config.wipeBottomRight; } if (!config.wipeUpLeft) { config.wipeUpLeft = config.wipeTopLeft; } if (!config.wipeUpRight) { config.wipeUpRight = config.wipeTopRight; } } // When touch events are not present, use mouse events. if (useMouseEvents) { startX = e.pageX; startY = e.pageY; $(this).bind("mousemove", onTouchMove); $(this).one("mouseup", onTouchEnd); } else { startX = e.originalEvent.touches[0].pageX; startY = e.originalEvent.touches[0].pageY; $(this).bind("touchmove", onTouchMove); } // Set the start date and current X/Y. startDate = new Date().getTime(); curX = startX; curY = startY; isMoving = true; touchedElement = $(e.target); } } // Called when user untouches the screen. function onTouchEnd(e) { if (config.preventDefault) { e.preventDefault(); } // When touch events are not present, use mouse events. if (useMouseEvents) { $(this).unbind("mousemove", onTouchMove); } else { $(this).unbind("touchmove", onTouchMove); } // If is moving then calculate the touch results, otherwise reset it. if (isMoving) { touchCalculate(e); } else { resetTouch(); } } // Called when user is touching and moving on the screen. function onTouchMove(e) { if (config.preventDefault) { e.preventDefault(); } if (useMouseEvents && !isMoving) { onTouchStart(e); } if (isMoving) { if (useMouseEvents) { curX = e.pageX; curY = e.pageY; } else { curX = e.originalEvent.touches[0].pageX; curY = e.originalEvent.touches[0].pageY; } // If there's a wipeMove event, call it passing // current X and Y position (curX and curY). if (config.wipeMove) { triggerEvent(config.wipeMove, { curX: curX, curY: curY }); } } } // ------------------------------------------------------------------------ // CALCULATE TOUCH AND TRIGGER // ------------------------------------------------------------------------ function touchCalculate(e) { var endDate = new Date().getTime(); // current date to calculate timing var ms = startDate - endDate; // duration of touch in milliseconds var x = curX; // current left position var y = curY; // current top position var dx = x - startX; // diff of current left to starting left var dy = y - startY; // diff of current top to starting top var ax = Math.abs(dx); // amount of horizontal movement var ay = Math.abs(dy); // amount of vertical movement // If moved less than 15 pixels, touch duration is less than 100ms, // and tapToClick is true then trigger a click event and stop processing. if (ax < 15 && ay < 15 && ms < 100) { clickEvent = false; if (config.preventDefault) { resetTouch(); touchedElement.trigger("click"); return; } } // When touch events are not present, use mouse events. else if (useMouseEvents) { var evts = touchedElement.data("events"); if (evts) { // Save click event to the temp clickEvent variable. var clicks = evts.click; if (clicks && clicks.length > 0) { $.each(clicks, function (i, f) { clickEvent = f; return; }); touchedElement.unbind("click"); } } } // Is it moving to the right or left, top or bottom? var toright = dx > 0; var tobottom = dy > 0; // Calculate speed from 1 to 5, 1 being slower and 5 faster. var s = ((ax + ay) * 60) / ((ms) / 6 * (ms)); if (s < 1) s = 1; if (s > 5) s = 5; var result = { speed: parseInt(s), x: ax, y: ay, source: touchedElement }; if (ax >= config.moveX) { // Check if it's allowed and trigger diagonal wipe events. if (config.allowDiagonal && ay >= config.moveY) { if (toright && tobottom) { triggerEvent(config.wipeDownRight, result); } else if (toright && !tobottom) { triggerEvent(config.wipeUpRight, result); } else if (!toright && tobottom) { triggerEvent(config.wipeDownLeft, result); } else { triggerEvent(config.wipeUpLeft, result); } } // Otherwise trigger horizontal events if X > Y. else if (ax >= ay) { if (toright) { triggerEvent(config.wipeRight, result); } else { triggerEvent(config.wipeLeft, result); } } } // If Y > X and no diagonal, trigger vertical events. else if (ay >= config.moveY && ay > ax) { if (tobottom) { triggerEvent(config.wipeDown, result); } else { triggerEvent(config.wipeUp, result); } } resetTouch(); } // Resets the cached variables. function resetTouch() { startX = false; startY = false; startDate = false; isMoving = false; // If there's a click event, bind after a few miliseconds. if (clickEvent) { window.setTimeout(function () { touchedElement.bind("click", clickEvent); clickEvent = false; }, 50); } } // Trigger a wipe event passing a result object with // speed from 1 to 5, x / y movement amount in pixels, // and the source element. function triggerEvent(wipeEvent, result) { if (wipeEvent) { wipeEvent(result); } } // ------------------------------------------------------------------------ // ADD TOUCHSTART AND TOUCHEND EVENT LISTENERS // ------------------------------------------------------------------------ if ("ontouchstart" in document.documentElement) { $(this).bind("touchstart", onTouchStart); $(this).bind("touchend", onTouchEnd); } else { useMouseEvents = true; $(this).bind("mousedown", onTouchStart); $(this).bind("mouseout", onTouchEnd); } }); return this; }; })(jQuery);