Add sliding animation

Can be disabled by setting `.pageAnimation` to `false`.
This commit is contained in:
John Factotum
2023-05-17 02:52:39 +08:00
parent 57ab79d598
commit ec512a8b7e
+33 -29
View File
@@ -157,6 +157,9 @@ class View {
overflow: 'hidden', overflow: 'hidden',
flex: '0 0 auto', flex: '0 0 auto',
width: '100%', height: '100%', width: '100%', height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}) })
Object.assign(this.#iframe.style, { Object.assign(this.#iframe.style, {
overflow: 'hidden', overflow: 'hidden',
@@ -288,13 +291,15 @@ class View {
const expandedSize = pageCount * this.#size const expandedSize = pageCount * this.#size
this.#element.style.padding = '0' this.#element.style.padding = '0'
this.#iframe.style[side] = `${expandedSize}px` this.#iframe.style[side] = `${expandedSize}px`
this.#element.style[side] = `${expandedSize}px` this.#element.style[side] = `${expandedSize + this.#size * 2}px`
this.#iframe.style[otherSide] = '100%' this.#iframe.style[otherSide] = '100%'
this.#element.style[otherSide] = '100%' this.#element.style[otherSide] = '100%'
if (this.document) if (this.document)
this.document.documentElement.style[side] = `${this.#size}px` this.document.documentElement.style[side] = `${this.#size}px`
if (this.#overlayer) { if (this.#overlayer) {
this.#overlayer.element.style.margin = '0' this.#overlayer.element.style.margin = '0'
this.#overlayer.element.style.left = this.#vertical ? '0' : this.#size
this.#overlayer.element.style.top = this.#vertical ? this.#size : '0'
this.#overlayer.element.style[side] = `${expandedSize}px` this.#overlayer.element.style[side] = `${expandedSize}px`
this.#overlayer.redraw() this.#overlayer.redraw()
} }
@@ -313,6 +318,8 @@ class View {
this.#element.style[otherSide] = '100%' this.#element.style[otherSide] = '100%'
if (this.#overlayer) { if (this.#overlayer) {
this.#overlayer.element.style.margin = padding this.#overlayer.element.style.margin = padding
this.#overlayer.element.style.left = '0'
this.#overlayer.element.style.top = '0'
this.#overlayer.element.style[side] = `${expandedSize}px` this.#overlayer.element.style[side] = `${expandedSize}px`
this.#overlayer.redraw() this.#overlayer.redraw()
} }
@@ -347,6 +354,7 @@ export class Paginator extends HTMLElement {
#anchor = 0 // anchor view to a fraction (0-1), Range, or Element #anchor = 0 // anchor view to a fraction (0-1), Range, or Element
#locked = false // while true, prevent any further navigation #locked = false // while true, prevent any further navigation
#styleMap = new WeakMap() #styleMap = new WeakMap()
pageAnimation = true
layout = { layout = {
margin: 48, margin: 48,
gap: 0.05, gap: 0.05,
@@ -587,9 +595,9 @@ export class Paginator extends HTMLElement {
} }
const offset = this.#getRectMapper()(rect).left const offset = this.#getRectMapper()(rect).left
+ this.layout.margin / 2 + this.layout.margin / 2
return this.#scrollToPage(Math.floor(offset / this.size), reason) return this.#scrollToPage(Math.floor(offset / this.size) + 1, reason)
} }
async #scrollTo(offset, reason) { async #scrollTo(offset, reason, smooth) {
const element = this.#container const element = this.#container
const { scrollProp } = this const { scrollProp } = this
if (element[scrollProp] === offset) { if (element[scrollProp] === offset) {
@@ -598,30 +606,29 @@ 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
element[scrollProp] = offset if (smooth && this.pageAnimation) return new Promise((resolve, reject) => {
this.#afterScroll(reason)
/*return new Promise((resolve, reject) => {
try { try {
const onScroll = () => { const onScroll = () => {
if (element[scrollProp] - offset > 2) return if (Math.abs(element[scrollProp] - offset) > 2) return
element.removeEventListener('scroll', onScroll) element.removeEventListener('scroll', onScroll)
resolve() resolve()
this.#afterScroll(reason) this.#afterScroll(reason)
} }
element.addEventListener('scroll', onScroll) element.addEventListener('scroll', onScroll)
if (this.scrolled) {
const coord = scrollProp === 'scrollLeft' ? 'left' : 'top' const coord = scrollProp === 'scrollLeft' ? 'left' : 'top'
element.scrollTo({ [coord]: offset, behavior: 'smooth' }) element.scrollTo({ [coord]: offset, behavior: 'smooth' })
}
element[scrollProp] = offset
} catch (e) { } catch (e) {
reject(e) reject(e)
} }
})*/ })
else {
element[scrollProp] = offset
this.#afterScroll(reason)
} }
async #scrollToPage(page, reason) { }
async #scrollToPage(page, reason, smooth) {
const offset = this.size * (this.#rtl ? -page : page) const offset = this.size * (this.#rtl ? -page : page)
return this.#scrollTo(offset, reason) return this.#scrollTo(offset, reason, smooth)
} }
async #scrollToAnchor(select) { async #scrollToAnchor(select) {
const rects = uncollapse(this.#anchor)?.getClientRects?.() const rects = uncollapse(this.#anchor)?.getClientRects?.()
@@ -643,8 +650,9 @@ export class Paginator extends HTMLElement {
} }
const { pages } = this const { pages } = this
if (!pages) return if (!pages) return
const newPage = Math.round(this.#anchor * (pages - 1)) const textPages = pages - 2
await this.#scrollToPage(newPage, 'anchor') const newPage = Math.round(this.#anchor * (textPages - 1))
await this.#scrollToPage(newPage + 1, 'anchor')
} }
#selectAnchor() { #selectAnchor() {
const { defaultView } = this.#view.document const { defaultView } = this.#view.document
@@ -668,9 +676,9 @@ export class Paginator extends HTMLElement {
if (this.scrolled) detail.fraction = this.start / this.viewSize if (this.scrolled) detail.fraction = this.start / this.viewSize
else if (this.pages > 0) { else if (this.pages > 0) {
const { page, pages } = this const { page, pages } = this
this.#header.style.visibility = page > 0 ? 'visible' : 'hidden' this.#header.style.visibility = page > 1 ? 'visible' : 'hidden'
detail.fraction = page / pages detail.fraction = (page - 1) / (pages - 2)
detail.size = 1 / pages detail.size = 1 / (pages - 2)
} }
this.dispatchEvent(new CustomEvent('relocate', { detail })) this.dispatchEvent(new CustomEvent('relocate', { detail }))
} }
@@ -703,30 +711,25 @@ export class Paginator extends HTMLElement {
? anchor(this.#view.document) : anchor) ?? 0 ? anchor(this.#view.document) : anchor) ?? 0
await this.#scrollToAnchor(select) await this.#scrollToAnchor(select)
} }
#canScrollToPage(page) {
return page > -1 && page < this.pages
}
scrollPrev() { scrollPrev() {
if (!this.#view) return null if (!this.#view) return null
if (this.scrolled) { if (this.scrolled) {
if (this.start > 0) if (this.start > 0)
return this.#scrollTo(Math.max(0, this.start - this.size)) return [true, this.#scrollTo(Math.max(0, this.start - this.size), '', true)]
else return null else return null
} }
const page = this.page - 1 const page = this.page - 1
if (this.#canScrollToPage(page)) return this.#scrollToPage(page) return [page > 0, this.#scrollToPage(page, '', true)]
return null
} }
scrollNext() { scrollNext() {
if (!this.#view) return null if (!this.#view) return null
if (this.scrolled) { if (this.scrolled) {
if (this.viewSize - this.end > 2) if (this.viewSize - this.end > 2)
return this.#scrollTo(Math.min(this.viewSize, this.end)) return [true, this.#scrollTo(Math.min(this.viewSize, this.end), '', true)]
else return null else return null
} }
const page = this.page + 1 const page = this.page + 1
if (this.#canScrollToPage(page)) return this.#scrollToPage(page) return [page < this.pages - 1, this.#scrollToPage(page, '', true)]
return null
} }
#canGoToIndex(index) { #canGoToIndex(index) {
return index >= 0 && index <= this.sections.length - 1 return index >= 0 && index <= this.sections.length - 1
@@ -735,8 +738,9 @@ export class Paginator extends HTMLElement {
if (this.#locked) return if (this.#locked) return
if (lock) this.#locked = true if (lock) this.#locked = true
const scroll = tryScroll?.() const scroll = tryScroll?.()
if (scroll) await scroll const shouldGo = !scroll?.[0]
else { if (scroll) await scroll[1]
if (shouldGo) {
const { index, anchor, select } = await target const { index, anchor, select } = await target
if (!this.#canGoToIndex(index)) { if (!this.#canGoToIndex(index)) {
this.#locked = false this.#locked = false