diff options
author | Shin'ya Ueoka <ueokande@i-beam.org> | 2019-02-11 20:11:13 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-11 20:11:13 +0900 |
commit | 21788740c1d4ee28ce05d6bd09d37901d1d88b68 (patch) | |
tree | 862f9d057b029a2cd0703f2b6087a2c1c0fb10b5 /src/content/scrolls.js | |
parent | b5a85ad059c45f6cdde432d656888710595d68a5 (diff) | |
parent | 68668cfefa3d2e90564c381f9f55167df75e4a75 (diff) |
Merge pull request #536 from ueokande/make-smooth-scroll-smoother
Make smooth-scroll smoother
Diffstat (limited to 'src/content/scrolls.js')
-rw-r--r-- | src/content/scrolls.js | 137 |
1 files changed, 57 insertions, 80 deletions
diff --git a/src/content/scrolls.js b/src/content/scrolls.js index b9a4bc3..a307aa7 100644 --- a/src/content/scrolls.js +++ b/src/content/scrolls.js @@ -1,11 +1,11 @@ import * as doms from 'shared/utils/dom'; -const SCROLL_DELTA_X = 48; -const SCROLL_DELTA_Y = 48; -const SMOOTH_SCROLL_DURATION = 150; +const SCROLL_DELTA_X = 64; +const SCROLL_DELTA_Y = 64; // 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,49 @@ const scrollTarget = () => { return window.document.documentElement; }; -class SmoothScroller { - constructor(element, repeat) { +const resetScrolling = () => { + scrolling = false; +}; + +class Scroller { + constructor(element, smooth) { this.element = element; - this.repeat = repeat; - this.scrolling = scrolling; - if (repeat) { - this.easing = SmoothScroller.linearEasing; - } else { - this.easing = SmoothScroller.inOutQuadEasing; - } + this.smooth = smooth; } - scroll(x, y) { - if (this.scrolling[0]) { + scrollTo(x, y) { + let behavior = this.smooth ? 'smooth' : 'auto'; + window.scrollTo({ + left: x, + top: y, + behavior: behavior, + }); + if (!this.smooth) { 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)); + this.prepareReset(); } - loop(time) { - if (!this.timeStart) { - this.timeStart = time; - } - - 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); + scrollBy(x, y) { + let behavior = this.smooth ? 'smooth' : 'auto'; + window.scrollBy({ + left: x, + top: y, + behavior: behavior, + }); + if (!this.smooth) { + return; } + this.prepareReset(); } - static inOutQuadEasing(t) { - if (t < 1) { - return t * t; + prepareReset() { + scrolling = true; + if (lastTimeoutId) { + clearTimeout(lastTimeoutId); + lastTimeoutId = null; } - return -(t - 1) * (t - 1) + 1; - } - - static linearEasing(t) { - return t; + lastTimeoutId = setTimeout(resetScrolling, 100); } } @@ -123,77 +107,70 @@ class RoughtScroller { } } -const scroller = (element, smooth, repeat) => { - if (smooth) { - return new SmoothScroller(element, repeat); - } - return new RoughtScroller(element); -}; - const getScroll = () => { let target = scrollTarget(); 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) { - y = target.scrollTop + SCROLL_DELTA_Y * count * 4; + let delta = SCROLL_DELTA_Y * count; + if (scrolling) { + delta = SCROLL_DELTA_Y * count * 4; } - scroller(target, smooth, repeat).scroll(x, y); + new Scroller(target, smooth).scrollBy(0, delta); }; -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) { - y = target.scrollTop + SCROLL_DELTA_Y * count * 4; + let delta = SCROLL_DELTA_X * count; + if (scrolling) { + delta = SCROLL_DELTA_X * count * 4; } - scroller(target, smooth, repeat).scroll(x, y); + new Scroller(target, smooth).scrollBy(delta, 0); }; -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); + let delta = height * count; + if (scrolling) { + delta = height * count; + } + new Scroller(target, smooth).scrollBy(0, delta); }; const scrollTo = (x, y, smooth) => { let target = scrollTarget(); - scroller(target, smooth, false).scroll(x, y); + new Scroller(target, smooth).scrollTo(x, y); }; const scrollToTop = (smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = 0; - scroller(target, smooth, false).scroll(x, y); + new Scroller(target, smooth).scrollTo(x, y); }; const scrollToBottom = (smooth) => { let target = scrollTarget(); let x = target.scrollLeft; let y = target.scrollHeight; - scroller(target, smooth, false).scroll(x, y); + new Scroller(target, smooth).scrollTo(x, y); }; const scrollToHome = (smooth) => { let target = scrollTarget(); let x = 0; let y = target.scrollTop; - scroller(target, smooth, false).scroll(x, y); + new Scroller(target, smooth).scrollTo(x, y); }; const scrollToEnd = (smooth) => { let target = scrollTarget(); let x = target.scrollWidth; let y = target.scrollTop; - scroller(target, smooth, false).scroll(x, y); + new Scroller(target, smooth).scrollTo(x, y); }; export { |