Commit initial
This commit is contained in:
parent
a5516c430f
commit
f2b4cceb72
|
@ -0,0 +1,5 @@
|
|||
Navigation :
|
||||
- Right arrow : focus next panel
|
||||
- Left arrow : focus previous panel
|
||||
- Ctrl + Right arrow : focus next page
|
||||
- Ctrl + Left arrow : focus current / previous page
|
|
@ -0,0 +1,82 @@
|
|||
#reader-frame {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#reader-pages {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 100%;
|
||||
transition: all 1.5s ease;
|
||||
}
|
||||
|
||||
#reader-pages > img {
|
||||
display: inline-block;
|
||||
opacity:0;
|
||||
transition: all 1.5s ease;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#focus-overlay, #focus-overlay * {
|
||||
transition: all 1.5s ease;
|
||||
}
|
||||
|
||||
#focus-overlay, #nav-controls {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: grid;
|
||||
|
||||
grid-template-areas:
|
||||
"left top right"
|
||||
"left center right"
|
||||
"left bottom right";
|
||||
}
|
||||
|
||||
#focus-overlay {
|
||||
grid-template-columns: 50% auto 50%;
|
||||
grid-template-rows: 50% auto 50%;
|
||||
}
|
||||
|
||||
#nav-controls {
|
||||
grid-template-columns: 1fr 15em 1fr;
|
||||
grid-template-rows: auto;
|
||||
}
|
||||
|
||||
#nav-controls > div {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.top {
|
||||
grid-area: top;
|
||||
}
|
||||
|
||||
.left {
|
||||
grid-area: left;
|
||||
}
|
||||
|
||||
.right {
|
||||
grid-area: right;
|
||||
}
|
||||
|
||||
.top {
|
||||
grid-area: top;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
grid-area: bottom;
|
||||
}
|
||||
|
||||
#focus-overlay > *:not(.center) {
|
||||
background-color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
#focus-overlay > .center {
|
||||
box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 0.85);
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
|
||||
PAGE_TRANSITION_SPEED = "1.5s"
|
||||
|
||||
READER_FRAME = document.getElementById("reader-frame")
|
||||
|
||||
READER_PAGES = document.getElementById("reader-pages")
|
||||
|
||||
FOCUS_OVERLAY = document.getElementById("focus-overlay")
|
||||
|
||||
CURRENT_ZOOM = 0
|
||||
|
||||
CURRENT_PAGE = 1
|
||||
|
||||
CURRENT_WIDTH = 0
|
||||
CURRENT_HEIGHT = 0
|
||||
CURRENT_X = 0
|
||||
CURRENT_Y = 0
|
||||
|
||||
IS_PAGE_MODE = false
|
||||
|
||||
// ===========
|
||||
// UTILITIES
|
||||
// ===========
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
function getReaderFrameRatio() {
|
||||
return READER_FRAME.clientWidth / READER_FRAME.clientHeight
|
||||
}
|
||||
|
||||
function getPagesCount() {
|
||||
return READER_PAGES.childElementCount
|
||||
}
|
||||
|
||||
function getPagesHeight() {
|
||||
return READER_PAGES.dataset.pagesHeight
|
||||
}
|
||||
|
||||
function getPagesWidth() {
|
||||
return READER_PAGES.dataset.pagesWidth
|
||||
}
|
||||
|
||||
function getPagesRatio() {
|
||||
return READER_PAGES.dataset.pagesWidth / READER_PAGES.dataset.pagesHeight
|
||||
}
|
||||
|
||||
|
||||
// =========
|
||||
// ACTIONS
|
||||
// =========
|
||||
|
||||
function initReader(){
|
||||
moveReaderDisplayToZoom(0)
|
||||
}
|
||||
|
||||
|
||||
function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
|
||||
|
||||
if (width == 0){
|
||||
width = getPagesWidth()
|
||||
}
|
||||
|
||||
if (height == 0){
|
||||
height = getPagesHeight()
|
||||
}
|
||||
|
||||
ratio = width / height
|
||||
|
||||
base_scale_factor = getPagesHeight() / READER_FRAME.clientHeight // This is the factor at 100% height
|
||||
|
||||
if (ratio < getReaderFrameRatio()) {
|
||||
|
||||
scale_factor = READER_FRAME.clientHeight / height
|
||||
|
||||
centering_padding = (READER_FRAME.clientWidth - width * scale_factor) / 2
|
||||
|
||||
pages_negative_padding = getPagesWidth() * scale_factor * (pageNumber - 1)
|
||||
|
||||
READER_PAGES.style.height = base_scale_factor * scale_factor * 100 + "%"
|
||||
|
||||
READER_PAGES.style.left = (- posx * scale_factor + centering_padding - pages_negative_padding) + "px"
|
||||
|
||||
READER_PAGES.style.top = -posy * scale_factor + "px"
|
||||
|
||||
updateFocusByWidth(width * scale_factor)
|
||||
|
||||
} else {
|
||||
|
||||
scale_factor = READER_FRAME.clientWidth / width
|
||||
|
||||
pages_negative_padding = getPagesWidth() * scale_factor * (pageNumber - 1)
|
||||
|
||||
scaled_height = height * scale_factor
|
||||
|
||||
READER_PAGES.style.height = base_scale_factor * scale_factor * 100 + "%"
|
||||
|
||||
READER_PAGES.style.left = (- posx * scale_factor - pages_negative_padding) + "px"
|
||||
|
||||
READER_PAGES.style.top = -posy * scale_factor + (READER_FRAME.clientHeight - scaled_height)/2 + "px"
|
||||
|
||||
updateFocusByHeight(scaled_height)
|
||||
|
||||
}
|
||||
|
||||
CURRENT_PAGE = pageNumber
|
||||
CURRENT_WIDTH = width
|
||||
CURRENT_HEIGHT = height
|
||||
CURRENT_X = posx
|
||||
CURRENT_Y = posy
|
||||
}
|
||||
|
||||
|
||||
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){
|
||||
|
||||
side_width = (READER_FRAME.clientWidth - width) / 2
|
||||
|
||||
FOCUS_OVERLAY.style.gridTemplateColumns = side_width +"px auto " + side_width + "px"
|
||||
FOCUS_OVERLAY.style.gridTemplateRows = "0px auto 0px";
|
||||
}
|
||||
|
||||
function updateFocusByHeight(height){
|
||||
|
||||
side_width = (READER_FRAME.clientHeight - height) / 2
|
||||
|
||||
FOCUS_OVERLAY.style.gridTemplateRows = side_width +"px auto " + side_width + "px"
|
||||
FOCUS_OVERLAY.style.gridTemplateColumns = "0px auto 0px";
|
||||
}
|
||||
|
||||
function moveReader(to_next, move_page) {
|
||||
|
||||
if (move_page){
|
||||
|
||||
if (IS_PAGE_MODE){
|
||||
if (to_next && CURRENT_PAGE < getPagesCount()) {
|
||||
moveReaderDisplayToPage(CURRENT_PAGE + 1)
|
||||
IS_PAGE_MODE = true
|
||||
}
|
||||
|
||||
else if (CURRENT_PAGE > 1) {
|
||||
moveReaderDisplayToPage(CURRENT_PAGE - 1)
|
||||
IS_PAGE_MODE = true
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
|
||||
if (to_next && CURRENT_PAGE < getPagesCount()) {
|
||||
moveReaderDisplayToPage(CURRENT_PAGE + 1)
|
||||
IS_PAGE_MODE = true
|
||||
}
|
||||
|
||||
else {
|
||||
moveReaderDisplayToPage(CURRENT_PAGE)
|
||||
IS_PAGE_MODE = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (IS_PAGE_MODE){
|
||||
|
||||
if (to_next) {
|
||||
moveReaderDisplayToZoom(getFirstZoomOfPage(CURRENT_PAGE))
|
||||
IS_PAGE_MODE = false
|
||||
}
|
||||
else {
|
||||
if (CURRENT_PAGE == 1) {
|
||||
moveReaderDisplayToZoom(0)
|
||||
IS_PAGE_MODE = false
|
||||
} else {
|
||||
moveReaderDisplayToZoom(getLastZoomOfPage(CURRENT_PAGE - 1))
|
||||
IS_PAGE_MODE = false
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (to_next && CURRENT_ZOOM < zooms.length - 1) {
|
||||
moveReaderDisplayToZoom(CURRENT_ZOOM + 1)
|
||||
IS_PAGE_MODE = false
|
||||
}
|
||||
|
||||
else if (CURRENT_ZOOM > 0) {
|
||||
moveReaderDisplayToZoom(CURRENT_ZOOM - 1)
|
||||
IS_PAGE_MODE = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function handleKeyPress(key, has_ctrl){
|
||||
|
||||
if (key == "ArrowRight") {
|
||||
moveReader(true, has_ctrl)
|
||||
}
|
||||
|
||||
else if (key == "ArrowLeft") {
|
||||
moveReader(false, has_ctrl)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ======
|
||||
// INIT
|
||||
// ======
|
||||
|
||||
window.addEventListener("load", (event) => {
|
||||
initReader()
|
||||
});
|
||||
|
||||
addEventListener("resize", (event) => {
|
||||
moveReaderDisplayToArea(CURRENT_PAGE, CURRENT_WIDTH, CURRENT_HEIGHT, CURRENT_X, CURRENT_Y)
|
||||
});
|
||||
|
||||
addEventListener("keydown", (event) => {
|
||||
handleKeyPress(event.key, event.ctrlKey)
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
|
||||
html, body {
|
||||
margin: 0px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 1em;
|
||||
height: 100vh;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
#reader-frame {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: 2px solid;
|
||||
box-sizing: border-box;
|
||||
background-color: black;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
<link rel="stylesheet" href="comic_reader_test.css">
|
||||
<link rel="stylesheet" href="comic_reader.css">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="reader-frame">
|
||||
<div id="reader-pages" data-pages-width="2481" data-pages-height="3503">
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg"/>
|
||||
<img loading="lazy" onload="event.target.style.opacity=1" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg"/>
|
||||
</div>
|
||||
|
||||
<div id="focus-overlay">
|
||||
<div class="top"></div>
|
||||
<div class="left"></div>
|
||||
<div class="center"></div>
|
||||
<div class="right"></div>
|
||||
<div class="bottom"></div>
|
||||
</div>
|
||||
|
||||
<div id="nav-controls">
|
||||
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
|
||||
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
<script src="zooms_data.js"></script>
|
||||
<script src="comic_reader.js"></script>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,45 @@
|
|||
import sys
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def extract_zooms(src_folder, dest_file):
|
||||
folder = Path(src_folder)
|
||||
|
||||
zooms = {}
|
||||
|
||||
for svg_path in folder.glob("*.svg"):
|
||||
print(svg_path.name)
|
||||
match = re.search("P(\d+)", svg_path.name)
|
||||
if match:
|
||||
|
||||
page_idx = int(match.group(1))
|
||||
|
||||
zooms[page_idx] = []
|
||||
|
||||
tree = ET.parse(svg_path)
|
||||
root = tree.getroot()
|
||||
|
||||
for area in root.findall('.//{*}rect'):
|
||||
zooms[page_idx].append([
|
||||
float(area.get("width")),
|
||||
float(area.get("height")),
|
||||
float(area.get("x")),
|
||||
float(area.get("y")),
|
||||
])
|
||||
|
||||
with open(dest_file, "w") as data_file:
|
||||
data_file.write("zooms = [\n")
|
||||
for page_idx in sorted(zooms.keys()):
|
||||
for zoom in zooms[page_idx]:
|
||||
|
||||
if zoom[2] < 0 or zoom[3] < 0 :
|
||||
print(f"WARNING: negative pos x / pos y in page {page_idx} for zoom {zoom} (is the rectangle flipped?)")
|
||||
|
||||
data_file.write(f" {[page_idx] + zoom},\n")
|
||||
data_file.write("]\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
extract_zooms(sys.argv[1], sys.argv[2])
|
Loading…
Reference in New Issue