swipe.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * Swipe 1.0
  3. *
  4. * Brad Birdsall, Prime
  5. * Copyright 2011, Licensed GPL & MIT
  6. *
  7. */
  8. window.Swipe = function(element, options) {
  9. // return immediately if element doesn't exist
  10. if (!element) return null;
  11. var _this = this;
  12. // retreive options
  13. this.options = options || {};
  14. this.index = this.options.startSlide || 0;
  15. this.speed = this.options.speed || 300;
  16. this.callback = this.options.callback || function() {};
  17. this.delay = this.options.auto || 0;
  18. this.unresize = this.options.unresize; //anjey
  19. // reference dom elements
  20. this.container = element;
  21. this.element = this.container.children[0]; // the slide pane
  22. // static css
  23. //this.container.style.overflow = 'hidden'; //by anjey
  24. this.element.style.listStyle = 'none';
  25. // trigger slider initialization
  26. this.setup();
  27. // begin auto slideshow
  28. this.begin();
  29. // add event listeners
  30. if (this.element.addEventListener) {
  31. //by anjey
  32. this.element.addEventListener('mousedown', this, false);
  33. this.element.addEventListener('touchstart', this, false);
  34. this.element.addEventListener('touchmove', this, false);
  35. this.element.addEventListener('touchend', this, false);
  36. this.element.addEventListener('webkitTransitionEnd', this, false);
  37. this.element.addEventListener('msTransitionEnd', this, false);
  38. this.element.addEventListener('oTransitionEnd', this, false);
  39. this.element.addEventListener('transitionend', this, false);
  40. if(!this.unresize){ // anjey
  41. window.addEventListener('resize', this, false);
  42. }
  43. }
  44. };
  45. Swipe.prototype = {
  46. setup: function() {
  47. // get and measure amt of slides
  48. this.slides = this.element.children;
  49. this.length = this.slides.length;
  50. // return immediately if their are less than two slides
  51. if (this.length < 2) return null;
  52. // determine width of each slide
  53. this.width = this.container.getBoundingClientRect().width || this.width; //anjey
  54. // return immediately if measurement fails
  55. if (!this.width) return null;
  56. // hide slider element but keep positioning during setup
  57. this.container.style.visibility = 'hidden';
  58. // dynamic css
  59. this.element.style.width = (this.slides.length * this.width) + 'px';
  60. var index = this.slides.length;
  61. while (index--) {
  62. var el = this.slides[index];
  63. el.style.width = this.width + 'px';
  64. el.style.display = 'table-cell';
  65. el.style.verticalAlign = 'top';
  66. }
  67. // set start position and force translate to remove initial flickering
  68. this.slide(this.index, 0);
  69. // show slider element
  70. this.container.style.visibility = 'visible';
  71. },
  72. slide: function(index, duration) {
  73. var style = this.element.style;
  74. // fallback to default speed
  75. if (duration == undefined) {
  76. duration = this.speed;
  77. }
  78. // set duration speed (0 represents 1-to-1 scrolling)
  79. style.webkitTransitionDuration = style.MozTransitionDuration = style.msTransitionDuration = style.OTransitionDuration = style.transitionDuration = duration + 'ms';
  80. // translate to given index position
  81. style.MozTransform = style.webkitTransform = 'translate3d(' + -(index * this.width) + 'px,0,0)';
  82. style.msTransform = style.OTransform = 'translateX(' + -(index * this.width) + 'px)';
  83. // set new index to allow for expression arguments
  84. this.index = index;
  85. },
  86. getPos: function() {
  87. // return current index position
  88. return this.index;
  89. },
  90. prev: function(delay) {
  91. // cancel next scheduled automatic transition, if any
  92. this.delay = delay || 0;
  93. clearTimeout(this.interval);
  94. // if not at first slide
  95. if (this.index) this.slide(this.index-1, this.speed);
  96. },
  97. next: function(delay) {
  98. // cancel next scheduled automatic transition, if any
  99. this.delay = delay || 0;
  100. clearTimeout(this.interval);
  101. if (this.index < this.length - 1) this.slide(this.index+1, this.speed); // if not last slide
  102. else this.slide(0, this.speed); //if last slide return to start
  103. },
  104. begin: function() {
  105. var _this = this;
  106. this.interval = (this.delay)
  107. ? setTimeout(function() {
  108. _this.next(_this.delay);
  109. }, this.delay)
  110. : 0;
  111. },
  112. stop: function() {
  113. this.delay = 0;
  114. clearTimeout(this.interval);
  115. },
  116. resume: function() {
  117. this.delay = this.options.auto || 0;
  118. this.begin();
  119. },
  120. handleEvent: function(e) {
  121. var that = this;
  122. if(!e.touches){
  123. e.touches = new Array(e);
  124. e.scale = false;
  125. }
  126. switch (e.type) {
  127. // by anjey
  128. case 'mousedown': (function(){
  129. that.element.addEventListener('mousemove', that, false);
  130. that.element.addEventListener('mouseup', that, false);
  131. that.element.addEventListener('mouseout', that, false);
  132. that.onTouchStart(e);
  133. })(); break;
  134. case 'mousemove': this.onTouchMove(e); break;
  135. case 'mouseup': (function(){
  136. that.element.removeEventListener('mousemove', that, false);
  137. that.element.removeEventListener('mouseup', that, false);
  138. that.element.removeEventListener('mouseout', that, false);
  139. that.onTouchEnd(e);
  140. })(); break;
  141. case 'mouseout': (function(){
  142. that.element.removeEventListener('mousemove', that, false);
  143. that.element.removeEventListener('mouseup', that, false);
  144. that.element.removeEventListener('mouseout', that, false);
  145. that.onTouchEnd(e);
  146. })(); break;
  147. case 'touchstart': this.onTouchStart(e); break;
  148. case 'touchmove': this.onTouchMove(e); break;
  149. case 'touchend': this.onTouchEnd(e); break;
  150. case 'webkitTransitionEnd':
  151. case 'msTransitionEnd':
  152. case 'oTransitionEnd':
  153. case 'transitionend': this.transitionEnd(e); break;
  154. case 'resize': this.setup(); break;
  155. }
  156. },
  157. transitionEnd: function(e) {
  158. e.preventDefault();
  159. if (this.delay) this.begin();
  160. this.callback(e, this.index, this.slides[this.index]);
  161. },
  162. onTouchStart: function(e) {
  163. this.start = {
  164. // get touch coordinates for delta calculations in onTouchMove
  165. pageX: e.touches[0].pageX,
  166. pageY: e.touches[0].pageY,
  167. // set initial timestamp of touch sequence
  168. time: Number( new Date() )
  169. };
  170. // used for testing first onTouchMove event
  171. this.isScrolling = undefined;
  172. // reset deltaX
  173. this.deltaX = 0;
  174. // set transition time to 0 for 1-to-1 touch movement
  175. this.element.style.MozTransitionDuration = this.element.style.webkitTransitionDuration = 0;
  176. },
  177. onTouchMove: function(e) {
  178. // ensure swiping with one touch and not pinching
  179. if(e.touches.length > 1 || e.scale && e.scale !== 1) return;
  180. this.deltaX = e.touches[0].pageX - this.start.pageX;
  181. // determine if scrolling test has run - one time test
  182. if ( typeof this.isScrolling == 'undefined') {
  183. this.isScrolling = !!( this.isScrolling || Math.abs(this.deltaX) < Math.abs(e.touches[0].pageY - this.start.pageY) );
  184. }
  185. // if user is not trying to scroll vertically
  186. if (!this.isScrolling) {
  187. // prevent native scrolling
  188. e.preventDefault();
  189. // cancel slideshow
  190. clearTimeout(this.interval);
  191. // increase resistance if first or last slide
  192. this.deltaX =
  193. this.deltaX /
  194. ( (!this.index && this.deltaX > 0 // if first slide and sliding left
  195. || this.index == this.length - 1 // or if last slide and sliding right
  196. && this.deltaX < 0 // and if sliding at all
  197. ) ?
  198. ( Math.abs(this.deltaX) / this.width + 1 ) // determine resistance level
  199. : 1 ); // no resistance if false
  200. // translate immediately 1-to-1
  201. this.element.style.MozTransform = this.element.style.webkitTransform = 'translate3d(' + (this.deltaX - this.index * this.width) + 'px,0,0)';
  202. }
  203. },
  204. onTouchEnd: function(e) {
  205. // determine if slide attempt triggers next/prev slide
  206. var isValidSlide =
  207. Number(new Date()) - this.start.time < 250 // if slide duration is less than 250ms
  208. && Math.abs(this.deltaX) > 20 // and if slide amt is greater than 20px
  209. || Math.abs(this.deltaX) > this.width/2, // or if slide amt is greater than half the width
  210. // determine if slide attempt is past start and end
  211. isPastBounds =
  212. !this.index && this.deltaX > 0 // if first slide and slide amt is greater than 0
  213. || this.index == this.length - 1 && this.deltaX < 0; // or if last slide and slide amt is less than 0
  214. // if not scrolling vertically
  215. if (!this.isScrolling) {
  216. // call slide function with slide end value based on isValidSlide and isPastBounds tests
  217. this.slide( this.index + ( isValidSlide && !isPastBounds ? (this.deltaX < 0 ? 1 : -1) : 0 ), this.speed );
  218. }
  219. }
  220. };