github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/app/script/swipe.js (about)

     1  /*
     2   * Swipe 2.0
     3   *
     4   * Brad Birdsall
     5   * Copyright 2013, MIT License
     6   *
     7   */
     8  
     9  function Swipe(container, options) {
    10  
    11      "use strict";
    12  
    13      // utilities
    14      var noop = function () {
    15      }; // simple no operation function
    16      var offloadFn = function (fn) {
    17          setTimeout(fn || noop, 0)
    18      }; // offload a functions execution
    19  
    20      // check browser capabilities
    21      var browser = {
    22          addEventListener: !!window.addEventListener,
    23          touch: ('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch,
    24          transitions: (function (temp) {
    25              var props = ['transitionProperty', 'WebkitTransition', 'MozTransition', 'OTransition', 'msTransition'];
    26              for (var i in props) if (temp.style[ props[i] ] !== undefined) return true;
    27              return false;
    28          })(document.createElement('swipe'))
    29      };
    30  
    31      // quit if no root element
    32      if (!container) return;
    33      var element = container.children[0];
    34      var slides, slidePos, width, length;
    35      options = options || {};
    36      var index = parseInt(options.startSlide, 10) || 0;
    37      var speed = options.speed || 300;
    38      options.continuous = options.continuous !== undefined ? options.continuous : true;
    39  
    40      function setup() {
    41  
    42          // cache slides
    43          slides = element.children;
    44          length = slides.length;
    45  
    46          // set continuous to false if only one slide
    47          if (slides.length < 2) options.continuous = false;
    48  
    49          //special case if two slides
    50          if (browser.transitions && options.continuous && slides.length < 3) {
    51              element.appendChild(slides[0].cloneNode(true));
    52              element.appendChild(element.children[1].cloneNode(true));
    53              slides = element.children;
    54          }
    55  
    56          // create an array to store current positions of each slide
    57          slidePos = new Array(slides.length);
    58  
    59          // determine width of each slide
    60          width = container.getBoundingClientRect().width || container.offsetWidth;
    61  
    62          element.style.width = (slides.length * width) + 'px';
    63  
    64          // stack elements
    65          var pos = slides.length;
    66          while (pos--) {
    67  
    68              var slide = slides[pos];
    69  
    70              slide.style.width = width + 'px';
    71              slide.setAttribute('data-index', pos);
    72  
    73              if (browser.transitions) {
    74                  slide.style.left = (pos * -width) + 'px';
    75                  move(pos, index > pos ? -width : (index < pos ? width : 0), 0);
    76              }
    77  
    78          }
    79  
    80          // reposition elements before and after index
    81          if (options.continuous && browser.transitions) {
    82              move(circle(index - 1), -width, 0);
    83              move(circle(index + 1), width, 0);
    84          }
    85  
    86          if (!browser.transitions) element.style.left = (index * -width) + 'px';
    87  
    88          container.style.visibility = 'visible';
    89  
    90      }
    91  
    92      function prev() {
    93  
    94          if (options.continuous) slide(index - 1);
    95          else if (index) slide(index - 1);
    96  
    97      }
    98  
    99      function next() {
   100          if (options.continuous) slide(index + 1);
   101          else if (index < slides.length - 1) slide(index + 1);
   102  
   103      }
   104  
   105      function circle(index) {
   106  
   107          // a simple positive modulo using slides.length
   108          return (slides.length + (index % slides.length)) % slides.length;
   109  
   110      }
   111  
   112      function slide(to, slideSpeed) {
   113  
   114          // do nothing if already on requested slide
   115          if (index == to) return;
   116  
   117          if (browser.transitions) {
   118  
   119              var direction = Math.abs(index - to) / (index - to); // 1: backward, -1: forward
   120  
   121              // get the actual position of the slide
   122              if (options.continuous) {
   123                  var natural_direction = direction;
   124                  direction = -slidePos[circle(to)] / width;
   125  
   126                  // if going forward but to < index, use to = slides.length + to
   127                  // if going backward but to > index, use to = -slides.length + to
   128                  if (direction !== natural_direction) to = -direction * slides.length + to;
   129  
   130              }
   131  
   132              var diff = Math.abs(index - to) - 1;
   133  
   134              // move all the slides between index and to in the right direction
   135              while (diff--) move(circle((to > index ? to : index) - diff - 1), width * direction, 0);
   136  
   137              to = circle(to);
   138  
   139              move(index, width * direction, slideSpeed || speed);
   140              move(to, 0, slideSpeed || speed);
   141  
   142              if (options.continuous) move(circle(to - direction), -(width * direction), 0); // we need to get the next in place
   143  
   144          } else {
   145  
   146              to = circle(to);
   147              animate(index * -width, to * -width, slideSpeed || speed);
   148              //no fallback for a circular continuous if the browser does not accept transitions
   149          }
   150  
   151          index = to;
   152          offloadFn(options.callback && options.callback(index, slides[index]));
   153      }
   154  
   155      function move(index, dist, speed) {
   156  
   157          translate(index, dist, speed);
   158          slidePos[index] = dist;
   159  
   160      }
   161  
   162      function translate(index, dist, speed) {
   163  
   164          var slide = slides[index];
   165          var style = slide && slide.style;
   166  
   167          if (!style) return;
   168  
   169          style.webkitTransitionDuration =
   170              style.MozTransitionDuration =
   171                  style.msTransitionDuration =
   172                      style.OTransitionDuration =
   173                          style.transitionDuration = speed + 'ms';
   174  
   175          style.webkitTransform = 'translate(' + dist + 'px,0)' + 'translateZ(0)';
   176          style.msTransform =
   177              style.MozTransform =
   178                  style.OTransform = 'translateX(' + dist + 'px)';
   179  
   180      }
   181  
   182      function animate(from, to, speed) {
   183  
   184          // if not an animation, just reposition
   185          if (!speed) {
   186  
   187              element.style.left = to + 'px';
   188              return;
   189  
   190          }
   191  
   192          var start = +new Date;
   193  
   194          var timer = setInterval(function () {
   195  
   196              var timeElap = +new Date - start;
   197  
   198              if (timeElap > speed) {
   199  
   200                  element.style.left = to + 'px';
   201  
   202                  if (delay) begin();
   203  
   204                  options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);
   205  
   206                  clearInterval(timer);
   207                  return;
   208  
   209              }
   210  
   211              element.style.left = (( (to - from) * (Math.floor((timeElap / speed) * 100) / 100) ) + from) + 'px';
   212  
   213          }, 4);
   214  
   215      }
   216  
   217      // setup auto slideshow
   218      var delay = options.auto || 0;
   219      var interval;
   220  
   221      function begin() {
   222  
   223          interval = setTimeout(next, delay);
   224  
   225      }
   226  
   227      function stop() {
   228  
   229          delay = 0;
   230          clearTimeout(interval);
   231  
   232      }
   233  
   234  
   235      // setup initial vars
   236      var start = {};
   237      var delta = {};
   238      var isScrolling;
   239  
   240      // setup event capturing
   241      var events = {
   242  
   243          handleEvent: function (event) {
   244  
   245              switch (event.type) {
   246                  case 'touchstart':
   247                      this.start(event);
   248                      break;
   249                  case 'touchmove':
   250                      this.move(event);
   251                      break;
   252                  case 'touchend':
   253                      this.end(event);
   254                      break;    //modify by Alon Zhang
   255                  // case 'touchend': offloadFn(this.end(event)); break;
   256                  case 'webkitTransitionEnd':
   257                  case 'msTransitionEnd':
   258                  case 'oTransitionEnd':
   259                  case 'otransitionend':
   260                  case 'transitionend':
   261                      offloadFn(this.transitionEnd(event));
   262                      break;
   263                  case 'resize':
   264                      offloadFn(setup);
   265                      break;
   266              }
   267  
   268              if (options.stopPropagation) event.stopPropagation();
   269  
   270          },
   271          start: function (event) {
   272  
   273              var touches = event.touches[0];
   274  
   275              // measure start values
   276              start = {
   277  
   278                  // get initial touch coords
   279                  x: touches.pageX,
   280                  y: touches.pageY,
   281  
   282                  // store time to determine touch duration
   283                  time: +new Date
   284  
   285              };
   286  
   287              // used for testing first move event
   288              isScrolling = undefined;
   289  
   290              // reset delta and end measurements
   291              delta = {};
   292  
   293              // attach touchmove and touchend listeners
   294              element.addEventListener('touchmove', this, false);
   295              element.addEventListener('touchend', this, false);
   296  
   297          },
   298          move: function (event) {
   299  
   300              // ensure swiping with one touch and not pinching
   301              if (event.touches.length > 1 || event.scale && event.scale !== 1) return
   302  
   303              if (options.disableScroll) event.preventDefault();
   304  
   305              var touches = event.touches[0];
   306  
   307              // measure change in x and y
   308              delta = {
   309                  x: touches.pageX - start.x,
   310                  y: touches.pageY - start.y
   311              }
   312  
   313              // determine if scrolling test has run - one time test
   314              if (typeof isScrolling == 'undefined') {
   315                  isScrolling = !!( isScrolling || Math.abs(delta.x) < Math.abs(delta.y) );
   316              }
   317  
   318              // if user is not trying to scroll vertically
   319              if (!isScrolling) {
   320  
   321                  // prevent native scrolling
   322                  event.preventDefault();
   323  
   324                  // stop slideshow
   325                  stop();
   326  
   327                  // increase resistance if first or last slide
   328                  if (options.continuous) { // we don't add resistance at the end
   329  
   330                      translate(circle(index - 1), delta.x + slidePos[circle(index - 1)], 0);
   331                      translate(index, delta.x + slidePos[index], 0);
   332                      translate(circle(index + 1), delta.x + slidePos[circle(index + 1)], 0);
   333  
   334                  } else {
   335  
   336                      delta.x =
   337                          delta.x /
   338                          ( (!index && delta.x > 0               // if first slide and sliding left
   339                              || index == slides.length - 1        // or if last slide and sliding right
   340                              && delta.x < 0                       // and if sliding at all
   341                              ) ?
   342                              ( Math.abs(delta.x) / width + 1 )      // determine resistance level
   343                              : 1 );                                 // no resistance if false
   344  
   345                      // translate 1:1
   346                      translate(index - 1, delta.x + slidePos[index - 1], 0);
   347                      translate(index, delta.x + slidePos[index], 0);
   348                      translate(index + 1, delta.x + slidePos[index + 1], 0);
   349                  }
   350  
   351              }
   352  
   353          },
   354          end: function (event) {
   355  
   356              // measure duration
   357              var duration = +new Date - start.time;
   358  
   359              // determine if slide attempt triggers next/prev slide
   360              var isValidSlide =
   361                  Number(duration) < 250               // if slide duration is less than 250ms
   362                  && Math.abs(delta.x) > 20            // and if slide amt is greater than 20px
   363                  || Math.abs(delta.x) > width / 2;      // or if slide amt is greater than half the width
   364  
   365              // determine if slide attempt is past start and end
   366              var isPastBounds =
   367                  !index && delta.x > 0                            // if first slide and slide amt is greater than 0
   368                  || index == slides.length - 1 && delta.x < 0;    // or if last slide and slide amt is less than 0
   369  
   370              if (options.continuous) isPastBounds = false;
   371  
   372              // determine direction of swipe (true:right, false:left)
   373              var direction = delta.x < 0;
   374  
   375              // if not scrolling vertically
   376              if (!isScrolling) {
   377  
   378                  if (isValidSlide && !isPastBounds) {
   379  
   380                      if (direction) {
   381  
   382                          if (options.continuous) { // we need to get the next in this direction in place
   383  
   384                              move(circle(index - 1), -width, 0);
   385                              move(circle(index + 2), width, 0);
   386  
   387                          } else {
   388                              move(index - 1, -width, 0);
   389                          }
   390  
   391                          move(index, slidePos[index] - width, speed);
   392                          move(circle(index + 1), slidePos[circle(index + 1)] - width, speed);
   393                          index = circle(index + 1);
   394  
   395                      } else {
   396                          if (options.continuous) { // we need to get the next in this direction in place
   397  
   398                              move(circle(index + 1), width, 0);
   399                              move(circle(index - 2), -width, 0);
   400  
   401                          } else {
   402                              move(index + 1, width, 0);
   403                          }
   404  
   405                          move(index, slidePos[index] + width, speed);
   406                          move(circle(index - 1), slidePos[circle(index - 1)] + width, speed);
   407                          index = circle(index - 1);
   408  
   409                      }
   410  
   411                      options.callback && options.callback(index, slides[index]);
   412  
   413                  } else {
   414  
   415                      if (options.continuous) {
   416  
   417                          move(circle(index - 1), -width, speed);
   418                          move(index, 0, speed);
   419                          move(circle(index + 1), width, speed);
   420  
   421                      } else {
   422  
   423                          move(index - 1, -width, speed);
   424                          move(index, 0, speed);
   425                          move(index + 1, width, speed);
   426                      }
   427  
   428                  }
   429  
   430              }
   431  
   432              // kill touchmove and touchend event listeners until touchstart called again
   433              element.removeEventListener('touchmove', events, false);
   434              element.removeEventListener('touchend', events, false);
   435  
   436              //add by Alon Zhang
   437              //resume slide
   438              delay = options.auto;
   439  
   440          },
   441          transitionEnd: function (event) {
   442  
   443              if (parseInt(event.target.getAttribute('data-index'), 10) == index) {
   444  
   445                  if (delay) begin();
   446  
   447                  options.transitionEnd && options.transitionEnd.call(event, index, slides[index]);
   448  
   449              }
   450  
   451          }
   452  
   453      }
   454  
   455      // trigger setup
   456      setup();
   457  
   458      // start auto slideshow if applicable
   459      if (delay) begin();
   460  
   461  
   462      // add event listeners
   463      if (browser.addEventListener) {
   464  
   465          // set touchstart event on element
   466          if (browser.touch) element.addEventListener('touchstart', events, false);
   467  
   468          if (browser.transitions) {
   469              element.addEventListener('webkitTransitionEnd', events, false);
   470              element.addEventListener('msTransitionEnd', events, false);
   471              element.addEventListener('oTransitionEnd', events, false);
   472              element.addEventListener('otransitionend', events, false);
   473              element.addEventListener('transitionend', events, false);
   474          }
   475  
   476          // set resize event on window
   477          window.addEventListener('resize', events, false);
   478  
   479      } else {
   480  
   481          window.onresize = function () {
   482              setup()
   483          }; // to play nice with old IE
   484  
   485      }
   486  
   487      // expose the Swipe API
   488      return {
   489          setup: function () {
   490  
   491              setup();
   492  
   493          },
   494          slide: function (to, speed) {
   495  
   496              // cancel slideshow
   497              stop();
   498  
   499              slide(to, speed);
   500  
   501          },
   502          prev: function () {
   503  
   504              // cancel slideshow
   505              stop();
   506  
   507              prev();
   508  
   509          },
   510          next: function () {
   511  
   512              // cancel slideshow
   513              stop();
   514  
   515              next();
   516  
   517          },
   518          stop: function () {
   519  
   520              // cancel slideshow
   521              stop();
   522  
   523          },
   524          getPos: function () {
   525  
   526              // return current index position
   527              return index;
   528  
   529          },
   530          getNumSlides: function () {
   531  
   532              // return total number of slides
   533              return length;
   534          },
   535          kill: function () {
   536  
   537              // cancel slideshow
   538              stop();
   539  
   540              // reset element
   541              element.style.width = '';
   542              element.style.left = '';
   543  
   544              // reset slides
   545              var pos = slides.length;
   546              while (pos--) {
   547  
   548                  var slide = slides[pos];
   549                  slide.style.width = '';
   550                  slide.style.left = '';
   551  
   552                  if (browser.transitions) translate(pos, 0, 0);
   553  
   554              }
   555  
   556              // removed event listeners
   557              if (browser.addEventListener) {
   558  
   559                  // remove current event listeners
   560                  element.removeEventListener('touchstart', events, false);
   561                  element.removeEventListener('webkitTransitionEnd', events, false);
   562                  element.removeEventListener('msTransitionEnd', events, false);
   563                  element.removeEventListener('oTransitionEnd', events, false);
   564                  element.removeEventListener('otransitionend', events, false);
   565                  element.removeEventListener('transitionend', events, false);
   566                  window.removeEventListener('resize', events, false);
   567  
   568              }
   569              else {
   570  
   571                  window.onresize = null;
   572  
   573              }
   574  
   575          }
   576      }
   577  
   578  }
   579  
   580  
   581  if (window.jQuery || window.Zepto) {
   582      (function ($) {
   583          $.fn.Swipe = function (params) {
   584              return this.each(function () {
   585                  $(this).data('Swipe', new Swipe($(this)[0], params));
   586              });
   587          }
   588      })(window.jQuery || window.Zepto)
   589  }