metafizzy / flickity

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

Add autoPlay events: play, stop, pause, unpause #429

Open evolutionxbox opened 8 years ago

evolutionxbox commented 8 years ago

I have a playpause button, which I'd like to update the icon of, when the player paused state has changed.

Currently I cannot find any events for the player, and I'd like to suggest adding play, stop, pause, and unpause events.

For example:

// jQuery
$carousel.on( 'play.flickity', function() {
  console.log( 'Flickity player playing')
})
// vanilla JS
flkty.on( 'play', function() {...})
evolutionxbox commented 8 years ago

After some investigating, I don't think the unpause event should be included, as all it only invokes the play method.

desandro commented 8 years ago

Thank you for this feature request. Add a 👍 reaction if you'd like to see this feature added to Flickity.


For now, you can hack in these events by adding this code:

[ 'play', 'stop', 'pause', 'unpause' ].forEach( function( action ) {
  var methodName = action + 'Player';
  Flickity.prototype[ methodName ] = function() {
    this.player[ action ]();
    this.dispatchEvent( methodName );
  };
});

You can then listen for events: playPlayer, stopPlayer, pausePlayer, unpausePlayer.

desandro commented 6 years ago

autoPlay is designed to stop and stay stopped any time the user interacts with the carousel. This gives user control and does not take it away from the user. On mobile, there is no hover event so there is no way to detect when a cursor has exited the carousel.

That said, some developers still would like a way to resume autoPlay after being stopped for a period of time. If you wish to implement that behavior, you can do so with your own JS and the Flickity API.

Here is one solution that will always resume after being stopped for 3 seconds 🚨 even if the user has interacted with the carousel 🚨

// overwrite stopPlayer method
Flickity.prototype.stopPlayer = function() {
  this.player.stop();
  // always resume play after 3 seconds
  setTimeout( () => {
    this.player.play();
  }, 3000 )
};
daGUY commented 5 years ago

Although there are no play/pause events emitted, you can still read the current state of the player from the Flickity instance and update your play/pause button accordingly, like this:

var flkty = $carousel.data("flickity"),
    $playPause = $carousel.find(".play-pause");

$playPause.on("click", function () {
    if (flkty.player.state === "playing") {
        $carousel.flickity("stopPlayer");
        // logic to show play icon here
    } else {
        $carousel.flickity("playPlayer");
        // logic to show pause icon here
    }
});
kubik101 commented 7 months ago

Hi Guys.

I have been using Flickity for a long time and everything I do is from scratch. I am in no way a hard core coder, but I am continuing to learn and improve daily.

I have just started paying attention to how things load and have been refining my setup.

Currently focusing on how things load into the page (lazyload) and also, which is relevant to this post, improving my AutoPlay intersection observer (only when on screen).

I wanted to re-enable the autoPlay after user interaction, but in my case only after you scroll down and come back up (intersection observer).

This post helped me coz I needed to know what state the player was in, I have this in place now and I am hoping that my solution may help someone else.

/* **********************************************************
    Flickity Function
********************************************************** */

function flickityCarousel() {
    // <div class="carousel my-carousel" data-auto-play="true|false">
    var $myCarousel = jQuery('.my-carousel')
    $myCarousel.flickity({
        cellAlign: 'left',
        contain: true,
        groupCells: true,
        imagesLoaded: true,
        autoPlay: 6000,
        pauseAutoPlayOnHover: true,
        arrowShape:
            'm51.08,100c.67,0,1.34-.26,1.85-.77,1.02-1.02,1.02-2.68,0-3.7L7.4,50,52.93,4.46c1.02-1.02,1.02-2.68,0-3.7s-2.68-1.02-3.7,0L0,50l49.23,49.23c.51.51,1.18.77,1.85.77Z',
        on: {
            ready: function () {
                // setting timeout coz without flickit is not intialised
                setTimeout(() => {
                    // pausing straight away coz myAutoPlayFlickity will handle the playing if set to AutoPlay
                    $myCarousel.flickity('pausePlayer')
                }, 0)
            },
        },
    })
    //
}

/* **********************************************************
    AutoPlay Flickity When in View
********************************************************** */

function myAutoPlayFlickity() {
    // find by attribute: <div class="carousel my-carousel" data-auto-play="true|false">
    const autoPlayCarousels = document.querySelectorAll('[data-auto-play]')
    // check if exists
    if (!autoPlayCarousels) return
    // observer
    var observer = new IntersectionObserver(
        function (entries) {
            entries.forEach(entry => {
                // vars
                var isAutoPlay = entry.target.dataset.autoPlay
                var flkty = new Flickity(entry.target, {})
                // if set to autoplay
                if (isAutoPlay) {
                    if (entry.isIntersecting) {
                        // user interaction stops player, so we check if it's stopped and play it again if so
                        // https://github.com/metafizzy/flickity/issues/429
                        if (flkty.player.state === 'stopped') {
                            flkty.playPlayer()
                        } else {
                            flkty.unpausePlayer()
                        }
                    } else {
                        flkty.pausePlayer()
                    }
                } else {
                    // because autoPlay is alway on in flickity options we stop it if data-auto-play="false"
                    flkty.stopPlayer()
                }
                // end
            })
        },
        {
            threshold: 0.8, // how much visible: determines when to pause etc.. eg: 0.2 (up to 1)
        }
    )
    // carousels
    autoPlayCarousels.forEach(carousel => {
        observer.observe(carousel)
    })
    // end
}

/* **********************************************************
    Doc Ready
********************************************************** */

document.addEventListener('DOMContentLoaded', function () {
    flickityCarousel()
    myAutoPlayFlickity()
})