iscroll.js 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124
  1. /*!
  2. *
  3. *
  4. *
  5. * iScroll v4.2 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org
  6. * Released under MIT license, http://cubiq.org/license
  7. */
  8. /*! layer mobile-v1.5 弹层组件移动版 License LGPL http://sentsin.com/layui/layer/ By 贤心 */
  9. ;!function(a){"use strict";var b="";b=b?b:document.scripts[document.scripts.length-1].src.match(/[\s\S]*\//)[0];var c=document,d="querySelectorAll",e="getElementsByClassName",f=function(a){return c[d](a)}; document.getElementsByTagName('head')[0].appendChild(function(){var a=c.createElement("link");return a.href=b+"need/layer.css",a.type="text/css",a.rel="styleSheet",a.id="layermcss",a}());var g={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:!0};a.ready={extend:function(a){var b=JSON.parse(JSON.stringify(g));for(var c in a)b[c]=a[c];return b},timer:{},end:{}};var h=0,i=["layermbox"],j=function(a){var b=this;b.config=ready.extend(a),b.view()};j.prototype.view=function(){var a=this,b=a.config,d=c.createElement("div");a.id=d.id=i[0]+h,d.setAttribute("class",i[0]+" "+i[0]+(b.type||0)),d.setAttribute("index",h);var g=function(){var a="object"==typeof b.title;return b.title?'<h3 style="'+(a?b.title[1]:"")+'">'+(a?b.title[0]:b.title)+'</h3><button class="layermend"></button>':""}(),j=function(){var a,c=(b.btn||[]).length;return 0!==c&&b.btn?(a='<span type="1">'+b.btn[0]+"</span>",2===c&&(a='<span type="0">'+b.btn[1]+"</span>"+a),'<div class="layermbtn">'+a+"</div>"):""}();if(b.fixed||(b.top=b.hasOwnProperty("top")?b.top:100,b.style=b.style||"",b.style+=" top:"+(c.body.scrollTop+b.top)+"px"),2===b.type&&(b.content='<i></i><i class="laymloadtwo"></i><i></i><div>'+(b.content||"")+"</div>"),d.innerHTML=(b.shade?"<div "+("string"==typeof b.shade?'style="'+b.shade+'"':"")+' class="laymshade"></div>':"")+'<div class="layermmain" '+(b.fixed?"":'style="position:static;"')+'><div class="section"><div class="layermchild '+(b.className?b.className:"")+" "+(b.type||b.shade?"":"layermborder ")+(b.anim?"layermanim":"")+'" '+(b.style?'style="'+b.style+'"':"")+">"+g+'<div class="layermcont">'+b.content+"</div>"+j+"</div></div></div>",!b.type||2===b.type){var l=c[e](i[0]+b.type),m=l.length;m>=1&&k.close(l[0].getAttribute("index"))}document.body.appendChild(d);var n=a.elem=f("#"+a.id)[0];setTimeout(function(){try{n.className=n.className+" layermshow"}catch(a){return}b.success&&b.success(n)},1),a.index=h++,a.action(b,n)},j.prototype.action=function(a,b){var c=this;if(a.time&&(ready.timer[c.index]=setTimeout(function(){k.close(c.index)},1e3*a.time)),a.title&&(b[e]("layermend")[0].onclick=function(){a.cancel&&a.cancel(),k.close(c.index)}),a.btn)for(var d=b[e]("layermbtn")[0].children,f=d.length,g=0;f>g;g++)d[g].onclick=function(){var b=this.getAttribute("type");0==b?(a.no&&a.no(),k.close(c.index)):a.yes?a.yes(c.index):k.close(c.index)};if(a.shade&&a.shadeClose){var h=b[e]("laymshade")[0];h.onclick=function(){k.close(c.index,a.end)},h.ontouchmove=function(){k.close(c.index,a.end)}}a.end&&(ready.end[c.index]=a.end)};var k={v:"1.5",index:h,open:function(a){var b=new j(a||{});return b.index},close:function(a){var b=f("#"+i[0]+a)[0];b&&(b.innerHTML="",c.body.removeChild(b),clearTimeout(ready.timer[a]),delete ready.timer[a],"function"==typeof ready.end[a]&&ready.end[a](),delete ready.end[a])},closeAll:function(){for(var a=c[e](i[0]),b=0,d=a.length;d>b;b++)k.close(0|a[0].getAttribute("index"))}};"function"==typeof define?define(function(){return k}):a.layer=k}(window);
  10. function hideJZ(){
  11. $("#pullUp").hide();
  12. $("#pullUp").html('<div></div>');
  13. $("#pullUp").height("0");
  14. }
  15. function wcJZ(){
  16. $("#pullUp").show();
  17. $("#pullUp").html('<div>已经没有更多数据了</div>');
  18. $("#pullUp").height("45");
  19. }
  20. function showJZ(){
  21. $("#pullUp").attr("class","");
  22. $("#pullUp").html('<span class="pullUpIcon"></span><span class="pullUpLabel">上拉加载更多...</span>')
  23. $("#pullUp").height("45");
  24. $("#pullUp").show();
  25. }
  26. (function(window, doc){
  27. var m = Math,
  28. dummyStyle = doc.createElement('div').style,
  29. vendor = (function () {
  30. var vendors = 't,webkitT,MozT,msT,OT'.split(','),
  31. t,
  32. i = 0,
  33. l = vendors.length;
  34. for ( ; i < l; i++ ) {
  35. t = vendors[i] + 'ransform';
  36. if ( t in dummyStyle ) {
  37. return vendors[i].substr(0, vendors[i].length - 1);
  38. }
  39. }
  40. return false;
  41. })(),
  42. cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '',
  43. // Style properties
  44. transform = prefixStyle('transform'),
  45. transitionProperty = prefixStyle('transitionProperty'),
  46. transitionDuration = prefixStyle('transitionDuration'),
  47. transformOrigin = prefixStyle('transformOrigin'),
  48. transitionTimingFunction = prefixStyle('transitionTimingFunction'),
  49. transitionDelay = prefixStyle('transitionDelay'),
  50. // Browser capabilities
  51. isAndroid = (/android/gi).test(navigator.appVersion),
  52. isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
  53. isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
  54. has3d = prefixStyle('perspective') in dummyStyle,
  55. hasTouch = 'ontouchstart' in window && !isTouchPad,
  56. hasTransform = !!vendor,
  57. hasTransitionEnd = prefixStyle('transition') in dummyStyle,
  58. RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
  59. START_EV = hasTouch ? 'touchstart' : 'mousedown',
  60. MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
  61. END_EV = hasTouch ? 'touchend' : 'mouseup',
  62. CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
  63. WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel',
  64. TRNEND_EV = (function () {
  65. if ( vendor === false ) return false;
  66. var transitionEnd = {
  67. '' : 'transitionend',
  68. 'webkit' : 'webkitTransitionEnd',
  69. 'Moz' : 'transitionend',
  70. 'O' : 'oTransitionEnd',
  71. 'ms' : 'MSTransitionEnd'
  72. };
  73. return transitionEnd[vendor];
  74. })(),
  75. nextFrame = (function() {
  76. return window.requestAnimationFrame ||
  77. window.webkitRequestAnimationFrame ||
  78. window.mozRequestAnimationFrame ||
  79. window.oRequestAnimationFrame ||
  80. window.msRequestAnimationFrame ||
  81. function(callback) { return setTimeout(callback, 1); };
  82. })(),
  83. cancelFrame = (function () {
  84. return window.cancelRequestAnimationFrame ||
  85. window.webkitCancelAnimationFrame ||
  86. window.webkitCancelRequestAnimationFrame ||
  87. window.mozCancelRequestAnimationFrame ||
  88. window.oCancelRequestAnimationFrame ||
  89. window.msCancelRequestAnimationFrame ||
  90. clearTimeout;
  91. })(),
  92. // Helpers
  93. translateZ = has3d ? ' translateZ(0)' : '',
  94. // Constructor
  95. iScroll = function (el, options) {
  96. var that = this,
  97. i;
  98. that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
  99. that.wrapper.style.overflow = 'hidden';
  100. that.scroller = that.wrapper.children[0];
  101. // Default options
  102. that.options = {
  103. hScroll: true,
  104. vScroll: true,
  105. x: 0,
  106. y: 0,
  107. bounce: true,
  108. bounceLock: false,
  109. momentum: true,
  110. lockDirection: true,
  111. useTransform: true,
  112. useTransition: false,
  113. topOffset: 0,
  114. checkDOMChanges: false, // Experimental
  115. handleClick: true,
  116. // Scrollbar
  117. hScrollbar: true,
  118. vScrollbar: true,
  119. fixedScrollbar: isAndroid,
  120. hideScrollbar: isIDevice,
  121. fadeScrollbar: isIDevice && has3d,
  122. scrollbarClass: '',
  123. // Zoom
  124. zoom: false,
  125. zoomMin: 1,
  126. zoomMax: 4,
  127. doubleTapZoom: 2,
  128. wheelAction: 'scroll',
  129. // Snap
  130. snap: false,
  131. snapThreshold: 1,
  132. // Events
  133. onRefresh: null,
  134. onBeforeScrollStart: function (e) { e.preventDefault(); },
  135. onScrollStart: null,
  136. onBeforeScrollMove: null,
  137. onScrollMove: null,
  138. onBeforeScrollEnd: null,
  139. onScrollEnd: null,
  140. onTouchEnd: null,
  141. onDestroy: null,
  142. onZoomStart: null,
  143. onZoom: null,
  144. onZoomEnd: null
  145. };
  146. // User defined options
  147. for (i in options) that.options[i] = options[i];
  148. // Set starting position
  149. that.x = that.options.x;
  150. that.y = that.options.y;
  151. // Normalize options
  152. that.options.useTransform = hasTransform && that.options.useTransform;
  153. that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
  154. that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
  155. that.options.zoom = that.options.useTransform && that.options.zoom;
  156. that.options.useTransition = hasTransitionEnd && that.options.useTransition;
  157. // Helpers FIX ANDROID BUG!
  158. // translate3d and scale doesn't work together!
  159. // Ignoring 3d ONLY WHEN YOU SET that.options.zoom
  160. if ( that.options.zoom && isAndroid ){
  161. translateZ = '';
  162. }
  163. // Set some default styles
  164. that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left';
  165. that.scroller.style[transitionDuration] = '0';
  166. that.scroller.style[transformOrigin] = '0 0';
  167. if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)';
  168. if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ;
  169. else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
  170. if (that.options.useTransition) that.options.fixedScrollbar = true;
  171. that.refresh();
  172. that._bind(RESIZE_EV, window);
  173. that._bind(START_EV);
  174. if (!hasTouch) {
  175. if (that.options.wheelAction != 'none')
  176. that._bind(WHEEL_EV);
  177. }
  178. if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
  179. that._checkDOMChanges();
  180. }, 500);
  181. };
  182. // Prototype
  183. iScroll.prototype = {
  184. enabled: true,
  185. x: 0,
  186. y: 0,
  187. steps: [],
  188. scale: 1,
  189. currPageX: 0, currPageY: 0,
  190. pagesX: [], pagesY: [],
  191. aniTime: null,
  192. wheelZoomCount: 0,
  193. handleEvent: function (e) {
  194. var that = this;
  195. switch(e.type) {
  196. case START_EV:
  197. if (!hasTouch && e.button !== 0) return;
  198. that._start(e);
  199. break;
  200. case MOVE_EV: that._move(e); break;
  201. case END_EV:
  202. case CANCEL_EV: that._end(e); break;
  203. case RESIZE_EV: that._resize(); break;
  204. case WHEEL_EV: that._wheel(e); break;
  205. case TRNEND_EV: that._transitionEnd(e); break;
  206. }
  207. },
  208. _checkDOMChanges: function () {
  209. if (this.moved || this.zoomed || this.animating ||
  210. (this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
  211. this.refresh();
  212. },
  213. _scrollbar: function (dir) {
  214. var that = this,
  215. bar;
  216. if (!that[dir + 'Scrollbar']) {
  217. if (that[dir + 'ScrollbarWrapper']) {
  218. if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = '';
  219. that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
  220. that[dir + 'ScrollbarWrapper'] = null;
  221. that[dir + 'ScrollbarIndicator'] = null;
  222. }
  223. return;
  224. }
  225. if (!that[dir + 'ScrollbarWrapper']) {
  226. // Create the scrollbar wrapper
  227. bar = doc.createElement('div');
  228. if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
  229. else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px');
  230. bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1');
  231. that.wrapper.appendChild(bar);
  232. that[dir + 'ScrollbarWrapper'] = bar;
  233. // Create the scrollbar indicator
  234. bar = doc.createElement('div');
  235. if (!that.options.scrollbarClass) {
  236. bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px';
  237. }
  238. bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ;
  239. if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
  240. that[dir + 'ScrollbarWrapper'].appendChild(bar);
  241. that[dir + 'ScrollbarIndicator'] = bar;
  242. }
  243. if (dir == 'h') {
  244. that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
  245. that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
  246. that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
  247. that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
  248. that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
  249. } else {
  250. that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
  251. that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
  252. that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
  253. that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
  254. that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
  255. }
  256. // Reset position
  257. that._scrollbarPos(dir, true);
  258. },
  259. _resize: function () {
  260. var that = this;
  261. setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
  262. },
  263. _pos: function (x, y) {
  264. if (this.zoomed) return;
  265. x = this.hScroll ? x : 0;
  266. y = this.vScroll ? y : 0;
  267. if (this.options.useTransform) {
  268. this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ;
  269. } else {
  270. x = m.round(x);
  271. y = m.round(y);
  272. this.scroller.style.left = x + 'px';
  273. this.scroller.style.top = y + 'px';
  274. }
  275. this.x = x;
  276. this.y = y;
  277. this._scrollbarPos('h');
  278. this._scrollbarPos('v');
  279. },
  280. _scrollbarPos: function (dir, hidden) {
  281. var that = this,
  282. pos = dir == 'h' ? that.x : that.y,
  283. size;
  284. if (!that[dir + 'Scrollbar']) return;
  285. pos = that[dir + 'ScrollbarProp'] * pos;
  286. if (pos < 0) {
  287. if (!that.options.fixedScrollbar) {
  288. size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3);
  289. if (size < 8) size = 8;
  290. that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
  291. }
  292. pos = 0;
  293. } else if (pos > that[dir + 'ScrollbarMaxScroll']) {
  294. if (!that.options.fixedScrollbar) {
  295. size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
  296. if (size < 8) size = 8;
  297. that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
  298. pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
  299. } else {
  300. pos = that[dir + 'ScrollbarMaxScroll'];
  301. }
  302. }
  303. that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0';
  304. that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
  305. that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ;
  306. },
  307. _start: function (e) {
  308. var that = this,
  309. point = hasTouch ? e.touches[0] : e,
  310. matrix, x, y,
  311. c1, c2;
  312. if (!that.enabled) return;
  313. if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
  314. if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
  315. that.moved = false;
  316. that.animating = false;
  317. that.zoomed = false;
  318. that.distX = 0;
  319. that.distY = 0;
  320. that.absDistX = 0;
  321. that.absDistY = 0;
  322. that.dirX = 0;
  323. that.dirY = 0;
  324. // Gesture start
  325. if (that.options.zoom && hasTouch && e.touches.length > 1) {
  326. c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
  327. c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
  328. that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
  329. that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x;
  330. that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y;
  331. if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
  332. }
  333. if (that.options.momentum) {
  334. if (that.options.useTransform) {
  335. // Very lame general purpose alternative to CSSMatrix
  336. matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(',');
  337. x = matrix[4] * 1;
  338. y = matrix[5] * 1;
  339. } else {
  340. x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1;
  341. y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1;
  342. }
  343. if (x != that.x || y != that.y) {
  344. if (that.options.useTransition) that._unbind(TRNEND_EV);
  345. else cancelFrame(that.aniTime);
  346. that.steps = [];
  347. that._pos(x, y);
  348. }
  349. }
  350. that.absStartX = that.x; // Needed by snap threshold
  351. that.absStartY = that.y;
  352. that.startX = that.x;
  353. that.startY = that.y;
  354. that.pointX = point.pageX;
  355. that.pointY = point.pageY;
  356. that.startTime = e.timeStamp || Date.now();
  357. if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
  358. that._bind(MOVE_EV, window);
  359. that._bind(END_EV, window);
  360. that._bind(CANCEL_EV, window);
  361. },
  362. _move: function (e) {
  363. var that = this,
  364. point = hasTouch ? e.touches[0] : e,
  365. deltaX = point.pageX - that.pointX,
  366. deltaY = point.pageY - that.pointY,
  367. newX = that.x + deltaX,
  368. newY = that.y + deltaY,
  369. c1, c2, scale,
  370. timestamp = e.timeStamp || Date.now();
  371. if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
  372. // Zoom
  373. if (that.options.zoom && hasTouch && e.touches.length > 1) {
  374. c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
  375. c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
  376. that.touchesDist = m.sqrt(c1*c1+c2*c2);
  377. that.zoomed = true;
  378. scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
  379. if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
  380. else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
  381. that.lastScale = scale / this.scale;
  382. newX = this.originX - this.originX * that.lastScale + this.x,
  383. newY = this.originY - this.originY * that.lastScale + this.y;
  384. this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ;
  385. if (that.options.onZoom) that.options.onZoom.call(that, e);
  386. return;
  387. }
  388. that.pointX = point.pageX;
  389. that.pointY = point.pageY;
  390. // Slow down if outside of the boundaries
  391. if (newX > 0 || newX < that.maxScrollX) {
  392. newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
  393. }
  394. if (newY > that.minScrollY || newY < that.maxScrollY) {
  395. newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
  396. }
  397. that.distX += deltaX;
  398. that.distY += deltaY;
  399. that.absDistX = m.abs(that.distX);
  400. that.absDistY = m.abs(that.distY);
  401. if (that.absDistX < 6 && that.absDistY < 6) {
  402. return;
  403. }
  404. // Lock direction
  405. if (that.options.lockDirection) {
  406. if (that.absDistX > that.absDistY + 5) {
  407. newY = that.y;
  408. deltaY = 0;
  409. } else if (that.absDistY > that.absDistX + 5) {
  410. newX = that.x;
  411. deltaX = 0;
  412. }
  413. }
  414. that.moved = true;
  415. that._pos(newX, newY);
  416. that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
  417. that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
  418. if (timestamp - that.startTime > 300) {
  419. that.startTime = timestamp;
  420. that.startX = that.x;
  421. that.startY = that.y;
  422. }
  423. if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
  424. },
  425. _end: function (e) {
  426. if (hasTouch && e.touches.length !== 0) return;
  427. var that = this,
  428. point = hasTouch ? e.changedTouches[0] : e,
  429. target, ev,
  430. momentumX = { dist:0, time:0 },
  431. momentumY = { dist:0, time:0 },
  432. duration = (e.timeStamp || Date.now()) - that.startTime,
  433. newPosX = that.x,
  434. newPosY = that.y,
  435. distX, distY,
  436. newDuration,
  437. snap,
  438. scale;
  439. that._unbind(MOVE_EV, window);
  440. that._unbind(END_EV, window);
  441. that._unbind(CANCEL_EV, window);
  442. if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
  443. if (that.zoomed) {
  444. scale = that.scale * that.lastScale;
  445. scale = Math.max(that.options.zoomMin, scale);
  446. scale = Math.min(that.options.zoomMax, scale);
  447. that.lastScale = scale / that.scale;
  448. that.scale = scale;
  449. that.x = that.originX - that.originX * that.lastScale + that.x;
  450. that.y = that.originY - that.originY * that.lastScale + that.y;
  451. that.scroller.style[transitionDuration] = '200ms';
  452. that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ;
  453. that.zoomed = false;
  454. that.refresh();
  455. if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
  456. return;
  457. }
  458. if (!that.moved) {
  459. if (hasTouch) {
  460. if (that.doubleTapTimer && that.options.zoom) {
  461. // Double tapped
  462. clearTimeout(that.doubleTapTimer);
  463. that.doubleTapTimer = null;
  464. if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
  465. that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
  466. if (that.options.onZoomEnd) {
  467. setTimeout(function() {
  468. that.options.onZoomEnd.call(that, e);
  469. }, 200); // 200 is default zoom duration
  470. }
  471. } else if (this.options.handleClick) {
  472. that.doubleTapTimer = setTimeout(function () {
  473. that.doubleTapTimer = null;
  474. // Find the last touched element
  475. target = point.target;
  476. while (target.nodeType != 1) target = target.parentNode;
  477. if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
  478. ev = doc.createEvent('MouseEvents');
  479. ev.initMouseEvent('click', true, true, e.view, 1,
  480. point.screenX, point.screenY, point.clientX, point.clientY,
  481. e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
  482. 0, null);
  483. ev._fake = true;
  484. target.dispatchEvent(ev);
  485. }
  486. }, that.options.zoom ? 250 : 0);
  487. }
  488. }
  489. that._resetPos(400);
  490. if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
  491. return;
  492. }
  493. if (duration < 300 && that.options.momentum) {
  494. momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
  495. momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
  496. newPosX = that.x + momentumX.dist;
  497. newPosY = that.y + momentumY.dist;
  498. if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
  499. if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
  500. }
  501. if (momentumX.dist || momentumY.dist) {
  502. newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
  503. // Do we need to snap?
  504. if (that.options.snap) {
  505. distX = newPosX - that.absStartX;
  506. distY = newPosY - that.absStartY;
  507. if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
  508. else {
  509. snap = that._snap(newPosX, newPosY);
  510. newPosX = snap.x;
  511. newPosY = snap.y;
  512. newDuration = m.max(snap.time, newDuration);
  513. }
  514. }
  515. that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration);
  516. if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
  517. return;
  518. }
  519. // Do we need to snap?
  520. if (that.options.snap) {
  521. distX = newPosX - that.absStartX;
  522. distY = newPosY - that.absStartY;
  523. if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
  524. else {
  525. snap = that._snap(that.x, that.y);
  526. if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
  527. }
  528. if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
  529. return;
  530. }
  531. that._resetPos(200);
  532. if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
  533. },
  534. _resetPos: function (time) {
  535. var that = this,
  536. resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
  537. resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
  538. if (resetX == that.x && resetY == that.y) {
  539. if (that.moved) {
  540. that.moved = false;
  541. if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end
  542. }
  543. if (that.hScrollbar && that.options.hideScrollbar) {
  544. if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms';
  545. that.hScrollbarWrapper.style.opacity = '0';
  546. }
  547. if (that.vScrollbar && that.options.hideScrollbar) {
  548. if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms';
  549. that.vScrollbarWrapper.style.opacity = '0';
  550. }
  551. return;
  552. }
  553. that.scrollTo(resetX, resetY, time || 0);
  554. },
  555. _wheel: function (e) {
  556. var that = this,
  557. wheelDeltaX, wheelDeltaY,
  558. deltaX, deltaY,
  559. deltaScale;
  560. if ('wheelDeltaX' in e) {
  561. wheelDeltaX = e.wheelDeltaX / 12;
  562. wheelDeltaY = e.wheelDeltaY / 12;
  563. } else if('wheelDelta' in e) {
  564. wheelDeltaX = wheelDeltaY = e.wheelDelta / 12;
  565. } else if ('detail' in e) {
  566. wheelDeltaX = wheelDeltaY = -e.detail * 3;
  567. } else {
  568. return;
  569. }
  570. if (that.options.wheelAction == 'zoom') {
  571. deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
  572. if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
  573. if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
  574. if (deltaScale != that.scale) {
  575. if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
  576. that.wheelZoomCount++;
  577. that.zoom(e.pageX, e.pageY, deltaScale, 400);
  578. setTimeout(function() {
  579. that.wheelZoomCount--;
  580. if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
  581. }, 400);
  582. }
  583. return;
  584. }
  585. deltaX = that.x + wheelDeltaX;
  586. deltaY = that.y + wheelDeltaY;
  587. if (deltaX > 0) deltaX = 0;
  588. else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
  589. if (deltaY > that.minScrollY) deltaY = that.minScrollY;
  590. else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
  591. if (that.maxScrollY < 0) {
  592. that.scrollTo(deltaX, deltaY, 0);
  593. }
  594. },
  595. _transitionEnd: function (e) {
  596. var that = this;
  597. if (e.target != that.scroller) return;
  598. that._unbind(TRNEND_EV);
  599. that._startAni();
  600. },
  601. /**
  602. *
  603. * Utilities
  604. *
  605. */
  606. _startAni: function () {
  607. var that = this,
  608. startX = that.x, startY = that.y,
  609. startTime = Date.now(),
  610. step, easeOut,
  611. animate;
  612. if (that.animating) return;
  613. if (!that.steps.length) {
  614. that._resetPos(400);
  615. return;
  616. }
  617. step = that.steps.shift();
  618. if (step.x == startX && step.y == startY) step.time = 0;
  619. that.animating = true;
  620. that.moved = true;
  621. if (that.options.useTransition) {
  622. that._transitionTime(step.time);
  623. that._pos(step.x, step.y);
  624. that.animating = false;
  625. if (step.time) that._bind(TRNEND_EV);
  626. else that._resetPos(0);
  627. return;
  628. }
  629. animate = function () {
  630. var now = Date.now(),
  631. newX, newY;
  632. if (now >= startTime + step.time) {
  633. that._pos(step.x, step.y);
  634. that.animating = false;
  635. if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end
  636. that._startAni();
  637. return;
  638. }
  639. now = (now - startTime) / step.time - 1;
  640. easeOut = m.sqrt(1 - now * now);
  641. newX = (step.x - startX) * easeOut + startX;
  642. newY = (step.y - startY) * easeOut + startY;
  643. that._pos(newX, newY);
  644. if (that.animating) that.aniTime = nextFrame(animate);
  645. };
  646. animate();
  647. },
  648. _transitionTime: function (time) {
  649. time += 'ms';
  650. this.scroller.style[transitionDuration] = time;
  651. if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time;
  652. if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time;
  653. },
  654. _momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
  655. var deceleration = 0.0006,
  656. speed = m.abs(dist) / time,
  657. newDist = (speed * speed) / (2 * deceleration),
  658. newTime = 0, outsideDist = 0;
  659. // Proportinally reduce speed if we are outside of the boundaries
  660. if (dist > 0 && newDist > maxDistUpper) {
  661. outsideDist = size / (6 / (newDist / speed * deceleration));
  662. maxDistUpper = maxDistUpper + outsideDist;
  663. speed = speed * maxDistUpper / newDist;
  664. newDist = maxDistUpper;
  665. } else if (dist < 0 && newDist > maxDistLower) {
  666. outsideDist = size / (6 / (newDist / speed * deceleration));
  667. maxDistLower = maxDistLower + outsideDist;
  668. speed = speed * maxDistLower / newDist;
  669. newDist = maxDistLower;
  670. }
  671. newDist = newDist * (dist < 0 ? -1 : 1);
  672. newTime = speed / deceleration;
  673. return { dist: newDist, time: m.round(newTime) };
  674. },
  675. _offset: function (el) {
  676. var left = -el.offsetLeft,
  677. top = -el.offsetTop;
  678. while (el = el.offsetParent) {
  679. left -= el.offsetLeft;
  680. top -= el.offsetTop;
  681. }
  682. if (el != this.wrapper) {
  683. left *= this.scale;
  684. top *= this.scale;
  685. }
  686. return { left: left, top: top };
  687. },
  688. _snap: function (x, y) {
  689. var that = this,
  690. i, l,
  691. page, time,
  692. sizeX, sizeY;
  693. // Check page X
  694. page = that.pagesX.length - 1;
  695. for (i=0, l=that.pagesX.length; i<l; i++) {
  696. if (x >= that.pagesX[i]) {
  697. page = i;
  698. break;
  699. }
  700. }
  701. if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
  702. x = that.pagesX[page];
  703. sizeX = m.abs(x - that.pagesX[that.currPageX]);
  704. sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
  705. that.currPageX = page;
  706. // Check page Y
  707. page = that.pagesY.length-1;
  708. for (i=0; i<page; i++) {
  709. if (y >= that.pagesY[i]) {
  710. page = i;
  711. break;
  712. }
  713. }
  714. if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
  715. y = that.pagesY[page];
  716. sizeY = m.abs(y - that.pagesY[that.currPageY]);
  717. sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
  718. that.currPageY = page;
  719. // Snap with constant speed (proportional duration)
  720. time = m.round(m.max(sizeX, sizeY)) || 200;
  721. return { x: x, y: y, time: time };
  722. },
  723. _bind: function (type, el, bubble) {
  724. (el || this.scroller).addEventListener(type, this, !!bubble);
  725. },
  726. _unbind: function (type, el, bubble) {
  727. (el || this.scroller).removeEventListener(type, this, !!bubble);
  728. },
  729. /**
  730. *
  731. * Public methods
  732. *
  733. */
  734. destroy: function () {
  735. var that = this;
  736. that.scroller.style[transform] = '';
  737. // Remove the scrollbars
  738. that.hScrollbar = false;
  739. that.vScrollbar = false;
  740. that._scrollbar('h');
  741. that._scrollbar('v');
  742. // Remove the event listeners
  743. that._unbind(RESIZE_EV, window);
  744. that._unbind(START_EV);
  745. that._unbind(MOVE_EV, window);
  746. that._unbind(END_EV, window);
  747. that._unbind(CANCEL_EV, window);
  748. if (!that.options.hasTouch) {
  749. that._unbind(WHEEL_EV);
  750. }
  751. if (that.options.useTransition) that._unbind(TRNEND_EV);
  752. if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
  753. if (that.options.onDestroy) that.options.onDestroy.call(that);
  754. },
  755. refresh: function () {
  756. var that = this,
  757. offset,
  758. i, l,
  759. els,
  760. pos = 0,
  761. page = 0;
  762. if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
  763. that.wrapperW = that.wrapper.clientWidth || 1;
  764. that.wrapperH = that.wrapper.clientHeight || 1;
  765. that.minScrollY = -that.options.topOffset || 0;
  766. that.scrollerW = m.round(that.scroller.offsetWidth * that.scale);
  767. that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale);
  768. that.maxScrollX = that.wrapperW - that.scrollerW;
  769. that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
  770. that.dirX = 0;
  771. that.dirY = 0;
  772. if (that.options.onRefresh) that.options.onRefresh.call(that);
  773. that.hScroll = that.options.hScroll && that.maxScrollX < 0;
  774. that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
  775. that.hScrollbar = that.hScroll && that.options.hScrollbar;
  776. that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
  777. offset = that._offset(that.wrapper);
  778. that.wrapperOffsetLeft = -offset.left;
  779. that.wrapperOffsetTop = -offset.top;
  780. // Prepare snap
  781. if (typeof that.options.snap == 'string') {
  782. that.pagesX = [];
  783. that.pagesY = [];
  784. els = that.scroller.querySelectorAll(that.options.snap);
  785. for (i=0, l=els.length; i<l; i++) {
  786. pos = that._offset(els[i]);
  787. pos.left += that.wrapperOffsetLeft;
  788. pos.top += that.wrapperOffsetTop;
  789. that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
  790. that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
  791. }
  792. } else if (that.options.snap) {
  793. that.pagesX = [];
  794. while (pos >= that.maxScrollX) {
  795. that.pagesX[page] = pos;
  796. pos = pos - that.wrapperW;
  797. page++;
  798. }
  799. if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
  800. pos = 0;
  801. page = 0;
  802. that.pagesY = [];
  803. while (pos >= that.maxScrollY) {
  804. that.pagesY[page] = pos;
  805. pos = pos - that.wrapperH;
  806. page++;
  807. }
  808. if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
  809. }
  810. // Prepare the scrollbars
  811. that._scrollbar('h');
  812. that._scrollbar('v');
  813. if (!that.zoomed) {
  814. that.scroller.style[transitionDuration] = '0';
  815. that._resetPos(400);
  816. }
  817. },
  818. scrollTo: function (x, y, time, relative) {
  819. var that = this,
  820. step = x,
  821. i, l;
  822. that.stop();
  823. if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
  824. for (i=0, l=step.length; i<l; i++) {
  825. if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
  826. that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
  827. }
  828. that._startAni();
  829. },
  830. scrollToElement: function (el, time) {
  831. var that = this, pos;
  832. el = el.nodeType ? el : that.scroller.querySelector(el);
  833. if (!el) return;
  834. pos = that._offset(el);
  835. pos.left += that.wrapperOffsetLeft;
  836. pos.top += that.wrapperOffsetTop;
  837. pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
  838. pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
  839. time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
  840. that.scrollTo(pos.left, pos.top, time);
  841. },
  842. scrollToPage: function (pageX, pageY, time) {
  843. var that = this, x, y;
  844. time = time === undefined ? 400 : time;
  845. if (that.options.onScrollStart) that.options.onScrollStart.call(that);
  846. if (that.options.snap) {
  847. pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
  848. pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
  849. pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
  850. pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
  851. that.currPageX = pageX;
  852. that.currPageY = pageY;
  853. x = that.pagesX[pageX];
  854. y = that.pagesY[pageY];
  855. } else {
  856. x = -that.wrapperW * pageX;
  857. y = -that.wrapperH * pageY;
  858. if (x < that.maxScrollX) x = that.maxScrollX;
  859. if (y < that.maxScrollY) y = that.maxScrollY;
  860. }
  861. that.scrollTo(x, y, time);
  862. },
  863. disable: function () {
  864. this.stop();
  865. this._resetPos(0);
  866. this.enabled = false;
  867. // If disabled after touchstart we make sure that there are no left over events
  868. this._unbind(MOVE_EV, window);
  869. this._unbind(END_EV, window);
  870. this._unbind(CANCEL_EV, window);
  871. },
  872. enable: function () {
  873. this.enabled = true;
  874. },
  875. stop: function () {
  876. if (this.options.useTransition) this._unbind(TRNEND_EV);
  877. else cancelFrame(this.aniTime);
  878. this.steps = [];
  879. this.moved = false;
  880. this.animating = false;
  881. },
  882. zoom: function (x, y, scale, time) {
  883. var that = this,
  884. relScale = scale / that.scale;
  885. if (!that.options.useTransform) return;
  886. that.zoomed = true;
  887. time = time === undefined ? 200 : time;
  888. x = x - that.wrapperOffsetLeft - that.x;
  889. y = y - that.wrapperOffsetTop - that.y;
  890. that.x = x - x * relScale + that.x;
  891. that.y = y - y * relScale + that.y;
  892. that.scale = scale;
  893. that.refresh();
  894. that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
  895. that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
  896. that.scroller.style[transitionDuration] = time + 'ms';
  897. that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ;
  898. that.zoomed = false;
  899. },
  900. isReady: function () {
  901. return !this.moved && !this.zoomed && !this.animating;
  902. }
  903. };
  904. function prefixStyle (style) {
  905. if ( vendor === '' ) return style;
  906. style = style.charAt(0).toUpperCase() + style.substr(1);
  907. return vendor + style;
  908. }
  909. dummyStyle = null; // for the sake of it
  910. if (typeof exports !== 'undefined') exports.iScroll = iScroll;
  911. else window.iScroll = iScroll;
  912. })(window, document);