Websites are used more and more on mobile devices like phones and tablets. These are touch based devices and people are starting to expect they can navigate through a slideshow simply by swiping it left or right.

See for inspiration http://us.blackberry.com which apparantly uses the overscroll plugin (http://azoffdesign.com/overscroll) to create such an effect.

As far as I'm aware this is currently not available functionality in views_slideshow (or any other jquery based slideshow module in Drupal). It would be awesome to see this happen!

Comments

actually, Views Slideshow: ImageFlow does support iPhone touch swipes.

Actually, I used Imageflow and it does not offer this functionality. Basically it's just 'point + click' while I'm talking about 'click(hold) + sweep'.

I would probably use a jQuery plugin like http://plugins.jquery.com/plugin-tags/touch, and apply it to my slideshow. Could be used with jQuery cycle plugin quite easily for creating slideshows.

i don't have an iphone to test, @askibinski. could you confirm that on the demo at http://finnrudolph.de/ImageFlow/Introduction as well?

thanks!

@aaron I can confirm the demo does not work as expected on android mobile. I'm pretty sure it's the same on iphone.
The only way to scroll by holding is to use the slider beneath the images, but that's just wrong ;)

By the way, scratch overscroll, that doesn't work on mobile browsers either, but @tchilly's solution seems to be in the right direction.

+1 subscribing. The demo doesn't swipe on HTC desire.

Version:6.x-3.x-dev» 7.x-3.x-dev

Moving to 7 since it's not 6 specific

See also this related issue about flexslider, which support touch gestures.
#1251388: Support FlexSlider

Here's an implementation you can put in a global.js in your theme:

https://gist.github.com/1343996

+1 sounds promising

Here are some sliders that work, have not checked how hard they would be to implement
http://unoslider.heroku.com/
http://dimsemenov.com/plugins/royal-slider/
(Royal slider site is no mobile site, swiping the image still works)
Both build as Jquery Plugins.

@9 - Works like a charm!
+1 add into module

Status:Active» Needs review

#9 Working fine with Cycle slideshows!

And with #9 working, it would be nice to have an option to decide to respond only to swiping left and right OR up and down (OR both like it does now), because when trying to scroll the page up when swiping up over the slideshow, now it moves to the next slide instead of scrolling the page…

@eigentor Thank you so much for tip about RoyalSlider (http://dimsemenov.com/plugins/royal-slider/), saved me so much time

I'm pretty sure #9 saved me a ton of time. Thank you so much!

@stovak, you are incredible! :)
Thank you soo much for this implementation. It works perfectly on my phone, even with Views Slideshow JCarousel.
It would be really great to see this feature implemented - maybe as an option (checkbox on the settings page).

#9 Doesn't work for me. I use Drupal 6 and Views Slideshow 6.x 3.0.

Is there something different I need to change in the javascript file?

It's weird because I thought it worked for a second, but then it stopped working. Also is there any specific setting/effect I need to use, or can I use fade as well as slideHorz?

I ended up including this as a custom module on my site. It only looks for left and right actions be it could be easily modified to detect up and down and the type easing.

(function( $ ) {
  $('document').ready(function(){
    if ( $('[id^="views_slideshow_cycle_main"]').length > 0 ) {
      var $slider = $('[id^="views_slideshow_cycle_main"]');
      var opts = {
        start: {x: 0, y: 0},
        end: {x: 0, y: 0},
        hdiff: 0,
        vdiff: 0,
        length: 0,
        angle: null,
        direction: null,
      };
      var optsReset = $.extend(true, {}, opts);
      $slider.data('bw', opts);
      $slider.bind('touchstart', function (e) {
        if (e.originalEvent.touches.length == 1) {
          var data = $(this).data('bw');
          data.start.x = e.originalEvent.targetTouches[0].pageX;
          data.start.y = e.originalEvent.targetTouches[0].pageY;
          $(this).data('bw', data);
          //e.preventDefault();
        }
      });
      $slider.bind('touchmove', function (e) {
        var data = $(this).data('bw');
        data.end.x = e.originalEvent.targetTouches[0].pageX;
        data.end.y = e.originalEvent.targetTouches[0].pageY;
        $(this).data('bw', data);
        //e.preventDefault();
      });
      $slider.bind('touchend', function (e) {
        var data = $(this).data('bw');
        if ( data.start.x != 0 && data.start.y != 0 ) {
          data.vdiff = data.start.x - data.end.x;
          data.hdiff = data.end.y - data.start.y;
          var length = Math.round(Math.sqrt(Math.pow(data.vdiff,2) + Math.pow(data.hdiff,2)));
          var rads = Math.atan2(data.hdiff, data.vdiff);
          var angle = Math.round(rads*180/Math.PI);
          if ( angle < 0 ) { angle = 360 - Math.abs(angle); }
          if (length > 300) {
            e.preventDefault();
            if (angle > 135 && angle < 225) {
              var cyopt = $slider.data('cycle.opts');
              if (cyopt.currSlide > 0) {
                $slider.cycle((cyopt.currSlide - 1), 'scrollRight');
              }
              else {
                 $slider.cycle((cyopt.slideCount - 1), 'scrollRight');
              }
            }
            else if (angle > 315 || angle < 45) {
              $slider.cycle('next');
            }
          }
        }
        data = $.extend(true, {}, optsReset);
      });
    }
  });
})( jQuery );

I modified the code in comment #9 to allow for click events to work. It has a 0 tolerance for short swipes, but that could be modified fairly easily.
https://gist.github.com/4170907

You may also use this plugin for views slideshow in Drupal 7 - http://drupal.org/project/flexslider or see this custom implementation http://www.daymuse.com/blogs/creating-swiping-hero-drupal using the jQuery TouchSwipe plugin.

I modified the jQuery bindings in #19 above:

  • Included a Modernizr check for touch devices along with the views slideshow element check
  • Changed the pageX / Y for data.end to touchend; the original code seems to miscalculate the X and Y delta if there was no touchmove event
  • Added horizontal and vertical threshold constants to trigger a slider action

(function( $ ) {
  $('document').ready(function(){
    if ( Modernizr.touch && $('.views-slideshow-cycle-main-frame').length ) {
      var $slider = $('.views-slideshow-cycle-main-frame')
          , opts = {
            start: {x: 0, y: 0},
            end: {x: 0, y: 0},
            hdiff: 0,
            vdiff: 0,
            length: 0,
            angle: null,
            direction: null,
          }
          , optsReset = $.extend(true, {}, opts)
          , H_THRESHOLD =  110 // roughly one inch effective resolution on ipad
          , V_THRESHOLD = 50;
      $slider.data('bw', opts)
      .bind('touchstart.cycle', function (e) {
        var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
        if ( e.originalEvent.touches.length == 1 ) {
          var data = $(this).data('bw');
          data.start.x = touch.pageX;
          data.start.y = touch.pageY;
          $(this).data('bw', data);
          //e.preventDefault();
        }
      })
      .bind('touchend.cycle', function (e) {
          var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
          var data = $(this).data('bw');
          data.end.x = touch.pageX;
          data.end.y = touch.pageY;
          $(this).data('bw', data);
          if ( data.start.x != 0 && data.start.y != 0 ) {
            data.vdiff = data.start.x - data.end.x;
            data.hdiff = data.end.y - data.start.y;
            if ( Math.abs(data.vdiff) == data.start.x && Math.abs(data.hdiff) == data.start.y ){
              data.vdiff = 0;
              data.hdiff = 0;
            }
            var length = Math.round(Math.sqrt(Math.pow(data.vdiff,2) + Math.pow(data.hdiff,2)));
            var rads = Math.atan2(data.hdiff, data.vdiff);
            var angle = Math.round(rads*180/Math.PI);
            if ( angle < 0 ) { angle = 360 - Math.abs(angle); }
            if (length > H_THRESHOLD && V_THRESHOLD > data.hdiff ) {
              e.preventDefault();
              if (angle > 135 && angle < 225) {
                var cyopt = $slider.data('cycle.opts');
                if (cyopt.currSlide > 0) {
                  $slider.cycle((cyopt.currSlide - 1), 'scrollRight');
                }
                else {
                   $slider.cycle((cyopt.slideCount - 1), 'scrollRight');
                }
              }
              else if (angle > 315 || angle < 45) {
                $slider.cycle('next');
              }
            }
          }
        data = $.extend(true, {}, optsReset);
      });
    }
  });
})( jQuery );

How do I implement the code in #22 to my site ?