2023-04-16 21:35:32 +02:00
|
|
|
//============
|
|
|
|
// CONTROLS
|
|
|
|
//============
|
|
|
|
|
|
|
|
MOVE_NEXT = "ArrowRight"
|
|
|
|
MOVE_BACK = "ArrowLeft"
|
|
|
|
TOGGLE_FULLSCREEN = "F"
|
2023-04-17 20:45:46 +02:00
|
|
|
TOGGLE_PROGRESSBAR = "P"
|
2023-04-17 20:59:32 +02:00
|
|
|
TOGGLE_VIEW_MODE = "V"
|
2023-04-16 21:35:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
//========================
|
|
|
|
// NAVIGATION CONSTANTS
|
|
|
|
//========================
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
PAGE_TRANSITION_SPEED = "1.5s"
|
2023-04-16 21:35:32 +02:00
|
|
|
MOUSEWHELL_MIN_DELAY = 50
|
2023-04-16 22:44:17 +02:00
|
|
|
DELAY_BEFORE_HIDDING_CONTROLS = 4000;
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
//====================
|
|
|
|
// STATES CONSTANTS
|
|
|
|
//====================
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
READER_FRAME = document.getElementById("reader-frame")
|
2023-04-17 20:45:46 +02:00
|
|
|
READER_CONTENT_FRAME = document.getElementById("reader-content-frame")
|
2023-04-16 21:35:32 +02:00
|
|
|
READER_PAGES = document.getElementById("reader-pages")
|
2023-04-15 13:12:49 +02:00
|
|
|
FOCUS_OVERLAY = document.getElementById("focus-overlay")
|
2023-04-16 22:24:59 +02:00
|
|
|
HELP_CONTROLS = document.getElementById("help-controls")
|
2023-04-17 20:45:46 +02:00
|
|
|
PROGRESS_BAR_CONTAINER = document.getElementById("reader-progress-container")
|
2023-04-17 19:33:41 +02:00
|
|
|
PROGRESS_BAR = document.getElementById("reader-progress-bar")
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
CURRENT_ZOOM = 0
|
|
|
|
CURRENT_PAGE = 1
|
|
|
|
CURRENT_WIDTH = 0
|
|
|
|
CURRENT_HEIGHT = 0
|
|
|
|
CURRENT_X = 0
|
|
|
|
CURRENT_Y = 0
|
|
|
|
|
|
|
|
IS_PAGE_MODE = false
|
2023-04-16 17:43:37 +02:00
|
|
|
MOUSEWHELL_WAIT = false
|
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
// =============
|
|
|
|
// UTILITIES
|
|
|
|
// =============
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
// Zooms utilites
|
|
|
|
// --------------
|
|
|
|
|
2023-04-15 13:12:49 +02:00
|
|
|
function getFirstZoomOfPage(pageNumber){
|
|
|
|
|
|
|
|
for (var zoom_idx = 0; zoom_idx < zooms.length; zoom_idx++){
|
|
|
|
if (zooms[zoom_idx][0] == pageNumber) {
|
|
|
|
return zoom_idx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLastZoomOfPage(pageNumber){
|
|
|
|
let res = null
|
|
|
|
|
|
|
|
for (var zoom_idx = 0; zoom_idx < zooms.length; zoom_idx++){
|
|
|
|
if (zooms[zoom_idx][0] == pageNumber) {
|
|
|
|
res = zoom_idx
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res != null && zooms[zoom_idx][0] != pageNumber) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2023-04-17 19:33:41 +02:00
|
|
|
function getZoomCountForPage(pageNumber) {
|
|
|
|
return zooms.filter(zoom => zoom[0] == pageNumber).length
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCurrentZoomIndexForPage() {
|
|
|
|
previousZoomsCount = zooms.filter(zoom => zoom[0] < CURRENT_PAGE).length
|
|
|
|
return CURRENT_ZOOM - previousZoomsCount + 1
|
|
|
|
}
|
|
|
|
|
|
|
|
function getReadingProgressPercent() {
|
|
|
|
progressPerPage = 1 / getPagesCount()
|
|
|
|
|
|
|
|
if (IS_PAGE_MODE){
|
|
|
|
return 100 * progressPerPage * CURRENT_PAGE
|
|
|
|
}
|
|
|
|
|
|
|
|
progressPerZoom = progressPerPage / getZoomCountForPage(CURRENT_PAGE)
|
|
|
|
|
|
|
|
readingProgress = (CURRENT_PAGE - 1) * progressPerPage + getCurrentZoomIndexForPage() * progressPerZoom
|
|
|
|
|
|
|
|
return 100 * readingProgress
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateProgressBar(){
|
|
|
|
PROGRESS_BAR.style.width = getReadingProgressPercent() + "%"
|
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
// Dimensions utilites
|
|
|
|
// -------------------
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
function getPagesCount() {
|
|
|
|
return READER_PAGES.childElementCount
|
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
function pageOriginalHeight() {
|
|
|
|
return parseInt(READER_PAGES.dataset.pagesHeight)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
function pageOriginalWidth() {
|
|
|
|
return parseInt(READER_PAGES.dataset.pagesWidth)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
function readerFrameRatio() {
|
2023-04-17 20:45:46 +02:00
|
|
|
return READER_CONTENT_FRAME.clientWidth / READER_CONTENT_FRAME.clientHeight
|
2023-04-15 17:30:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function pageRatio() {
|
2023-04-15 13:12:49 +02:00
|
|
|
return READER_PAGES.dataset.pagesWidth / READER_PAGES.dataset.pagesHeight
|
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
function isFrameRatioWiderThanPage(){
|
|
|
|
return readerFrameRatio() > pageRatio()
|
|
|
|
}
|
|
|
|
|
|
|
|
function pageToFrameScaleFactor(useHeight){
|
|
|
|
// The scale factor to apply to a page so it exactly fit in the reader frame
|
|
|
|
if (useHeight) {
|
2023-04-17 20:45:46 +02:00
|
|
|
return READER_CONTENT_FRAME.clientHeight / pageOriginalHeight()
|
2023-04-15 17:30:49 +02:00
|
|
|
}
|
2023-04-17 20:45:46 +02:00
|
|
|
return READER_CONTENT_FRAME.clientWidth / pageOriginalWidth()
|
2023-04-15 17:30:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function totalPagesWidth() {
|
|
|
|
// The width of all cumuled pages with scale factor applied
|
|
|
|
return pageOriginalWidth() * getPagesCount()
|
|
|
|
}
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
// =========
|
|
|
|
// ACTIONS
|
|
|
|
// =========
|
|
|
|
|
|
|
|
function initReader(){
|
|
|
|
moveReaderDisplayToZoom(0)
|
2023-04-15 17:30:49 +02:00
|
|
|
|
2023-04-15 18:14:57 +02:00
|
|
|
// Smoothly show pictures when they intersect with the viewport
|
|
|
|
let visibilityObserver = new IntersectionObserver((entries, observer) => {
|
|
|
|
entries.forEach((entry) => {
|
|
|
|
if (entry.isIntersecting) {
|
|
|
|
entry.target.style.opacity = 1
|
|
|
|
entry.target.style.visibility = "visible"
|
|
|
|
} else {
|
|
|
|
entry.target.style.opacity = 0
|
|
|
|
entry.target.style.visibility = "hidden"
|
|
|
|
}
|
|
|
|
});
|
2023-04-17 20:45:46 +02:00
|
|
|
}, { root: READER_CONTENT_FRAME, rootMargin: "-10px" });
|
2023-04-15 18:14:57 +02:00
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
for (var i = 0; i < READER_PAGES.children.length; i++) {
|
|
|
|
let img = READER_PAGES.children[i];
|
|
|
|
img.style.width = 100 / getPagesCount() + "%"
|
2023-04-15 18:14:57 +02:00
|
|
|
visibilityObserver.observe(img)
|
2023-04-15 17:30:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
READER_PAGES.style.display = "flex"
|
2023-04-15 18:14:57 +02:00
|
|
|
|
2023-04-15 17:38:46 +02:00
|
|
|
setTimeout(() => {
|
|
|
|
READER_PAGES.hidden = false
|
|
|
|
}, "300")
|
|
|
|
|
2023-04-16 22:24:59 +02:00
|
|
|
setTimeout(() => {
|
|
|
|
HELP_CONTROLS.style.opacity = null;
|
2023-04-17 20:32:13 +02:00
|
|
|
HELP_CONTROLS.style.transform = null;
|
2023-04-16 22:24:59 +02:00
|
|
|
}, DELAY_BEFORE_HIDDING_CONTROLS)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
|
|
|
|
|
|
|
|
if (width == 0){
|
2023-04-15 17:30:49 +02:00
|
|
|
width = pageOriginalWidth()
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (height == 0){
|
2023-04-15 17:30:49 +02:00
|
|
|
height = pageOriginalHeight()
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
zoomRatio = width / height
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
if (readerFrameRatio() > zoomRatio) {
|
|
|
|
// Frame wider than zoom
|
|
|
|
var zoomToFrameScaleFactor = pageToFrameScaleFactor(true) * pageOriginalHeight() / height
|
2023-04-17 20:45:46 +02:00
|
|
|
var zoomToFrameCenteringOffset = [(READER_CONTENT_FRAME.clientWidth - width * zoomToFrameScaleFactor) / 2, 0]
|
2023-04-15 17:30:49 +02:00
|
|
|
updateFocusByWidth(width * zoomToFrameScaleFactor)
|
2023-04-15 13:12:49 +02:00
|
|
|
} else {
|
2023-04-15 17:30:49 +02:00
|
|
|
var zoomToFrameScaleFactor = pageToFrameScaleFactor(false) * pageOriginalWidth() / width
|
2023-04-17 20:45:46 +02:00
|
|
|
var zoomToFrameCenteringOffset = [0, (READER_CONTENT_FRAME.clientHeight - height * zoomToFrameScaleFactor) / 2]
|
2023-04-15 17:30:49 +02:00
|
|
|
updateFocusByHeight(height * zoomToFrameScaleFactor)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-15 17:30:49 +02:00
|
|
|
previousPagesOffset = pageOriginalWidth() * (pageNumber - 1) * zoomToFrameScaleFactor
|
|
|
|
|
|
|
|
READER_PAGES.style.width = totalPagesWidth() * zoomToFrameScaleFactor + "px"
|
|
|
|
READER_PAGES.style.height = pageOriginalHeight() * zoomToFrameScaleFactor + "px"
|
|
|
|
|
|
|
|
READER_PAGES.style.left = (- posx * zoomToFrameScaleFactor + zoomToFrameCenteringOffset[0] - previousPagesOffset) + "px"
|
|
|
|
READER_PAGES.style.top = (- posy * zoomToFrameScaleFactor + zoomToFrameCenteringOffset[1]) + "px"
|
|
|
|
|
2023-04-15 13:12:49 +02:00
|
|
|
CURRENT_PAGE = pageNumber
|
|
|
|
CURRENT_WIDTH = width
|
|
|
|
CURRENT_HEIGHT = height
|
|
|
|
CURRENT_X = posx
|
|
|
|
CURRENT_Y = posy
|
|
|
|
}
|
|
|
|
|
2023-04-17 20:45:46 +02:00
|
|
|
function refreshReaderDisplay() {
|
|
|
|
moveReaderDisplayToArea(CURRENT_PAGE, CURRENT_WIDTH, CURRENT_HEIGHT, CURRENT_X, CURRENT_Y)
|
|
|
|
}
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
function moveReaderDisplayToPage(pageNumber) {
|
|
|
|
moveReaderDisplayToArea(pageNumber, 0, 0, 0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
function moveReaderDisplayToZoom(index) {
|
|
|
|
|
|
|
|
moveReaderDisplayToArea(zooms[index][0], zooms[index][1], zooms[index][2], zooms[index][3], zooms[index][4])
|
|
|
|
|
|
|
|
CURRENT_ZOOM = index
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateFocusByWidth(width){
|
|
|
|
|
2023-04-17 20:45:46 +02:00
|
|
|
side_width = (READER_CONTENT_FRAME.clientWidth - width) / 2
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
FOCUS_OVERLAY.style.gridTemplateColumns = side_width +"px auto " + side_width + "px"
|
|
|
|
FOCUS_OVERLAY.style.gridTemplateRows = "0px auto 0px";
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateFocusByHeight(height){
|
|
|
|
|
2023-04-17 20:45:46 +02:00
|
|
|
side_width = (READER_CONTENT_FRAME.clientHeight - height) / 2
|
2023-04-15 13:12:49 +02:00
|
|
|
|
|
|
|
FOCUS_OVERLAY.style.gridTemplateRows = side_width +"px auto " + side_width + "px"
|
|
|
|
FOCUS_OVERLAY.style.gridTemplateColumns = "0px auto 0px";
|
|
|
|
}
|
|
|
|
|
2023-04-17 20:59:32 +02:00
|
|
|
function toggleViewMode() {
|
|
|
|
if (IS_PAGE_MODE){
|
|
|
|
if (CURRENT_ZOOM != null){
|
|
|
|
moveReaderDisplayToZoom(CURRENT_ZOOM)
|
|
|
|
} else {
|
|
|
|
moveReaderDisplayToZoom(getFirstZoomOfPage(CURRENT_PAGE))
|
|
|
|
}
|
|
|
|
IS_PAGE_MODE = false
|
|
|
|
} else {
|
|
|
|
moveReaderDisplayToPage(CURRENT_PAGE)
|
|
|
|
IS_PAGE_MODE = true
|
|
|
|
}
|
2023-04-17 21:03:31 +02:00
|
|
|
|
|
|
|
updateProgressBar()
|
2023-04-17 20:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function moveReader(to_next) {
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-17 20:59:32 +02:00
|
|
|
if (IS_PAGE_MODE){
|
|
|
|
if (to_next && CURRENT_PAGE < getPagesCount()) {
|
|
|
|
moveReaderDisplayToPage(CURRENT_PAGE + 1)
|
|
|
|
CURRENT_ZOOM = null
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-17 20:59:32 +02:00
|
|
|
else if (!to_next && CURRENT_PAGE > 1) {
|
|
|
|
moveReaderDisplayToPage(CURRENT_PAGE - 1)
|
|
|
|
CURRENT_ZOOM = null
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2023-04-17 20:59:32 +02:00
|
|
|
|
|
|
|
if (to_next && CURRENT_ZOOM < zooms.length - 1) {
|
|
|
|
moveReaderDisplayToZoom(CURRENT_ZOOM + 1)
|
|
|
|
}
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-17 20:59:32 +02:00
|
|
|
else if (!to_next && CURRENT_ZOOM > 0) {
|
|
|
|
moveReaderDisplayToZoom(CURRENT_ZOOM - 1)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-17 19:33:41 +02:00
|
|
|
updateProgressBar()
|
|
|
|
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
|
|
|
|
// =============
|
|
|
|
// CALLBACKS
|
|
|
|
// =============
|
|
|
|
|
2023-04-17 20:59:32 +02:00
|
|
|
function handleKeyPress(key){
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
if (key == MOVE_NEXT) {
|
2023-04-17 20:59:32 +02:00
|
|
|
moveReader(true)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
else if (key == MOVE_BACK) {
|
2023-04-17 20:59:32 +02:00
|
|
|
moveReader(false)
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
2023-04-16 17:43:37 +02:00
|
|
|
|
2023-04-16 21:35:32 +02:00
|
|
|
else if (key.toUpperCase() == TOGGLE_FULLSCREEN){
|
2023-04-16 17:43:37 +02:00
|
|
|
if (document.fullscreenElement == null){
|
|
|
|
READER_FRAME.requestFullscreen();
|
|
|
|
} else {
|
|
|
|
document.exitFullscreen();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-04-17 20:45:46 +02:00
|
|
|
|
|
|
|
else if (key.toUpperCase() == TOGGLE_PROGRESSBAR){
|
|
|
|
if (PROGRESS_BAR_CONTAINER.hidden == true) {
|
|
|
|
PROGRESS_BAR_CONTAINER.hidden = false
|
|
|
|
} else {
|
|
|
|
PROGRESS_BAR_CONTAINER.hidden = true
|
|
|
|
}
|
|
|
|
refreshReaderDisplay();
|
|
|
|
}
|
2023-04-17 20:59:32 +02:00
|
|
|
|
|
|
|
else if (key.toUpperCase() == TOGGLE_VIEW_MODE) {
|
|
|
|
toggleViewMode()
|
|
|
|
}
|
2023-04-16 17:43:37 +02:00
|
|
|
|
|
|
|
}
|
2023-04-15 13:12:49 +02:00
|
|
|
|
2023-04-16 17:43:37 +02:00
|
|
|
function handleMouseWhell(deltaY){
|
|
|
|
|
|
|
|
if (MOUSEWHELL_WAIT){
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
MOUSEWHELL_WAIT = true
|
|
|
|
setTimeout(() => {
|
|
|
|
MOUSEWHELL_WAIT = false
|
|
|
|
}, MOUSEWHELL_MIN_DELAY)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (deltaY > 0) {
|
|
|
|
moveReader(true, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
moveReader(false, false)
|
|
|
|
}
|
2023-04-15 13:12:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ======
|
|
|
|
// INIT
|
|
|
|
// ======
|
|
|
|
|
|
|
|
window.addEventListener("load", (event) => {
|
|
|
|
initReader()
|
|
|
|
});
|
|
|
|
|
|
|
|
addEventListener("resize", (event) => {
|
2023-04-17 20:45:46 +02:00
|
|
|
refreshReaderDisplay();
|
2023-04-15 13:12:49 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
addEventListener("keydown", (event) => {
|
2023-04-17 18:44:24 +02:00
|
|
|
handleKeyPress(event.key, event.shiftKey)
|
2023-04-16 17:43:37 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
addEventListener("wheel", (event) => {
|
|
|
|
handleMouseWhell(event.deltaY)
|
|
|
|
});
|