metafizzy / flickity

:leaves: Touch, responsive, flickable carousels
https://flickity.metafizzy.co
7.53k stars 602 forks source link

Continuous autoPlay scrolling - autoScroll #77

Open slcr opened 9 years ago

slcr commented 9 years ago

Looks awesome and quite perfect to me. The only thing i’m missing so far is some kind of ‘autoScroll’ when using the ‘freeScroll’ Option. ‘autoPlay’ is not working as expected.

( copy of comment made here: https://css-tricks.com/creating-responsive-touch-friendly-carousels-with-flickity/#comment-1592976 )

desandro commented 9 years ago

Thanks for this feature request.

Add a 👍 reaction or subscribe to this issue if you would like to see this feature added. +1 comments will be deleted.

eballeste commented 9 years ago

+1 for a continous, ticker-style scroll

mauricesnip commented 9 years ago

+1 for continuous autoplay scrolling

As a separate feature perhaps? Something like continuousAutoPlay: true or autoPlaySkipCell: true. You can still swipe/navigate to cells this way.

EugeneDae commented 9 years ago

+1

adam-h commented 9 years ago

+1

adam-h commented 9 years ago

I just implemented this as I needed it for my project, would be great to have it upstream and may be useful to others :)

PatrikLythell commented 9 years ago

@adam-h thanks for this!

However I ran into a bug where the slider would skip a bit on mouseleave.

I tried fixing it inside your release but the code was a bit hard to get. Anyway, I've pinned down the root of the problem and it is the minimun return value of 10 inside proto.animate:

proto.animate = function() {
  if( this.isContinuous ) {
    var passed = +new Date() - this.lastAnimate;
    var move = Math.min( ( 1 / passed ) * Math.abs( this.freePlaySpeed ), 10 );

i fixed it as so:

proto.animate = function() {
  if( this.isContinuous ) {
    var passed = +new Date() - this.lastAnimate;
    var move = ( 1 / passed ) * Math.abs( this.freePlaySpeed );
    move = (isFinite(move)) ? move : 0;

But i'm not sure what the 10 was for originally so don't want to PR.

adam-h commented 9 years ago

@PatrikLythell The Math.min() was to stop it moving too much in one step (if the animation frame were delayed a significant amount it would jump along a little).

The finite check looks good. What are your thoughts on removing the Math.min() as it could be moved to after the isFinite() check or just removed.

maxackerman commented 8 years ago

+1 for a constant speed scrolling autoplay

wagich commented 8 years ago

+1 that would be really useful

desandro commented 8 years ago

I'm going to stick with my position and decline this feature request. The autoPlay feature is a suitable solution. Adding another type of auto-motion behavior is not worth the cost of additional complexity.

Thanks for all your feedback!

daslicht commented 8 years ago

Anyone found an alternative to Flickity which has this feature, please?

stefenphelps commented 8 years ago

@daslicht I found what you're looking for and it even has support all the way back to IE5:

<marquee></marquee>

In all seriousness, I have had clients ask for continues scroll rather than pausing. Maybe @desandro will get to it by V3.

daslicht commented 8 years ago

@stefenphelps

<marquee></marquee>

don't give you an infinite flow, at least I haven't found a solution , yet.

The text (or something else) would run entirely from one side to another until it disappear completely. After that it would restart.

Try to make something like this with the marquee tag and post the result please:

http://www.davidpayr.com

HowdyMcGee commented 7 years ago

Would love to see this feature

pstinnett commented 7 years ago

@desandro hopefully it's OK to post this here...

I stumbled across this site which seems to be using Flickity combined with what I assume is some custom code to achieve the continuous marquee effect. I haven't spent much time looking to reverse engineer but I thought it might be useful to post incase someone else wants to take a look.

Checkout the Instagram section here:

https://www.mendo.nl/about/flagship-store/

r00dY commented 7 years ago

Hey guys,

I took a look into source code of flickity and found pretty simple solution. It's not thoroughly tested etc, just a quick idea and example. Implementing this in current project, will see how it behaves.

    var previousDate; // if undefined, animation is paused

    function step() {
        if (typeof previousDate == 'undefined') { return; }

        var date = new Date();
        var diff = (date - previousDate) / 20; // in this case 20 is "speed constant", the higher value, the slower movement
        previousDate = date;

        /* key 2 lines of code */
        flkty.x -= diff;
        flkty.positionSlider();

        requestAnimationFrame(step);
    }

    function play() {
        if (typeof previousDate == 'undefined') {
            previousDate = new Date();
        }

        requestAnimationFrame(step);
    }

    function pause() {
        previousDate = undefined;
    }

    play();

Initially I planned to call play/pause on dragStart / dragEnd events, but somehow flickity works nice without it. But it might be worth considering if something went wrong.

bennyjien commented 7 years ago

@r00dY Thank you for this! It works quite nice, but on iOS scrolling the page will cause the current slider position to reset.

antoniofelizardo commented 7 years ago

@r00dY @bennyjien Would you please share any more info on how you've implemented your code? Currently toying around with Flickity and wondering if there is indeed a chance of turning it into a continuous scrolling slideshow. Thanks in advance

TomDeSmet commented 6 years ago

To bad this won't be implemented. I think Flickity is probably the best slider out there, but I realy need this for a webapp. It seems a logical feature request and autoPlay does not offer a solution as it is now. Other sliders (such as Slick) offer a combination of settings with which you can achieve every effect:

speed: 2500,
autoplay: true,
autoplaySpeed: 0,

Unfortunately, the responsiveness of Flickity is far better than most.

koraysels commented 6 years ago

I needed this behaviour for my site too and i found @pstinnett example on that mendo.com website. I looked a bit in the source code and it is failry easily done in fact... here's the mimimum required code to do it (without pause on hover etc... you need to implement that yourself or if I ever get to it i will post it here.):

init() {
    this.flkty = new Flickity('<someDOMElement>', {
          prevNextButtons: false, 
          pageDots: false,
          wrapAround: true,
          freeScroll: true
     });
    this.flkty.x = 0;
    this.loop();
}

loop() {
    this.flkty.x--;
    this.flkty.integratePhysics();
    this.flkty.settle( this.flkty.x);
    window.requestAnimationFrame(this.loop.bind(this));
}
pveen2 commented 6 years ago

@koraysels Did you already implemented it? I can't get it working.

richardwiggins commented 6 years ago

@r00dY @bennyjien I'm also try to get something like this working but unsure how to implement this code suggestion. It's not playing ball for me.

roberrrt-s commented 6 years ago

Following @koraysels pattern, I believe I found a really nice way to apply pause/play into his solution:

// For every container, do the following:
_$container.each((i, el) => {
    // Set a unique animation request id variable
    let requestId;

    // Check if the slider contains more than 3 slides
    if($(el).children().length > 3) {
        // Initialize the slider
        const mainTicker = new Flickity('.js-main-slider', {
            accessibility: true,
            resize: true,
            wrapAround: true,
            prevNextButtons: false,
            pageDots: false,
            percentPosition: true,
            setGallerySize: true,
        });

        // Set initial position to be 0
        mainTicker.x = 0;

        // Start the marquee animation
        play();

        // Main function that 'plays' the marquee.
        function play() {
            // Set the decrement of position x
            mainTicker.x = mainTicker.x - 1.5;

            // Settle position into the slider
            mainTicker.settle(mainTicker.x);

            // Set the requestId to the local variable
            requestId = window.requestAnimationFrame(play);
        }

        // Main function to cancel the animation.
        function pause() {
            if(requestId) {
                // Cancel the animation
                window.cancelAnimationFrame(requestId)

                // Reset the requestId for the next animation.
                requestId = undefined;
            }
        }

        // Pause on hover/focus
        $(el).on('mouseenter focusin', e => {
            pause();
        })

        // Unpause on mouse out / defocus
        $(el).on('mouseleave', e => {
            play();
        })
    }
})
jshrssll commented 5 years ago

@roberrrt-s nice solution dude! Thanks for sharing 👍

theleeno84 commented 5 years ago

Is there still no option for continuous autoPlay scrolling after clicking on the slide?

discoliam commented 5 years ago

If anyone needs @roberrrt-s solution in Vanilla JS, I've re-worked it slighlty. Thanks for doing the hard work though :) Might not be perfect, but working for us at least.

const carousels = document.querySelectorAll('.carousel'), 
  args = {
    accessibility: true,
    resize: true,
    wrapAround: true,
    prevNextButtons: false,
    pageDots: false,
    percentPosition: true,
    setGallerySize: true,
  };

carousels.forEach((carousel) => {
  let requestId;

  if (carousel.childNodes.length > 3) {
    const mainTicker = new Flickity(carousel, args);

    // Set initial position to be 0
    mainTicker.x = 0;

    // Start the marquee animation
    play();

    // Main function that 'plays' the marquee.
    function play() {
      mainTicker.x = mainTicker.x - 1.5;
      mainTicker.settle(mainTicker.x);
      requestId = window.requestAnimationFrame(play);
    }

    // Main function to cancel the animation.
    function pause() {
      if (requestId) {
        window.cancelAnimationFrame(requestId)
        requestId = undefined;
      }
    }

    // Pause on mouse over / focusin
    carousel.addEventListener('mouseover', pause, false);
    carousel.addEventListener('focusin', pause, false);

    // Unpause on mouse out / focusout
    carousel.addEventListener('mouseout', play, false);
    carousel.addEventListener('focusout', play, false);

  }

});
srikat commented 5 years ago

Do any of these solutions do "pause on hover" on the continuously scrolling carousel?

roberrrt-s commented 5 years ago

@srikat Mine and @discoliam does.

srikat commented 5 years ago

@srikat Mine and @discoliam does.

Is the pause instant or after some delay?

cmalven commented 5 years ago

The above posted solutions work remarkably well. The only small issue I've found is that if you use this approach with prevNextButtons or pageDots enabled, Flickity never actually updates the slide index, and gets confused by the extreme x position when you try to navigate to a new slide.

A very quick glance at the Flickity source didn't uncover anything, but anyone know if Flickity provides any method that would help manually set the slide index based on x position on every requestAnimationFrame so Flickity will jump to the closest slide when navigated?

cmalven commented 5 years ago

Upon some farther investigation of the Flickity source (and lots of trial and error) I was able to solve the above pretty easily. Below is my "update" code, which runs in a requestAnimationFrame:

const _updateTicker = function() {
  flickity.x = (flickity.x - tickerAmount) % flickity.slideableWidth;
  flickity.selectedIndex = flickity.dragEndRestingSelect();
  flickity.updateSelectedSlide();
  flickity.settle(flickity.x);
  window.requestAnimationFrame(_updateTicker);
};

This was tested with the following settings:

autoPlay: false,
prevNextButtons: true,
draggable: true,
wrapAround: true
elliottmangham commented 5 years ago

@cmalven @roberrrt-s any chance anybody can stick a working example on CodePen/jsFiddle? Would appreciate seeing a working example!

Thanks a lot

cmalven commented 5 years ago

@elliottmangham

https://codepen.io/cmalven/pen/vqbJPM

Also includes pausing/playing of ticker when the slideshow is hovered.

elliottmangham commented 5 years ago

@elliottmangham

https://codepen.io/cmalven/pen/vqbJPM

Also includes pausing/playing of ticker when the slideshow is hovered.

You, sir, are a legend. Thanks for sharing.

desandro commented 4 years ago

Re-opening for visibility.

Add a 👍 reaction to this issue if you would like to see this feature added.

csjui commented 4 years ago

Following @koraysels pattern, I believe I found a really nice way to apply pause/play into his solution:

Boss! Thank you

joebentaylor1995 commented 4 years ago

Everybody wants this feature added, just add it 😂

yepecece commented 3 years ago

This great, thanks.

Also, do you know a way to implement a smooth pause on hover like here? https://brand.uber.com (Best-in-class examples section)

willslater commented 3 years ago

Has anybody managed to get this working on React JS?

I have the scrolling working, and play/pause is hooked up. However, the issue is with window.requestAnimationFrame(update); as it re-renders the component so even when it triggers, i have a new component rendered so its ignored and simply continues.

Any guidance or a nudge in the right direction would be appreciated.

willslater commented 3 years ago

The reason is that I was changing isPaused with state, that was waiting for the re render to use, but the re render was causing it to reset to initial value.

I changed to using ,

const isPaused = useRef(true);

and

if (isPaused.current) return;

and now it works.

ocripps24 commented 3 years ago

Has anyone managed to get @cmalven 's solution working with lazy loading? At present mine will only load the selected number of images defined by the lazyload option and then it fails to convert the data attribute into a src attribute for any unloading images.

mizzyexists commented 3 years ago

This honestly feels like an essential feature for a powerful slider like Flickity.

+1

tlhfckoctbcr commented 3 years ago

Must concur. I use this tool everywhere; this feature would be a gamechanger. Keep up the great work.

eduardopalmeida commented 2 years ago

The reason is that I was changing isPaused with state, that was waiting for the re render to use, but the re render was causing it to reset to initial value.

I changed to using ,

const isPaused = useRef(true);

and

if (isPaused.current) return;

and now it works.

Hi @willslater,

Can you explain how you managed to get "scrolling working, and play/pause is hooked up" ? Thanks so much.

eduardopalmeida commented 2 years ago

Hi, anyone got this working on a React project? Thanks

maximilianschmitt commented 2 years ago

If anybody is encountering jumpy movements on mobile browsers during scrolling. This is happens because the browser's viewport resizes when the mobile browser UI gets smaller/bigger, causing Flickity to resize itself.

To fix this, turn the resize option off. You might then need to programmatically tell flickity to resize itself when you deem it appropriate.

dangelion commented 2 years ago

They added this feature?

darslu commented 1 year ago

@elliottmangham

https://codepen.io/cmalven/pen/vqbJPM

Also includes pausing/playing of ticker when the slideshow is hovered.

maybe have any solution for slider with img when lazyloading? Right now is terrible shaking every time image is loaded

charlotteMARQ commented 1 year ago

has anyone figured out how to slow the speed for this down?