Skip to content

Instantly share code, notes, and snippets.

@signalwerk
Last active November 30, 2024 14:24
Show Gist options
  • Save signalwerk/88bd68b60f63b9199bddfee67cc531f4 to your computer and use it in GitHub Desktop.
Save signalwerk/88bd68b60f63b9199bddfee67cc531f4 to your computer and use it in GitHub Desktop.
Slideshow for Marc Rudin
<!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