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>
);
};