I am trying to implement a smooth scroll functionality using RXJS.
The following code scrolls smoothly but not as intended. it takes much longer time than the duration to reach the target.
Any idea how to fix it?
const scrollableEl = document.getElementById('view');
const btn = document.getElementById('testBtn');
btn.addEventListener('click', () => {
scrollTo(scrollableEl, 1000, 300);
});
function scrollTo(scrollableEl: HTMLElement, point: number, duration: number) {
timer(0, 20, animationFrame).pipe(
map((elapsedTime: number) => {
const delta = point - scrollableEl.offsetTop;
return {
top: easeInOutQuad(elapsedTime, scrollableEl.offsetTop, delta, duration),
elapsedTime
};
}),
tap((target) => {
console.log('scrollTo: ', target);
scrollableEl.scrollTop = target.top;
}),
// Stop timer
takeWhile((target: any) => target.elapsedTime < duration)
).subscribe();
}
Here is a reproduction: https://stackblitz.com/edit/rxjs-35vjhu
The timer
function doesn't emit elapsed time, its output is a sequence of numbers starting from 0: 0, 1, 2, 3 etc. I think you need to measure elapsed time yourself:
const startTime = new Date().getTime();
timer(0, 20, animationFrame).pipe(
map(() => {
const elapsedTime = new Date().getTime() - startTime;
const delta = point - scrollableEl.offsetTop;
return {
top: easeInOutQuad(elapsedTime, scrollableEl.offsetTop, delta, duration),
elapsedTime
};
}),
tap((target) => {
console.log('scrollTo: ', target);
scrollableEl.scrollTop = target.top;
}),
// Stop timer
takeWhile((target: any) => target.elapsedTime < duration),
).subscribe();
This is updated example: https://stackblitz.com/edit/rxjs-dr44gy