123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- var SUPPORT_TOUCH = "ontouchstart" in window;
- var touchEvents = [
- ["touchstart", "start"],
- ["touchmove", "move"],
- ["touchend", "end"],
- ["touchcancel", "cancel"]
- ];
- var mouseEvents = [
- ["mousedown", "start"],
- ["mouseup", "end"],
- ["mousemove", "move"]
- ];
- var events = SUPPORT_TOUCH ? touchEvents : mouseEvents;
- function forEach(obj, callback) {
- for (key in obj) {
- if (obj.hasOwnProperty(key)) callback(obj[key], key, obj);
- }
- }
- /*
- options{
- leading:false 表示禁用第一次执行
- trailing: false 表示禁用停止触发的回调
- }
- */
- function throttle(func, wait, options) {
- var timeout, context, args, result;
- var previous = 0;
- if (!options) options = {};
- var later = function() {
- previous = options.leading === false ? 0 : new Date().getTime();
- timeout = null;
- func.apply(context, args);
- if (!timeout) context = args = null;
- };
- var throttled = function() {
- var now = new Date().getTime();
- if (!previous && options.leading === false) previous = now;
- var remaining = wait - (now - previous);
- context = this;
- args = arguments;
- // 如果没有剩余的时间了或者你改了系统时间
- if (remaining <= 0 || remaining > wait) {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- previous = now;
- func.apply(context, args);
- if (!timeout) context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- };
- return throttled;
- }
- /*
- @params options : {
- string name
- function start ,
- function move,
- function end,
- function cancel
- }
- */
- function Gesture(options) {
- var _this = this;
- forEach(options, function(v, k) {
- _this[k] = v;
- });
- if (this.init) this.init();
- events.forEach(function(ev) {
- document.addEventListener(
- [ev[0]],
- function(e) {
- if (_this[ev[1]]) _this[ev[1]](e);
- },
- false
- );
- });
- }
- Gesture.prototype = {
- pos: function(e, identifier) {
- var target = this.target(e, identifier);
- if (target) {
- return {
- x: target.clientX,
- y: target.clientY,
- identifier: identifier
- };
- } else {
- return false;
- }
- },
- target: function(e, identifier) {
- var target;
- if (SUPPORT_TOUCH) {
- if (typeof identifier === "number") {
- e.changedTouches.forEach(function(touch) {
- if (touch.identifier === identifier) target = touch;
- });
- } else {
- target = e.changedTouches[0];
- }
- } else {
- target = e;
- }
- return target;
- },
- dispatch: function(e, name, detail) {
- e.target.dispatchEvent(
- new CustomEvent(name, {
- detail: detail,
- bubbles: true,
- cancelable: true
- })
- );
- }
- };
- var tap = new Gesture({
- name: "tap",
- init: function() {
- this.moved = false;
- this.startX = 0;
- this.startY = 0;
- this.number = 0;
- this.identifier = undefined;
- },
- start: function(e) {
- if (SUPPORT_TOUCH && e.touches.length > 1) return;
- this.init();
- var pos = this.pos(e);
- this.startX = pos.x;
- this.startY = pos.y;
- this.identifier = pos.identifier;
- },
- move: function(e) {
- var pos = this.pos(e, this.identifier);
- if (
- pos &&
- (Math.abs(pos.x - this.startX) > 10 || Math.abs(pos.y - this.startY) > 10)
- ) {
- this.moved = true;
- }
- },
- end: function(e) {
- if (this.target(e, this.identifier) && !this.moved) {
- this.dispatch(e, this.name, this.pos(e));
- }
- },
- cancel: function(e) {
- this.end(e)
- }
- });
- var pan = new Gesture({
- name: "pan",
- init: function() {
- this.isStart = false;
- this.startX = 0;
- this.startY = 0;
- this.prevX = 0;
- this.prevY = 0;
- this.prevT = 0;
- this.identifier = undefined;
- this.history = [];
- this.directionX = "none";
- this.directionY = "none";
- },
- start: function(e) {
- if (SUPPORT_TOUCH && e.touches.length > 1) return;
- this.init();
- var pos = this.pos(e);
- this.startX = this.prevX = pos.x;
- this.startY = this.prevY = pos.y;
- this.prevY = e.timeStamp;
- this.identifier = pos.identifier;
- },
- move: function(e) {
- var pos = this.pos(e, this.identifier);
- if (pos) {
- var detail = this.detail(pos);
- // 方向相同且时间短记录,不然清空
- if (
- detail.directionX === this.directionX &&
- e.timeStamp - this.prevT < 50
- ) {
- if (this.history.length >= 10) this.history.shift();
- } else {
- this.history = [];
- }
- this.history.push({
- x: detail.x,
- y: detail.y,
- t: e.timeStamp,
- deltaX: detail.deltaX,
- deltaY: detail.deltaY
- });
- if (!this.isStart) {
- this.isStart = true;
- this.dispatch(e, this.name + "start", detail);
- }
- this.throttleDispatch(e, this.name, detail)
- this.prevX = pos.x;
- this.prevY = pos.y;
- this.prevT = e.timeStamp;
- this.directionX = detail.directionX;
- this.directionY = detail.directionY;
- }
- },
- end: function(e) {
- var pos = this.pos(e, this.identifier);
- var detail = this.detail(pos);
- detail.fast =
- this.history.length > 3 &&
- e.timeStamp - this.prevT < 50 &&
- Math.abs(
- (this.history[this.history.length - 1].x - this.history[0].x) /
- (this.history[this.history.length - 1].t - this.history[0].t)
- ) > 1;
- if (pos && this.isStart) this.dispatch(e, this.name + "end", detail);
- },
- cancel: function(e) {
- this.end(e);
- },
- detail: function(pos) {
- var deltaX = pos.x - this.startX,
- deltaY = pos.y - this.startY;
- if (this.prevX < pos.x) {
- var directionX = "right";
- } else if (this.prevX > pos.x) {
- var directionX = "left";
- } else {
- directionX = this.directionX;
- }
- if (this.prevY < pos.y) {
- var directionY = "bottom";
- } else if (this.prevY > pos.y) {
- var directionY = "top";
- } else {
- directionY = this.directionY;
- }
- return {
- x: pos.x,
- y: pos.y,
- deltaX: deltaX,
- deltaY: deltaY,
- directionY: directionY,
- directionX: directionX
- };
- },
- throttleDispatch: throttle(Gesture.prototype.dispatch,20,{ trailing: false })
- });
|