feat(ipub): on-screen interaction trigger
This commit is contained in:
98
.epub/example/OEBPS/scripts/ipub.js
Normal file
98
.epub/example/OEBPS/scripts/ipub.js
Normal file
@@ -0,0 +1,98 @@
|
||||
"use strict";
|
||||
|
||||
globalThis.addEventListener("load", () => {
|
||||
console.log("IPUB SCRIPT LOADED");
|
||||
|
||||
/** @type {Map<string, Element>} */
|
||||
const onScreenMap = new Map();
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach((e) => {
|
||||
if (e.intersectionRatio > 0) {
|
||||
console.debug(
|
||||
`IntersectionObserver: adding element #${e.target.id} to onScreenMap`,
|
||||
);
|
||||
onScreenMap.set(e.target.id, e.target);
|
||||
} else {
|
||||
console.debug(
|
||||
`IntersectionObserver: removing element #${e.target.id} to onScreenMap`,
|
||||
);
|
||||
onScreenMap.delete(e.target.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
for (const element of document.querySelectorAll(
|
||||
`[data-ipub-trigger="on-screen"]`,
|
||||
)) {
|
||||
observer.observe(element);
|
||||
}
|
||||
|
||||
document.addEventListener("scroll", async () => {
|
||||
for (const [id, element] of onScreenMap) {
|
||||
const perc = getPercentageInView(element);
|
||||
console.debug(`Element #${id} is now ${perc}% on screen`);
|
||||
|
||||
const played = element.getAttribute("data-ipub-trigger-played") == "true";
|
||||
|
||||
if (perc >= 100 && !played) {
|
||||
await playIpubElement(element);
|
||||
element.setAttribute("data-ipub-trigger-played", "true");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {Element} element
|
||||
*/
|
||||
async function playIpubElement(element) {
|
||||
switch (element.tagName) {
|
||||
case "audio": {
|
||||
/** @type {HTMLAudioElement} */
|
||||
const audio = element;
|
||||
|
||||
await audio.play();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Element} element
|
||||
* @returns {number}
|
||||
*/
|
||||
function getPercentageInView(element) {
|
||||
const viewTop = globalThis.pageYOffset;
|
||||
const viewBottom = viewTop + globalThis.innerHeight;
|
||||
|
||||
const rect = element.getBoundingClientRect();
|
||||
const elementTop = rect.y + viewTop;
|
||||
const elementBottom = rect.y + rect.height + viewTop;
|
||||
|
||||
if (viewTop > elementBottom || viewBottom < elementTop) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (
|
||||
(viewTop < elementTop && viewBottom > elementBottom) ||
|
||||
(elementTop < viewTop && elementBottom > viewBottom)
|
||||
) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
let inView = rect.height;
|
||||
|
||||
if (elementTop < viewTop) {
|
||||
inView = rect.height - (globalThis.pageYOffset - elementTop);
|
||||
}
|
||||
|
||||
if (elementBottom > viewBottom) {
|
||||
inView = inView - (elementBottom - viewBottom);
|
||||
}
|
||||
|
||||
return Math.round((inView / globalThis.innerHeight) * 100);
|
||||
}
|
||||
@@ -59,6 +59,39 @@
|
||||
we want the editor to "guess" what controls to provide the user with.
|
||||
-->
|
||||
</section>
|
||||
<section data-ipub-element="page" id="page02">
|
||||
<span data-ipub-element="image">
|
||||
<img src="../images/image0002.png" />
|
||||
</span>
|
||||
<!--
|
||||
This in the UI would be an "Area Interaction". The editor would first place
|
||||
the first top-left point, and then the bottom-right one, to select an area/size
|
||||
of the interaction.
|
||||
|
||||
The element wound not have a "action" per say, but would have a "on screen" trigger,
|
||||
which in itself would have the action "play sound".
|
||||
-->
|
||||
<audio data-ipub-element="interaction" data-ipub-trigger="on-screen" controls="true"
|
||||
volume="0" style="--ipub-x:20%;--ipub-y:25%;--ipub-width:50%;--ipub-height:50%;"
|
||||
id="int-audio0001">
|
||||
<source src="../audios/audio0001.wav.disable" />
|
||||
</audio>
|
||||
</section>
|
||||
<section data-ipub-element="page" id="page03">
|
||||
<span data-ipub-element="image">
|
||||
<img src="../images/image0003.png" />
|
||||
</span>
|
||||
</section>
|
||||
<section data-ipub-element="page" id="page04">
|
||||
<span data-ipub-element="image">
|
||||
<img src="../images/image0004.png" />
|
||||
</span>
|
||||
</section>
|
||||
<section data-ipub-element="page" id="page02">
|
||||
<span data-ipub-element="image">
|
||||
<img src="../images/image0002.png" />
|
||||
</span>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user