Compare commits

..

1 Commits

Author SHA1 Message Date
caribaud c35e426838 Fix licence button URL 2023-05-22 01:12:37 +02:00
9 changed files with 477 additions and 382 deletions

View File

@ -1,6 +1,6 @@
# Melpomene
![](https://licensebuttons.net/l/by-nc-sa/4.0/88x31.png)
![](https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png)
Melpomene is a a simple, HTML/CSS/JS webcomic reading utility .
@ -30,9 +30,10 @@ Melpomene is mainly one JS file and one CSS file. You only need to include them
The JS files expect you to write some very specific HTML tags to be able to work.
To simplify things, you only need to copy-paste the content of `melpomene.html` into your own page and change a few things :
+ `data-pages-width` must be set to your comic pages width in px
+ `data-pages-height` must be set to your comic pages height in px
+ You must duplicate the `img` tag for each of you comic page and :
+ set `url` to the actual URL of your page
+ set `height` and `width` to the actual image sizes
+ set `data-zooms` with the zooms information, like so : `<zoom 1 width>, <zoom 1 height>, <zoom 1 x offset>, <zoom 1 y offset>; <zoom 2 width> ...`
+ example : `<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg" data-zooms="2481.0,1327.1057,0.0,0.0;593.15338,1076.4635,0.0,1364.053;890.72864,491.29874,830.81415,1751.5;2481.0,1078.4192,0.0,1364.053;562.77032,909.44702,102.48115,2491.6567;920.74463,909.44702,698.55927,2491.6567;728.776,909.44702,1652.3695,2491.6567"/>`
@ -44,6 +45,7 @@ The following limitations are known and will be improved upon :
+ Mobile support is currently limited
+ There are some performences issues
+ Your comic pages need to be the same size
# How to setup Melpomene ?
@ -80,15 +82,7 @@ If you wish to run a custom generation process, this generator can output a JSON
You are now ready to integrate Melpomene in your website!
## Advanced usage
If you need to do some global scaling / offset of all zooms in HTML (if for example you reuse zooms data for multiple resolutions), you can add the following attributes to the `<div id="reader-pages" ...>` tag :
+ `data-global-zoom-offset="<x offset float value>,<y offset float value>"` : offset all positions by the provided x / y values
+ If they become negative, they get clamped to 0 and width / height get reduced to compensate
+ If they become greater than the page size, they get clamped to the page size and width / height get reduced to compensate
+ `data-global-zoom-scale="<float value>"` : scale all positions / sizes by this factor
# Credits
Most examples and the documentation of Melpomene uses illustrations from David "Deevad" Revoy's "Pepper & Carrot" webcomic, which is published under CC-BY 4.0. Full licence [here](https://www.peppercarrot.com/en/license/index.html).
Most examples and the documentation of Melpomene uses illustrations from David "Deevad" Revoy's "Pepper & Carrot" webcomic, which is published under CC-BY 4.0. Full licence [here](https://www.peppercarrot.com/en/license/index.html).

83
demos/demo_data.js Normal file
View File

@ -0,0 +1,83 @@
PAGES_ZOOMS = [
[1, 2481.0, 1327.1057, 0.0, 0.0],
[1, 593.15338, 1076.4635, 0.0, 1364.053],
[1, 890.72864, 491.29874, 830.81415, 1751.5],
[1, 2481.0, 1078.4192, 0.0, 1364.053],
[1, 562.77032, 909.44702, 102.48115, 2491.6567],
[1, 920.74463, 909.44702, 698.55927, 2491.6567],
[1, 728.776, 909.44702, 1652.3695, 2491.6567],
[2, 1459.9161, 960.62878, 99.857468, 103.85177],
[2, 788.87384, 960.62878, 1593.7252, 103.85177],
[2, 455.35007, 305.56384, 389.44412, 1376.0359],
[2, 2282.7415, 760.914, 99.857475, 1114.4093],
[2, 1069.9728, 496.29166, 101.85461, 1928.2478],
[2, 1209.7733, 496.29166, 1172.3267, 1928.2478],
[2, 788.87402, 926.67731, 101.85462, 2474.468],
[2, 415.40707, 926.67731, 924.68018, 2474.468],
[2, 1008.5604, 926.67731, 1372.0416, 2474.468],
[3, 2278.4634, 1424.0264, 103.9937, 103.9937],
[3, 457.3472, 589.15906, 816.83411, 469.33011],
[3, 618.69055, 832.04285, 104.47829, 1578.7172],
[3, 1170.7311, 832.04285, 756.71887, 1578.7172],
[3, 418.14838, 832.04285, 1962.6545, 1578.7172],
[3, 2280.6614, 940.57422, 100.82664, 2461.1147],
[4, 1128.3893, 547.21899, 100.85604, 101.85461],
[4, 1125.3937, 505.27878, 101.85462, 700.99945],
[4, 659.59674, 1104.1381, 1237.9126, 100.46677],
[4, 474.09705, 1104.7645, 1908.0801, 103.04887],
[4, 991.58466, 641.08496, 365.47833, 1256.2069],
[4, 2276.7502, 1268.1899, 101.85461, 1256.2069],
[4, 669.66565, 827.24689, 100.95136, 2574.8799],
[4, 1574.1992, 825.24969, 806.56573, 2576.877],
[5, 2270.7588, 1348.0758, 107.84606, 109.84322],
[5, 828.80096, 1879.4762, 104.70337, 1519.7256],
[5, 606.50098, 1877.479, 975.78717, 1521.7228],
[5, 755.02411, 1139.5406, 1623.401, 1521.7228],
[5, 757.02124, 680.4198, 1621.4038, 2716.7849],
[6, 2273.6387, 1248.3829, 104.50265, 107.32705],
[6, 624.19147, 440.60574, 1259.6805, 771.06006],
[6, 830.37231, 940.5238, 110.15143, 1415.0222],
[6, 1395.2515, 1313.3441, 985.71411, 1409.3734],
[6, 1321.8173, 796.47961, 112.97583, 2417.6829],
[6, 974.4165, 754.11365, 1403.7247, 2646.4587],
[7, 828.81702, 497.29019, 443.36716, 531.2417],
[7, 2275.0127, 1188.0789, 105.30553, 109.78442],
[7, 2275.0127, 804.28339, 105.30553, 1356.3481],
[7, 847.87823, 1182.9146, 105.30553, 2210.6436],
[7, 497.6918, 1185.7389, 994.37964, 2213.468],
[7, 854.35431, 1185.7389, 1528.7885, 2213.468],
[8, 2272.7561, 1228.2468, 101.85461, 107.84607],
[8, 497.29019, 756.91962, 994.58044, 569.18756],
[8, 2276.7502, 1052.4977, 101.85461, 1336.0929],
[8, 2278.7473, 958.63165, 101.85462, 2444.5107],
[9, 1131.1705, 453.31552, 101.67825, 103.09045],
[9, 1148.1168, 453.31552, 1232.8488, 103.09045],
[9, 1481.6407, 453.31552, 501.89209, 103.09045],
[9, 2282.1118, 855.79193, 98.853851, 604.42072],
[9, 1776.5449, 881.21149, 290.91275, 1355.71],
[9, 703.27454, 398.23981, 762.58685, 2863.9373],
[9, 2270.8142, 1132.5826, 107.32704, 2270.8142],
[10, 2278.7473, 1240.2297, 101.85461, 101.85461],
[10, 667.04791, 1016.549, 99.857468, 1390.016],
[10, 1583.7395, 1014.5519, 798.85974, 1390.016],
[10, 2280.7446, 944.65161, 99.857468, 2456.4937],
[11, 830.81415, 1194.2953, 97.860321, 101.85461],
[11, 774.89398, 1198.2897, 960.62885, 99.857468],
[11, 609.13055, 1192.2982, 1769.4744, 101.85461],
[11, 363.4812, 868.75995, 99.857468, 1348.0758],
[11, 1495.8649, 870.75714, 493.2959, 1346.0787],
[11, 357.48975, 870.75714, 2023.1123, 1348.0758],
[11, 529.24457, 499.28735, 103.85177, 2280.7446],
[11, 531.24176, 687.01941, 99.857468, 2716.123],
[11, 1022.5405, 1120.4008, 669.04504, 2280.7446],
[11, 657.06213, 1120.4008, 1725.5371, 2280.7446],
[12, 704.99371, 341.51254, 619.11633, 281.59805],
[12, 393.43842, 551.21326, 1459.9161, 159.77196],
[12, 2280.7446, 691.01367, 99.857468, 101.85461],
[12, 718.97375, 1198.2897, 99.857468, 840.79987],
[12, 712.9823, 1196.2925, 850.78564, 842.79706],
[12, 780.88538, 1192.2982, 1599.7167, 842.79706],
[12, 2366.6221, 1445.9362, 61.911629, 2049.0752],
[12, 922.68298, 551.21326, 984.59467, 2378.605],
[12, 631.09918, 211.69783, 1851.3574, 3289.3049],
]

View File

@ -11,66 +11,59 @@
<body>
<div id="melpomene">
<!-- Melpomene comic reader -->
<!-- Version 1.0.0_RC1 -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="melpomene-content-frame">
<div id="melpomene-pages" hidden>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg" data-zooms="2481.0,1327.1057,0.0,0.0;593.15338,1076.4635,0.0,1364.053;890.72864,491.29874,830.81415,1751.5;2481.0,1078.4192,0.0,1364.053;562.77032,909.44702,102.48115,2491.6567;920.74463,909.44702,698.55927,2491.6567;728.776,909.44702,1652.3695,2491.6567"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg" data-zooms="1459.9161,960.62878,99.857468,103.85177;788.87384,960.62878,1593.7252,103.85177;455.35007,305.56384,389.44412,1376.0359;2282.7415,760.914,99.857475,1114.4093;1069.9728,496.29166,101.85461,1928.2478;1209.7733,496.29166,1172.3267,1928.2478;788.87402,926.67731,101.85462,2474.468;415.40707,926.67731,924.68018,2474.468;1008.5604,926.67731,1372.0416,2474.468"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg" data-zooms="2278.4634,1424.0264,103.9937,103.9937;457.3472,589.15906,816.83411,469.33011;618.69055,832.04285,104.47829,1578.7172;1170.7311,832.04285,756.71887,1578.7172;418.14838,832.04285,1962.6545,1578.7172;2280.6614,940.57422,100.82664,2461.1147"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg" data-zooms="1128.3893,547.21899,100.85604,101.85461;1125.3937,505.27878,101.85462,700.99945;659.59674,1104.1381,1237.9126,100.46677;474.09705,1104.7645,1908.0801,103.04887;991.58466,641.08496,365.47833,1256.2069;2276.7502,1268.1899,101.85461,1256.2069;669.66565,827.24689,100.95136,2574.8799;1574.1992,825.24969,806.56573,2576.877"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg" data-zooms="2270.7588,1348.0758,107.84606,109.84322;828.80096,1879.4762,104.70337,1519.7256;606.50098,1877.479,975.78717,1521.7228;755.02411,1139.5406,1623.401,1521.7228;757.02124,680.4198,1621.4038,2716.7849"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg" data-zooms="2273.6387,1248.3829,104.50265,107.32705;624.19147,440.60574,1259.6805,771.06006;830.37231,940.5238,110.15143,1415.0222;1395.2515,1313.3441,985.71411,1409.3734;1321.8173,796.47961,112.97583,2417.6829;974.4165,754.11365,1403.7247,2646.4587"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg" data-zooms="828.81702,497.29019,443.36716,531.2417;2275.0127,1188.0789,105.30553,109.78442;2275.0127,804.28339,105.30553,1356.3481;847.87823,1182.9146,105.30553,2210.6436;497.6918,1185.7389,994.37964,2213.468;854.35431,1185.7389,1528.7885,2213.468"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg" data-zooms="2272.7561,1228.2468,101.85461,107.84607;497.29019,756.91962,994.58044,569.18756;2276.7502,1052.4977,101.85461,1336.0929;2278.7473,958.63165,101.85462,2444.5107"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg" data-zooms="1131.1705,453.31552,101.67825,103.09045;1148.1168,453.31552,1232.8488,103.09045;1481.6407,453.31552,501.89209,103.09045;2282.1118,855.79193,98.853851,604.42072;1776.5449,881.21149,290.91275,1355.71;703.27454,398.23981,762.58685,2863.9373;2270.8142,1132.5826,107.32704,2270.8142"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg" data-zooms="2278.7473,1240.2297,101.85461,101.85461;667.04791,1016.549,99.857468,1390.016;1583.7395,1014.5519,798.85974,1390.016;2280.7446,944.65161,99.857468,2456.4937"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg" data-zooms="830.81415,1194.2953,97.860321,101.85461;774.89398,1198.2897,960.62885,99.857468;609.13055,1192.2982,1769.4744,101.85461;363.4812,868.75995,99.857468,1348.0758;1495.8649,870.75714,493.2959,1346.0787;357.48975,870.75714,2023.1123,1348.0758;529.24457,499.28735,103.85177,2280.7446;531.24176,687.01941,99.857468,2716.123;1022.5405,1120.4008,669.04504,2280.7446;657.06213,1120.4008,1725.5371,2280.7446"/>
<img loading="lazy" height="3503" width="2481" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg" data-zooms="704.99371,341.51254,619.11633,281.59805;393.43842,551.21326,1459.9161,159.77196;2280.7446,691.01367,99.857468,101.85461;718.97375,1198.2897,99.857468,840.79987;712.9823,1196.2925,850.78564,842.79706;780.88538,1192.2982,1599.7167,842.79706;2366.6221,1445.9362,61.911629,2049.0752;922.68298,551.21326,984.59467,2378.605;631.09918,211.69783,1851.3574,3289.3049"/>
<!-- Melpomene comic reader -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-frame">
<div id="reader-content-frame">
<div id="reader-pages" class="animated" data-pages-width="2481" data-pages-height="3503" hidden>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg"/>
</div>
<div id="melpomene-focus-container">
<div></div>
<div id="melpomene-focus-col">
<div></div>
<div id="melpomene-focus"></div>
<div></div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div>
<div id="focus-overlay-height" class="flex animated" style="height:100%">
<div class="grow obscured animated"></div>
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div>
<div class="grow obscured animated"></div>
</div>
<div></div>
<div class="grow obscured animated"></div>
</div>
<div id="melpomene-help-menu" style="opacity:1; transform: translate(0,0);">
<div><div class="melpomene-key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="melpomene-key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="melpomene-key">F</div>: Toggle fullscreen</div>
<div><div class="melpomene-key">P</div>: Toggle progress bar</div>
<div><div class="melpomene-key">V</div>: Toggle panel / page viewing mode</div>
<div>-----------------------</div>
<div id="melpomene-version" class="melpomene-credits">Melpomene comic reader - Unknown version</div>
<div class="melpomene-credits">CC-BY-NC-SA 4.0 / <a target="_blank" href="https://git.aribaud.net/caribaud/melpomene">credits</a></div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
</div>
<div id="melpomene-nav-controls">
<div onclick="moveReader(false,false)"></div>
<div onclick="moveReader(true,false)"></div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="key">F</div>: Toggle fullscreen</div>
<div><div class="key">P</div>: Toggle progress bar</div>
<div><div class="key">V</div>: Toggle panel / page viewing mode</div>
</div>
</div>
</div>
<div id="melpomene-progress-container">
<div id="melpomene-progress-bar"></div>
<div id="melpomene-progress-sections"></div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div>
<div id="reader-progress-pages"></div>
</div>
</div>
<!-- End of Melpomene comic reader -->
</body>
<!-- melpomene_js.html import -->
<script src="demo_data.js"></script>
<script src="../melpomene.js"></script>
</html>
</html>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="demo.css">
<!-- melpomene_head.html import -->
<link rel="stylesheet" href="../melpomene.css">
</head>
<body>
<!-- Melpomene comic reader -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-frame">
<div id="reader-content-frame">
<div id="reader-pages" class="animated" data-pages-width="2481" data-pages-height="3503" hidden>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg" data-zooms="2481.0,1327.1057,0.0,0.0;593.15338,1076.4635,0.0,1364.053;890.72864,491.29874,830.81415,1751.5;2481.0,1078.4192,0.0,1364.053;562.77032,909.44702,102.48115,2491.6567;920.74463,909.44702,698.55927,2491.6567;728.776,909.44702,1652.3695,2491.6567"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg" data-zooms="1459.9161,960.62878,99.857468,103.85177;788.87384,960.62878,1593.7252,103.85177;455.35007,305.56384,389.44412,1376.0359;2282.7415,760.914,99.857475,1114.4093;1069.9728,496.29166,101.85461,1928.2478;1209.7733,496.29166,1172.3267,1928.2478;788.87402,926.67731,101.85462,2474.468;415.40707,926.67731,924.68018,2474.468;1008.5604,926.67731,1372.0416,2474.468"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg" data-zooms="2278.4634,1424.0264,103.9937,103.9937;457.3472,589.15906,816.83411,469.33011;618.69055,832.04285,104.47829,1578.7172;1170.7311,832.04285,756.71887,1578.7172;418.14838,832.04285,1962.6545,1578.7172;2280.6614,940.57422,100.82664,2461.1147"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg" data-zooms="1128.3893,547.21899,100.85604,101.85461;1125.3937,505.27878,101.85462,700.99945;659.59674,1104.1381,1237.9126,100.46677;474.09705,1104.7645,1908.0801,103.04887;991.58466,641.08496,365.47833,1256.2069;2276.7502,1268.1899,101.85461,1256.2069;669.66565,827.24689,100.95136,2574.8799;1574.1992,825.24969,806.56573,2576.877"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg" data-zooms="2270.7588,1348.0758,107.84606,109.84322;828.80096,1879.4762,104.70337,1519.7256;606.50098,1877.479,975.78717,1521.7228;755.02411,1139.5406,1623.401,1521.7228;757.02124,680.4198,1621.4038,2716.7849"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg" data-zooms="2273.6387,1248.3829,104.50265,107.32705;624.19147,440.60574,1259.6805,771.06006;830.37231,940.5238,110.15143,1415.0222;1395.2515,1313.3441,985.71411,1409.3734;1321.8173,796.47961,112.97583,2417.6829;974.4165,754.11365,1403.7247,2646.4587"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg" data-zooms="828.81702,497.29019,443.36716,531.2417;2275.0127,1188.0789,105.30553,109.78442;2275.0127,804.28339,105.30553,1356.3481;847.87823,1182.9146,105.30553,2210.6436;497.6918,1185.7389,994.37964,2213.468;854.35431,1185.7389,1528.7885,2213.468"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg" data-zooms="2272.7561,1228.2468,101.85461,107.84607;497.29019,756.91962,994.58044,569.18756;2276.7502,1052.4977,101.85461,1336.0929;2278.7473,958.63165,101.85462,2444.5107"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg" data-zooms="1131.1705,453.31552,101.67825,103.09045;1148.1168,453.31552,1232.8488,103.09045;1481.6407,453.31552,501.89209,103.09045;2282.1118,855.79193,98.853851,604.42072;1776.5449,881.21149,290.91275,1355.71;703.27454,398.23981,762.58685,2863.9373;2270.8142,1132.5826,107.32704,2270.8142"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg" data-zooms="2278.7473,1240.2297,101.85461,101.85461;667.04791,1016.549,99.857468,1390.016;1583.7395,1014.5519,798.85974,1390.016;2280.7446,944.65161,99.857468,2456.4937"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg" data-zooms="830.81415,1194.2953,97.860321,101.85461;774.89398,1198.2897,960.62885,99.857468;609.13055,1192.2982,1769.4744,101.85461;363.4812,868.75995,99.857468,1348.0758;1495.8649,870.75714,493.2959,1346.0787;357.48975,870.75714,2023.1123,1348.0758;529.24457,499.28735,103.85177,2280.7446;531.24176,687.01941,99.857468,2716.123;1022.5405,1120.4008,669.04504,2280.7446;657.06213,1120.4008,1725.5371,2280.7446"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg" data-zooms="704.99371,341.51254,619.11633,281.59805;393.43842,551.21326,1459.9161,159.77196;2280.7446,691.01367,99.857468,101.85461;718.97375,1198.2897,99.857468,840.79987;712.9823,1196.2925,850.78564,842.79706;780.88538,1192.2982,1599.7167,842.79706;2366.6221,1445.9362,61.911629,2049.0752;922.68298,551.21326,984.59467,2378.605;631.09918,211.69783,1851.3574,3289.3049"/>
</div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div>
<div id="focus-overlay-height" class="flex animated" style="height:100%">
<div class="grow obscured animated"></div>
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div>
<div class="grow obscured animated"></div>
</div>
<div class="grow obscured animated"></div>
</div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
</div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="key">F</div>: Toggle fullscreen</div>
<div><div class="key">P</div>: Toggle progress bar</div>
<div><div class="key">V</div>: Toggle panel / page viewing mode</div>
</div>
</div>
</div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div>
<div id="reader-progress-pages"></div>
</div>
</div>
<!-- End of Melpomene comic reader -->
</body>
<!-- melpomene_js.html import -->
<script src="../melpomene.js"></script>
</html>

View File

@ -11,66 +11,67 @@
<body>
<div id="melpomene">
<!-- Melpomene comic reader -->
<!-- Version 1.0.0_RC1 -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="melpomene-content-frame">
<!-- melpomene_reader.html import -->
<!-- Melpomene comic reader -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-frame">
<div id="reader-content-frame">
<div id="melpomene-pages" data-global-zoom-scale="0.4836759371221282" data-global-zoom-offset="0,-70" hidden>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg" data-zooms="2481.0,1327.1057,0.0,0.0;593.15338,1076.4635,0.0,1364.053;890.72864,491.29874,830.81415,1751.5;2481.0,1078.4192,0.0,1364.053;562.77032,909.44702,102.48115,2491.6567;920.74463,909.44702,698.55927,2491.6567;728.776,909.44702,1652.3695,2491.6567"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg" data-zooms="1459.9161,960.62878,99.857468,103.85177;788.87384,960.62878,1593.7252,103.85177;455.35007,305.56384,389.44412,1376.0359;2282.7415,760.914,99.857475,1114.4093;1069.9728,496.29166,101.85461,1928.2478;1209.7733,496.29166,1172.3267,1928.2478;788.87402,926.67731,101.85462,2474.468;415.40707,926.67731,924.68018,2474.468;1008.5604,926.67731,1372.0416,2474.468"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg" data-zooms="2278.4634,1424.0264,103.9937,103.9937;457.3472,589.15906,816.83411,469.33011;618.69055,832.04285,104.47829,1578.7172;1170.7311,832.04285,756.71887,1578.7172;418.14838,832.04285,1962.6545,1578.7172;2280.6614,940.57422,100.82664,2461.1147"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg" data-zooms="1128.3893,547.21899,100.85604,101.85461;1125.3937,505.27878,101.85462,700.99945;659.59674,1104.1381,1237.9126,100.46677;474.09705,1104.7645,1908.0801,103.04887;991.58466,641.08496,365.47833,1256.2069;2276.7502,1268.1899,101.85461,1256.2069;669.66565,827.24689,100.95136,2574.8799;1574.1992,825.24969,806.56573,2576.877"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg" data-zooms="2270.7588,1348.0758,107.84606,109.84322;828.80096,1879.4762,104.70337,1519.7256;606.50098,1877.479,975.78717,1521.7228;755.02411,1139.5406,1623.401,1521.7228;757.02124,680.4198,1621.4038,2716.7849"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg" data-zooms="2273.6387,1248.3829,104.50265,107.32705;624.19147,440.60574,1259.6805,771.06006;830.37231,940.5238,110.15143,1415.0222;1395.2515,1313.3441,985.71411,1409.3734;1321.8173,796.47961,112.97583,2417.6829;974.4165,754.11365,1403.7247,2646.4587"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg" data-zooms="828.81702,497.29019,443.36716,531.2417;2275.0127,1188.0789,105.30553,109.78442;2275.0127,804.28339,105.30553,1356.3481;847.87823,1182.9146,105.30553,2210.6436;497.6918,1185.7389,994.37964,2213.468;854.35431,1185.7389,1528.7885,2213.468"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg" data-zooms="2272.7561,1228.2468,101.85461,107.84607;497.29019,756.91962,994.58044,569.18756;2276.7502,1052.4977,101.85461,1336.0929;2278.7473,958.63165,101.85462,2444.5107"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg" data-zooms="1131.1705,453.31552,101.67825,103.09045;1148.1168,453.31552,1232.8488,103.09045;1481.6407,453.31552,501.89209,103.09045;2282.1118,855.79193,98.853851,604.42072;1776.5449,881.21149,290.91275,1355.71;703.27454,398.23981,762.58685,2863.9373;2270.8142,1132.5826,107.32704,2270.8142"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg" data-zooms="2278.7473,1240.2297,101.85461,101.85461;667.04791,1016.549,99.857468,1390.016;1583.7395,1014.5519,798.85974,1390.016;2280.7446,944.65161,99.857468,2456.4937"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg" data-zooms="830.81415,1194.2953,97.860321,101.85461;774.89398,1198.2897,960.62885,99.857468;609.13055,1192.2982,1769.4744,101.85461;363.4812,868.75995,99.857468,1348.0758;1495.8649,870.75714,493.2959,1346.0787;357.48975,870.75714,2023.1123,1348.0758;529.24457,499.28735,103.85177,2280.7446;531.24176,687.01941,99.857468,2716.123;1022.5405,1120.4008,669.04504,2280.7446;657.06213,1120.4008,1725.5371,2280.7446"/>
<img loading="lazy" height="1660" width="1200" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg" data-zooms="704.99371,341.51254,619.11633,281.59805;393.43842,551.21326,1459.9161,159.77196;2280.7446,691.01367,99.857468,101.85461;718.97375,1198.2897,99.857468,840.79987;712.9823,1196.2925,850.78564,842.79706;780.88538,1192.2982,1599.7167,842.79706;2366.6221,1445.9362,61.911629,2049.0752;922.68298,551.21326,984.59467,2378.605;631.09918,211.69783,1851.3574,3289.3049"/>
<div id="reader-pages" class="animated" data-pages-width="2481" data-pages-height="3503" hidden>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P01.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P02.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P03.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg"/>
<img loading="lazy" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/low-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg"/>
</div>
<div id="melpomene-focus-container">
<div></div>
<div id="melpomene-focus-col">
<div></div>
<div id="melpomene-focus"></div>
<div></div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div>
<div id="focus-overlay-height" class="flex animated" style="height:100%">
<div class="grow obscured animated"></div>
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div>
<div class="grow obscured animated"></div>
</div>
<div></div>
<div class="grow obscured animated"></div>
</div>
<div id="melpomene-help-menu" style="opacity:1; transform: translate(0,0);">
<div><div class="melpomene-key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="melpomene-key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="melpomene-key">F</div>: Toggle fullscreen</div>
<div><div class="melpomene-key">P</div>: Toggle progress bar</div>
<div><div class="melpomene-key">V</div>: Toggle panel / page viewing mode</div>
<div>-----------------------</div>
<div id="melpomene-version" class="melpomene-credits">Melpomene comic reader - Unknown version</div>
<div class="melpomene-credits">CC-BY-NC-SA 4.0 / <a target="_blank" href="https://git.aribaud.net/caribaud/melpomene">credits</a></div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
</div>
<div id="melpomene-nav-controls">
<div onclick="moveReader(false,false)"></div>
<div onclick="moveReader(true,false)"></div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="key">F</div>: Toggle fullscreen</div>
<div><div class="key">P</div>: Toggle progress bar</div>
<div><div class="key">V</div>: Toggle panel / page viewing mode</div>
</div>
</div>
</div>
<div id="melpomene-progress-container">
<div id="melpomene-progress-bar"></div>
<div id="melpomene-progress-sections"></div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div>
<div id="reader-progress-pages"></div>
</div>
</div>
<!-- End of Melpomene comic reader -->
</body>
<!-- melpomene_js.html import -->
<script src="demo_data.js"></script>
<script src="../melpomene.js"></script>
</html>
</html>

View File

@ -1,8 +1,43 @@
/* Melpomene webcomic reader CSS */
/* Version 1.0.0_RC1 */
/* Version 1.0.0 - UNSTABLE */
/* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */
#melpomene-focus-container, #melpomene-nav-controls, #melpomene-progress-sections {
:root {
--reader-progressbar-height: 0.3em;
}
.animated {
transition: all 1.5s ease;
}
#reader-frame {
display: flex;
flex-direction: column;
}
#reader-content-frame {
flex: 1;
position: relative;
overflow: hidden;
}
#reader-pages {
position: absolute;
flex-direction: row;
left: 0px;
right: 0px;
transform-origin: top left;
transform: scale(1) translate(0);
}
#reader-pages > img {
display: inline-block;
opacity: 0;
transition: all 1s cubic-bezier(.9,.03,.69,.22); /* ease-in quartic */
flex-shrink: 0;
}
.fill {
position: absolute;
top: 0;
left: 0;
@ -10,100 +45,82 @@
height: 100%;
}
#melpomene, #melpomene-focus-container, #melpomene-pages, #melpomene-nav-controls, #melpomene-focus-col {
.obscured {
background-color: rgba(0, 0, 0, 0.85);
}
.flex {
display: flex;
flex-direction: row;
}
#melpomene-pages, #melpomene-focus-container * {
transition: all 1.5s ease;
}
#melpomene, #melpomene-focus-col {
.flex-col {
display: flex;
flex-direction: column;
}
#melpomene {
height: 100%;
width: 100%;
border: 2px solid;
box-sizing: border-box;
background-color: black;
.grow {
flex: 1
}
/* Reset images style to avoid external CSS interfering */
#melpomene img {
all: initial;
}
#melpomene-content-frame {
position: relative;
flex: 1;
overflow: hidden;
}
#melpomene-pages {
transform-origin: top left;
transform: scale(1) translate(0);
align-items: center;
width: fit-content;
height: fit-content;
}
#melpomene-pages > img {
display: inline-block;
opacity: 0;
transition: all 1s cubic-bezier(.9,.03,.69,.22); /* ease-in quartic */
}
#melpomene-focus-container * {
background-color: rgba(0, 0, 0, 0.85);
flex-grow: 1;
}
#melpomene-focus-col, #melpomene-focus {
background-color: initial;
flex-grow: 0;
}
#melpomene-focus {
box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 0.85);
}
#melpomene-nav-controls {
display: flex;
#nav-controls {
display: grid;
grid-template-areas:
"left top right"
"left center right"
"left bottom right";
}
#nav-controls {
grid-template-columns: 33% 0 1fr;
grid-template-rows: auto;
}
#melpomene-nav-controls > div {
flex-grow: 1;
#nav-controls > div {
cursor: pointer;
}
#melpomene-nav-controls > div:first-child {
width: 35%;
flex-grow: 0
.top {
grid-area: top;
}
#melpomene-help-menu {
.left {
grid-area: left;
}
position: absolute;
bottom: 0;
right: 0;
.right {
grid-area: right;
}
.top {
grid-area: top;
}
.bottom {
grid-area: bottom;
}
.focus {
box-shadow: inset 0px 0px 5px 5px rgba(0, 0, 0, 0.85);
}
#help-menu{
font-size: 120%;
display: flex;
flex-direction: column;
color: white;
background-color: rgba(0,0,0,0.8);
background-color: rgba(0,0,0,0.8)
border: 0.1em solid black;
height: 100%;
justify-content: end;
box-sizing: border-box;
align-items: end;
}
#help-menu > #help-controls {
padding: 0 1em 1em 1em;
background-color: rgba(0,0,0,0.5);
z-index: 1;
opacity: 0;
transition: all 1.7s cubic-bezier(.76,.05,.86,.06);
@ -113,28 +130,18 @@
transform: translate(0, calc(100% - 2em));
}
#melpomene-help-menu:hover {
#help-menu > #help-controls:hover {
opacity: 1;
transition: all 0.3s linear;
transform: translate(0, 0);
}
#melpomene-help-menu * {
#help-menu > #help-controls > div {
margin-top: 1em;
text-align: center;
}
#melpomene-help-menu .melpomene-credits {
margin-top: 0.5em;
font-size: 70%;
text-align: right;
}
#melpomene-help-menu .melpomene-credits a {
color: white;
}
.melpomene-key {
.key {
display: inline;
margin: 0 0.5em;
border: 1px white solid;
@ -142,25 +149,30 @@
border-radius: 0.2em;
}
#melpomene-progress-container {
#reader-progress-container {
background-color: dimgray;
position: relative;
}
#melpomene-progress-bar{
height: 0.3em;
#reader-progress-bar{
height: var(--reader-progressbar-height);
background-color: whitesmoke;
transition: all 0.5s ease-in-out;
width: 0%;
transition: all 0.5s ease-in-out;
}
#melpomene-progress-sections {
#reader-progress-pages {
display: flex;
height: 100%;
position: absolute;
width: 100%;
top: 0;
left: 0;
}
#melpomene-progress-sections > * {
#reader-progress-pages > * {
height: 100%;
box-sizing: border-box;
border-right: 0.3em black solid;
flex: 1;
}
}

View File

@ -1,45 +1,39 @@
<div id="melpomene">
<!-- Melpomene comic reader -->
<!-- Version 1.0.0_RC1 -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="melpomene-content-frame">
<div id="melpomene-pages" hidden>
<!-- your img tags here, see documentation -->
<!-- Melpomene comic reader -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-frame">
<div id="reader-content-frame">
<!-- replace all 'xxxx' with the actual value -->
<div id="reader-pages" class="animated" data-pages-width="xxxx" data-pages-height="xxxx" hidden>
<img loading="lazy" src="xxxx" data-zooms="xxxx"/>
<!-- duplicate img for each comic page -->
</div>
<div id="melpomene-focus-container">
<div></div>
<div id="melpomene-focus-col">
<div></div>
<div id="melpomene-focus"></div>
<div></div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div>
<div id="focus-overlay-height" class="flex animated" style="height:100%">
<div class="grow obscured animated"></div>
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div>
<div class="grow obscured animated"></div>
</div>
<div></div>
<div class="grow obscured animated"></div>
</div>
<div id="melpomene-help-menu" style="opacity:1; transform: translate(0,0);">
<div><div class="melpomene-key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="melpomene-key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="melpomene-key">F</div>: Toggle fullscreen</div>
<div><div class="melpomene-key">P</div>: Toggle progress bar</div>
<div><div class="melpomene-key">V</div>: Toggle panel / page viewing mode</div>
<div>-----------------------</div>
<div id="melpomene-version" class="melpomene-credits">Melpomene comic reader - Unknown version</div>
<div class="melpomene-credits">CC-BY-NC-SA 4.0 / <a target="_blank" href="https://git.aribaud.net/caribaud/melpomene">credits</a></div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
</div>
<div id="melpomene-nav-controls">
<div onclick="moveReader(false,false)"></div>
<div onclick="moveReader(true,false)"></div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="key">F</div>: Toggle fullscreen</div>
<div><div class="key">P</div>: Toggle progress bar</div>
<div><div class="key">V</div>: Toggle panel / page viewing mode</div>
</div>
</div>
</div>
<div id="melpomene-progress-container">
<div id="melpomene-progress-bar"></div>
<div id="melpomene-progress-sections"></div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div>
<div id="reader-progress-pages"></div>
</div>
</div>
<!-- End of Melpomene comic reader -->

View File

@ -1,5 +1,5 @@
/* Melpomene webcomic reader JS */
/* Version 1.0.0_RC1 */
/* Version 1.0.0 - UNSTABLE */
/* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */
//============
@ -25,18 +25,15 @@ DELAY_BEFORE_HIDDING_CONTROLS = 4000;
// STATES CONSTANTS
//====================
MELPOMENE_VERSION = "1.0.0_RC1"
READER_FRAME = document.getElementById("melpomene")
READER_CONTENT_FRAME = document.getElementById("melpomene-content-frame")
READER_PAGES = document.getElementById("melpomene-pages")
FOCUS_OVERLAY_HEIGHT = document.getElementById("melpomene-focus")
FOCUS_OVERLAY_WIDTH = document.getElementById("melpomene-focus-col")
HELP_CONTROLS = document.getElementById("melpomene-help-menu")
PROGRESS_BAR_CONTAINER = document.getElementById("melpomene-progress-container")
PROGRESS_BAR = document.getElementById("melpomene-progress-bar")
PROGRESS_BAR_PAGES = document.getElementById("melpomene-progress-sections")
VERSION_DISPLAY = document.getElementById("melpomene-version")
READER_FRAME = document.getElementById("reader-frame")
READER_CONTENT_FRAME = document.getElementById("reader-content-frame")
READER_PAGES = document.getElementById("reader-pages")
FOCUS_OVERLAY_HEIGHT = document.getElementById("focus-overlay-height")
FOCUS_OVERLAY_WIDTH = document.getElementById("focus-overlay-width")
HELP_CONTROLS = document.getElementById("help-controls")
PROGRESS_BAR_CONTAINER = document.getElementById("reader-progress-container")
PROGRESS_BAR = document.getElementById("reader-progress-bar")
PROGRESS_BAR_PAGES = document.getElementById("reader-progress-pages")
//===========================
// STATES GLOBAL VARIABLES
@ -64,33 +61,6 @@ MOUSEWHELL_WAIT = false
// Zooms utilites
// --------------
function globalZoomScale(){
if (READER_PAGES.dataset.globalZoomScale != undefined){
return parseFloat(READER_PAGES.dataset.globalZoomScale)
}
return 1.0
}
function globalZoomOffsetX(){
if (READER_PAGES.dataset.globalZoomOffset != undefined){
return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(',')[0])
}
return 0.0
}
function globalZoomOffsetY(){
if (READER_PAGES.dataset.globalZoomOffset != undefined){
return parseFloat(READER_PAGES.dataset.globalZoomOffset.split(',')[1])
}
return 0.0
}
function loadZoomsFromImgTagsIfRequired(){
// Zooms may be defined by another JS file
@ -179,48 +149,37 @@ function getPagesCount() {
return READER_PAGES.childElementCount
}
function pageOriginalHeight(pageNumber) {
return READER_PAGES.children[pageNumber - 1].naturalHeight
function pageOriginalHeight() {
return parseInt(READER_PAGES.dataset.pagesHeight)
}
function pageOriginalWidth(pageNumber) {
return READER_PAGES.children[pageNumber - 1].naturalWidth
function pageOriginalWidth() {
return parseInt(READER_PAGES.dataset.pagesWidth)
}
function readerFrameRatio() {
return READER_CONTENT_FRAME.clientWidth / READER_CONTENT_FRAME.clientHeight
}
function pageRatio(pageNumber) {
return READER_PAGES.children[pageNumber - 1].naturalWidth / READER_PAGES.children[pageNumber - 1].naturalHeight
function pageRatio() {
return READER_PAGES.dataset.pagesWidth / READER_PAGES.dataset.pagesHeight
}
function pageMaxHeight(){
let max_height = 0
for (var i = 0; i < READER_PAGES.children.length; i++) {
if(READER_PAGES.children[i].naturalHeight > max_height){
max_height = READER_PAGES.children[i].naturalHeight
}
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) {
return READER_CONTENT_FRAME.clientHeight / pageOriginalHeight()
}
return max_height
return READER_CONTENT_FRAME.clientWidth / pageOriginalWidth()
}
function pageVerticalOffset(pageNumber) {
return ( pageMaxHeight() - pageOriginalHeight(pageNumber) ) / 2
}
function previousPagesWidth(pageNumber) {
// The width of all previous pages relative to the provided index
let totalWidth = 0
for (let idx = 0; idx < pageNumber - 1; idx++){
totalWidth = totalWidth + READER_PAGES.children[idx].naturalWidth
}
return totalWidth
function totalPagesWidth() {
// The width of all cumuled pages with scale factor applied
return pageOriginalWidth() * getPagesCount()
}
// =========
@ -246,6 +205,7 @@ function initReader(){
for (var i = 0; i < READER_PAGES.children.length; i++) {
let img = READER_PAGES.children[i];
img.style.width = 100 / getPagesCount() + "%"
visibilityObserver.observe(img)
PROGRESS_BAR_PAGES.appendChild(document.createElement("div"))
@ -266,53 +226,22 @@ function initReader(){
function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
// Keep original values for registering
o_width = width
o_height = height
o_posx = posx
o_posy = posy
// First, scale so the page is at scale 1 compared to the frame
READER_PAGES.style.transform = "scale(" + totalPagesWidth() / READER_CONTENT_FRAME.clientWidth + ")"
// Apply global offsets before scales if we are displaying a zoom
// Pages display uses width & height = 0
if (width != 0 || height != 0){
width = width * globalZoomScale()
height = height * globalZoomScale()
posx = (posx + globalZoomOffsetX()) * globalZoomScale()
posy = (posy + globalZoomOffsetY()) * globalZoomScale()
}
// reduce width if offset sent us outside of page
if (posx < 0) {
width = width + posx
posx = 0
}
if ((posx + width) > pageOriginalWidth(pageNumber)) {
width = pageOriginalWidth(pageNumber) - posx
}
// reduce height if offset sent us outside of page
if (posy < 0) {
height = height + posy
posy = 0
}
if ((posy + height) > pageOriginalHeight(pageNumber)) {
height = pageOriginalHeight(pageNumber) - posy
}
// Align the top-left corner of the frame with the page
READER_PAGES.style.transform = "translate(-" + previousPagesWidth(pageNumber) + "px, -" + pageVerticalOffset(pageNumber) + "px )"
// Then, move to the correct page
READER_PAGES.style.transform = "translateX(" + (- pageOriginalWidth() * (pageNumber - 1)) + "px )" + READER_PAGES.style.transform
// Then move so the top-left point of the zoom match the frame top-left
READER_PAGES.style.transform = "translate(" + (- posx) + "px, " + (-posy) + "px )" + READER_PAGES.style.transform
// Then, scale so the zoom would fit the frame, and center the zoom
if (width == 0){
width = pageOriginalWidth(pageNumber)
width = pageOriginalWidth()
}
if (height == 0){
height = pageOriginalHeight(pageNumber)
height = pageOriginalHeight()
}
zoomRatio = width / height
@ -343,12 +272,11 @@ function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
updateFocusByHeight(scaledHeight)
}
// Use values before global offset / scale
CURRENT_PAGE = pageNumber
CURRENT_WIDTH = o_width
CURRENT_HEIGHT = o_height
CURRENT_X = o_posx
CURRENT_Y = o_posy
CURRENT_WIDTH = width
CURRENT_HEIGHT = height
CURRENT_X = posx
CURRENT_Y = posy
}
function refreshReaderDisplay() {
@ -459,19 +387,7 @@ function handleKeyPress(key){
}
function handleMouseWhell(event){
// Only handle scroll event if the target is the nav controls
// to avoid preventing page scrolling.
// Do disable page scrolling when we do prev/next, though
if (! READER_FRAME.contains(event.target)){
return
}
event.preventDefault()
event.stopPropagation()
function handleMouseWhell(deltaY){
if (MOUSEWHELL_WAIT){
return
@ -482,7 +398,7 @@ function handleMouseWhell(event){
}, MOUSEWHELL_MIN_DELAY)
}
if (event.deltaY > 0) {
if (deltaY > 0) {
moveReader(true, false)
}
@ -496,7 +412,6 @@ function handleMouseWhell(event){
// ======
window.addEventListener("load", (event) => {
VERSION_DISPLAY.innerText = VERSION_DISPLAY.innerText.replace("Unknown version", MELPOMENE_VERSION)
initReader()
});
@ -509,5 +424,5 @@ addEventListener("keydown", (event) => {
});
addEventListener("wheel", (event) => {
handleMouseWhell(event)
}, { passive:false });
handleMouseWhell(event.deltaY)
});

View File

@ -1,5 +1,5 @@
# Melpomene webcomic reader JSON/JS/HTML generator
# Version 1.0.0_RC1
# Version 1.0.0 - UNSTABLE
# CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/
import sys
@ -10,8 +10,45 @@ import argparse
from pathlib import Path
HTML_TEMPLATE = Path(__file__).parent / "melpomene.html"
HTML_TO_REPLACE = "<!-- your img tags here, see documentation -->"
HTML_START_CONSTANT = """\
<!-- Melpomene comic reader -->
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-frame">
<div id="reader-content-frame">
"""
HTML_END_CONSTANT = """\
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div>
<div id="focus-overlay-height" class="flex animated" style="height:100%">
<div class="grow obscured animated"></div>
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div>
<div class="grow obscured animated"></div>
</div>
<div class="grow obscured animated"></div>
</div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div>
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div>
</div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div>
<div>-----------------------</div>
<div><div class="key">F</div>: Toggle fullscreen</div>
<div><div class="key">P</div>: Toggle progress bar</div>
<div><div class="key">V</div>: Toggle panel / page viewing mode</div>
</div>
</div>
</div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div>
<div id="reader-progress-pages"></div>
</div>
</div>
<!-- End of Melpomene comic reader -->
"""
def extract_zooms(src_folder):
@ -32,20 +69,17 @@ def extract_zooms(src_folder):
zooms[idx] = {
"name": svg_path.stem,
"width": 0,
"height": 0,
"zooms": [],
}
tree = ET.parse(svg_path)
root = tree.getroot()
if "." in root.get("width"):
print(f"WARNING: file {svg_path} has a floating width, it will be rounded", file=sys.stderr)
zooms[idx]["width"] = round(float(root.get("width")))
if "." in root.get("height"):
print(f"WARNING: file {svg_path} has a floating height, it will be rounded", file=sys.stderr)
zooms[idx]["height"] = round(float(root.get("height")))
for svg in root.findall('.//{*}svg'):
if area.get("width") > max_width:
max_width = area.get("width")
if area.get("height") > max_width:
max_width = area.get("height")
for area in root.findall('.//{*}rect'):
zooms[idx]["zooms"].append([
@ -82,21 +116,21 @@ def write_json_or_js(zooms, dest_file, is_js):
def write_html(zooms, dest_file, pages_width, pages_height, prefix, extention):
img_tags = ""
for page_idx in sorted(zooms.keys()):
img_url = f"{prefix}{zooms[page_idx]['name']}.{extention}"
zoom_html_data = [','.join([str(zoom) for zoom in page_zooms]) for page_zooms in zooms[page_idx]["zooms"]]
zoom_html_str = ';'.join(zoom_html_data)
img_tags = img_tags + f' <img loading="lazy" height="{zooms[page_idx]["height"]}" width="{zooms[page_idx]["width"]}" src="{img_url}" data-zooms="{zoom_html_str}"/>\n'
with open(dest_file, "w") as data_file:
img_tags = img_tags.strip()
data_file.write(HTML_START_CONSTANT)
with open(HTML_TEMPLATE) as template_file, open(dest_file, "w") as data_file:
data_file.write(f' <div id="reader-pages" class="animated" data-pages-width="{pages_width}" data-pages-height="{pages_height}" hidden>\n')
data = template_file.read().replace(HTML_TO_REPLACE, img_tags)
data_file.write(data)
for page_idx in sorted(zooms.keys()):
img_url = f"{prefix}{zooms[page_idx]['name']}.{extention}"
zoom_html_data = [','.join([str(zoom) for zoom in page_zooms]) for page_zooms in zooms[page_idx]["zooms"]]
zoom_html_str = ';'.join(zoom_html_data)
data_file.write(f' <img loading="lazy" src="{img_url}" data-zooms="{zoom_html_str}"/>\n')
data_file.write(f' </div>\n')
data_file.write(HTML_END_CONSTANT)
def generate_argparse():
""" Generate Melpomene's generator input parser"""
@ -145,4 +179,4 @@ if __name__ == "__main__":
write_json_or_js(zooms, output, False)
elif args.output_format == "js":
write_json_or_js(zooms, output, True)
write_json_or_js(zooms, output, True)