ylsv
ylsv

Reputation: 123

How to drag carousel on swipe in React

I'm a junior dev and am struggling with an issue where there is a carousel with about 10 cards on top of the page. All cards do not fit at once on the screen, so there are 2 arrows in the corner to scroll them (arrow left and arrow right). When you click arrow right, the cards scroll to the end and when you click arrow left they move backwards from right to left.

How can I make it that when you click mouse down and hold the images and drag them they move left or right? I need to make them move not only with arrow clicks but with mouse drag also... Do i need to use some library (i found react-hammerjs, but didn't find any good docs/examples how to use it)? Thank you in advance for your help

Here's some code to reference:

export const CardsBlock = () => {
  const scrollContainer = useRef(null)
  const [scrolled, setScrolled] = useState(false)
  const dispatch = useDispatch()

  useEffect(() => {
    const resizeListener = (e) => {
      if (e.target.outerWidth <= sizes.mobile) {
        setScrolled(null)
      } else {
        setScrolled(false)
      }
    }
    window.addEventListener('resize', resizeListener)
    return () => {
      window.removeEventListener('resize', resizeListener)
    }
  }, [])


  useEffect(() => {
    if (scrolled) {
      scrollTo(scrollContainer.current, scrollContainer.current.offsetWidth)
    } else {
      scrollTo(scrollContainer.current, 0)
    }
  }, [scrolled])

  return (
    <Well>
      <Container>
        <Wrapper padding={'0 0 16px'} justify={'space-between'} align={'center'}>
          <TitleText width={'auto'}>{translator('specilization.title', true)}</TitleText>
          <ArrowsContainer>
            <Icon
              onClick={() => setScrolled(false)}
              cursor={'pointer'}
              type={'arrow_left'}
              color={scrolled ? 'black4' : 'black1'}
            />
            <Icon
              onClick={() => setScrolled(true)}
              cursor={'pointer'}
              type={'arrow_right'}
              color={scrolled ? 'black1' : 'black4'}
            />
          </ArrowsContainer>
        </Wrapper>
        <SpecializationsInnerContainer ref={scrollContainer}>
          {specializations.map((specialization) =>
            <SpecializationCard
              key={specialization.id}
              image={specialization.image}
              title={specialization.title}
              color={'black1'}
              borderColor={'transparent'}
              onClick={() => handleOnClick(specialization.id)}
            />
          )}
          <SpecializationCard borderColor={'black15'} image={'image.png'} isAll onClick={openSpecializationFilter} title={translator('specilization.all', true)} color={'transparent'}/>
        </SpecializationsInnerContainer>
      </Container>
    </Well>
  )
}

Upvotes: 1

Views: 13901

Answers (2)

ylsv
ylsv

Reputation: 123

During more research found an answer in 'react-swipeable' npm module https://www.npmjs.com/package/react-swipeable

As the arrow icons onclick logic is already defined here, added the same logic to react swipeable component:

       <Swipeable onSwipedLeft={() => setScrolled(true)} onSwipedRight={() => setScrolled(false)} trackMouse={true}>
        <SpecializationsInnerContainer ref={scrollContainer}>
          {specializations.map((specialization) =>
            <SpecializationCard
              key={specialization.id}
              image={specialization.image}
              title={specialization.title}
              color={'black1'}
              borderColor={'transparent'}
              onClick={() => handleOnClick(specialization.id)}
            />
          )}
          <SpecializationCard borderColor={'black15'} image={'image.png'} isAll onClick={openSpecializationFilter} title={translator('specilization.all', true)} color={'transparent'}/>
        </SpecializationsInnerContainer>
       </Swipeable>

Upvotes: 1

Bojan
Bojan

Reputation: 140

Since you did not provide any snippet or source code, here is some basic example. It should get you started.

const slider = document.querySelector('.items');
let isDown = false;
let startX;
let scrollLeft;

slider.addEventListener('mousedown', (e) => {
  isDown = true;
  startX = e.pageX - slider.offsetLeft;
  scrollLeft = slider.scrollLeft;
});

slider.addEventListener('mouseleave', () => {
  isDown = false;
});

slider.addEventListener('mouseup', () => {
  isDown = false;
});

slider.addEventListener('mousemove', (e) => {
  if(!isDown) return;
  e.preventDefault();
  const x = e.pageX - slider.offsetLeft;
  const walk = (x - startX) * 3; //scroll-fast
  slider.scrollLeft = scrollLeft - walk;
});

https://codepen.io/toddwebdev/pen/yExKoj

Upvotes: 7

Related Questions