mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Animate scroll manually instead of using scroll-behavior smooth
This commit is contained in:
+21
-26
@@ -14,6 +14,20 @@ const debounce = (f, wait, immediate) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lerp = (min, max, x) => x * (max - min) + min
|
||||||
|
const easeOutQuad = x => 1 - (1 - x) * (1 - x)
|
||||||
|
const animate = (a, b, duration, ease, render) => new Promise(resolve => {
|
||||||
|
let start
|
||||||
|
const step = now => {
|
||||||
|
start ??= now
|
||||||
|
const fraction = Math.min(1, (now - start) / duration)
|
||||||
|
render(lerp(a, b, ease(fraction)))
|
||||||
|
if (fraction < 1) requestAnimationFrame(step)
|
||||||
|
else resolve()
|
||||||
|
}
|
||||||
|
requestAnimationFrame(step)
|
||||||
|
})
|
||||||
|
|
||||||
// collapsed range doesn't return client rects sometimes (or always?)
|
// collapsed range doesn't return client rects sometimes (or always?)
|
||||||
// try make get a non-collapsed range or element
|
// try make get a non-collapsed range or element
|
||||||
const uncollapse = range => {
|
const uncollapse = range => {
|
||||||
@@ -601,7 +615,7 @@ export class Paginator extends HTMLElement {
|
|||||||
const page = Math.floor(
|
const page = Math.floor(
|
||||||
Math.max(min, Math.min(max, (start + end) / 2
|
Math.max(min, Math.min(max, (start + end) / 2
|
||||||
+ (isNaN(d) ? 0 : d))) / size)
|
+ (isNaN(d) ? 0 : d))) / size)
|
||||||
// TODO: ideally should snap by continuing the same velocity
|
|
||||||
this.#scrollToPage(page, 'snap').then(() => {
|
this.#scrollToPage(page, 'snap').then(() => {
|
||||||
const dir = page <= 0 ? -1 : page >= pages - 1 ? 1 : null
|
const dir = page <= 0 ? -1 : page >= pages - 1 ? 1 : null
|
||||||
if (dir) return this.#goTo({
|
if (dir) return this.#goTo({
|
||||||
@@ -673,31 +687,12 @@ export class Paginator extends HTMLElement {
|
|||||||
}
|
}
|
||||||
// FIXME: vertical-rl only, not -lr
|
// FIXME: vertical-rl only, not -lr
|
||||||
if (this.scrolled && this.#vertical) offset = -offset
|
if (this.scrolled && this.#vertical) offset = -offset
|
||||||
if (reason === 'snap'
|
if (reason === 'snap' || smooth && this.pageAnimation) return animate(
|
||||||
|| smooth && this.pageAnimation) return new Promise((resolve, reject) => {
|
element[scrollProp], offset, 300, easeOutQuad,
|
||||||
// `requestAnimationFrame` fixes the whole page getting "stuck" when
|
x => element[scrollProp] = x,
|
||||||
// transitioning chapters in Foliate (the GTK 4 app).
|
).then(() => {
|
||||||
// It happens often but not always, and resolves itself after
|
this.#scrollBounds = [offset, this.atStart ? 0 : size, this.atEnd ? 0 : size]
|
||||||
// interacting with the page (e.g. clicking on it).
|
this.#afterScroll(reason)
|
||||||
// IDK what causes it and I can't reproduce it in any other browser
|
|
||||||
// or even with a WebKitGTK WebView, but this trick seems to fix it
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
try {
|
|
||||||
const onScroll = () => {
|
|
||||||
if (Math.abs(element[scrollProp] - offset) > 2) return
|
|
||||||
element.removeEventListener('scroll', onScroll)
|
|
||||||
resolve()
|
|
||||||
this.#scrollBounds = [offset,
|
|
||||||
this.atStart ? 0 : size, this.atEnd ? 0 : size]
|
|
||||||
this.#afterScroll(reason)
|
|
||||||
}
|
|
||||||
element.addEventListener('scroll', onScroll)
|
|
||||||
const coord = scrollProp === 'scrollLeft' ? 'left' : 'top'
|
|
||||||
element.scrollTo({ [coord]: offset, behavior: 'smooth' })
|
|
||||||
} catch (e) {
|
|
||||||
reject(e)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
else {
|
else {
|
||||||
element[scrollProp] = offset
|
element[scrollProp] = offset
|
||||||
|
|||||||
Reference in New Issue
Block a user