123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- /**
- * mui gestures
- * @param {type} $
- * @param {type} window
- * @returns {undefined}
- */
- (function($, window) {
- $.gestures = {
- session: {}
- };
- /**
- * Gesture preventDefault
- * @param {type} e
- * @returns {undefined}
- */
- $.preventDefault = function(e) {
- e.preventDefault();
- };
- /**
- * Gesture stopPropagation
- * @param {type} e
- * @returns {undefined}
- */
- $.stopPropagation = function(e) {
- e.stopPropagation();
- };
- /**
- * register gesture
- * @param {type} gesture
- * @returns {$.gestures}
- */
- $.addGesture = function(gesture) {
- return $.addAction('gestures', gesture);
- };
- var round = Math.round;
- var abs = Math.abs;
- var sqrt = Math.sqrt;
- var atan = Math.atan;
- var atan2 = Math.atan2;
- /**
- * distance
- * @param {type} p1
- * @param {type} p2
- * @returns {Number}
- */
- var getDistance = function(p1, p2, props) {
- if(!props) {
- props = ['x', 'y'];
- }
- var x = p2[props[0]] - p1[props[0]];
- var y = p2[props[1]] - p1[props[1]];
- return sqrt((x * x) + (y * y));
- };
- /**
- * scale
- * @param {Object} starts
- * @param {Object} moves
- */
- var getScale = function(starts, moves) {
- if(starts.length >= 2 && moves.length >= 2) {
- var props = ['pageX', 'pageY'];
- return getDistance(moves[1], moves[0], props) / getDistance(starts[1], starts[0], props);
- }
- return 1;
- };
- /**
- * angle
- * @param {type} p1
- * @param {type} p2
- * @returns {Number}
- */
- var getAngle = function(p1, p2, props) {
- if(!props) {
- props = ['x', 'y'];
- }
- var x = p2[props[0]] - p1[props[0]];
- var y = p2[props[1]] - p1[props[1]];
- return atan2(y, x) * 180 / Math.PI;
- };
- /**
- * direction
- * @param {Object} x
- * @param {Object} y
- */
- var getDirection = function(x, y) {
- if(x === y) {
- return '';
- }
- if(abs(x) >= abs(y)) {
- return x > 0 ? 'left' : 'right';
- }
- return y > 0 ? 'up' : 'down';
- };
- /**
- * rotation
- * @param {Object} start
- * @param {Object} end
- */
- var getRotation = function(start, end) {
- var props = ['pageX', 'pageY'];
- return getAngle(end[1], end[0], props) - getAngle(start[1], start[0], props);
- };
- /**
- * px per ms
- * @param {Object} deltaTime
- * @param {Object} x
- * @param {Object} y
- */
- var getVelocity = function(deltaTime, x, y) {
- return {
- x: x / deltaTime || 0,
- y: y / deltaTime || 0
- };
- };
- /**
- * detect gestures
- * @param {type} event
- * @param {type} touch
- * @returns {undefined}
- */
- var detect = function(event, touch) {
- if($.gestures.stoped) {
- return;
- }
- $.doAction('gestures', function(index, gesture) {
- if(!$.gestures.stoped) {
- if($.options.gestureConfig[gesture.name] !== false) {
- gesture.handle(event, touch);
- }
- }
- });
- };
- /**
- * 暂时无用
- * @param {Object} node
- * @param {Object} parent
- */
- var hasParent = function(node, parent) {
- while(node) {
- if(node == parent) {
- return true;
- }
- node = node.parentNode;
- }
- return false;
- };
- var uniqueArray = function(src, key, sort) {
- var results = [];
- var values = [];
- var i = 0;
- while(i < src.length) {
- var val = key ? src[i][key] : src[i];
- if(values.indexOf(val) < 0) {
- results.push(src[i]);
- }
- values[i] = val;
- i++;
- }
- if(sort) {
- if(!key) {
- results = results.sort();
- } else {
- results = results.sort(function sortUniqueArray(a, b) {
- return a[key] > b[key];
- });
- }
- }
- return results;
- };
- var getMultiCenter = function(touches) {
- var touchesLength = touches.length;
- if(touchesLength === 1) {
- return {
- x: round(touches[0].pageX),
- y: round(touches[0].pageY)
- };
- }
- var x = 0;
- var y = 0;
- var i = 0;
- while(i < touchesLength) {
- x += touches[i].pageX;
- y += touches[i].pageY;
- i++;
- }
- return {
- x: round(x / touchesLength),
- y: round(y / touchesLength)
- };
- };
- var multiTouch = function() {
- return $.options.gestureConfig.pinch;
- };
- var copySimpleTouchData = function(touch) {
- var touches = [];
- var i = 0;
- while(i < touch.touches.length) {
- touches[i] = {
- pageX: round(touch.touches[i].pageX),
- pageY: round(touch.touches[i].pageY)
- };
- i++;
- }
- return {
- timestamp: $.now(),
- gesture: touch.gesture,
- touches: touches,
- center: getMultiCenter(touch.touches),
- deltaX: touch.deltaX,
- deltaY: touch.deltaY
- };
- };
- var calDelta = function(touch) {
- var session = $.gestures.session;
- var center = touch.center;
- var offset = session.offsetDelta || {};
- var prevDelta = session.prevDelta || {};
- var prevTouch = session.prevTouch || {};
- if(touch.gesture.type === $.EVENT_START || touch.gesture.type === $.EVENT_END) {
- prevDelta = session.prevDelta = {
- x: prevTouch.deltaX || 0,
- y: prevTouch.deltaY || 0
- };
- offset = session.offsetDelta = {
- x: center.x,
- y: center.y
- };
- }
- touch.deltaX = prevDelta.x + (center.x - offset.x);
- touch.deltaY = prevDelta.y + (center.y - offset.y);
- };
- var calTouchData = function(touch) {
- var session = $.gestures.session;
- var touches = touch.touches;
- var touchesLength = touches.length;
- if(!session.firstTouch) {
- session.firstTouch = copySimpleTouchData(touch);
- }
- if(multiTouch() && touchesLength > 1 && !session.firstMultiTouch) {
- session.firstMultiTouch = copySimpleTouchData(touch);
- } else if(touchesLength === 1) {
- session.firstMultiTouch = false;
- }
- var firstTouch = session.firstTouch;
- var firstMultiTouch = session.firstMultiTouch;
- var offsetCenter = firstMultiTouch ? firstMultiTouch.center : firstTouch.center;
- var center = touch.center = getMultiCenter(touches);
- touch.timestamp = $.now();
- touch.deltaTime = touch.timestamp - firstTouch.timestamp;
- touch.angle = getAngle(offsetCenter, center);
- touch.distance = getDistance(offsetCenter, center);
- calDelta(touch);
- touch.offsetDirection = getDirection(touch.deltaX, touch.deltaY);
- touch.scale = firstMultiTouch ? getScale(firstMultiTouch.touches, touches) : 1;
- touch.rotation = firstMultiTouch ? getRotation(firstMultiTouch.touches, touches) : 0;
- calIntervalTouchData(touch);
- };
- var CAL_INTERVAL = 25;
- var calIntervalTouchData = function(touch) {
- var session = $.gestures.session;
- var last = session.lastInterval || touch;
- var deltaTime = touch.timestamp - last.timestamp;
- var velocity;
- var velocityX;
- var velocityY;
- var direction;
- if(touch.gesture.type != $.EVENT_CANCEL && (deltaTime > CAL_INTERVAL || last.velocity === undefined)) {
- var deltaX = last.deltaX - touch.deltaX;
- var deltaY = last.deltaY - touch.deltaY;
- var v = getVelocity(deltaTime, deltaX, deltaY);
- velocityX = v.x;
- velocityY = v.y;
- velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
- direction = getDirection(deltaX, deltaY) || last.direction;
- session.lastInterval = touch;
- } else {
- velocity = last.velocity;
- velocityX = last.velocityX;
- velocityY = last.velocityY;
- direction = last.direction;
- }
- touch.velocity = velocity;
- touch.velocityX = velocityX;
- touch.velocityY = velocityY;
- touch.direction = direction;
- };
- var targetIds = {};
- var convertTouches = function(touches) {
- for(var i = 0; i < touches.length; i++) {
- !touches['identifier'] && (touches['identifier'] = 0);
- }
- return touches;
- };
- var getTouches = function(event, touch) {
- var allTouches = convertTouches($.slice.call(event.touches || [event]));
- var type = event.type;
- var targetTouches = [];
- var changedTargetTouches = [];
- //当touchstart或touchmove且touches长度为1,直接获得all和changed
- if((type === $.EVENT_START || type === $.EVENT_MOVE) && allTouches.length === 1) {
- targetIds[allTouches[0].identifier] = true;
- targetTouches = allTouches;
- changedTargetTouches = allTouches;
- touch.target = event.target;
- } else {
- var i = 0;
- var targetTouches = [];
- var changedTargetTouches = [];
- var changedTouches = convertTouches($.slice.call(event.changedTouches || [event]));
- touch.target = event.target;
- var sessionTarget = $.gestures.session.target || event.target;
- targetTouches = allTouches.filter(function(touch) {
- return hasParent(touch.target, sessionTarget);
- });
- if(type === $.EVENT_START) {
- i = 0;
- while(i < targetTouches.length) {
- targetIds[targetTouches[i].identifier] = true;
- i++;
- }
- }
- i = 0;
- while(i < changedTouches.length) {
- if(targetIds[changedTouches[i].identifier]) {
- changedTargetTouches.push(changedTouches[i]);
- }
- if(type === $.EVENT_END || type === $.EVENT_CANCEL) {
- delete targetIds[changedTouches[i].identifier];
- }
- i++;
- }
- if(!changedTargetTouches.length) {
- return false;
- }
- }
- targetTouches = uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true);
- var touchesLength = targetTouches.length;
- var changedTouchesLength = changedTargetTouches.length;
- if(type === $.EVENT_START && touchesLength - changedTouchesLength === 0) { //first
- touch.isFirst = true;
- $.gestures.touch = $.gestures.session = {
- target: event.target
- };
- }
- touch.isFinal = ((type === $.EVENT_END || type === $.EVENT_CANCEL) && (touchesLength - changedTouchesLength === 0));
- touch.touches = targetTouches;
- touch.changedTouches = changedTargetTouches;
- return true;
- };
- var handleTouchEvent = function(event) {
- var touch = {
- gesture: event
- };
- var touches = getTouches(event, touch);
- if(!touches) {
- return;
- }
- calTouchData(touch);
- detect(event, touch);
- $.gestures.session.prevTouch = touch;
- if(event.type === $.EVENT_END && !$.isTouchable) {
- $.gestures.touch = $.gestures.session = {};
- }
- };
- var supportsPassive = (function checkPassiveListener() {
- var supportsPassive = false;
- try {
- var opts = Object.defineProperty({}, 'passive', {
- get: function get() {
- supportsPassive = true;
- },
- });
- window.addEventListener('testPassiveListener', null, opts);
- } catch(e) {
- // No support
- }
- return supportsPassive;
- }())
- window.addEventListener($.EVENT_START, handleTouchEvent);
- window.addEventListener($.EVENT_MOVE, handleTouchEvent, supportsPassive ? {
- passive: false,
- capture: false
- } : false);
- window.addEventListener($.EVENT_END, handleTouchEvent);
- window.addEventListener($.EVENT_CANCEL, handleTouchEvent);
- //fixed hashchange(android)
- window.addEventListener($.EVENT_CLICK, function(e) {
- //TODO 应该判断当前target是不是在targets.popover内部,而不是非要相等
- if(($.os.android || $.os.ios) && (($.targets.popover && e.target === $.targets.popover) || ($.targets.tab) || $.targets.offcanvas || $.targets.modal)) {
- e.preventDefault();
- }
- }, true);
- //增加原生滚动识别
- $.isScrolling = false;
- var scrollingTimeout = null;
- window.addEventListener('scroll', function() {
- $.isScrolling = true;
- scrollingTimeout && clearTimeout(scrollingTimeout);
- scrollingTimeout = setTimeout(function() {
- $.isScrolling = false;
- }, 250);
- });
- })(mui, window);
|