| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- /* AlloyFinger v0.1.15
- * By dntzhang
- * Github: https://github.com/AlloyTeam/AlloyFinger
- * 监听触摸的工具类
- */
- (function () {
- // 获取两点距离
- function getLen(v) {
- return Math.sqrt(v.x * v.x + v.y * v.y);
- }
- function dot(v1, v2) {
- return v1.x * v2.x + v1.y * v2.y;
- }
- // 获取角度
- function getAngle(v1, v2) {
- var mr = getLen(v1) * getLen(v2);
- if (mr === 0) return 0;
- var r = dot(v1, v2) / mr;
- if (r > 1) r = 1;
- return Math.acos(r);
- }
- function cross(v1, v2) {
- return v1.x * v2.y - v2.x * v1.y;
- }
- function getRotateAngle(v1, v2) {
- var angle = getAngle(v1, v2);
- if (cross(v1, v2) > 0) {
- angle *= -1;
- }
- return (angle * 180) / Math.PI;
- }
- var HandlerAdmin = function (el) {
- this.handlers = [];
- this.el = el;
- };
- HandlerAdmin.prototype.add = function (handler) {
- this.handlers.push(handler);
- };
- HandlerAdmin.prototype.del = function (handler) {
- if (!handler) this.handlers = [];
- for (var i = this.handlers.length; i >= 0; i--) {
- if (this.handlers[i] === handler) {
- this.handlers.splice(i, 1);
- }
- }
- };
- HandlerAdmin.prototype.dispatch = function () {
- for (var i = 0, len = this.handlers.length; i < len; i++) {
- var handler = this.handlers[i];
- if (typeof handler === "function") handler.apply(this.el, arguments);
- }
- };
- function wrapFunc(el, handler) {
- var handlerAdmin = new HandlerAdmin(el);
- handlerAdmin.add(handler);
- return handlerAdmin;
- }
- var AlloyFinger = function (el, option) {
- this.element = typeof el == "string" ? document.querySelector(el) : el;
- this.start = this.start.bind(this);
- this.move = this.move.bind(this);
- this.end = this.end.bind(this);
- this.cancel = this.cancel.bind(this);
- this.element.addEventListener("touchstart", this.start, false);
- this.element.addEventListener("touchmove", this.move, false);
- this.element.addEventListener("touchend", this.end, false);
- this.element.addEventListener("touchcancel", this.cancel, false);
- this.preV = {
- x: null,
- y: null,
- };
- this.pinchStartLen = null;
- this.zoom = 1;
- this.isDoubleTap = false;
- var noop = function () {};
- this.rotate = wrapFunc(this.element, option.rotate || noop);
- this.touchStart = wrapFunc(this.element, option.touchStart || noop);
- this.multipointStart = wrapFunc(
- this.element,
- option.multipointStart || noop
- );
- this.multipointEnd = wrapFunc(this.element, option.multipointEnd || noop);
- this.pinch = wrapFunc(this.element, option.pinch || noop);
- this.swipe = wrapFunc(this.element, option.swipe || noop);
- this.tap = wrapFunc(this.element, option.tap || noop);
- this.doubleTap = wrapFunc(this.element, option.doubleTap || noop);
- this.longTap = wrapFunc(this.element, option.longTap || noop);
- this.singleTap = wrapFunc(this.element, option.singleTap || noop);
- this.pressMove = wrapFunc(this.element, option.pressMove || noop);
- this.twoFingerPressMove = wrapFunc(
- this.element,
- option.twoFingerPressMove || noop
- );
- this.touchMove = wrapFunc(this.element, option.touchMove || noop);
- this.touchEnd = wrapFunc(this.element, option.touchEnd || noop);
- this.touchCancel = wrapFunc(this.element, option.touchCancel || noop);
- this._cancelAllHandler = this.cancelAll.bind(this);
- window.addEventListener("scroll", this._cancelAllHandler);
- this.delta = null;
- this.last = null;
- this.now = null;
- this.tapTimeout = null;
- this.singleTapTimeout = null;
- this.longTapTimeout = null;
- this.swipeTimeout = null;
- this.x1 = this.x2 = this.y1 = this.y2 = null;
- this.preTapPosition = {
- x: null,
- y: null,
- };
- };
- AlloyFinger.prototype = {
- start: function (evt) {
- if (!evt.touches) return;
- this.now = Date.now();
- this.x1 = evt.touches[0].pageX;
- this.y1 = evt.touches[0].pageY;
- this.delta = this.now - (this.last || this.now);
- this.touchStart.dispatch(evt, this.element);
- if (this.preTapPosition.x !== null) {
- this.isDoubleTap =
- this.delta > 0 &&
- this.delta <= 250 &&
- Math.abs(this.preTapPosition.x - this.x1) < 30 &&
- Math.abs(this.preTapPosition.y - this.y1) < 30;
- if (this.isDoubleTap) clearTimeout(this.singleTapTimeout);
- }
- this.preTapPosition.x = this.x1;
- this.preTapPosition.y = this.y1;
- this.last = this.now;
- var preV = this.preV,
- len = evt.touches.length;
- if (len > 1) {
- this._cancelLongTap();
- this._cancelSingleTap();
- var v = {
- x: evt.touches[1].pageX - this.x1,
- y: evt.touches[1].pageY - this.y1,
- };
- preV.x = v.x;
- preV.y = v.y;
- this.pinchStartLen = getLen(preV);
- this.multipointStart.dispatch(evt, this.element);
- }
- this._preventTap = false;
- this.longTapTimeout = setTimeout(
- function () {
- this.longTap.dispatch(evt, this.element);
- this._preventTap = true;
- }.bind(this),
- 750
- );
- },
- move: function (evt) {
- if (!evt.touches) return;
- var preV = this.preV,
- len = evt.touches.length,
- currentX = evt.touches[0].pageX,
- currentY = evt.touches[0].pageY;
- this.isDoubleTap = false;
- if (len > 1) {
- var sCurrentX = evt.touches[1].pageX,
- sCurrentY = evt.touches[1].pageY;
- var v = {
- x: evt.touches[1].pageX - currentX,
- y: evt.touches[1].pageY - currentY,
- };
- if (preV.x !== null) {
- if (this.pinchStartLen > 0) {
- evt.zoom = getLen(v) / this.pinchStartLen;
- this.pinch.dispatch(evt, this.element);
- }
- evt.angle = getRotateAngle(v, preV);
- this.rotate.dispatch(evt, this.element);
- }
- preV.x = v.x;
- preV.y = v.y;
- if (this.x2 !== null && this.sx2 !== null) {
- evt.deltaX = (currentX - this.x2 + sCurrentX - this.sx2) / 2;
- evt.deltaY = (currentY - this.y2 + sCurrentY - this.sy2) / 2;
- } else {
- evt.deltaX = 0;
- evt.deltaY = 0;
- }
- this.twoFingerPressMove.dispatch(evt, this.element);
- this.sx2 = sCurrentX;
- this.sy2 = sCurrentY;
- } else {
- if (this.x2 !== null) {
- evt.deltaX = currentX - this.x2;
- evt.deltaY = currentY - this.y2;
- //move事件中添加对当前触摸点到初始触摸点的判断,
- //如果曾经大于过某个距离(比如10),就认为是移动到某个地方又移回来,应该不再触发tap事件才对。
- var movedX = Math.abs(this.x1 - this.x2),
- movedY = Math.abs(this.y1 - this.y2);
- if (movedX > 10 || movedY > 10) {
- this._preventTap = true;
- }
- } else {
- evt.deltaX = 0;
- evt.deltaY = 0;
- }
- this.pressMove.dispatch(evt, this.element);
- }
- this.touchMove.dispatch(evt, this.element);
- this._cancelLongTap();
- this.x2 = currentX;
- this.y2 = currentY;
- if (len > 1) {
- evt.preventDefault();
- }
- },
- end: function (evt) {
- if (!evt.changedTouches) return;
- this._cancelLongTap();
- var self = this;
- if (evt.touches.length < 2) {
- this.multipointEnd.dispatch(evt, this.element);
- this.sx2 = this.sy2 = null;
- }
- //swipe
- if (
- (this.x2 && Math.abs(this.x1 - this.x2) > 30) ||
- (this.y2 && Math.abs(this.y1 - this.y2) > 30)
- ) {
- evt.direction = this._swipeDirection(
- this.x1,
- this.x2,
- this.y1,
- this.y2
- );
- this.swipeTimeout = setTimeout(function () {
- self.swipe.dispatch(evt, self.element);
- }, 0);
- } else {
- this.tapTimeout = setTimeout(function () {
- if (!self._preventTap) {
- self.tap.dispatch(evt, self.element);
- }
- // trigger double tap immediately
- if (self.isDoubleTap) {
- self.doubleTap.dispatch(evt, self.element);
- self.isDoubleTap = false;
- }
- }, 0);
- if (!self.isDoubleTap) {
- self.singleTapTimeout = setTimeout(function () {
- self.singleTap.dispatch(evt, self.element);
- }, 250);
- }
- }
- this.touchEnd.dispatch(evt, this.element);
- this.preV.x = 0;
- this.preV.y = 0;
- this.zoom = 1;
- this.pinchStartLen = null;
- this.x1 = this.x2 = this.y1 = this.y2 = null;
- },
- cancelAll: function () {
- this._preventTap = true;
- clearTimeout(this.singleTapTimeout);
- clearTimeout(this.tapTimeout);
- clearTimeout(this.longTapTimeout);
- clearTimeout(this.swipeTimeout);
- },
- cancel: function (evt) {
- this.cancelAll();
- this.touchCancel.dispatch(evt, this.element);
- },
- _cancelLongTap: function () {
- clearTimeout(this.longTapTimeout);
- },
- _cancelSingleTap: function () {
- clearTimeout(this.singleTapTimeout);
- },
- _swipeDirection: function (x1, x2, y1, y2) {
- return Math.abs(x1 - x2) >= Math.abs(y1 - y2)
- ? x1 - x2 > 0
- ? "Left"
- : "Right"
- : y1 - y2 > 0
- ? "Up"
- : "Down";
- },
- on: function (evt, handler) {
- if (this[evt]) {
- this[evt].add(handler);
- }
- },
- off: function (evt, handler) {
- if (this[evt]) {
- this[evt].del(handler);
- }
- },
- destroy: function () {
- if (this.singleTapTimeout) clearTimeout(this.singleTapTimeout);
- if (this.tapTimeout) clearTimeout(this.tapTimeout);
- if (this.longTapTimeout) clearTimeout(this.longTapTimeout);
- if (this.swipeTimeout) clearTimeout(this.swipeTimeout);
- this.element.removeEventListener("touchstart", this.start);
- this.element.removeEventListener("touchmove", this.move);
- this.element.removeEventListener("touchend", this.end);
- this.element.removeEventListener("touchcancel", this.cancel);
- this.rotate.del();
- this.touchStart.del();
- this.multipointStart.del();
- this.multipointEnd.del();
- this.pinch.del();
- this.swipe.del();
- this.tap.del();
- this.doubleTap.del();
- this.longTap.del();
- this.singleTap.del();
- this.pressMove.del();
- this.twoFingerPressMove.del();
- this.touchMove.del();
- this.touchEnd.del();
- this.touchCancel.del();
- this.preV =
- this.pinchStartLen =
- this.zoom =
- this.isDoubleTap =
- this.delta =
- this.last =
- this.now =
- this.tapTimeout =
- this.singleTapTimeout =
- this.longTapTimeout =
- this.swipeTimeout =
- this.x1 =
- this.x2 =
- this.y1 =
- this.y2 =
- this.preTapPosition =
- this.rotate =
- this.touchStart =
- this.multipointStart =
- this.multipointEnd =
- this.pinch =
- this.swipe =
- this.tap =
- this.doubleTap =
- this.longTap =
- this.singleTap =
- this.pressMove =
- this.touchMove =
- this.touchEnd =
- this.touchCancel =
- this.twoFingerPressMove =
- null;
- window.removeEventListener("scroll", this._cancelAllHandler);
- return null;
- },
- };
- if (typeof module !== "undefined" && typeof exports === "object") {
- module.exports = AlloyFinger;
- } else {
- window.AlloyFinger = AlloyFinger;
- }
- })();
|