UNPKG

pinch-slider

Version:

a slider for images which can be zoomed or pinched

249 lines (219 loc) 8.69 kB
/* AlloyFinger v0.1.3 * 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) { 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++) { this.handlers[i].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.element.addEventListener("touchstart", this.start.bind(this), false); this.element.addEventListener("touchmove", this.move.bind(this), false); this.element.addEventListener("touchend", this.end.bind(this), false); this.element.addEventListener("touchcancel", this.cancel.bind(this), false); this.preV = { x: null, y: null }; this.pinchStartLen = null; this.scale = 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.touchMove = wrapFunc(this.element, option.touchMove || noop); this.touchEnd = wrapFunc(this.element, option.touchEnd || noop); this.touchCancel = wrapFunc(this.element, option.touchCancel || noop); this.delta = null; this.last = null; this.now = null; this.tapTimeout = null; this.touchTimeout = 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); 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); } 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(); 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.longTapTimeout = setTimeout(function () { this.longTap.dispatch(evt); }.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 v = { x: evt.touches[1].pageX - currentX, y: evt.touches[1].pageY - currentY }; if (preV.x !== null) { if (this.pinchStartLen > 0) { evt.scale = getLen(v) / this.pinchStartLen; this.pinch.dispatch(evt); } evt.angle = getRotateAngle(v, preV); this.rotate.dispatch(evt); } preV.x = v.x; preV.y = v.y; } else { if (this.x2 !== null) { evt.deltaX = currentX - this.x2; evt.deltaY = currentY - this.y2; } else { evt.deltaX = 0; evt.deltaY = 0; } this.pressMove.dispatch(evt); } this.touchMove.dispatch(evt); this._cancelLongTap(); this.x2 = currentX; this.y2 = currentY; if (evt.touches.length > 1) { this._cancelLongTap(); evt.preventDefault(); } }, end: function (evt) { if (!evt.changedTouches) return; this._cancelLongTap(); var self = this; if (evt.touches.length < 2) { this.multipointEnd.dispatch(evt); } this.touchEnd.dispatch(evt); //swipe if ((this.x2 && Math.abs(this.x1 - this.x2) > 30) || (this.y2 && Math.abs(this.preV.y - this.y2) > 30)) { evt.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2); this.swipeTimeout = setTimeout(function () { self.swipe.dispatch(evt); }, 0) } else { this.tapTimeout = setTimeout(function () { self.tap.dispatch(evt); // trigger double tap immediately if (self.isDoubleTap) { self.doubleTap.dispatch(evt); clearTimeout(self.touchTimeout); self.isDoubleTap = false; } else { self.touchTimeout = setTimeout(function () { self.singleTap.dispatch(evt); }, 250); } }, 0) } this.preV.x = 0; this.preV.y = 0; this.scale = 1; this.pinchStartLen = null; this.x1 = this.x2 = this.y1 = this.y2 = null; }, cancel: function (evt) { clearTimeout(this.touchTimeout); clearTimeout(this.tapTimeout); clearTimeout(this.longTapTimeout); clearTimeout(this.swipeTimeout); this.touchCancel.dispatch(evt); }, _cancelLongTap: function () { clearTimeout(this.longTapTimeout); }, _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); } } }; if (typeof module !== 'undefined' && typeof exports === 'object') { module.exports = AlloyFinger; } else { window.AlloyFinger = AlloyFinger; } })();