davidjerleke / embla-carousel

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

Add friction to configurable options #483

Closed riordanpawley closed 1 year ago

riordanpawley commented 1 year ago

Feature request is related to

Is your feature request related to an issue?

I want to be able to make the friction higher to better match ios picker

Describe the solution you'd like

Add ability to adjust numbers such as friction, dragSpeed, anything else...

davidjerleke commented 1 year ago

Hi @riordanpawley,

I'm going to assume that you missed this pinned information about creating issues. There's a good reason why I chose not to expose friction because it's pretty easy to destroy the carousel behaviour when not configured properly. I have zero spare time to handle a bunch of "false" bug reports from devs messing the carousel up, so I have to be smart and limit this sort of unnecessary work.

Having said that, you can change stuff in an unofficial way. For example, assuming dragFree: true just like the iOS picker example, you can adjust this (this code is from the iOS picker example):

emblaApi.on('pointerUp', () => {
  const { scrollTo, target, location } = emblaApi.internalEngine()
  const diffToTarget = target.get() - location.get()

  // This factor is multiplied with the drag force applied by the user
  // Adjust it to increase/decrease the distance each swipe scrolls the carousel
  const factor = Math.abs(diffToTarget) < WHEEL_ITEM_SIZE / 2.5 ? 10 : 0.1
  const distance = diffToTarget * factor
  scrollTo.distance(distance, true)
})

You can actually change friction and duration with emblaApi.internalEngine(). For example, you can intercept the pointerUp and select event in order to change the duration and friction:

emblaApi.on('pointerUp', (emblaApi) => {
  emblaApi.internalEngine().scrollBody.useFriction(0.68).useDuration(25)

  // or just:
  emblaApi.internalEngine().scrollBody.useFriction(0.68)
})

emblaApi.on('select', (emblaApi) => {
  emblaApi.internalEngine().scrollBody.useFriction(0.68).useDuration(25)

  // or just:
  emblaApi.internalEngine().scrollBody.useFriction(0.68)
})

If you choose to use this, please pay attention to what the documentation says about the internalEngine method:

Note: Please refrain from creating bug reports related to this method. If you're using this and running into problems, it's a 99.8% chance that you don't understand how this works. Use at your own risk.

Best, David