From 514f91f8dc1eee8f3e1c6ef7c9cef6776c3b86d7 Mon Sep 17 00:00:00 2001 From: Shin'ya Ueoka Date: Mon, 11 Feb 2019 19:54:54 +0900 Subject: [PATCH] Make smooth-scroll smoother --- src/content/scrolls.js | 95 +++++++++++++----------------------------- 1 file changed, 30 insertions(+), 65 deletions(-) diff --git a/src/content/scrolls.js b/src/content/scrolls.js index b9a4bc3..e4431ec 100644 --- a/src/content/scrolls.js +++ b/src/content/scrolls.js @@ -2,10 +2,10 @@ import * as doms from 'shared/utils/dom'; const SCROLL_DELTA_X = 48; const SCROLL_DELTA_Y = 48; -const SMOOTH_SCROLL_DURATION = 150; // dirty way to store scrolling state on globally -let scrolling = [false]; +let scrolling = false; +let lastTimeoutId = null; const isScrollableStyle = (element) => { let { overflowX, overflowY } = window.getComputedStyle(element); @@ -51,65 +51,27 @@ const scrollTarget = () => { return window.document.documentElement; }; +const resetScrolling = () => { + scrolling = false; +}; + class SmoothScroller { - constructor(element, repeat) { + constructor(element) { this.element = element; - this.repeat = repeat; - this.scrolling = scrolling; - if (repeat) { - this.easing = SmoothScroller.linearEasing; - } else { - this.easing = SmoothScroller.inOutQuadEasing; - } } scroll(x, y) { - if (this.scrolling[0]) { - return; - } - scrolling[0] = true; - - this.startX = this.element.scrollLeft; - this.startY = this.element.scrollTop; - - this.targetX = x; - this.targetY = y; - this.distanceX = x - this.startX; - this.distanceY = y - this.startY; - this.timeStart = 0; - - window.requestAnimationFrame(this.loop.bind(this)); - } - - loop(time) { - if (!this.timeStart) { - this.timeStart = time; + window.scrollTo({ + left: x, + top: y, + behavior: 'smooth', + }); + scrolling = true; + if (lastTimeoutId) { + clearTimeout(lastTimeoutId); + lastTimeoutId = null; } - - let elapsed = time - this.timeStart; - let v = this.easing(elapsed / SMOOTH_SCROLL_DURATION); - let nextX = this.startX + this.distanceX * v; - let nextY = this.startY + this.distanceY * v; - - window.scrollTo(nextX, nextY); - - if (elapsed < SMOOTH_SCROLL_DURATION) { - window.requestAnimationFrame(this.loop.bind(this)); - } else { - scrolling[0] = false; - this.element.scrollTo(this.targetX, this.targetY); - } - } - - static inOutQuadEasing(t) { - if (t < 1) { - return t * t; - } - return -(t - 1) * (t - 1) + 1; - } - - static linearEasing(t) { - return t; + lastTimeoutId = setTimeout(resetScrolling, 100); } } @@ -123,9 +85,9 @@ class RoughtScroller { } } -const scroller = (element, smooth, repeat) => { +const scroller = (element, smooth) => { if (smooth) { - return new SmoothScroller(element, repeat); + return new SmoothScroller(element); } return new RoughtScroller(element); }; @@ -135,32 +97,35 @@ const getScroll = () => { return { x: target.scrollLeft, y: target.scrollTop }; }; -const scrollVertically = (count, smooth, repeat) => { +const scrollVertically = (count, smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = target.scrollTop + SCROLL_DELTA_Y * count; - if (repeat && smooth) { + if (scrolling) { y = target.scrollTop + SCROLL_DELTA_Y * count * 4; } - scroller(target, smooth, repeat).scroll(x, y); + scroller(target, smooth).scroll(x, y); }; -const scrollHorizonally = (count, smooth, repeat) => { +const scrollHorizonally = (count, smooth) => { let target = scrollTarget(); let x = target.scrollLeft + SCROLL_DELTA_X * count; let y = target.scrollTop; - if (repeat && smooth) { + if (scrolling) { y = target.scrollTop + SCROLL_DELTA_Y * count * 4; } - scroller(target, smooth, repeat).scroll(x, y); + scroller(target, smooth).scroll(x, y); }; -const scrollPages = (count, smooth, repeat) => { +const scrollPages = (count, smooth) => { let target = scrollTarget(); let height = target.clientHeight; let x = target.scrollLeft; let y = target.scrollTop + height * count; - scroller(target, smooth, repeat).scroll(x, y); + if (scrolling) { + y = target.scrollTop + height * count * 4; + } + scroller(target, smooth).scroll(x, y); }; const scrollTo = (x, y, smooth) => {