154 lines
4 KiB
JavaScript
154 lines
4 KiB
JavaScript
let EventEmitter = require('events').EventEmitter
|
|
let Canvas = require('./view/canvas')
|
|
let LoadIndicator = require('./view/load-indicator')
|
|
let ProgressBar = require('./view/progress-bar')
|
|
|
|
class ComicBook extends EventEmitter {
|
|
|
|
constructor (srcs = [], options) {
|
|
super()
|
|
|
|
this.options = Object.assign({
|
|
// manga mode
|
|
rtl: false,
|
|
doublePage: false
|
|
}, options)
|
|
|
|
// requested image srcs
|
|
this.srcs = srcs
|
|
|
|
// loaded image objects
|
|
this.pages = new Map()
|
|
|
|
this.preloadBuffer = 4
|
|
|
|
// TODO move this logic into the router
|
|
this.currentPageIndex = 0
|
|
|
|
this.canvas = new Canvas()
|
|
this.loadIndicator = new LoadIndicator()
|
|
this.progressBar = new ProgressBar()
|
|
|
|
this.addEventListeners()
|
|
}
|
|
|
|
addEventListeners () {
|
|
this.on('preload:start', this.loadIndicator.show.bind(this.loadIndicator))
|
|
this.on('preload:start', this.progressBar.show.bind(this.progressBar))
|
|
this.on('preload:image', this.updateProgressBar.bind(this))
|
|
this.on('preload:ready', this.loadIndicator.hide.bind(this.loadIndicator))
|
|
this.on('preload:ready', this.drawPage.bind(this))
|
|
this.on('preload:finish', this.progressBar.hide.bind(this.progressBar))
|
|
}
|
|
|
|
render () {
|
|
this.pageRendered = false
|
|
this.el = document.createElement('div')
|
|
this.el.appendChild(this.canvas.canvas)
|
|
this.el.appendChild(this.progressBar.el)
|
|
this.el.appendChild(this.loadIndicator.el)
|
|
this.drawPage()
|
|
return this
|
|
}
|
|
|
|
// TODO use a queue, only allow x concurrent downloads at a time
|
|
// TODO preload in both directions
|
|
// TODO fire ready on forward direction only
|
|
preload (startIndex) {
|
|
this.emit('preload:start')
|
|
|
|
if (startIndex == null || startIndex >= this.srcs.length) {
|
|
startIndex = this.currentPageIndex
|
|
}
|
|
|
|
// reorder srcs to start from the requested index
|
|
let _srcs = this.srcs.slice()
|
|
let srcs = _srcs.splice(startIndex).concat(_srcs)
|
|
|
|
this.currentPageIndex = startIndex
|
|
|
|
srcs.forEach((src, pageIndex) => {
|
|
|
|
// allow preload to be run multiple times without duplicating requests
|
|
if (this.pages.has(pageIndex)) return
|
|
|
|
let image = new window.Image()
|
|
|
|
image.src = src
|
|
image.onload = setImage.bind(this, image, pageIndex)
|
|
|
|
function setImage (image, index) {
|
|
this.pages.set(index, image)
|
|
this.emit('preload:image', image)
|
|
|
|
if (this.pages.size >= this.preloadBuffer && !this.pageRendered) {
|
|
this.emit('preload:ready')
|
|
}
|
|
|
|
if (this.pages.size === this.srcs.length) {
|
|
this.emit('preload:finish')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
updateProgressBar () {
|
|
let percentage = Math.floor((this.pages.size / this.srcs.length) * 100)
|
|
this.progressBar.update(percentage)
|
|
}
|
|
|
|
drawPage (pageIndex) {
|
|
if (typeof pageIndex !== 'number') pageIndex = this.currentPageIndex
|
|
|
|
let page = this.pages.get(pageIndex)
|
|
|
|
// if the requested image hasn't been loaded yet, force another preload run
|
|
if (!page) return this.preload(pageIndex)
|
|
|
|
let args = [ page ]
|
|
|
|
if (this.options.doublePage) {
|
|
let page2Index = pageIndex + 1
|
|
let page2 = this.pages.get(page2Index)
|
|
|
|
if (page2Index <= (this.pages.size - 1) && !page2) {
|
|
return this.preload(page2Index)
|
|
}
|
|
|
|
args.push(page2)
|
|
|
|
if (this.options.rtl) {
|
|
args.reverse()
|
|
}
|
|
}
|
|
|
|
args.push(this.options)
|
|
|
|
try {
|
|
this.canvas.drawImage.apply(this.canvas, args)
|
|
this.currentPageIndex = pageIndex
|
|
this.pageRendered = true
|
|
} catch (e) {
|
|
if (e.message !== 'Invalid image') throw e
|
|
}
|
|
}
|
|
|
|
drawNextPage () {
|
|
let increment = this.options.doublePage ? 2 : 1
|
|
let index = this.currentPageIndex + increment
|
|
if (index >= this.pages.size) {
|
|
index = this.pages.size - 1
|
|
}
|
|
this.drawPage(index)
|
|
}
|
|
|
|
drawPreviousPage () {
|
|
let increment = this.options.doublePage ? 2 : 1
|
|
let index = this.currentPageIndex - increment
|
|
if (index < 0) index = 0
|
|
this.drawPage(index)
|
|
}
|
|
}
|
|
|
|
module.exports = ComicBook
|
|
|