// smooth scroll // only for special usage of lrc maker export default ((): void => { const duration = 468; const getNow = performance || Date; const ease = (k: number): number => { return 0.5 * (1 - Math.cos(Math.PI * k)); }; interface IContext { method: (x: number, y: number) => void; startTime: number; startX: number; startY: number; stopY: number; } const rafID = { current: 0, }; const cancelScroll = (): void => { cancelAnimationFrame(rafID.current); cleanEventListener(); }; const listenerOptions = { passive: true, once: true, }; const atachEventListener = (): void => { window.addEventListener("wheel", cancelScroll, listenerOptions); window.addEventListener("touchmove", cancelScroll, listenerOptions); }; const cleanEventListener = (): void => { window.removeEventListener("wheel", cancelScroll); window.removeEventListener("touchmove", cancelScroll); }; const step = (context: IContext): void => { const time = getNow.now(); const { startTime, startX, startY, stopY } = context; const elapsed = (time - startTime) / duration; if (elapsed >= 1) { context.method(startX, stopY); cleanEventListener(); return; } // apply easing to elapsed time const value = ease(elapsed); const currentY = startY + (stopY - startY) * value; context.method(startX, currentY); if (currentY !== stopY) { rafID.current = requestAnimationFrame(() => step(context)); } }; const scrollingElement = document.scrollingElement || document.documentElement; Element.prototype.scrollIntoView = function (): void { const { top, bottom } = this.getBoundingClientRect(); const center = (top + bottom) / 2; const viewportHeight = window.visualViewport ? window.visualViewport.height : innerHeight; const startX = scrollingElement.scrollLeft; const startY = scrollingElement.scrollTop; const stopY = startY + center - viewportHeight / 2; cancelAnimationFrame(rafID.current); atachEventListener(); step({ method: (x: number, y: number) => window.scroll(x, y), startTime: getNow.now(), startX, startY, stopY, }); }; })();