Search code examples
reactjsanimationreact-springframer-motion

When ViewPager move to next slide then previous slide should decrease opacity value for every move


My requirement is when ViewPager click and drag image for next image then previous image should decrease opacity for every drag. This is my codesandbox code.

This image is small example of my requirement.

ViewPager

import React, { useRef } from 'react'
import clamp from 'lodash-es/clamp'
import { useSprings, animated } from 'react-spring'
import { useDrag } from 'react-use-gesture'
import './styles.css'

function Viewpager() {
  const index = useRef(0)

  const [props, set] = useSprings(alphabets.length, i => ({
    x: i * window.innerWidth,
    scale: 1,
    opacity: 1,
    display: 'block'
  }))
  const bind = useDrag(({ active, down, movement: [mx], direction: [xDir], distance, cancel }) => {
    set(i => {
      if (i < index.current - 1 || i > index.current + 1) return { display: 'none' }
      const x = (i - index.current) * window.innerWidth + (down ? mx : 0)
      const scale = down ? 1 - distance / window.innerWidth / 2 : 1
      const opacity = active ? distance * 0.01 : 1
      return { x, scale, opacity, display: 'block' }
    })
  })

  return props.map(({ x, display, scale, opacity }, i) => (
    <animated.div
      {...bind()}
      key={i}
      style={{
        opacity,
        display,
        x
      }}
    />
  ))
}

I need same functionality like codesandbox code and reduce opacity parallely when drag card to other card. If Anyone have any other solution in other library like framer-motion. That is also helpful.


Solution

  • You should interpolate the x value to the opacity. The x value is between 0 and negative innerWitdh / 2. You should transfer it to get a value between 1 to 0.

    Here is the working formula.

    opacity: x.to(x => 1 + x / (window.innerWidth / 2)),
    

    Here is the example: https://codesandbox.io/s/card-slider-jwf3f

    Side Note:

    You can check, the formula easily if you display it on screen. All you have to do is put it as the text of an animated.div. For example:

     <animated.div>{x.to(x => 1 - Math.abs(x / (window.innerWidth / 2)))}</animated.div>