davidjerleke / embla-carousel

A lightweight carousel library with fluid motion and great swipe precision.
https://www.embla-carousel.com
MIT License
5.91k stars 177 forks source link

Discuss/Question: Is it possible to do windowing with the carousel #120

Closed arihantverma closed 3 years ago

arihantverma commented 3 years ago

Hello!

Is it possible to do windowing, if a carousel has lot of items? Say an image gallery which has a lot of (>300) images

davidjerleke commented 3 years ago

Hello Arihant (@arihantverma),

Thank you for your question. I'm not quite understanding the feature request. Would you mind sharing an example of this? Like a link to a demo page or similar.

Kindly, David

arihantverma commented 3 years ago

Hey David!

Yes sure!

There are instances on one of our pages in our product, where there are a LOT of DOM nodes on the ( product listing ) page. We've tried to mitigate the performance overhead with react-window. React window shows only those dom nodes that are currently in the browser/parent container viewport and keeps hiding the ones that go outside of the container, showing new ones as the user scrolls. This way DOM remains light since it only shows the nodes which are in the container viewport.

On that page itself, we also have a carousel where a LOT of user generated ( hotel ) images are shown. They range from a couple of hundreds to more in some cases. We were exploring ways in which we could do windowing with embla carousel.

I had been trying to do it with react-window itself, but have not yet been able to successfully do it because of the extra html elements and styles that react-window injects in order to function properly.

Here's an example of horizontal 'windowing' from react-window docs. I want to do something similar but with embla.

Would it be a valid use case to support windowing inherently with embla?

Does this make sense? If not I'll try to me more clear.

Regards, Arihant

davidjerleke commented 3 years ago

Hello again Arihant (@arihantverma),

Thanks for the clarification 👍.

I think what you're asking for is quite achievable with Embla, by utilizing its API. But I'm not sure it makes sense to add this as a feature to the core, because it will add to the bundle weight and burden users that don't need this feature.

Here's what I would try in order to achieve this:

This would be my To Do in code:

let lastScrollProgress = embla.scrollProgress()
let loopCounter = 0

embla.on('scroll', () => {
  // Get the current scroll progress
  // Compare with the last scroll progress to determine scroll direction.
  // If the scroll progress starts over we know that the carousel has looped.
  // In that case, increment or decrement the loop counter variable.
  // Replace the slide content for slides that are out of view.
})

Right now, I have tons to do so I don't know when I'll be able to create a CodeSandbox demonstrating this.

Best, David

arihantverma commented 3 years ago

Hey @davidjerleke

Thank you for the explanation! This really helps. I get the point that adding it as a feature doesn't make sense, because that's how embla carousel is made - giving the bare bones api to enable developers to make features on top of it.

I'll try making a codesandbox if I'm able to get it working meanwhile, and wait for you to provide one whenever you can.

Thanks again!

Best Arihant

arihantverma commented 3 years ago

Hey David @davidjerleke

I tried, understood what needs to be done, but haven't been able to wrap my head around how to do it 😔. If you could find time, given that you were busy before, would appreciate your help here, if you could.

Best, Arihant

davidjerleke commented 3 years ago

Hi Arihant (@arihantverma),

I understand. Thanks for letting me know. I'll see when I have time to work on this, and will let you know when I have something.

Best, David

cliffordfajardo commented 3 years ago

@davidjerleke @arihantverma - I was also thinking about the multiple items per slide too. Note: this doesn't address the windowing stuff you talked about. Specifically this is an example of creating multiple pages per slides, which seemed relevant here, and just in case other people run into this thread as well.

I have a code sandbox demo here at my attempt:

One way I was able to achieve this to create a utility method to split an array of flat items into sub arrays.

/*
 * const items = [item1, item2, item3, item4, item5, item6]
 * let slides = createMultiItemSlides(items);
 * slides === [[item1, item2], [item3, item4], [item5, item6]]
 */
export const createMultiItemSlides = <T,>(list: Array<T>, itemsPerSlide: number) => {
  return list.map((item, index, list) => {
    const page = index % itemsPerSlide === 0 ? list.slice(index, index + itemsPerSlide) : null;
    return page;
  })
  .filter((array) => array !== null)
}

/*
 * @description
 * Given a list of items, restructure the original flat list of items
 * into sub arrays, where each sub array will contain `itemsPerSlide`
 * items in them.
 * 
 * The reason why we need this utility is to create a carousel with multiple
 * items per slide.
 * 
 * The problem:
 * Passing a 1 dimensional list like this one: [item1, item2, item3, item4, item5, item6]
 * to our carousel won't work if our goal is to have multiple items per slide.
 * 
 * Most carousel API's  expect you to define the width of each item. Given my flat list of items above,
 *  if I said, make each slide item 33% (3 per page), what will happen is
 * the slide items will have huge gaps between them so they meet the 33% width rule.
 * 
 * Potential solution:
 * Say I want to show 2 items per slide without the huge gaps in between the items and I have an array of 6 items
 * const list = [item1, item2, item3, item4, item5, item6]
 * 
 * I need transform the array to this: [[item1, item2], [item3, item4], [item5, item6]].
 * Each item in the array now represents a slide.
 * 
 * Each slide itself will be 100%. So when I hit 'next' in my carousel, it will shift the entire
 * slide to the next set of items. 
 */
kaufmann42 commented 1 year ago

Any follow up here? I think this would be a valuable feature. Web performance and audits are becoming a mainstay here and carousels that have features such as this are going to win out @davidjerleke

davidjerleke commented 1 year ago

Hi @kaufmann42,

Thank you for your question. Embla has a plugin system so why don't you create a virtualising/windowing plugin? With the Embla API you already have the information about what slides are in view or not:

You can check out the embla-carousel-class-names plugin to see how to structure an Embla plugin.

Best, David

zhondori commented 3 months ago

Helo Everyone.

I made a virtualized carousel using Embla Carousel React.

Here is the code

IgnisDa commented 2 months ago

@zhondori Would it be possible for your to publish this as a package? Totally understandable if not. Thanks for the code snippet!

zhondori commented 2 months ago

@zhondori Would it be possible for your to publish this as a package? Totally understandable if not. Thanks for the code snippet!

I will try

IgnisDa commented 2 months ago

Thanks! That would be awesome! I would be really grateful if you could do that and inform me with the name of the npm package.

LMK if you need help with testing etc/