UNPKG

hammerjs

Version:

A javascript library for multi-touch gestures

341 lines (299 loc) 8.74 kB
/** * @module hammer * * @class Utils * @static */ var Utils = Hammer.utils = { /** * extend method, could also be used for cloning when `dest` is an empty object. * changes the dest object * @method extend * @param {Object} dest * @param {Object} src * @param {Boolean} [merge=false] do a merge * @return {Object} dest */ extend: function extend(dest, src, merge) { for(var key in src) { if(dest[key] !== undefined && merge || key == 'returnValue') { continue; } dest[key] = src[key]; } return dest; }, /** * simple addEventListener wrapper * @method on * @param {HTMLElement} element * @param {String} type * @param {Function} handler */ on: function on(element, type, handler) { element.addEventListener(type, handler, false); }, /** * simple removeEventListener wrapper * @method off * @param {HTMLElement} element * @param {String} type * @param {Function} handler */ off: function off(element, type, handler) { element.removeEventListener(type, handler, false); }, /** * forEach over arrays and objects * @method each * @param {Object|Array} obj * @param {Function} iterator * @param {any} iterator.item * @param {Number} iterator.index * @param {Object|Array} iterator.obj the source object * @param {Object} context value to use as `this` in the iterator */ each: function each(obj, iterator, context) { var i, len; // native forEach on arrays if ('forEach' in obj) { obj.forEach(iterator, context); } // arrays else if(obj.length !== undefined) { for(i=0,len=obj.length; i<len; i++) { if (iterator.call(context, obj[i], i, obj) === false) { return; } } } // objects else { for(i in obj) { if(obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj) === false) { return; } } } }, /** * find if a string contains the string using indexOf * @method inStr * @param {String} src * @param {String} find * @return {Boolean} found */ inStr: function inStr(src, find) { return src.indexOf(find) > -1; }, /** * find if a array contains the object using indexOf or a simple polyfill * @method inArray * @param {String} src * @param {String} find * @return {Boolean|Number} false when not found, or the index */ inArray: function inArray(src, find) { if(src.indexOf) { var index = src.indexOf(find); return (index === -1) ? false : index; } else { for(var i= 0,len=src.length;i<len; i++) { if(src[i] === find) { return i; } } return false; } }, /** * convert an array-like object (`arguments`, `touchlist`) to an array * @method toArray * @param {Object} obj * @return {Array} */ toArray: function toArray(obj) { return Array.prototype.slice.call(obj, 0); }, /** * find if a node is in the given parent * @method hasParent * @param {HTMLElement} node * @param {HTMLElement} parent * @return {Boolean} found */ hasParent: function hasParent(node, parent) { while(node) { if(node == parent) { return true; } node = node.parentNode; } return false; }, /** * get the center of all the touches * @method getCenter * @param {Array} touches * @return {Object} center contains `pageX`, `pageY`, `clientX` and `clientY` properties */ getCenter: function getCenter(touches) { var pageX = [] , pageY = [] , clientX = [] , clientY = [] , min = Math.min , max = Math.max; // no need to loop when only one touch if(touches.length === 1) { return { pageX: touches[0].pageX, pageY: touches[0].pageY, clientX: touches[0].clientX, clientY: touches[0].clientY }; } Utils.each(touches, function(touch) { pageX.push(touch.pageX); pageY.push(touch.pageY); clientX.push(touch.clientX); clientY.push(touch.clientY); }); return { pageX: (min.apply(Math, pageX) + max.apply(Math, pageX)) / 2, pageY: (min.apply(Math, pageY) + max.apply(Math, pageY)) / 2, clientX: (min.apply(Math, clientX) + max.apply(Math, clientX)) / 2, clientY: (min.apply(Math, clientY) + max.apply(Math, clientY)) / 2 }; }, /** * calculate the velocity between two points. unit is in px per ms. * @method getVelocity * @param {Number} delta_time * @param {Number} delta_x * @param {Number} delta_y * @return {Object} velocity `x` and `y` */ getVelocity: function getVelocity(delta_time, delta_x, delta_y) { return { x: Math.abs(delta_x / delta_time) || 0, y: Math.abs(delta_y / delta_time) || 0 }; }, /** * calculate the angle between two coordinates * @method getAngle * @param {Touch} touch1 * @param {Touch} touch2 * @return {Number} angle */ getAngle: function getAngle(touch1, touch2) { var x = touch2.clientX - touch1.clientX , y = touch2.clientY - touch1.clientY; return Math.atan2(y, x) * 180 / Math.PI; }, /** * do a small comparision to get the direction between two touches. * @method getDirection * @param {Touch} touch1 * @param {Touch} touch2 * @return {String} direction matches `DIRECTION_LEFT|RIGHT|UP|DOWN` */ getDirection: function getDirection(touch1, touch2) { var x = Math.abs(touch1.clientX - touch2.clientX) , y = Math.abs(touch1.clientY - touch2.clientY); if(x >= y) { return touch1.clientX - touch2.clientX > 0 ? DIRECTION_LEFT : DIRECTION_RIGHT; } return touch1.clientY - touch2.clientY > 0 ? DIRECTION_UP : DIRECTION_DOWN; }, /** * calculate the distance between two touches * @method getDistance * @param {Touch}touch1 * @param {Touch} touch2 * @return {Number} distance */ getDistance: function getDistance(touch1, touch2) { var x = touch2.clientX - touch1.clientX , y = touch2.clientY - touch1.clientY; return Math.sqrt((x * x) + (y * y)); }, /** * calculate the scale factor between two touchLists * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out * @method getScale * @param {Array} start array of touches * @param {Array} end array of touches * @return {Number} scale */ getScale: function getScale(start, end) { // need two fingers... if(start.length >= 2 && end.length >= 2) { return this.getDistance(end[0], end[1]) / this.getDistance(start[0], start[1]); } return 1; }, /** * calculate the rotation degrees between two touchLists * @method getRotation * @param {Array} start array of touches * @param {Array} end array of touches * @return {Number} rotation */ getRotation: function getRotation(start, end) { // need two fingers if(start.length >= 2 && end.length >= 2) { return this.getAngle(end[1], end[0]) - this.getAngle(start[1], start[0]); } return 0; }, /** * find out if the direction is vertical * * @method isVertical * @param {String} direction matches `DIRECTION_UP|DOWN` * @return {Boolean} is_vertical */ isVertical: function isVertical(direction) { return direction == DIRECTION_UP || direction == DIRECTION_DOWN; }, /** * toggle browser default behavior by setting css properties. * `userSelect='none'` also sets `element.onselectstart` to false * `userDrag='none'` also sets `element.ondragstart` to false * * @method toggleBehavior * @param {HtmlElement} element * @param {Object} props * @param {Boolean} [toggle=false] */ toggleBehavior: function toggleBehavior(element, props, toggle) { if(!props || !element || !element.style) { return; } // with css properties for modern browsers Utils.each(['webkit', 'moz', 'Moz', 'ms', 'o', ''], function setStyle(vendor) { Utils.each(props, function(value, prop) { // vender prefix at the property if(vendor) { prop = vendor + prop.substring(0, 1).toUpperCase() + prop.substring(1); } // set the style if(prop in element.style) { element.style[prop] = !toggle && value; } }); }); var false_fn = function(){ return false; }; // also the disable onselectstart if(props.userSelect == 'none') { element.onselectstart = !toggle && false_fn; } // and disable ondragstart if(props.userDrag == 'none') { element.ondragstart = !toggle && false_fn; } } };