Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Continuously running carousel (ticker, marquee, ..) #114

Closed
openscript opened this issue Oct 31, 2020 · 31 comments · Fixed by #634
Closed

[Feat]: Continuously running carousel (ticker, marquee, ..) #114

openscript opened this issue Oct 31, 2020 · 31 comments · Fixed by #634
Labels
feature request New feature or request plugin Issue is related to plugins resolved This issue is resolved

Comments

@openscript
Copy link
Contributor

Hello everybody

I'm using Embla already in a project and it's great. Thank you for the amazing work!

Now I have the use case to build a carousel which runs continuously like a "stock market" ticker. So no speed up and slow down. Do you think it's easy to build something like that with Embla? Where would be a good starting point?

@davidjerleke
Copy link
Owner

davidjerleke commented Oct 31, 2020

Hello Robin (@openscript),

Thank you for your question.
Is the CodeSandbox in this conversation what you’re looking for?

Let me know if I understod you correctly and it did help.

Best,
David

@openscript
Copy link
Contributor Author

openscript commented Oct 31, 2020

Hello David (@davidjerleke)

Thank you for the very quick response.

The CodeSandbox shows exactly what I want, except that it doesn't start running after it has been dragged, but I think it's not to hard to implement this for the settle hook? :)

@davidjerleke
Copy link
Owner

davidjerleke commented Oct 31, 2020

Hi again Robin (@openscript),

Yes, I think the settle hook is appropriate for what you want to achieve. So something along these lines:

embla.on('settle', () => {
  /*
    Run the same code that scrolls the carousel slowly.
    You probably want to extract it into a reusable function.
  */
})

Please let me know if you have additional requirements or questions 🙂.

Kindly,
David

@davidjerleke davidjerleke added the awaiting response Issue is awaiting feedback label Oct 31, 2020
@openscript
Copy link
Contributor Author

openscript commented Oct 31, 2020

Hi again @davidjerleke

Thank you for taking the time and helping me out.

I've tried to implement it for a while, but I get very strange side-effects. I thought a video of the screen would be the easiest to show it:

https://drive.google.com/file/d/1rBKMEgZJFVjHT49NW9YL5_2PpxtwU3BJ/view

My code looks like this:

import styled from '@emotion/styled';
import { useEmblaCarousel } from 'embla-carousel/react';
import { EmblaCarousel } from 'embla-carousel/vanilla';
import { Engine } from 'embla-carousel/vanilla/components/engine';
import React, { useEffect } from 'react';

const Viewport = styled.section`
  overflow: hidden;
`;

const Container = styled.div`
  display: flex;
`;

const Slide = styled.div`
  position: relative;
  min-width: 100%;
`;

export type TickerProps = {};

export function Ticker() {
  const [tickerRef, ticker] = useEmblaCarousel({ loop: true, dragFree: true, containScroll: 'trimSnaps' });

  const startScrolling = (engine: Engine, ticker: EmblaCarousel) => {
    engine.scrollBody.useSpeed(0.01);
    engine.scrollTo.index((ticker.scrollSnapList().length || 0) - 1, -10);
  };

  useEffect(() => {
    const engine = ticker?.dangerouslyGetEngine();

    if (engine && ticker) {
      ticker?.on('settle', () => startScrolling(engine, ticker));

      startScrolling(engine, ticker);
    }
  }, [ticker]);

  return (
    <Viewport ref={tickerRef}>
      <Container>
        <Slide>111111111111</Slide>
        <Slide>222222222222</Slide>
        <Slide>333333333333</Slide>
      </Container>
    </Viewport>
  );
}

The direction parameter I set to -10 at engine.scrollTo.index I've chosen because with -1 the 'error' is barely visible. An observation I have made is, that the last slide (3) is getting slower and slower the closer it comes to the left end.

It is reproducible with this. It seems like the original has the same problem without my modifications. If you wait until it comes to the end, it is also getting slower and slower.

Greetings to the north,
Robin

@davidjerleke
Copy link
Owner

davidjerleke commented Nov 1, 2020

Hello Robin (@openscript),

Side note: I took the liberty to modify your latest comment, only to add syntax highlight to your code. I hope that was ok?

Thank you for the additional information. Seems like I might be misunderstanding you.

It seems like the original has the same problem without my modifications. If you wait until it comes to the end, it is also getting slower and slower.

The requirements mentioned in issue #105 was to show users that the content is scrollable. So the idea was to start scrolling automatically from the beginning and stop scrolling at the end of the content. The easing at the beginning and the end was not an issue there.

Let's go through your use case and requirements again. Is this what you're looking for?

  • The content should scroll automatically without any easing whatsoever as long as the carousel isn't dragged.
  • It should scroll and loop endlessly.
  • It should stop when the user drags the carousel, and start over when the carousel has settled.

Feel free to provide an example of what you want to achieve (share a link to a website or similar).

Thanks in advance,
David

@davidjerleke davidjerleke added investigating Issue is being looked into and removed awaiting response Issue is awaiting feedback labels Nov 1, 2020
@openscript
Copy link
Contributor Author

openscript commented Nov 1, 2020

Hello David (@davidjerleke)

It made me happy to see your kind reply. Thank you!

Yes, I think we are talking about the same use cases. Easing is not required, but it would maybe be nice for the speed up at the beginning and after dragging. Easing at the end doesn't make sense to me, if it's an endless loop.

I want to achieve something like on the Gatsby website, but with dragging:
image

Have a great day,

Robin

@davidjerleke
Copy link
Owner

davidjerleke commented Nov 1, 2020

Hi Robin (@openscript),

Thanks for the example link. That helps 🙂. I'll see if I can create a CodeSandbox for you, and I'll let you know how it goes when I've had the chance to do so.

Best,
David

@davidjerleke
Copy link
Owner

davidjerleke commented Nov 2, 2020

Hello again Robin (@openscript),

I've created a CodeSandbox for you. This sandbox basically re-creates the internal Embla animation loop without the easing. I haven't had the time to test this thoroughly so I'm going to leave that up to you. I hope that's ok.

Please let me know if it's working as expected.

Kindly,
David

@davidjerleke davidjerleke added awaiting response Issue is awaiting feedback and removed investigating Issue is being looked into labels Nov 2, 2020
@openscript
Copy link
Contributor Author

openscript commented Nov 2, 2020

Hi David (@davidjerleke)

Thank you so much! This is exactly what I wanted to achieve. It's pretty amazing that embla allows to configure this from outside.

Have a great day

Robin

@davidjerleke davidjerleke added question Question about how to achieve something resolved This issue is resolved and removed awaiting response Issue is awaiting feedback labels Nov 2, 2020
@filiptvarek
Copy link

Hello, this solution isn't working since version 4.4.0. Loop does not working properly. Is here any solution for 4.5.3 please? To reproduce it you can only swap version in your CodeSandobox or my modified version with 4.5.3 and faster scroll.

@davidjerleke
Copy link
Owner

Hi @filiptvarek,

Thanks for noticing this. It stopped working because I refactored some internal methods in later versions. I've updated the original CodeSandbox in this comment and it should work as expected now.

Cheers,
David

@filiptvarek
Copy link

filiptvarek commented Sep 16, 2021

It works. Thank you very much

@easydrops
Copy link

easydrops commented Jun 17, 2022

@ameliagroen @samdhoffman As for VanillaJS, I am fiddling around with this myself. Adapting the sandbox above, this seems to be working for me.
But tbh I am not very familiar with the requestAnimationFrame API. So I don't know if this might lead to any drawbacks.

let rafId = 0;

const animate = () => {
  const engine = embla.dangerouslyGetEngine();
  engine.location.add(-0.025); // controls the speed
  engine.target.set(engine.location);
  engine.scrollLooper.loop(-1);
  engine.slideLooper.loop();
  engine.translate.to(engine.location);
  rafId = requestAnimationFrame(animate)
}
const startAutoScroll = () => {
 rafId = requestAnimationFrame(animate)
}
const stopAutoScroll = () => {
  rafId = cancelAnimationFrame(rafId) || 0;
}
embla.on("settle", startAutoScroll);
embla.on("pointerDown", stopAutoScroll);
startAutoScroll();    

Hope this helps :)

@7iomka
Copy link

7iomka commented Oct 2, 2023

It is a pity that there is no official example that would be supported when the next update version is released.

@davidjerleke
Copy link
Owner

davidjerleke commented Oct 3, 2023

Hi @7iomka,

I don't doubt that you mean well, but I don't think it's helping. I'm the sole maintainer of this project and always have an insane backlog. This is what's been done for the upcoming v8.

If devs really want me to add more features/plugins, and if I'm to spend even more of my unpaid spare time than I already do, I have to be motivated by something. I want this comment to be constructive so here are ways to not just say I want this an that, but also ways to actually support this project:

  • ⭐ Star it if you already haven't, and you find yourself using it in multiple projects and you're overall satisfied with it.
  • 📣 Share it in social media like Reddit or similar.
  • 💰 Donate to this project.

More support means better chances for me to add more examples, more features and plugins.

Best,
David

@davidjerleke
Copy link
Owner

davidjerleke commented Nov 14, 2023

@Poylar, @dash-james, @AmeerSapadmi, @7iomka, @pedrobernardina, @abdulrauf11, @ameliagroen, @ruie, @samdhoffman:

There is a plugin being developed for this purpose that will be named embla-carousel-auto-scroll which at the time of writing is 80% complete. I'm hoping to be able to finish it soon:

@davidjerleke davidjerleke removed resolved This issue is resolved question Question about how to achieve something labels Nov 16, 2023
@Poylar
Copy link

Poylar commented Jan 12, 2024

hi, i would prefer react + js

@davidjerleke
Copy link
Owner

davidjerleke commented Jan 13, 2024

@Poylar and @mdrahiem thank you for considering testing this plugin. CodeSandboxes here:

React + JavaScript

React + TypeScript

Also may I know what test scenarios you want me to cover?

Please feel free to test it anyway you want. For example, you can read what the different options do below and test and see if they behave as expected. I will temporarily just dump the documentation page for the AutoScroll plugin below:


Documentation here

@mdrahiem
Copy link

Hello @davidjerleke I did test options and methods and below are the results.

Options:
✅ speed
✅ startDelay
✅ direction
✅ playOnInit
✅ stopOnInteraction
✅ stopOnMouseEnter
✅ stopOnFocusIn
❓ rootNode

Methods:
❌ play
✅ stop
❌ reset
❌ isPlaying

Events:
❓autoScroll:play
❓autoScroll:stop

✅ - Success ❓- Not sure how to test ❌ - Not working (I think)

For isPlaying I tried the below code.

     <div>
        status:{' '}
        {emblaApi?.plugins().autoScroll?.isPlaying()
          ? 'playing'
          : 'not playing'}
      </div>

For play, reset I tried with below code.

  const stopPlay = useCallback(
    (index) => {
      if (!emblaApi) return
      emblaApi.plugins().autoScroll?.stop()
      emblaApi.scrollTo(index)
    },
    [emblaApi]
  )

  const resumePlay = useCallback(
    (index) => {
      if (!emblaApi) return
      emblaApi.plugins().autoScroll?.play()
      emblaApi.scrollTo(index)
    },
    [emblaApi]
  )

  const resetPlay = useCallback(
    (index) => {
      if (!emblaApi) return
      emblaApi.plugins().autoScroll?.reset()
      emblaApi.scrollTo(index)
    },
    [emblaApi]
  )

      <button onClick={stopPlay}>Stop</button>
      <button onClick={resumePlay}>Resume</button>
      <button onClick={resetPlay}>Reset</button>

Please correct me if my above implementation is wrong for play, reset, isPlaying and I would be glad to test Events if I find some example. Thanks!

@davidjerleke
Copy link
Owner

Thanks a lot for testing @mdrahiem!

I will update the CodeSandbox with the playing state, events and demonstrate how to do it. Stay tuned 👍.

@mdrahiem
Copy link

Also an update on browsers.

✅ - Chromium Engine Version 120
✅ - Firefox 121.0
✅ - Safari Version 17.2.1

@davidjerleke
Copy link
Owner

@mdrahiem please check the CodeSandbox again, I've added the features you weren't sure about so you can see how it's intended to work.

Best,
David

@mdrahiem
Copy link

Thanks for updating the code @davidjerleke Below is the update on testing.

Methods:
✅ play
✅ stop
✅ isPlaying

Events:
✅ autoScroll:play
✅ autoScroll:stop

❌ reset - I was expecting the slider to be reset (start from slide 1) but what I see is, it stops for a while (because of startDelay) and then it plays from the same position. Please correct if my expectation is wrong.

❓ rootNode - I still couldn't find any implementation for this. I see the implementation in javascript version though. 😄

@davidjerleke
Copy link
Owner

@mdrahiem thank you for testing again 🙂!

❌ reset - I was expecting the slider to be reset (start from slide 1) but what I see is, it stops for a while (because of startDelay) and then it plays from the same position. Please correct if my expectation is wrong.

I think I need to update the description of what this does. That's valuable input, thanks 👍. The reset method does the following:

  • If auto scroll is scrolling, it stops.
  • When the carousel settles, the timer restarts using the startDelay option value.

It's useful when you're using previous/next buttons and want the carousel to continue after the user has navigated with the buttons and the carousel has settled. See here and here.


❓ rootNode - I still couldn't find any implementation for this. I see the implementation in javascript version though. 😄

This allows you to select a custom element that should listen for mouseenter and mouseleave, if you don't want the default Embla root node (which is the element you attach emblaRef to). It's used when stopOnMouseEnter is true.


Did these explanations make sense?

Best,
David

@mdrahiem
Copy link

Thank you so much for taking time and explaining these. They makes sense now 🙂

@davidjerleke
Copy link
Owner

@mdrahiem thanks for testing ⭐! The plugin will be released soon.

@mdrahiem
Copy link

Glad I could be of some help. Please feel free to tell me if I can contribute more in anyway. 🙂

@davidjerleke
Copy link
Owner

Thanks that's very kind of you @mdrahiem. @mdrahiem and anyone else reading this for that matter:

If you want to make contributions you can browse discussions with the label help wanted. We are happy to accept contributions from our users. For more details see the contributing guidelines.

After your pull request have been merged, you will automatically be added as a contributor here and here.

Best,
David

@davidjerleke davidjerleke changed the title Continuously running carousel (ticker, marquee, ..) [Feat]: Continuously running carousel (ticker, marquee, ..) Jan 25, 2024
davidjerleke added a commit that referenced this issue Jan 26, 2024
davidjerleke added a commit that referenced this issue Jan 26, 2024
[Feat]: Continuously running carousel (ticker, marquee, ..)
@davidjerleke davidjerleke added the resolved This issue is resolved label Jan 26, 2024
Repository owner deleted a comment from Github010101011 Jan 27, 2024
Repository owner deleted a comment from Github010101011 Jan 27, 2024
Repository owner deleted a comment from ameliagroen Jan 27, 2024
Repository owner deleted a comment from samdhoffman Jan 27, 2024
Repository owner deleted a comment from pedrobernardina Jan 27, 2024
Repository owner deleted a comment from abdulrauf11 Jan 27, 2024
Repository owner deleted a comment from ruie Jan 27, 2024
Repository owner deleted a comment from dash-james Jan 27, 2024
Repository owner deleted a comment from Poylar Jan 27, 2024
Repository owner deleted a comment from dcapitator Jan 31, 2024
@davidjerleke
Copy link
Owner

davidjerleke commented Jan 31, 2024

Update 2024-01-30 🎉

embla-carousel-auto-scroll has been released to the NPM registry!

Update 2024-01-29

The person in question unpublished their package but the NPM registry threw errors when I tried to publish embla-carousel-auto-scroll. I've contacted NPM support and they said that the package wasn't properly unpublished so they did that for me. Unfortunately, NPM say that I have to wait 24h before I can try publishing embla-carousel-auto-scroll again.

Update 2024-01-26

Sorry guys, was just about to publish this package (embla-carousel-auto-scroll), but someone has taken a too similar name so I've asked them to unpublish their package before I can release the official package:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request plugin Issue is related to plugins resolved This issue is resolved
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants