React-responsive-carousel: Vertical scroll on on mobile affects changes the slide

Created on 3 Sep 2019  Â·  15Comments  Â·  Source: leandrowd/react-responsive-carousel

Hi all.
I want to submit an issue.
When carousel is opened on a mobile, on android/chrome for example, vertical swiping on mobile screen causes carousel slide to be changed: swiped to next or prev.

bug help wanted good first issue

Most helpful comment

I am encountering the same issue. As a temporary fix, I am using the following:

let [swipeable, setSwipeable] = useState(true);

```javascript

useEffect(() => {
if (images.length) {
function disableScroll() {
let carousel = document.querySelector('.carousel');

            let startPos;
            let endPos;
            let isScrolling = 1;

            function touchMove(e) {
                if (
                    e.targetTouches.length > 1 ||
                    (e.scale && e.scale !== 1) ||
                    !startPos
                )
                    return;

                var touch = e.targetTouches[0];

                endPos = {
                    x: touch.pageX - startPos.x,
                    y: touch.pageY - startPos.y
                };
                isScrolling =
                    Math.abs(endPos.x) <= Math.abs(endPos.y)
                        ? 1
                        : 0; //When isScrolling is 1, it means vertical sliding and 0 is horizontal sliding
                if (isScrolling && swipeable) {
                    setSwipeable(false);
                }
            }

            function touchEnd() {
                setSwipeable(true);
                carousel.removeEventListener(
                    'touchmove',
                    touchMove
                );
            }

            function touchStart(e) {
                var touch = e.targetTouches[0]; //The touches array object gets all the touches on the screen, taking the first touch
                startPos = {
                    x: touch.pageX,
                    y: touch.pageY
                };

                carousel.addEventListener('touchmove', touchMove);
            }

            carousel.addEventListener('touchstart', touchStart);
            carousel.addEventListener('touchend', touchEnd);
        }


        disableScroll();
    }
}, [images, swipeable]);

```javascript
{!!images.length && (
 <Carousel
      swipeable={swipeable}
      showThumbs={false}
      swipeScrollTolerance={30}
 >
     {images.map(renderImage)}
</Carousel>
)}

It does make the scroll lag but works quite well on the production build in iOS. Not tested on Android

All 15 comments

The same thing happen is want to do up/down scroll, it will register as left/right as well.

Having the same issue .

I have this problem as well.

I am also having the same issue..

Same here

Same. Also getting an err:
react-swipe.js:226 [Intervention] Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted. ¯_(ツ)_/¯

To anyone having this issue, I've submitted a PR to the react-easy-swipe repo (also managed by leandrowd) to fix the error message mentioned by @swedenSnow, so you can look at that if you want it to stop spitting out the error, but if you want to stop the vertical swipes from switching the panels there is a prop on the carousel swipeScrollTolerance which takes a number (default is 5) to affect the sensitivity of scrolls till a swipe is created (my testing found 30 to be a good value, YMMV).

Hello,
I think that the transform CSS property should not happen if the swipe is kind of up and down...I've set the swipeScrollTolerance to 100...which indeed is preventing the slide switch from happening on touch end. The problem is that while touch move is active and you're swiping up or down but not perfectly up or down...the next or previous slide still show up a little until you release the touch.

So I think as long as the intent of the touch is up/down the transition should not even begin. You are probably checking the swipeScrollTolerance only on touch end....but by then the transform CSS property already happened.

same

swipeable={false} since nothing else helps.

I am encountering the same issue. As a temporary fix, I am using the following:

let [swipeable, setSwipeable] = useState(true);

```javascript

useEffect(() => {
if (images.length) {
function disableScroll() {
let carousel = document.querySelector('.carousel');

            let startPos;
            let endPos;
            let isScrolling = 1;

            function touchMove(e) {
                if (
                    e.targetTouches.length > 1 ||
                    (e.scale && e.scale !== 1) ||
                    !startPos
                )
                    return;

                var touch = e.targetTouches[0];

                endPos = {
                    x: touch.pageX - startPos.x,
                    y: touch.pageY - startPos.y
                };
                isScrolling =
                    Math.abs(endPos.x) <= Math.abs(endPos.y)
                        ? 1
                        : 0; //When isScrolling is 1, it means vertical sliding and 0 is horizontal sliding
                if (isScrolling && swipeable) {
                    setSwipeable(false);
                }
            }

            function touchEnd() {
                setSwipeable(true);
                carousel.removeEventListener(
                    'touchmove',
                    touchMove
                );
            }

            function touchStart(e) {
                var touch = e.targetTouches[0]; //The touches array object gets all the touches on the screen, taking the first touch
                startPos = {
                    x: touch.pageX,
                    y: touch.pageY
                };

                carousel.addEventListener('touchmove', touchMove);
            }

            carousel.addEventListener('touchstart', touchStart);
            carousel.addEventListener('touchend', touchEnd);
        }


        disableScroll();
    }
}, [images, swipeable]);

```javascript
{!!images.length && (
 <Carousel
      swipeable={swipeable}
      showThumbs={false}
      swipeScrollTolerance={30}
 >
     {images.map(renderImage)}
</Carousel>
)}

It does make the scroll lag but works quite well on the production build in iOS. Not tested on Android

Same problem

same :)

You can use preventMovementUntilSwipeScrollTolerance prop with swipeScrollTolerance={100}.

@ghariosk Thank you for the script.
I encountered an issue when swipable set to false, touchEnd function won't call, and it causes next swipe to be disabled.
I modified the script a little to fix that issue, and also made it less laggy.

  const [ swipeEnabled, setSwipeEnabled ] = useState(true)
  const [ touchEventsSet, setTouchEventsSet ] = useState(false)
  const swipeScrollTolerance = 30

  useEffect(() => {
    if (images.length) {
      const disableScroll = () => {
        let carousel = document.querySelector('.carousel')

        let startPos
        let endPos
        let isScrolling
        let passedSwipeScrollTolerance = false

        function touchMove(e) {
          if (
            e.targetTouches.length > 1 ||
            ( e.scale && e.scale !== 1 ) ||
            !startPos
          ) {
            return
          }

          if (!passedSwipeScrollTolerance && swipeEnabled) {
            const touch = e.targetTouches[ 0 ]
            endPos = {
              x: Math.abs(touch.pageX - startPos.x),
              y: Math.abs(touch.pageY - startPos.y),
            }
            passedSwipeScrollTolerance = endPos.x > swipeScrollTolerance

            isScrolling = endPos.x < endPos.y //When isScrolling it means vertical sliding
            if (isScrolling) {
              setSwipeEnabled(false)
            }
          }
        }

        function touchEnd() {
          setSwipeEnabled(true)
          passedSwipeScrollTolerance = false
          carousel.removeEventListener('touchmove', touchMove)
        }

        function touchStart(e) {
          const touch = e.targetTouches[ 0 ] //The touches array object gets all the touches on the screen, taking the first touch
          startPos = {
            x: touch.pageX,
            y: touch.pageY,
          }

          carousel.addEventListener('touchmove', touchMove)
        }

        if (!touchEventsSet) {
          carousel.addEventListener('touchstart', touchStart)
          carousel.addEventListener('touchend', touchEnd)
          setTouchEventsSet(true)
        }

        if (!swipeEnabled) {
          setSwipeEnabled(true)
          passedSwipeScrollTolerance = false
        }
      }

      disableScroll()
    }
  }, [ images, swipeEnabled ])
{Boolean(images.length) && (
 <Carousel
      swipeable={swipeEnabled}
      showThumbs={false}
 >
     {images.map(renderImage)}
</Carousel>
)}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

kartikeyb picture kartikeyb  Â·  5Comments

anhkhoi picture anhkhoi  Â·  6Comments

anoush-soghomonyan picture anoush-soghomonyan  Â·  6Comments

LeopoldLerch picture LeopoldLerch  Â·  5Comments

ledbetterljoshua picture ledbetterljoshua  Â·  6Comments