Compare commits

...

7 Commits
main ... dev

9 changed files with 361 additions and 480 deletions

View File

@ -30,10 +30,9 @@ 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. 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 : 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 : + You must duplicate the `img` tag for each of you comic page and :
+ set `url` to the actual URL of your page + 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> ...` + 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"/>` + 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"/>`
@ -45,7 +44,6 @@ The following limitations are known and will be improved upon :
+ Mobile support is currently limited + Mobile support is currently limited
+ There are some performences issues + There are some performences issues
+ Your comic pages need to be the same size
# How to setup Melpomene ? # How to setup Melpomene ?
@ -82,7 +80,15 @@ 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! 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 # 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).

View File

@ -1,83 +0,0 @@
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,59 +11,65 @@
<body> <body>
<!-- Melpomene comic reader --> <div id="melpomene">
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ --> <!-- Melpomene comic reader -->
<div id="reader-frame"> <!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-content-frame">
<div id="reader-pages" class="animated" data-pages-width="2481" data-pages-height="3503" hidden> <div id="melpomene-content-frame">
<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"/> <div id="melpomene-pages" hidden>
<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" 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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P04.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P05.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P06.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P07.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P08.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P09.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P10.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P11.jpg"/> <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" src="https://www.peppercarrot.com/0_sources/ep35_The-Reflection/hi-res/en_Pepper-and-Carrot_by-David-Revoy_E35P12.jpg"/> <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"/>
</div> </div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div> <div id="melpomene-focus-container">
<div id="focus-overlay-height" class="flex animated" style="height:100%"> <div></div>
<div class="grow obscured animated"></div> <div id="melpomene-focus-col">
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div> <div></div>
<div class="grow obscured animated"></div> <div id="melpomene-focus"></div>
<div></div>
</div> </div>
<div class="grow obscured animated"></div> <div></div>
</div> </div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div> <div id="melpomene-help-menu" style="opacity:1; transform: translate(0,0);">
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div> <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> </div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);"> <div id="melpomene-nav-controls">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div> <div onclick="moveReader(false,false)"></div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div> <div onclick="moveReader(true,false)"></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> </div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div> <div id="melpomene-progress-container">
<div id="reader-progress-pages"></div> <div id="melpomene-progress-bar"></div>
<div id="melpomene-progress-sections"></div>
</div> </div>
</div> </div>
<!-- End of Melpomene comic reader -->
</body> </body>
<!-- melpomene_js.html import --> <!-- melpomene_js.html import -->
<script src="demo_data.js"></script>
<script src="../melpomene.js"></script> <script src="../melpomene.js"></script>
</html> </html>

View File

@ -1,69 +0,0 @@
<!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,67 +11,65 @@
<body> <body>
<!-- melpomene_reader.html import --> <div id="melpomene">
<!-- Melpomene comic reader -->
<!-- Melpomene comic reader --> <!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<!-- 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/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="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 id="melpomene-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>
<div id="melpomene-focus-container">
<div></div>
<div id="melpomene-focus-col">
<div></div>
<div id="melpomene-focus"></div>
<div></div>
</div>
<div></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>
<div id="melpomene-nav-controls">
<div onclick="moveReader(false,false)"></div>
<div onclick="moveReader(true,false)"></div>
</div>
</div> </div>
<div id="reader-progress-container"> <div id="melpomene-progress-container">
<div id="reader-progress-bar"></div> <div id="melpomene-progress-bar"></div>
<div id="reader-progress-pages"></div> <div id="melpomene-progress-sections"></div>
</div> </div>
</div> </div>
<!-- End of Melpomene comic reader -->
</body> </body>
<!-- melpomene_js.html import --> <!-- melpomene_js.html import -->
<script src="demo_data.js"></script>
<script src="../melpomene.js"></script> <script src="../melpomene.js"></script>
</html> </html>

View File

@ -1,43 +1,8 @@
/* Melpomene webcomic reader CSS */ /* Melpomene webcomic reader CSS */
/* Version 1.0.0 - UNSTABLE */ /* Version 1.0.0_UNSTABLE */
/* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */ /* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */
:root { #melpomene-focus-container, #melpomene-nav-controls, #melpomene-progress-sections {
--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; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -45,82 +10,95 @@
height: 100%; height: 100%;
} }
.obscured { #melpomene, #melpomene-focus-container, #melpomene-pages, #melpomene-nav-controls, #melpomene-focus-col {
background-color: rgba(0, 0, 0, 0.85);
}
.flex {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.flex-col { #melpomene-pages, #melpomene-focus-container * {
display: flex; transition: all 1.5s ease;
}
#melpomene, #melpomene-focus-col {
flex-direction: column; flex-direction: column;
} }
.grow { #melpomene {
flex: 1 height: 100%;
width: 100%;
border: 2px solid;
box-sizing: border-box;
background-color: black;
} }
#nav-controls { #melpomene-content-frame {
display: grid; 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;
grid-template-areas: grid-template-areas:
"left top right" "left top right"
"left center right" "left center right"
"left bottom right"; "left bottom right";
}
#nav-controls {
grid-template-columns: 33% 0 1fr; grid-template-columns: 33% 0 1fr;
grid-template-rows: auto; grid-template-rows: auto;
} }
#nav-controls > div { #melpomene-nav-controls > div {
flex-grow: 1;
cursor: pointer; cursor: pointer;
} }
.top { #melpomene-nav-controls > div:first-child {
grid-area: top; width: 35%;
flex-grow: 0
} }
.left { #melpomene-help-menu {
grid-area: left;
}
.right { position: absolute;
grid-area: right; bottom: 0;
} right: 0;
.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%; font-size: 120%;
display: flex;
flex-direction: column;
color: white; 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; padding: 0 1em 1em 1em;
background-color: rgba(0,0,0,0.5);
z-index: 1; z-index: 1;
opacity: 0; opacity: 0;
transition: all 1.7s cubic-bezier(.76,.05,.86,.06); transition: all 1.7s cubic-bezier(.76,.05,.86,.06);
@ -130,18 +108,28 @@
transform: translate(0, calc(100% - 2em)); transform: translate(0, calc(100% - 2em));
} }
#help-menu > #help-controls:hover { #melpomene-help-menu:hover {
opacity: 1; opacity: 1;
transition: all 0.3s linear; transition: all 0.3s linear;
transform: translate(0, 0); transform: translate(0, 0);
} }
#help-menu > #help-controls > div { #melpomene-help-menu * {
margin-top: 1em; margin-top: 1em;
text-align: center; text-align: center;
} }
.key { #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 {
display: inline; display: inline;
margin: 0 0.5em; margin: 0 0.5em;
border: 1px white solid; border: 1px white solid;
@ -149,30 +137,25 @@
border-radius: 0.2em; border-radius: 0.2em;
} }
#reader-progress-container { #melpomene-progress-container {
background-color: dimgray; background-color: dimgray;
position: relative; position: relative;
} }
#reader-progress-bar{ #melpomene-progress-bar{
height: var(--reader-progressbar-height); height: 0.3em;
background-color: whitesmoke; background-color: whitesmoke;
width: 0%;
transition: all 0.5s ease-in-out; transition: all 0.5s ease-in-out;
width: 0%;
} }
#reader-progress-pages { #melpomene-progress-sections {
display: flex; display: flex;
height: 100%;
position: absolute;
width: 100%;
top: 0;
left: 0;
} }
#reader-progress-pages > * { #melpomene-progress-sections > * {
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
border-right: 0.3em black solid; border-right: 0.3em black solid;
flex: 1; flex: 1;
} }

View File

@ -1,39 +1,44 @@
<!-- Melpomene comic reader --> <div id="melpomene">
<!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ --> <!-- Melpomene comic reader -->
<div id="reader-frame"> <!-- CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ -->
<div id="reader-content-frame">
<!-- replace all 'xxxx' with the actual value --> <div id="melpomene-content-frame">
<div id="reader-pages" class="animated" data-pages-width="xxxx" data-pages-height="xxxx" hidden>
<img loading="lazy" src="xxxx" data-zooms="xxxx"/> <div id="melpomene-pages" hidden>
<!-- duplicate img for each comic page --> <!-- your img tags here, see documentation -->
</div> </div>
<div id="focus-overlay" class="flex-col fill">
<div class="grow obscured animated"></div> <div id="melpomene-focus-container">
<div id="focus-overlay-height" class="flex animated" style="height:100%"> <div></div>
<div class="grow obscured animated"></div> <div id="melpomene-focus-col">
<div id="focus-overlay-width" class="focus animated" style="width:100%"></div> <div></div>
<div class="grow obscured animated"></div> <div id="melpomene-focus"></div>
<div></div>
</div> </div>
<div class="grow obscured animated"></div> <div></div>
</div> </div>
<div id="nav-controls" class="fill">
<div class="left" id="nav-left" onclick="moveReader(false,false)"></div> <div id="melpomene-help-menu" style="opacity:1; transform: translate(0,0);">
<div class="right" id="nav-right" onclick="moveReader(true,false)"></div> <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> </div>
<div id="help-menu">
<div id="help-controls" style="opacity:1; transform: translate(0,0);"> <div id="melpomene-nav-controls">
<div><div class="key">&larr;</div>/ scroll up / clic : previous</div> <div onclick="moveReader(false,false)"></div>
<div><div class="key">&rarr;</div>/ scroll down / clic : next</div> <div onclick="moveReader(true,false)"></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> </div>
<div id="reader-progress-container">
<div id="reader-progress-bar"></div> <div id="melpomene-progress-container">
<div id="reader-progress-pages"></div> <div id="melpomene-progress-bar"></div>
<div id="melpomene-progress-sections"></div>
</div> </div>
</div> </div>
<!-- End of Melpomene comic reader -->

View File

@ -1,5 +1,5 @@
/* Melpomene webcomic reader JS */ /* Melpomene webcomic reader JS */
/* Version 1.0.0 - UNSTABLE */ /* Version 1.0.0_UNSTABLE */
/* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */ /* CC-BY-NC-SA : https://git.aribaud.net/caribaud/melpomene/ */
//============ //============
@ -25,15 +25,18 @@ DELAY_BEFORE_HIDDING_CONTROLS = 4000;
// STATES CONSTANTS // STATES CONSTANTS
//==================== //====================
READER_FRAME = document.getElementById("reader-frame") MELPOMENE_VERSION = "1.0.0_UNSTABLE"
READER_CONTENT_FRAME = document.getElementById("reader-content-frame")
READER_PAGES = document.getElementById("reader-pages") READER_FRAME = document.getElementById("melpomene")
FOCUS_OVERLAY_HEIGHT = document.getElementById("focus-overlay-height") READER_CONTENT_FRAME = document.getElementById("melpomene-content-frame")
FOCUS_OVERLAY_WIDTH = document.getElementById("focus-overlay-width") READER_PAGES = document.getElementById("melpomene-pages")
HELP_CONTROLS = document.getElementById("help-controls") FOCUS_OVERLAY_HEIGHT = document.getElementById("melpomene-focus")
PROGRESS_BAR_CONTAINER = document.getElementById("reader-progress-container") FOCUS_OVERLAY_WIDTH = document.getElementById("melpomene-focus-col")
PROGRESS_BAR = document.getElementById("reader-progress-bar") HELP_CONTROLS = document.getElementById("melpomene-help-menu")
PROGRESS_BAR_PAGES = document.getElementById("reader-progress-pages") 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")
//=========================== //===========================
// STATES GLOBAL VARIABLES // STATES GLOBAL VARIABLES
@ -61,6 +64,33 @@ MOUSEWHELL_WAIT = false
// Zooms utilites // 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(){ function loadZoomsFromImgTagsIfRequired(){
// Zooms may be defined by another JS file // Zooms may be defined by another JS file
@ -149,37 +179,48 @@ function getPagesCount() {
return READER_PAGES.childElementCount return READER_PAGES.childElementCount
} }
function pageOriginalHeight() { function pageOriginalHeight(pageNumber) {
return parseInt(READER_PAGES.dataset.pagesHeight) return READER_PAGES.children[pageNumber - 1].height
} }
function pageOriginalWidth() { function pageOriginalWidth(pageNumber) {
return parseInt(READER_PAGES.dataset.pagesWidth) return READER_PAGES.children[pageNumber - 1].width
} }
function readerFrameRatio() { function readerFrameRatio() {
return READER_CONTENT_FRAME.clientWidth / READER_CONTENT_FRAME.clientHeight return READER_CONTENT_FRAME.clientWidth / READER_CONTENT_FRAME.clientHeight
} }
function pageRatio() { function pageRatio(pageNumber) {
return READER_PAGES.dataset.pagesWidth / READER_PAGES.dataset.pagesHeight return READER_PAGES.children[pageNumber - 1].width / READER_PAGES.children[pageNumber - 1].height
} }
function isFrameRatioWiderThanPage(){ function pageMaxHeight(){
return readerFrameRatio() > pageRatio() let max_height = 0
}
for (var i = 0; i < READER_PAGES.children.length; i++) {
function pageToFrameScaleFactor(useHeight){ if(READER_PAGES.children[i].height > max_height){
// The scale factor to apply to a page so it exactly fit in the reader frame max_height = READER_PAGES.children[i].height
if (useHeight) { }
return READER_CONTENT_FRAME.clientHeight / pageOriginalHeight()
} }
return READER_CONTENT_FRAME.clientWidth / pageOriginalWidth()
return max_height
} }
function totalPagesWidth() { function pageVerticalOffset(pageNumber) {
// The width of all cumuled pages with scale factor applied return ( pageMaxHeight() - pageOriginalHeight(pageNumber) ) / 2
return pageOriginalWidth() * getPagesCount() }
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].width
}
return totalWidth
} }
// ========= // =========
@ -205,7 +246,6 @@ function initReader(){
for (var i = 0; i < READER_PAGES.children.length; i++) { for (var i = 0; i < READER_PAGES.children.length; i++) {
let img = READER_PAGES.children[i]; let img = READER_PAGES.children[i];
img.style.width = 100 / getPagesCount() + "%"
visibilityObserver.observe(img) visibilityObserver.observe(img)
PROGRESS_BAR_PAGES.appendChild(document.createElement("div")) PROGRESS_BAR_PAGES.appendChild(document.createElement("div"))
@ -226,22 +266,53 @@ function initReader(){
function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){ function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
// First, scale so the page is at scale 1 compared to the frame // Keep original values for registering
READER_PAGES.style.transform = "scale(" + totalPagesWidth() / READER_CONTENT_FRAME.clientWidth + ")" o_width = width
o_height = height
o_posx = posx
o_posy = posy
// Then, move to the correct page // Apply global offsets before scales if we are displaying a zoom
READER_PAGES.style.transform = "translateX(" + (- pageOriginalWidth() * (pageNumber - 1)) + "px )" + READER_PAGES.style.transform // 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 so the top-left point of the zoom match the frame top-left // 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 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 // Then, scale so the zoom would fit the frame, and center the zoom
if (width == 0){ if (width == 0){
width = pageOriginalWidth() width = pageOriginalWidth(pageNumber)
} }
if (height == 0){ if (height == 0){
height = pageOriginalHeight() height = pageOriginalHeight(pageNumber)
} }
zoomRatio = width / height zoomRatio = width / height
@ -272,11 +343,12 @@ function moveReaderDisplayToArea(pageNumber, width, height, posx, posy){
updateFocusByHeight(scaledHeight) updateFocusByHeight(scaledHeight)
} }
// Use values before global offset / scale
CURRENT_PAGE = pageNumber CURRENT_PAGE = pageNumber
CURRENT_WIDTH = width CURRENT_WIDTH = o_width
CURRENT_HEIGHT = height CURRENT_HEIGHT = o_height
CURRENT_X = posx CURRENT_X = o_posx
CURRENT_Y = posy CURRENT_Y = o_posy
} }
function refreshReaderDisplay() { function refreshReaderDisplay() {
@ -412,6 +484,7 @@ function handleMouseWhell(deltaY){
// ====== // ======
window.addEventListener("load", (event) => { window.addEventListener("load", (event) => {
VERSION_DISPLAY.innerText = VERSION_DISPLAY.innerText.replace("Unknown version", MELPOMENE_VERSION)
initReader() initReader()
}); });

View File

@ -1,5 +1,5 @@
# Melpomene webcomic reader JSON/JS/HTML generator # Melpomene webcomic reader JSON/JS/HTML generator
# Version 1.0.0 - UNSTABLE # Version 1.0.0_UNSTABLE
# CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/ # CC-BY-NC-SA https://git.aribaud.net/caribaud/melpomene/
import sys import sys
@ -10,45 +10,8 @@ import argparse
from pathlib import Path from pathlib import Path
HTML_START_CONSTANT = """\ HTML_TEMPLATE = Path(__file__).parent / "melpomene.html"
<!-- Melpomene comic reader --> HTML_TO_REPLACE = "<!-- your img tags here, see documentation -->"
<!-- 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): def extract_zooms(src_folder):
@ -69,17 +32,16 @@ def extract_zooms(src_folder):
zooms[idx] = { zooms[idx] = {
"name": svg_path.stem, "name": svg_path.stem,
"width": 0,
"height": 0,
"zooms": [], "zooms": [],
} }
tree = ET.parse(svg_path) tree = ET.parse(svg_path)
root = tree.getroot() root = tree.getroot()
for svg in root.findall('.//{*}svg'): zooms[idx]["width"] = int(root.get("width"))
if area.get("width") > max_width: zooms[idx]["height"] = int(root.get("height"))
max_width = area.get("width")
if area.get("height") > max_width:
max_width = area.get("height")
for area in root.findall('.//{*}rect'): for area in root.findall('.//{*}rect'):
zooms[idx]["zooms"].append([ zooms[idx]["zooms"].append([
@ -116,21 +78,21 @@ def write_json_or_js(zooms, dest_file, is_js):
def write_html(zooms, dest_file, pages_width, pages_height, prefix, extention): def write_html(zooms, dest_file, pages_width, pages_height, prefix, extention):
with open(dest_file, "w") as data_file: 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'
data_file.write(HTML_START_CONSTANT) img_tags = img_tags.strip()
data_file.write(f' <div id="reader-pages" class="animated" data-pages-width="{pages_width}" data-pages-height="{pages_height}" hidden>\n') with open(HTML_TEMPLATE) as template_file, open(dest_file, "w") as data_file:
for page_idx in sorted(zooms.keys()): data = template_file.read().replace(HTML_TO_REPLACE, img_tags)
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"]] data_file.write(data)
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(): def generate_argparse():
""" Generate Melpomene's generator input parser""" """ Generate Melpomene's generator input parser"""
@ -179,4 +141,4 @@ if __name__ == "__main__":
write_json_or_js(zooms, output, False) write_json_or_js(zooms, output, False)
elif args.output_format == "js": elif args.output_format == "js":
write_json_or_js(zooms, output, True) write_json_or_js(zooms, output, True)