Last active
November 30, 2024 14:24
-
-
Save signalwerk/88bd68b60f63b9199bddfee67cc531f4 to your computer and use it in GitHub Desktop.
Slideshow for Marc Rudin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Marc Rudin</title> | |
<style> | |
body, | |
html { | |
margin: 0; | |
padding: 0; | |
height: 100%; | |
width: 100%; | |
overflow: hidden; | |
background-color: black; | |
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", | |
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", | |
"Helvetica Neue", sans-serif; | |
-webkit-font-smoothing: antialiased; | |
-moz-osx-font-smoothing: grayscale; | |
} | |
#slideshow, | |
#slideshowNext { | |
position: absolute; | |
height: 100%; | |
width: 100%; | |
background-size: contain; | |
background-repeat: no-repeat; | |
background-position: center; | |
background-color: black; | |
} | |
#slideshowNext { | |
opacity: 0; | |
transition: opacity 0.3s ease-in-out; | |
} | |
#slideshowNext.visible { | |
opacity: 1; | |
} | |
#controls { | |
position: absolute; | |
bottom: 2.5rem; | |
left: 50%; | |
transform: translateX(-50%); | |
display: none; | |
background-color: rgba(0, 0, 0, 0.85); | |
color: white; | |
padding: 0.5rem; | |
border-radius: 0.4rem; | |
} | |
#controls button, | |
#controls input { | |
font-family: inherit; | |
font-size: inherit; | |
margin-right: 0.5rem; | |
padding: 0.5rem; | |
border: none; | |
border-radius: 0.2rem; | |
background-color: white; | |
color: black; | |
cursor: pointer; | |
} | |
#controls input[type="number"] { | |
width: 3rem; | |
} | |
</style> | |
<script> | |
var images = []; | |
var slideshow, | |
slideshowNext, | |
imageIndex = 0, | |
timer; | |
var isPlaying = true; | |
var interval; // Interval now initialized from #slideshow | |
// if you want to load images from a template, use this function | |
// <template id="imageTemplate"> | |
// https://marc-media.signalwerk.ch/img/w2400/0007f1b87b224fe8784ac3d76713ce38e755d5763738b43678d4c2f2a46cea6b.jpg | |
// https://marc-media.signalwerk.ch/img/w2400/000da9ce58c77a9e31efed3710a19b132c3bf5ee96a554d4030db3307babfe0c.jpg | |
// ... | |
// https://marc-media.signalwerk.ch/img/w2400/fec287181cd01aff9e4b93061b1d607a5b0f72e3295d5845d3ce320ac0479c67.jpg | |
// </template> | |
// function loadImagesFromTemplate() { | |
// var template = document.getElementById("imageTemplate"); | |
// images = template.innerHTML.trim().split("\n"); | |
// images = images.map((url) => url.trim()); // trim each url | |
// prefetchImage(imageIndex); | |
// changeImage(); | |
// } | |
async function loadImagesFromJSON() { | |
try { | |
const response = await fetch( | |
"https://marc-media.signalwerk.ch/data.json", | |
); | |
const data = await response.json(); | |
if (data && data.data && data.data.media) { | |
images = data.data.media.map( | |
(item) => | |
`https://marc-media.signalwerk.ch/img/w2400/${item.hash}.jpg`, | |
); | |
prefetchImage(imageIndex); | |
changeImage(); | |
} else { | |
console.error("Invalid JSON structure"); | |
} | |
} catch (error) { | |
console.error("Error loading images:", error); | |
} | |
} | |
function prefetchImage(index) { | |
const nextImage = new Image(); | |
nextImage.src = images[index]; | |
} | |
function changeImage() { | |
prefetchImage((imageIndex + 1) % images.length); | |
slideshowNext.style.backgroundImage = | |
"url('" + images[imageIndex] + "')"; | |
slideshowNext.classList.add("visible"); | |
setTimeout(function () { | |
slideshow.style.backgroundImage = "url('" + images[imageIndex] + "')"; | |
slideshowNext.classList.remove("visible"); | |
}, 300); | |
document.getElementById("playPause").textContent = isPlaying | |
? "Pause" | |
: "Play"; | |
if (isPlaying) { | |
timer = setTimeout(nextImage, interval * 1000); | |
} | |
} | |
function nextImage() { | |
clearTimeout(timer); | |
imageIndex = (imageIndex + 1) % images.length; | |
changeImage(); | |
} | |
function previousImage() { | |
clearTimeout(timer); | |
imageIndex = (imageIndex - 1 + images.length) % images.length; | |
changeImage(); | |
} | |
function playPause() { | |
isPlaying = !isPlaying; | |
clearTimeout(timer); | |
if (isPlaying) { | |
nextImage(); | |
} else { | |
changeImage(); | |
} | |
} | |
function fullScreenMode() { | |
if (document.documentElement.requestFullscreen) { | |
document.documentElement.requestFullscreen(); | |
} | |
} | |
function changeInterval() { | |
interval = document.getElementById("intervalInput").value; | |
clearTimeout(timer); | |
if (isPlaying) { | |
timer = setTimeout(nextImage, interval * 1000); | |
} | |
} | |
function handleKeyboardEvent(e) { | |
switch (e.code) { | |
case "Space": | |
playPause(); | |
e.preventDefault(); // Prevent scrolling | |
break; | |
case "ArrowRight": | |
nextImage(); | |
break; | |
case "ArrowLeft": | |
previousImage(); | |
break; | |
} | |
} | |
window.onload = function () { | |
slideshow = document.getElementById("slideshow"); | |
slideshowNext = document.getElementById("slideshowNext"); | |
var controls = document.getElementById("controls"); | |
// Initialize interval from #slideshow | |
interval = parseInt(slideshow.dataset.interval, 10); | |
document.getElementById("intervalInput").value = interval; | |
loadImagesFromJSON(); | |
document.body.onmousemove = function () { | |
if (controls.style.display !== "block") { | |
controls.style.display = "block"; | |
setTimeout(function () { | |
controls.style.display = "none"; | |
}, 5000); | |
} | |
}; | |
document.addEventListener("keydown", handleKeyboardEvent); | |
}; | |
</script> | |
</head> | |
<body> | |
<div id="slideshow" data-interval="5"></div> | |
<div id="slideshowNext"></div> | |
<div id="controls"> | |
<button onclick="previousImage()">Previous</button> | |
<button id="playPause" onclick="playPause()">Pause</button> | |
<button onclick="nextImage()">Next</button> | |
<button onclick="fullScreenMode()">Fullscreen</button> | |
<input | |
id="intervalInput" | |
type="number" | |
min="1" | |
onchange="changeInterval()" | |
/> | |
<label for="intervalInput">Interval (seconds)</label> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment