malsup / cycle2

2nd gen cycling
899 stars 236 forks source link

Scroll the carousel more than one slide at a time #106

Open daltonrooney opened 11 years ago

daltonrooney commented 11 years ago

I have a carousel that's set to show four slides, and I'd like it to advance four slides at a time to the next group. Is there any way to do that?

DannyJasper commented 11 years ago

Have exactly the same issue/question. Maybe it's possible with some nifty callback on the next button, but I can not get it to work.

mpettitt commented 11 years ago

Instead of showing four slides, show one slide with 4 elements in. Then the cycle just happily displays the outer groups, and you get the same visual effect.

Something like (this won't work without adjustment!):

<div class="cycle">
  <div class="group">
    <img src="img1.png" />
    <img src="img2.png" />
  </div>
  <div class="group">
    <img src="img3.png" />
    <img src="img4.png" />
  </div>
</div>
daltonrooney commented 11 years ago

@mpettitt That's what I ended up doing, but if you have an odd number of items in your carousel, then it won't be continuous. http://cl.ly/1l2k1D133t2U

I'd like the ability to create a continuous carousel but advance the entire row in one shot.

malsup commented 11 years ago

This is a feature I plan to add, just haven't had time. I have a lot of work to do on the carousel implementation.

gabrielfin commented 11 years ago

I've been playing around a bit and came up with the following solution, while we wait for something more official. You can choose the number of slides it "hops" with the setting data-cycle-carousel-hops

@@ -6,6 +6,10 @@
     if ( opts.fx !== 'carousel' )
         return;

+    function _modulo(m,n) {
+        return ((m%n)+n)%n;
+    }
+    
     API.getSlideIndex = function( el ) {
         var slides = this.opts()._carouselWrap.children();
         var i = slides.index( el );
@@ -17,10 +21,47 @@
         var count = opts.reverse ? -1 : 1;
         if ( opts.allowWrap === false && ( opts.currSlide + count ) > opts.slideCount - opts.carouselVisible )
             return;
-        opts.API.advanceSlide( count );
+        opts.API.advanceSlide( count * opts.carouselHops );
         opts.API.trigger('cycle-next', [ opts ]).log('cycle-next');
     };
-
+    
+    API.prev = function() {
+        var opts = this.opts();
+        if ( opts.busy && ! opts.manualTrump )
+            return;
+        var count = opts.reverse ? 1 : -1;
+        if ( opts.allowWrap === false && ( opts.currSlide + count ) < 0 )
+            return;
+
+        opts.API.advanceSlide( count * opts.carouselHops );
+        opts.API.trigger('cycle-prev', [ opts ]).log('cycle-prev');
+    };
+    
+    API.calcFirstSlide = function() {
+        var opts = this.opts();
+        var firstSlideIndex;
+        firstSlideIndex = parseInt( opts.startingSlide || 0, 10 );
+        if (firstSlideIndex >= opts.slides.length || firstSlideIndex < 0)
+            firstSlideIndex = 0;
+
+        opts.currSlide = firstSlideIndex;
+        opts.nextSlide = _modulo(firstSlideIndex + opts.carouselHops * (opts.reverse ? -1 : 1), opts.slideCount);
+    };
+    
+    API.calcNextSlide = function(){
+        opts.currSlide = opts.nextSlide;
+        opts.nextSlide = _modulo(opts.currSlide + opts.carouselHops * (opts.reverse ? -1 : 1), opts.slideCount);
+    }
+
+    API.advanceSlide = function( val ) {
+        var opts = this.opts();
+        clearTimeout(opts.timeoutId);
+        opts.timeoutId = 0;
+        opts.nextSlide = _modulo(opts.currSlide + val, opts.slides.length);
+
+        opts.API.prepareTx( true,  val >= 0 );
+        return false;
+    };
 });

@@ -46,6 +87,12 @@
         if (opts.carouselVisible && opts.carouselVisible > opts.slideCount)
             opts.carouselVisible = opts.slideCount - 1;
         var visCount = opts.carouselVisible || opts.slides.length;
+        
+        if( opts.carouselVisible )
+            opts.carouselHops = Math.min(opts.carouselHops || 1, opts.slideCount - opts.carouselVisible + 1);
+        else
+            opts.carouselHops = Math.min(opts.carouselHops || 1, opts.slideCount - 1);
+
         var slideCSS = { display: vert ? 'block' : 'inline-block', position: 'static' };

         // required styles
@@ -194,14 +237,16 @@
             opts.API.opts()._currSlide = opts.nextSlide > maxCurr ? maxCurr : opts.nextSlide;
         }
         else {
-            if ( fwd && opts.nextSlide === 0 ) {
-                // moving from last slide to first
-                moveBy = this.getDim( opts, opts.currSlide, vert );
+            if ( fwd && opts.nextSlide < opts.currSlide ) {
+                // wrap around on the right
+                moveBy = this.getScroll( opts, vert, opts.currSlide, opts.slideCount-opts.currSlide );
+                moveBy += this.getScroll( opts, vert, 0, opts.nextSlide );
                 callback = this.genCallback( opts, fwd, vert, callback );
             }
-            else if ( !fwd && opts.nextSlide == opts.slideCount - 1 ) {
-                // moving from first slide to last
-                moveBy = this.getDim( opts, opts.currSlide, vert );
+            else if ( !fwd && opts.nextSlide > opts.currSlide ) {
+                // wrap around on the left
+                moveBy = this.getScroll( opts, vert, opts.nextSlide, opts.slideCount-opts.nextSlide );
+                moveBy += this.getScroll( opts, vert, 0, opts.currSlide );
                 callback = this.genCallback( opts, fwd, vert, callback );
             }
             else {
poisonkitty commented 11 years ago

@gabrielfin do you have a working example of your "hops" working? i'd love to see it in action, as i desperately need to find a way to step through multiple images at a time. thanks!

poisonkitty commented 11 years ago

@gabrielfin never mind, got it going. works great! thanks!!!

ninedoors commented 11 years ago

@gabrielfin or @poisonkitty can one of you post the working code? I can't seem to get this to work properly. Thanks

ninedoors commented 11 years ago

@gabrielfin or @poisonkitty I got it working, forgot was missing a ; from the copy paste. Thanks for the code @gabrielfin

davorpeic commented 10 years ago

+1 for official solution,

the code pasted here works 50-50, going forward works ok, but going back shows empty slides (visibility:hidden)

flyarrowplane commented 10 years ago

+1 here, too.

phenaproxima commented 10 years ago

+1 from me too.

wmitchellUK commented 10 years ago

+1

@gabrielfin I'm using your soln as well. I have noticed tho as the above people have said that circular/wrap doesn't work properly ie (allowWrap=true) also the disabledClass functionality for your prev/next buttons doesn't work correctly when doing allowWrap=false

I am seeing my issues when you proceed to the end of your list of hops.

asdat commented 10 years ago

or you can just hide some pagers, for example, you need to slide elements every 3rd, then you just need only

pager span:nth-child(3n+2),#pager span:nth-child(3n+3){display:none;}

visutech commented 10 years ago

@asdat your CSS solution was easiest to implement +1

asdat commented 10 years ago

yes, but it works only for pagers, next/prev slides only next or prev, for prev/next navigation better overwrite prev/next sliding without using prev/next from cycle2, later i'll make an example and show it

amityweb commented 10 years ago

Just curious if an official version is going to be implemented? The only reason we dont use Carousel is because it moves 1 at a time which quite frankly is very annoying and dont understand why one anyone would do that. The user has already seen ALL images in the row, he wants to see the next row without clicking x number of times. Thanks!

visutech commented 10 years ago

@amityweb - it would be good if this could be added to the cycle carousel plugin, as I think it should reside with that. If you need a quick fix though, the css workaround does work (probably only on browsers that support the nth child).

BenRacicot commented 10 years ago

+1 - follow me on Twitter for chat about this @BenRacicot

I +1'ed this yesterday but was handcuffed to the project: I've built this (for a carousel type implementation), with some help, which works to move 3 slides at a time.

$('.slides').on('cycle-update-view', function (e, optionHash, slideOptionsHash, currSlideEl) {
    // +1 brings us current from the zero index
    currSlide = optionHash.currSlide + 1;
    fullCount = optionHash.slideCount;
});

$('.next').on( 'click', function() {
    $(this).prev('.slides').cycle('goto', currSlide + 2);
});

$('.prev').on( 'click', function() {
    var minus = currSlide - 4;
    $(this).next('.slides').cycle('goto', minus);
});
jnz31 commented 10 years ago

@BenRacicot thanks for your work. this works somehow but is not "perfect". mine isn't eather, but lets call it improved.. currSlide + 2 could also make an invalid result, lets say your slideshow is 7 slides long and the current slide is 7, then next would be 9, but since 9 does not exist, the slideshow will do nothing. with this solution it jumps to slide 0 (zero-indexed).

plus i made it variable:

  1. if the current slide has class skip, then skip the next slide. if not proceed as normal (+1).
var cycle_all, cycle_next;

$(".slideshow").on("cycle-update-view", function (e, optionHash, slideOptionsHash, currSlideEl) {
    cycle_all = optionHash.slideCount;
    if ( $( currSlideEl ).is(".skip") ) {
        cycle_next = optionHash.currSlide + 2;
    } else {
        cycle_next = optionHash.currSlide + 1;
    }
    if ( cycle_next >= cycle_all ) {
        cycle_next = 0;
    }
});

$(".next").on( "click", function() {
    $(".slideshow").cycle( "goto", cycle_next );
});

(this only includes next since i don't needed prev..)

che-wf commented 10 years ago

+1

This worked perfectly! Thank you!

asdat commented 10 years ago

why don't you think about nested slideshows? for example n=3 you have HTML

<div class="cycle-slideshow" 
    data-cycle-fx=scrollHorz
    data-cycle-timeout=0
    data-cycle-slides="> div.slide"
    >
    <div class="cycle-prev"></div>
    <div class="cycle-next"></div>
    <div class="slide">
       <img src="http://malsup.github.io/images/p1.jpg">
       <img src="http://malsup.github.io/images/p2.jpg">
       <img src="http://malsup.github.io/images/p3.jpg">
    </div>
    <div class="slide">
       <img src="http://malsup.github.io/images/p4.jpg">
       <img src="http://malsup.github.io/images/p1.jpg">
       <img src="http://malsup.github.io/images/p2.jpg">
    </div>
</div>

then even pagers would work fine

the easiest decition fo sliding any n element is to slide n times next/prev HTML

<div class="prev"></div>
<div class="next"></div>
<div class="cycle-slideshow" 
    data-cycle-fx=scrollHorz
    data-cycle-timeout=0
    data-slides-perclick="3"
    >
    <img src="http://malsup.github.io/images/p1.jpg">
    <img src="http://malsup.github.io/images/p2.jpg">
    <img src="http://malsup.github.io/images/p3.jpg">
    <img src="http://malsup.github.io/images/p4.jpg">
    <img src="http://malsup.github.io/images/p1.jpg">
    <img src="http://malsup.github.io/images/p2.jpg">
</div>

JS

jQuery('div.next').click(function(){
  e.preventDefault();
  var count=jQuery('.cycle-slideshow').date('slides-perclick');
  for (i = 0; i < count; i++) { 
       jQuery('.cycle-slideshow').cycle('next');
  }
});
jQuery('div.prev').click(function(){
  e.preventDefault();
  var count=jQuery('.cycle-slideshow').date('slides-perclick');
  for (i = 0; i < count; i++) { 
       jQuery('.cycle-slideshow').cycle('prev');
  }
});

code not best, but easier to understand

mledwards commented 9 years ago

Did this ever get added to the official plugin?

MariuszDabrowski commented 9 years ago

Same question, need to skip multiple images at once - is there an official way to do this?

shawnholt commented 9 years ago

+1 for multple (like a slider) and if you do a web search there are a billion other people wanting to do this :+1:

Seb33300 commented 9 years ago

+1 waiting for this feature for a long time!

tangst commented 9 years ago

Is this feature implemented in the carousel plugin? The demo page still shows the carousel moving only one slide at a time. http://jquery.malsup.com/cycle2/demo/carousel.php

gabrielfin commented 9 years ago

Hi there! I just applied my patch to a fork so it's easier if anyone else wants to use it. I also fixed the issue with allowWrap=false and disabling the "next" button (@wmitchellUK). https://github.com/gabrielfin/cycle2/blob/issue-%23106/src/jquery.cycle2.carousel.js

mledwards commented 9 years ago

You little darling! :+1:

KZNcode commented 9 years ago

@gabrielfin doesn't work with allow-wrap: false

gabrielfin commented 9 years ago

@bbuds Can you upload an example?

willfaulds commented 9 years ago

@gabrielfin I've just installed this and very happy. It does need a default value though of either 1 or carouselVisible as without any carouselHops set nothing happens ^_^

I've fiddled with the cycle-after and cycle-before events to add a cycle-carousel-active class to all visible slides but I can't get it to reliably work because of the reordering...

willfaulds commented 9 years ago

very rough example of what could be achieved:

http://jsfiddle.net/4a8s15nt/16/

with this in mind I suggest naming convention similar to- Slides entering the cycle-carousel-wrap =.cycle-carousel-in-X (where X is a No. ++ where 0 enters frame first - so direction of movement alters numbering) Slides exiting the cycle-carousel-wrap =.cycle-carousel-out-X (where X is a No. ++ where 0 exits frame first - so direction of movement alters numbering)

This would allow for delayed CSS animations + a different animation for entering&exiting but also catch all CSS selector e.g. [class*="cycle-carousel-in-"]

Plus further improvements would be to upgrade responsive handling beyond carouselVisible (no. of slides to show) so that a slide min&max width are defined. Cycle2 then calcs the carouselVisible based on available width and available no. slides.

sharjilk commented 8 years ago

Great work ! Now I can move my slides any number of time.

Can you please give some suggestion about how to manage pagers per slide. For example, if we are using 5 hoops per transition and there are total 3 transitions with those 5 hoops. So how we can manage only 3 pager links as we have only 3 transitions?

gabrielfin commented 8 years ago

How about

.cycle-pager span:not(:nth-child(5n+1)){
   display: none;
}
gabrielfin commented 8 years ago

@willfaulds better late than never, I added a default value of 1 for carouselHops

sweintraub commented 7 years ago

@gabrielfin The CSS nth-child trick works only if you have the exact count of slides per hop (i.e., if you have 2 hops of 4 it's fine, but 2 hops of 4 plus a 3rd hop of 2 throws off the nth-child). A native solution for a "hop-pager" would be fantastic.