mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Add sliding animation
Can be disabled by setting `.pageAnimation` to `false`.
This commit is contained in:
+33
-29
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user