Adding paging controls to a full page touch swiper/slider - Hammer.js
Asked Answered
A

1

8

CLICK FOR FIDDLE

Below is a fully functional full page touch slider I have created using hammer.js

You can drag, swipe or pan to navigate between pages.

The slider works as expected but I am now trying to create fallback navigation by adding two buttons so paging left and right can occur on click also.


QUESTION

How can the hammer swipe left or right be called on click? (Javascript or jQuery).

CURRENT ATTEMPT

$('#Left').on('click', function() {
  HammerCarousel(document.querySelector('.Swiper'), 'Left');
});

FULL CODE

function swipe() {
  var reqAnimationFrame = (function () {
    return window[Hammer.prefixed(window, "requestAnimationFrame")] || function (callback) {
      setTimeout(callback, 1000 / 60);
    }
  })();

  function dirProp(direction, hProp, vProp) {
    return (direction & Hammer.DIRECTION_HORIZONTAL) ? hProp : vProp
  }

  function HammerCarousel(container, direction) {
    this.container = container;
    this.direction = direction;
    this.panes = Array.prototype.slice.call(this.container.children, 0);
    this.containerSize = this.container[dirProp(direction, 'offsetWidth', 'offsetHeight')];
    this.currentIndex = 0;
    this.hammer = new Hammer.Manager(this.container);
    this.hammer.add(new Hammer.Pan({ direction: this.direction, threshold: 10 }));
    this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this.onPan, this));
    this.show(this.currentIndex);
  }

  HammerCarousel.prototype = {
    show: function (showIndex, percent, animate) {
      showIndex = Math.max(0, Math.min(showIndex, this.panes.length - 1));
      percent = percent || 0;

      var className = this.container.className;
      if (animate) {
        if (className.indexOf('animate') === -1) {
          this.container.className += ' animate';
        }
      } else {
        if (className.indexOf('animate') !== -1) {
          this.container.className = className.replace('animate', '').trim();
        }
      }

      var paneIndex, pos, translate;        
      for (paneIndex = 0; paneIndex < this.panes.length; paneIndex++) {
        pos = (this.containerSize / 100) * (((paneIndex - showIndex) * 100) + percent);
        translate = 'translate3d(' + pos + 'px, 0, 0)';
        this.panes[paneIndex].style.transform = translate;
        this.panes[paneIndex].style.mozTransform = translate;
        this.panes[paneIndex].style.webkitTransform = translate;
      }
      this.currentIndex = showIndex;
    },

    onPan: function (ev) {
      var delta = dirProp(this.direction, ev.deltaX, ev.deltaY),
          percent = (100 / this.containerSize) * delta,
          animate = false;
      if (ev.type == 'panend' || ev.type == 'pancancel') {
        if (Math.abs(percent) > 20 && ev.type == 'panend') {
          this.currentIndex += (percent < 0) ? 1 : -1;
        }
        percent = 0;
        animate = true;
      }
      this.show(this.currentIndex, percent, animate);
    }
  };
    
  var outer = new HammerCarousel(document.querySelector('.Swiper'), Hammer.DIRECTION_HORIZONTAL);
};

$(swipe);
html,
body,
.Page,
.Swiper{
  position:relative;
  height:100%;
}
.Swiper{
  background:#666;
  overflow:hidden;
}
.Swiper.animate > .Page{
  transition:all .3s;
  -webkit-transition:all .3s;
}
.Page{
  position:absolute;
  top:0;
  left:0;
  height:100%;
  width:100%;
  padding:0 10px;
  font:42px Arial;
  color:#fff;
   padding-top:10%;
  text-align:center;
}
.Page:nth-child(odd) {
    background:#b00;
}
.Page:nth-child(even) {
    background:#58c;
}
#Left,
#Right{
    position:absolute;
    top:0;
    height:50px;
    width:50px;
    background:#fff;
    text-align:center;
    font:16px/3em Arial;
    cursor:pointer;
}
#Left{
    left:0;
}
#Right{
    right:0;
}
<script src="http://hammerjs.github.io/dist/hammer.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="Swiper">
    <div class="Page">PAGE 1<br/>DRAG LEFT</div>
    <div class="Page">PAGE 2<br/>SWIPE ME</div>
    <div class="Page">PAGE 3<br/>HOLD TO PAN</div>
    <div class="Page">PAGE 4<br/>FLICK TO GO BACK</div>
</div>

<div id="Left">Left</div>
<div id="Right">Right</div>
Activator answered 4/3, 2015 at 15:36 Comment(0)
S
2

I have crafted a jQuery solution for this that should satisfy the fallback you are looking for.

Some things to consider, though. In your example as well, page re-size is not accounted for. I have not done so in this either to remain consistent and solve the immediate issue, but you will notice I am grabbing the $('.Page').width(); as a variable in this solution. I would recommend re-assigning this value if you do account for re-sizing. Also, a mix of swiping/clicking will throw this off. I assume since you indicated this will be a fallback, the user will receive one of the two experiences. If not, we'll need a way to update tracker on swipe events as well.

You'll notice var tracker = { 'R': 0 }. While naming may not be the best, 'R' will account for how many right "swipes" (navigation clicks) the user has performed in a plus/minus 1 manner

<div id="Left" direction="L">Left</div>
<div id="Right" direction="R">Right</div> 

$(function() {
    var width = $('.Page').width();
    var pages = $('.Page').length;
    var tracker = { 'R': 0 }

    $('#Right, #Left').click(function() {

        $(this).attr('direction') === 'R' ? 
            ((tracker.R < (pages - 1) ? tracker.R += 1 : pages)) : 
            (tracker.R > 0) ? (tracker.R -= 1) : 0;

        $('.Swiper').animate({ 'scrollLeft': $('.Page').width() * tracker.R  }, 250)
    });
});

JSFiddle Link

So answered 21/4, 2015 at 18:47 Comment(5)
Yes this works and is a good idea however it doesn't entirely fill my needs. The buttons are a fallback but they will be visible at the same time and I cannot guarantee the user won't attempt to use a combination of both swipe and click. I genuinely thought there would be an easy way to simply invoke the animate left/right from an onclick call.Activator
I'd either update Tracker as a global var on your swipe callbacks, or find a way to not present both experiences to the user. Capability detection? Keeping the tracker accounted for really shouldn't be that difficult now. Can you fire code on a successful swipe? @ObsidianSo
Thanks @sal niro I will work with it. Thanks for the input and Good job.Activator
@Obsidian did you make any progress on this?- definitely curious. I see you have awarded bounty would you be willing to accept answer if you feel this was satisfactory?So
My apologies of coarse. Thanks for your help on this.Activator

© 2022 - 2024 — McMap. All rights reserved.