flipsnap.js 源码阅读备份
这是官网:http://hokaccha.github.io/js-flipsnap/
1.引入全局命名空间 类似jQuery插件写法 传入window, document,提高内部访问速度;
;(function(window, document, undefined){})(window, window.document)
2.定义全局变量
/* 新建div节点 */ var div = document.createElement('div'); /* 浏览器前缀 */ var prefix = ['webkit', 'moz', 'o', 'ms']; /* 存储属性对象 */ var saveProp = {}; /* 检测浏览器支持的对象 */ var support = Flipsnap.support = {}; /* 手势状态判断 */ var gestureStart = false; /* 阀值设置 */ var DISTANCE_THRESHOLD = 5; var ANGLE_THREHOLD = 55;
3.分别检测对transform3d, transform及trasition 3个css3属性的支持程度
support.transform3d = hasProp([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); support.transform = hasProp([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); support.transition = hasProp([ 'transitionProperty', 'WebkitTransitionProperty', 'MozTransitionProperty', 'OTransitionProperty', 'msTransitionProperty' ]);
使用hasProp()
函数
function hasProp(props) { return some(props, function(prop) { return div.style[ prop ] !== undefined; }); }
其中some()
闭包函数##为,只要数组内其中一个为true即判定为true
function some(ary, callback) { for (var i = 0, len = ary.length; i < len; i++) { if (callback(ary[i], i)) { return true; } } return false; }
4.其他浏览器的属性支持(事件监听属性及IE的指针事件的支持)及总的css动画属性支持判断
support.addEventListener = 'addEventListener' in window; support.mspointer = window.navigator.msPointerEnabled; support.cssAnimation = (support.transform3d || support.transform) && support.transition;
5.定义事件种类及相关事件对象
var eventTypes = ['touch', 'mouse']; var events = { start: { touch: 'touchstart', mouse: 'mousedown' }, move: { touch: 'touchmove', mouse: 'mousemove' }, end: { touch: 'touchend', mouse: 'mouseup' } };
6.添加事件监听
if (support.addEventListener) { document.addEventListener('gesturestart', function() { gestureStart = true; }); document.addEventListener('gestureend', function() { gestureStart = false; }); }
7.定义全局新类Flipsnap()
,并初始化新类,其中使用了Flipsnap类的初始方法init()
function Flipsnap(element, opts) { return (this instanceof Flipsnap) ? this.init(element, opts) : new Flipsnap(element, opts); }
8.定义Flipsnap类的初始化方法init()
Flipsnap.prototype.init = function(element, opts) { var self = this; // set element self.element = element; if (typeof element === 'string') { self.element = document.querySelector(element); } if (!self.element) { throw new Error('element not found'); } if (support.mspointer) { self.element.style.msTouchAction = 'pan-y'; } // set opts opts = opts || {}; self.distance = opts.distance; self.maxPoint = opts.maxPoint; self.disableTouch = (opts.disableTouch === undefined) ? false : opts.disableTouch; self.disable3d = (opts.disable3d === undefined) ? false : opts.disable3d; self.transitionDuration = (opts.transitionDuration === undefined) ? '350ms' : opts.transitionDuration + 'ms'; self.threshold = opts.threshold || 0; // set property self.currentPoint = 0; self.currentX = 0; self.animation = false; self.use3d = support.transform3d; if (self.disable3d === true) { self.use3d = false; } // set default style if (support.cssAnimation) { self._setStyle({ transitionProperty: getCSSVal('transform'), transitionTimingFunction: 'cubic-bezier(0,0,0.25,1)', transitionDuration: '0ms', transform: self._getTranslate(0) }); } else { self._setStyle({ position: 'relative', left: '0px' }); } // initilize self.refresh(); eventTypes.forEach(function(type) { // 为什么要传人self作回调函数,(self=Flipsnap())? self.element.addEventListener(events.start[type], self, false); }); return self; };
其中_setStyle()
为FLipsnap的内部方法
Flipsnap.prototype._setStyle = function(styles) { var self = this; var style = self.element.style; for (var prop in styles) { setStyle(style, prop, styles[prop]); } };
其中setStyle()
函数,设置对应css属性为对应值,具体为
function setStyle(style, prop, val) { var _saveProp = saveProp[ prop ]; if (_saveProp) { style[ _saveProp ] = val; } else if (style[ prop ] !== undefined) { saveProp[ prop ] = prop; style[ prop ] = val; } else { some(prefix, function(_prefix) { var _prop = ucFirst(_prefix) + ucFirst(prop); if (style[ _prop ] !== undefined) { saveProp[ prop ] = _prop; style[ _prop ] = val; return true; } }); } }
并在saveProp
中设置过的属性
getCSSVal()
函数用于获取已用的css属性值,具体如下
function getCSSVal(prop) { if (div.style[ prop ] !== undefined) { return prop; } else { var ret; some(prefix, function(_prefix) { var _prop = ucFirst(_prefix) + ucFirst(prop); if (div.style[ _prop ] !== undefined) { ret = '-' + _prefix + '-' + prop; return true; } }); return ret; } }
ucFirst()
函数用于将首字母变大写,具体如下 截取第一个字符串charAt(0)转为大写 拼接后面剩下的字符串(substr(1))
function ucFirst(str) { return str.charAt(0).toUpperCase() + str.substr(1); }
self._getTranslate
为Flipsnap的内部方法
Flipsnap.prototype._getTranslate = function(x) { var self = this; return self.use3d ? 'translate3d(' + x + 'px, 0, 0)' : 'translate(' + x + 'px, 0)'; };
refresh()
的Flipsnap方法,具体如下
Flipsnap.prototype.refresh = function() { var self = this; // setting max point self._maxPoint = (self.maxPoint === undefined) ? (function() { var childNodes = self.element.childNodes, itemLength = -1, i = 0, len = childNodes.length, node; for(; i < len; i++) { node = childNodes[i]; if (node.nodeType === 1) { itemLength++; } } return itemLength; })() : self.maxPoint; // setting distance if (self.distance === undefined) { if (self._maxPoint < 0) { self._distance = 0; } else { self._distance = self.element.scrollWidth / (self._maxPoint + 1); } } else { self._distance = self.distance; } // setting maxX self._maxX = -self._distance * self._maxPoint; self.moveToPoint(); };
通过refresh方法设定_maxPoint(最多移动次数)、_distance(移动距离)和_maxX(最大x轴偏向值)属性,从而控制最多的滑动次数;
moveToPoint()
的Flipsnap方法,判定是否需要滑动并触发事件,具体如下
Flipsnap.prototype.moveToPoint = function(point, transitionDuration) { var self = this; transitionDuration = transitionDuration === undefined ? self.transitionDuration : transitionDuration + 'ms'; var beforePoint = self.currentPoint; // not called from `refresh()` if (point === undefined) { point = self.currentPoint; } if (point < 0) { self.currentPoint = 0; } else if (point > self._maxPoint) { self.currentPoint = self._maxPoint; } else { self.currentPoint = parseInt(point, 10); } if (support.cssAnimation) { self._setStyle({ transitionDuration: transitionDuration }); } else { self.animation = true; } self._setX(- self.currentPoint * self._distance, transitionDuration); if (beforePoint !== self.currentPoint) { // is move? // `fsmoveend` is deprecated // `fspointmove` is recommend. self._triggerEvent('fsmoveend', true, false); self._triggerEvent('fspointmove', true, false); } };
其中_setX()为Flipsnap的内部方法,具体如下
Flipsnap.prototype._setX = function(x, transitionDuration) { var self = this; self.currentX = x; if (support.cssAnimation) { self.element.style[ saveProp.transform ] = self._getTranslate(x); } else { if (self.animation) { self._animate(x, transitionDuration || self.transitionDuration); } else { self.element.style.left = x + 'px'; } } };
其中_animate()为Flipsnap的内部方法,具体如下
Flipsnap.prototype._animate = function(x, transitionDuration) { var self = this; var elem = self.element; var begin = +new Date(); var from = parseInt(elem.style.left, 10); var to = x; var duration = parseInt(transitionDuration, 10); var easing = function(time, duration) { return -(time /= duration) * (time - 2); }; var timer = setInterval(function() { var time = new Date() - begin; var pos, now; if (time > duration) { clearInterval(timer); now = to; } else { pos = easing(time, duration); now = pos * (to - from) + from; } elem.style.left = now + "px"; }, 10); };
其中_triggerEvent() 为Flipsnap的内部方法,具体如下
Flipsnap.prototype._triggerEvent = function(type, bubbles, cancelable, data) { var self = this; var ev = document.createEvent('Event'); ev.initEvent(type, bubbles, cancelable); if (data) { for (var d in data) { if (data.hasOwnProperty(d)) { ev[d] = data[d]; } } } return self.element.dispatchEvent(ev); };
9.定义Flipsnap类的事件控制方法handleEvent()
Flipsnap.prototype.handleEvent = function(event) { var self = this; switch (event.type) { // start case events.start.touch: self._touchStart(event, 'touch'); break; case events.start.mouse: self._touchStart(event, 'mouse'); break; // move case events.move.touch: self._touchMove(event, 'touch'); break; case events.move.mouse: self._touchMove(event, 'mouse'); break; // end case events.end.touch: self._touchEnd(event, 'touch'); break; case events.end.mouse: self._touchEnd(event, 'mouse'); break; // click case 'click': self._click(event); break; } };
通过event.type进行条件判断,确定执行Flipsnap的四个内部处理方法中的一个
_touchStart()方法
Flipsnap.prototype._touchStart = function(event, type) { var self = this; if (self.disableTouch || self.scrolling || gestureStart) { return; } self.element.addEventListener(events.move[type], self, false); document.addEventListener(events.end[type], self, false); var tagName = event.target.tagName; if (type === 'mouse' && tagName !== 'SELECT' && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'BUTTON') { event.preventDefault(); } if (support.cssAnimation) { self._setStyle({ transitionDuration: '0ms' }); } else { self.animation = false; } self.scrolling = true; self.moveReady = false; self.startPageX = getPage(event, 'pageX'); self.startPageY = getPage(event, 'pageY'); self.basePageX = self.startPageX; self.directionX = 0; self.startTime = event.timeStamp; self._triggerEvent('fstouchstart', true, false); };
通过touchStart方法记录下触摸开始点开始时间等参数,并触发fstouchstart
事件;
getPage()函数如下
function getPage(event, page) { return event.changedTouches ? event.changedTouches[0][page] : event[page]; }
_touchMove()方法如下
Flipsnap.prototype._touchMove = function(event, type) { var self = this; if (!self.scrolling || gestureStart) { return; } var pageX = getPage(event, 'pageX'); var pageY = getPage(event, 'pageY'); var distX; var newX; if (self.moveReady) { event.preventDefault(); distX = pageX - self.basePageX; newX = self.currentX + distX; if (newX >= 0 || newX < self._maxX) { newX = Math.round(self.currentX + distX / 3); } // When distX is 0, use one previous value. // For android firefox. When touchend fired, touchmove also // fired and distX is certainly set to 0. self.directionX = distX === 0 ? self.directionX : distX > 0 ? -1 : 1; // if they prevent us then stop it var isPrevent = !self._triggerEvent('fstouchmove', true, true, { delta: distX, direction: self.directionX }); if (isPrevent) { self._touchAfter({ moved: false, originalPoint: self.currentPoint, newPoint: self.currentPoint, cancelled: true }); } else { self._setX(newX); } } else { // https://github.com/pxgrid/js-flipsnap/pull/36 var triangle = getTriangleSide(self.startPageX, self.startPageY, pageX, pageY); if (triangle.z > DISTANCE_THRESHOLD) { if (getAngle(triangle) > ANGLE_THREHOLD) { event.preventDefault(); self.moveReady = true; self.element.addEventListener('click', self, true); } else { self.scrolling = false; } } } self.basePageX = pageX; };
其中getTriangleSide()函数如下
function getTriangleSide(x1, y1, x2, y2) { var x = Math.abs(x1 - x2); var y = Math.abs(y1 - y2); var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); return { x: x, y: y, z: z }; }
其中getAngle()函数如下
function getAngle(triangle) { var cos = triangle.y / triangle.z; var radina = Math.acos(cos); return 180 / (Math.PI / radina); }
_touchEnd()方法如下
Flipsnap.prototype._touchEnd = function(event, type) { var self = this; self.element.removeEventListener(events.move[type], self, false); document.removeEventListener(events.end[type], self, false); if (!self.scrolling) { return; } var newPoint = -self.currentX / self._distance; newPoint = (self.directionX > 0) ? Math.ceil(newPoint) : (self.directionX < 0) ? Math.floor(newPoint) : Math.round(newPoint); if (newPoint < 0) { newPoint = 0; } else if (newPoint > self._maxPoint) { newPoint = self._maxPoint; } if (Math.abs(self.startPageX - self.basePageX) < self.threshold) { newPoint = self.currentPoint; } self._touchAfter({ moved: newPoint !== self.currentPoint, originalPoint: self.currentPoint, newPoint: newPoint, cancelled: false }); self.moveToPoint(newPoint); };
触发fstouchend
事件
其中_touchAfter()方法如下
Flipsnap.prototype._touchAfter = function(params) { var self = this; self.scrolling = false; self.moveReady = false; setTimeout(function() { self.element.removeEventListener('click', self, true); }, 200); self._triggerEvent('fstouchend', true, false, params); };
_clic()方法如下
Flipsnap.prototype._click = function(event) { var self = this; event.stopPropagation(); event.preventDefault(); };
10.定义Flipsnap类的状态判断方法hasNext()
Flipsnap.prototype.hasNext = function() { var self = this; return self.currentPoint < self._maxPoint; };
11.定义Flipsnap类的状态判断方法hasPrev()
Flipsnap.prototype.hasPrev = function() { var self = this; return self.currentPoint > 0; };
12.定义Flipsnap类的跳转下一个方法toNext()
Flipsnap.prototype.toNext = function(transitionDuration) { var self = this; if (!self.hasNext()) { return; } self.moveToPoint(self.currentPoint + 1, transitionDuration); };
13.定义Flipsnap类的跳转上一个方法toPrev()
Flipsnap.prototype.toPrev = function(transitionDuration) { var self = this; if (!self.hasPrev()) { return; } self.moveToPoint(self.currentPoint - 1, transitionDuration); };
14.定义Flipsnap类的跳转上一个方法destroy()
Flipsnap.prototype.destroy = function() { var self = this; eventTypes.forEach(function(type) { self.element.removeEventListener(events.start[type], self, false); }); };
取消在各个节点上的事件监听
15.将Flipsnap模块化
if (typeof exports == 'object') { module.exports = Flipsnap; } else if (typeof define == 'function' && define.amd) { define(function() { return Flipsnap; }); } else { window.Flipsnap = Flipsnap; }
/** * flipsnap.js * * @version 0.6.2 * @url http://hokaccha.github.com/js-flipsnap/ * * Copyright 2011 PixelGrid, Inc. * Licensed under the MIT License: * http://www.opensource.org/licenses/mit-license.php */ (function(window, document, undefined) { var div = document.createElement('div'); var prefix = ['webkit', 'moz', 'o', 'ms']; var saveProp = {}; var support = Flipsnap.support = {}; var gestureStart = false; var DISTANCE_THRESHOLD = 5; var ANGLE_THREHOLD = 55; support.transform3d = hasProp([ 'perspectiveProperty', 'WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective' ]); support.transform = hasProp([ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ]); support.transition = hasProp([ 'transitionProperty', 'WebkitTransitionProperty', 'MozTransitionProperty', 'OTransitionProperty', 'msTransitionProperty' ]); support.addEventListener = 'addEventListener' in window; support.mspointer = window.navigator.msPointerEnabled; support.cssAnimation = (support.transform3d || support.transform) && support.transition; var eventTypes = ['touch', 'mouse']; var events = { start: { touch: 'touchstart', mouse: 'mousedown' }, move: { touch: 'touchmove', mouse: 'mousemove' }, end: { touch: 'touchend', mouse: 'mouseup' } }; if (support.addEventListener) { document.addEventListener('gesturestart', function() { gestureStart = true; }); document.addEventListener('gestureend', function() { gestureStart = false; }); } function Flipsnap(element, opts) { return (this instanceof Flipsnap) ? this.init(element, opts) : new Flipsnap(element, opts); } Flipsnap.prototype.init = function(element, opts) { var self = this; // set element self.element = element; if (typeof element === 'string') { self.element = document.querySelector(element); } if (!self.element) { throw new Error('element not found'); } if (support.mspointer) { self.element.style.msTouchAction = 'pan-y'; } // set opts opts = opts || {}; self.distance = opts.distance; self.maxPoint = opts.maxPoint; self.disableTouch = (opts.disableTouch === undefined) ? false : opts.disableTouch; self.disable3d = (opts.disable3d === undefined) ? false : opts.disable3d; self.transitionDuration = (opts.transitionDuration === undefined) ? '350ms' : opts.transitionDuration + 'ms'; // set property self.currentPoint = 0; self.currentX = 0; self.animation = false; self.use3d = support.transform3d; if (self.disable3d === true) { self.use3d = false; } // set default style if (support.cssAnimation) { self._setStyle({ transitionProperty: getCSSVal('transform'), transitionTimingFunction: 'cubic-bezier(0,0,0.25,1)', transitionDuration: '0ms', transform: self._getTranslate(0) }); } else { self._setStyle({ position: 'relative', left: '0px' }); } // initilize self.refresh(); eventTypes.forEach(function(type) { self.element.addEventListener(events.start[type], self, false); }); return self; }; Flipsnap.prototype.handleEvent = function(event) { var self = this; switch (event.type) { // start case events.start.touch: self._touchStart(event, 'touch'); break; case events.start.mouse: self._touchStart(event, 'mouse'); break; // move case events.move.touch: self._touchMove(event, 'touch'); break; case events.move.mouse: self._touchMove(event, 'mouse'); break; // end case events.end.touch: self._touchEnd(event, 'touch'); break; case events.end.mouse: self._touchEnd(event, 'mouse'); break; // click case 'click': self._click(event); break; } }; Flipsnap.prototype.refresh = function() { var self = this; // setting max point self._maxPoint = (self.maxPoint === undefined) ? (function() { var childNodes = self.element.childNodes, itemLength = -1, i = 0, len = childNodes.length, node; for(; i < len; i++) { node = childNodes[i]; if (node.nodeType === 1) { itemLength++; } } return itemLength; })() : self.maxPoint; // setting distance if (self.distance === undefined) { if (self._maxPoint < 0) { self._distance = 0; } else { self._distance = self.element.scrollWidth / (self._maxPoint + 1); } } else { self._distance = self.distance; } // setting maxX self._maxX = -self._distance * self._maxPoint; self.moveToPoint(); }; Flipsnap.prototype.hasNext = function() { var self = this; return self.currentPoint < self._maxPoint; }; Flipsnap.prototype.hasPrev = function() { var self = this; return self.currentPoint > 0; }; Flipsnap.prototype.toNext = function(transitionDuration) { var self = this; if (!self.hasNext()) { return; } self.moveToPoint(self.currentPoint + 1, transitionDuration); }; Flipsnap.prototype.toPrev = function(transitionDuration) { var self = this; if (!self.hasPrev()) { return; } self.moveToPoint(self.currentPoint - 1, transitionDuration); }; Flipsnap.prototype.moveToPoint = function(point, transitionDuration) { var self = this; transitionDuration = transitionDuration === undefined ? self.transitionDuration : transitionDuration + 'ms'; var beforePoint = self.currentPoint; // not called from `refresh()` if (point === undefined) { point = self.currentPoint; } if (point < 0) { self.currentPoint = 0; } else if (point > self._maxPoint) { self.currentPoint = self._maxPoint; } else { self.currentPoint = parseInt(point, 10); } if (support.cssAnimation) { self._setStyle({ transitionDuration: transitionDuration }); } else { self.animation = true; } self._setX(- self.currentPoint * self._distance, transitionDuration); if (beforePoint !== self.currentPoint) { // is move? // `fsmoveend` is deprecated // `fspointmove` is recommend. self._triggerEvent('fsmoveend', true, false); self._triggerEvent('fspointmove', true, false); } }; Flipsnap.prototype._setX = function(x, transitionDuration) { var self = this; self.currentX = x; if (support.cssAnimation) { self.element.style[ saveProp.transform ] = self._getTranslate(x); } else { if (self.animation) { self._animate(x, transitionDuration || self.transitionDuration); } else { self.element.style.left = x + 'px'; } } }; Flipsnap.prototype._touchStart = function(event, type) { var self = this; if (self.disableTouch || self.scrolling || gestureStart) { return; } self.element.addEventListener(events.move[type], self, false); document.addEventListener(events.end[type], self, false); var tagName = event.target.tagName; if (type === 'mouse' && tagName !== 'SELECT' && tagName !== 'INPUT' && tagName !== 'TEXTAREA' && tagName !== 'BUTTON') { event.preventDefault(); } if (support.cssAnimation) { self._setStyle({ transitionDuration: '0ms' }); } else { self.animation = false; } self.scrolling = true; self.moveReady = false; self.startPageX = getPage(event, 'pageX'); self.startPageY = getPage(event, 'pageY'); self.basePageX = self.startPageX; self.directionX = 0; self.startTime = event.timeStamp; self._triggerEvent('fstouchstart', true, false); }; Flipsnap.prototype._touchMove = function(event, type) { var self = this; if (!self.scrolling || gestureStart) { return; } var pageX = getPage(event, 'pageX'); var pageY = getPage(event, 'pageY'); var distX; var newX; if (self.moveReady) { event.preventDefault(); distX = pageX - self.basePageX; newX = self.currentX + distX; if (newX >= 0 || newX < self._maxX) { newX = Math.round(self.currentX + distX / 3); } // When distX is 0, use one previous value. // For android firefox. When touchend fired, touchmove also // fired and distX is certainly set to 0. self.directionX = distX === 0 ? self.directionX : distX > 0 ? -1 : 1; // if they prevent us then stop it var isPrevent = !self._triggerEvent('fstouchmove', true, true, { delta: distX, direction: self.directionX }); if (isPrevent) { self._touchAfter({ moved: false, originalPoint: self.currentPoint, newPoint: self.currentPoint, cancelled: true }); } else { self._setX(newX); } } else { // https://github.com/hokaccha/js-flipsnap/pull/36 var triangle = getTriangleSide(self.startPageX, self.startPageY, pageX, pageY); if (triangle.z > DISTANCE_THRESHOLD) { if (getAngle(triangle) > ANGLE_THREHOLD) { event.preventDefault(); self.moveReady = true; self.element.addEventListener('click', self, true); } else { self.scrolling = false; } } } self.basePageX = pageX; }; Flipsnap.prototype._touchEnd = function(event, type) { var self = this; self.element.removeEventListener(events.move[type], self, false); document.removeEventListener(events.end[type], self, false); if (!self.scrolling) { return; } var newPoint = -self.currentX / self._distance; newPoint = (self.directionX > 0) ? Math.ceil(newPoint) : (self.directionX < 0) ? Math.floor(newPoint) : Math.round(newPoint); if (newPoint < 0) { newPoint = 0; } else if (newPoint > self._maxPoint) { newPoint = self._maxPoint; } self._touchAfter({ moved: newPoint !== self.currentPoint, originalPoint: self.currentPoint, newPoint: newPoint, cancelled: false }); self.moveToPoint(newPoint); }; Flipsnap.prototype._click = function(event) { var self = this; event.stopPropagation(); event.preventDefault(); }; Flipsnap.prototype._touchAfter = function(params) { var self = this; self.scrolling = false; self.moveReady = false; setTimeout(function() { self.element.removeEventListener('click', self, true); }, 200); self._triggerEvent('fstouchend', true, false, params); }; Flipsnap.prototype._setStyle = function(styles) { var self = this; var style = self.element.style; for (var prop in styles) { setStyle(style, prop, styles[prop]); } }; Flipsnap.prototype._animate = function(x, transitionDuration) { var self = this; var elem = self.element; var begin = +new Date(); var from = parseInt(elem.style.left, 10); var to = x; var duration = parseInt(transitionDuration, 10); var easing = function(time, duration) { return -(time /= duration) * (time - 2); }; var timer = setInterval(function() { var time = new Date() - begin; var pos, now; if (time > duration) { clearInterval(timer); now = to; } else { pos = easing(time, duration); now = pos * (to - from) + from; } elem.style.left = now + "px"; }, 10); }; Flipsnap.prototype.destroy = function() { var self = this; eventTypes.forEach(function(type) { self.element.removeEventListener(events.start[type], self, false); }); }; Flipsnap.prototype._getTranslate = function(x) { var self = this; return self.use3d ? 'translate3d(' + x + 'px, 0, 0)' : 'translate(' + x + 'px, 0)'; }; Flipsnap.prototype._triggerEvent = function(type, bubbles, cancelable, data) { var self = this; var ev = document.createEvent('Event'); ev.initEvent(type, bubbles, cancelable); if (data) { for (var d in data) { if (data.hasOwnProperty(d)) { ev[d] = data[d]; } } } return self.element.dispatchEvent(ev); }; function getPage(event, page) { return event.changedTouches ? event.changedTouches[0][page] : event[page]; } function hasProp(props) { return some(props, function(prop) { return div.style[ prop ] !== undefined; }); } function setStyle(style, prop, val) { var _saveProp = saveProp[ prop ]; if (_saveProp) { style[ _saveProp ] = val; } else if (style[ prop ] !== undefined) { saveProp[ prop ] = prop; style[ prop ] = val; } else { some(prefix, function(_prefix) { var _prop = ucFirst(_prefix) + ucFirst(prop); if (style[ _prop ] !== undefined) { saveProp[ prop ] = _prop; style[ _prop ] = val; return true; } }); } } function getCSSVal(prop) { if (div.style[ prop ] !== undefined) { return prop; } else { var ret; some(prefix, function(_prefix) { var _prop = ucFirst(_prefix) + ucFirst(prop); if (div.style[ _prop ] !== undefined) { ret = '-' + _prefix + '-' + prop; return true; } }); return ret; } } function ucFirst(str) { return str.charAt(0).toUpperCase() + str.substr(1); } function some(ary, callback) { for (var i = 0, len = ary.length; i < len; i++) { if (callback(ary[i], i)) { return true; } } return false; } function getTriangleSide(x1, y1, x2, y2) { var x = Math.abs(x1 - x2); var y = Math.abs(y1 - y2); var z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); return { x: x, y: y, z: z }; } function getAngle(triangle) { var cos = triangle.y / triangle.z; var radina = Math.acos(cos); return 180 / (Math.PI / radina); } if (typeof exports == 'object') { module.exports = Flipsnap; } else if (typeof define == 'function' && define.amd) { define(function() { return Flipsnap; }); } else { window.Flipsnap = Flipsnap; } })(window, window.document);