Skip to content

Instantly share code, notes, and snippets.

@egeozcan
Created October 18, 2024 08:40
Show Gist options
  • Select an option

  • Save egeozcan/b27e11a7e776972d18603222fa523ed4 to your computer and use it in GitHub Desktop.

Select an option

Save egeozcan/b27e11a7e776972d18603222fa523ed4 to your computer and use it in GitHub Desktop.

Revisions

  1. egeozcan created this gist Oct 18, 2024.
    292 changes: 292 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,292 @@
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Fullscreen Image Viewer</title>
    <style>
    body {
    font-family: Arial, sans-serif;
    }
    #imageDisplay {
    max-width: 80%;
    max-height: 78vh;
    height: auto;
    margin: 20px auto;
    border: 5px dashed #ddd;
    padding: 10px;
    cursor: pointer;
    }
    .btn {
    display: inline-block;
    padding: 10px;
    background-color: #007bff;
    color: white;
    cursor: pointer;
    margin: 10px;
    }
    .btn.danger {
    background-color: #dc3545;
    }
    #buttons {
    position: sticky;
    top: 0;
    display: block;
    background: white;
    user-select: none;
    }
    #container {
    width: 80%;
    margin: auto;
    text-align: center;
    }
    #thumbnails {
    display: flex;
    overflow-x: auto;
    padding: 10px;
    margin-top: 20px;
    justify-content: center;
    }
    .thumbnail {
    margin: 0 5px;
    cursor: pointer;
    }
    .thumbnail img {
    width: 100px;
    height: auto;
    border: 2px solid transparent;
    }
    .thumbnail img.active {
    border-color: blue;
    }
    [hidden] {
    display: none !important;
    }
    </style>
    </head>
    <body>

    <div id="container">
    <div>
    <input type="file" id="imageInput" multiple accept="image/*" style="display: none;">
    <label for="imageInput" class="btn">Select Images</label>
    </div>

    <div id="buttons" hidden>
    <button class="btn" onclick="previousImage()">Previous</button>
    <button class="btn" onclick="nextImage()">Next</button>
    <button class="btn danger" onclick="removeCurrentImage()">Remove Current Image</button>
    </div>
    <img id="imageDisplay" onclick="toggleFullscreen()">
    <div id="imageIndex"></div>
    <div id="thumbnails"></div>
    </div>

    <script>
    let images = [];
    let currentIndex = -1; // Start before the first index
    let touchstartX = 0;
    let touchendX = 0;

    function checkSwipeDirection() {
    if (touchstartX - touchendX > 100) nextImage();
    if (touchendX - touchstartX > 100) previousImage();
    }

    document.addEventListener("touchstart", e => {
    touchstartX = e.changedTouches[0].screenX;
    });

    document.addEventListener("touchend", e => {
    touchendX = e.changedTouches[0].screenX;
    checkSwipeDirection();
    });

    document.getElementById("imageInput").addEventListener("change", handleFiles);
    document.getElementById("container").addEventListener("paste", handlePaste);
    document.addEventListener("dragover", preventDefault);
    document.addEventListener("drop", handleDrop);
    document.addEventListener("keydown", handleKeydown);

    function handleFiles(e) {
    const files = e.target.files;
    for (let i = 0; i < files.length; i++) {
    if (files[i].type.startsWith("image/")) {
    const fileReader = new FileReader();
    fileReader.onload = (e) => {
    images.push(e.target.result);
    if (i === 0) displayImage(images.length - 1); // Display the last image added
    addThumbnail(e.target.result, images.length - 1);
    document.getElementById("buttons").removeAttribute("hidden");
    };
    fileReader.onerror = (e) => console.log(e.target.error);
    fileReader.readAsDataURL(files[i]);
    }
    }
    }

    function handlePaste(e) {
    const files = e.clipboardData.files;
    handleFiles({ target: { files } });
    }

    function preventDefault(e) {
    e.preventDefault();
    }

    function handleDrop(e) {
    e.preventDefault();
    if (!e.dataTransfer) {
    console.log("DataTransfer is null, this drop event cannot be processed.");
    return;
    }
    const files = e.dataTransfer.files;
    if (files && files.length > 0) {
    // Handle files from the user's computer
    handleFiles({ target: { files } });
    } else {
    // Handle images dragged from other web pages
    const htmlContent = e.dataTransfer.getData("text/html");
    const match = htmlContent && htmlContent.match(/<img [^>]*src="([^"]+)"[^>]*>/i);
    if (match && match[1]) {
    images.push(match[1]);
    displayImage(images.length - 1); // Display the last image added
    addThumbnail(match[1], images.length - 1);
    }
    }
    }

    function removeThumbnail(index) {
    const thumbnailsContainer = document.getElementById("thumbnails");
    thumbnailsContainer.removeChild(thumbnailsContainer.children[index]);
    }

    function displayImage(index) {
    const nothingToDisplay = images.length === 0;

    if (nothingToDisplay) {
    document.getElementById("buttons").setAttribute("hidden", "");
    } else {
    document.getElementById("buttons").removeAttribute("hidden");
    }

    currentIndex = nothingToDisplay ? -1 : index;
    document.getElementById("imageDisplay").src = nothingToDisplay ? "" : images[index];
    document.getElementById("imageIndex").innerText = nothingToDisplay ? "" : `Image ${index + 1} of ${images.length}`;
    updateThumbnailActiveState();
    }

    function addThumbnail(imageSrc, index) {
    const thumbnailWrapper = document.createElement("div");
    const thumbnailsContainer = document.getElementById("thumbnails");

    thumbnailWrapper.classList.add("thumbnail");
    thumbnailWrapper.addEventListener("click", () => displayImage([...thumbnailsContainer.children].indexOf(thumbnailWrapper)));

    const img = document.createElement("img");
    img.src = imageSrc;

    thumbnailWrapper.appendChild(img);
    thumbnailsContainer.appendChild(thumbnailWrapper);
    updateThumbnailActiveState();
    }

    function updateThumbnailActiveState() {
    const thumbnails = document.querySelectorAll(".thumbnail img");
    thumbnails.forEach((img, idx) => {
    img.classList.remove("active");
    if (idx === currentIndex) {
    img.classList.add("active");
    }
    });
    }

    function nextImage() {
    if (currentIndex === -1) {
    return;
    }

    displayImage((currentIndex + 1) % images.length);
    }

    function previousImage() {
    if (currentIndex === -1) {
    return;
    }

    displayImage((currentIndex - 1 + images.length) % images.length);
    }

    function handleKeydown(e) {
    if (e.key === "ArrowRight") {
    nextImage();
    } else if (e.key === "ArrowLeft") {
    previousImage();
    } else if (e.key === "Escape") {
    exitFullscreen();
    } else if (e.key === "Delete") {
    removeCurrentImage();
    } else if (e.key === "Enter") {
    toggleFullscreen();
    }
    }

    function removeCurrentImage() {
    if (currentIndex === -1) {
    return;
    }

    images.splice(currentIndex, 1);
    removeThumbnail(currentIndex);
    displayImage(currentIndex % images.length);
    }

    function toggleFullscreen() {
    const imgDisplay = document.getElementById("imageDisplay");
    if (!document.fullscreenElement) {
    if (currentIndex === -1) {
    return;
    }
    imgDisplay.requestFullscreen().catch(err => console.log(err));
    } else {
    if (document.exitFullscreen) {
    document.exitFullscreen();
    }
    }
    }

    function exitFullscreen() {
    if (document.fullscreenElement) {
    document.exitFullscreen();
    }
    }

    // load existing images when the page loads from the leftover thumbnails
    document.addEventListener("DOMContentLoaded", () => {
    let activeIndex = 0;

    const thumbnails = document.querySelectorAll(".thumbnail img");
    thumbnails.forEach((img, idx) => {
    images.push(img.src);
    img.addEventListener("click", () => displayImage(idx));
    if (img.classList.contains("active")) {
    activeIndex = idx;
    }
    });
    displayImage(activeIndex);
    });

    // change the image when the user uses scroll wheel
    document.getElementById("imageDisplay").addEventListener("wheel", e => {
    e.preventDefault();

    if (e.deltaY > 0) {
    nextImage();
    } else {
    previousImage();
    }
    });
    </script>

    </body>
    </html>