0

Why cancelAnimationFrame () doesn't stop animation on MouseDown event? But animation stops triggered by a second click. What could be the problem? And is there a way, after premature stopping the animation, to return the current "cur" and "rez" values from the "animate function"?

Full version of the code. https://codesandbox.io/s/peaceful-silence-bm6hx?file=/src/scroll.js

const Scrollable = (props) => {
  const items = props.items;

  let ref = useRef();
  let refAnimation = useRef();

  const [state, setState] = useState({
    isScrolling: false,
    clientX: 0, //Position of the mouse on the object
    scrollX: 0 //Position of the propelled object
  });
  const [touchStart, setTouchStart] = useState(0);

  const onMouseDown = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();
    ///////////////-----------------////////////////
    cancelAnimationFrame(refAnimation.current);
    //////////////------------------///////////////
  };

  /////////Mouse Move Event///////////
  const onMouseMove = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();
    

    if (isScrolling === true) {
      let sX = scrollX - e.clientX + clientX;
      let cX = e.clientX;


        ref.current.scrollLeft = scrollX - e.clientX + clientX;
        setState({
          ...state,
          scrollX: sX,
          clientX: cX
        });
    }
  };

  /////Mouse UP Event/////
  const onMouseUp = (e) => {
    if (ref && ref.current && !ref.current.contains(e.target)) {
      return;
    }
    e.preventDefault();

    let touchShift = touchStart - state.clientX;
    let rez;
    let shift;


    if (touchShift < 0) {
      shift = 300 + touchShift;
      rez = state.scrollX - shift;
      let speed = shift / 400;
      let cur = state.scrollX;

      if (rez <= -300) {
        setState({
          ...state,
          isScrolling: false
        });
      } else {
        refAnimation.current = requestAnimationFrame(() =>
          animate(cur, speed, rez, "left")
        );
      }
    }

    if (touchShift > 0) {
      ...
    }

    if (touchShift === 0) {
      setState({
        ...state,
        isScrolling: false
      });
    }
  };

  //////A callable function that should do the animation
  const animate = (cur, speed, rez, dir = "left", callback) => {
    refAnimation.current = requestAnimationFrame(() =>
      animate(cur, speed, rez, dir)
    );
    cur = dir === "left" ? cur - speed : cur + speed;
    ref.current.scrollLeft = cur.toFixed(2);
    
    if (Math.round(cur) === rez) {
      cancelAnimationFrame(refAnimation.current);
      setState({
        ...state,
        scrollX: rez,
        isScrolling: false
      });
    }
  };

  /////////////////////////////////////////

  useEffect(() => {
    document.addEventListener("mousedown", onMouseDown);
    document.addEventListener("mouseup", onMouseUp);
    document.addEventListener("mousemove", onMouseMove);
    return () => {
      document.removeEventListener("mousedown", onMouseDown);
      document.removeEventListener("mouseup", onMouseUp);
      document.removeEventListener("mousemove", onMouseMove);
    };
  });
  useEffect(() => {
    if (ref.current === true) {
      refAnimation.current = requestAnimationFrame(() => animate(0, 0, 0));
    }
    return () => {
      cancelAnimationFrame(refAnimation.current);
    };
  }, []);


  return (
    <div className={classes.charPage}>
      <div
        className={classes.items}
        ref={ref}
        onMouseDown={onMouseDown}
        onMouseUp={onMouseUp}
        onMouseMove={onMouseMove}
      >
      </div>
    </div>
  );
};
Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
Dio
  • 245
  • 3
  • 15

1 Answers1

0

In the event to which the animation is attached, before calling the animation again, you must first clear the old one using the function --> cancelAnimationFrame(refAnimation.current)

   else {      

cancelAnimationFrame(refAnimation.current)

    refAnimation.current = requestAnimationFrame(() =>
      animate(cur, speed, rez, "left")
    );
Dio
  • 245
  • 3
  • 15