Beispiel:JS-Komfort-Bildwechsler.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

<!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" media="screen" href="./Beispiel:SELFHTML-Beispiel-Grundlayout.css"> <title>Komfort-Bildwechsler</title> <style>

.gallery {

 & a {
   text-decoration: none;
   display: inline-block;
   
   &:focus {
     outline: 2px solid black;
   }
   
   & img {
     width: 100px;
     display: block;
   }
 }

}

  1. gallery-fullview {
 width: 100vw; height: 100vh;
 padding: 2em 5vw 8vh 5vw;
 background-color: #888;
 box-sizing: border-box;
 border-radius: 10px;
 &::backdrop { 
   background: rgb(200 200 200 /.8) ;
 }
 & figure {
   border: thin solid #aaa;
   margin: 0;
   box-sizing: border-box;
   width: 100%;
   height: 100%;
   background: #ccc;
 }
 & img {
   display: block;
   margin: auto;
   width: 100%;
   height: 100%;
   object-fit: contain;
 }
 & figcaption {
   font-style: italic;
   text-align: center;
   background-color: white;
 }
 & button {
   position: absolute;
   width: 2rem;
   height: 2rem;
   cursor: pointer;	
   border: 0;
   background-color: transparent;
   --fill: none;
   --stroke: white;
   
   &:focus {
     outline: none;
   }
   
   &[value=close],
   &[value=shuffle],
   &[value=play] {
     top: 0;
     right: 0;
     --fill: firebrick;
     
     &:hover,
     &:focus {
       --fill: red;
     }
   }
   
   &[value=shuffle],
   &[value=play] {
     & svg {
       &:nth-of-type(1) {
         display: inline;
       }
       
       &:nth-of-type(2) {
         display: none;
       }
     }
   }
   
   &[value=shuffle] {
     right: 4rem;	
     
     .shuffle & svg {
       &:nth-of-type(1) {
         display: none;
       }
       
       &:nth-of-type(2) {
         display: inline;
       }
     }
   }
     
   &[value=play] {
     right: 8rem;	
     
     .play & svg {
       &:nth-of-type(1) {
         display: none;
       }
       
       &:nth-of-type(2) {
         display: inline;
       }
     }
   }
   &[value=prev],
   &[value=next] {
     top: calc(50% - 100px);
     width: 100px;
     height: 200px;
     padding: 0;
     --stroke: #fff6;
     &:hover,
     &:focus {
       --stroke: skyblue;
     }
   }
   
   &[value=prev] {
     left: 2vw;
   }
   
   &[value=next] {
     right: 2vw;
   }
 }

}

.visually-hidden { position: absolute !important; clip: rect(1px, 1px, 1px, 1px) !important; padding: 0 !important; border: 0 !important; height: 1px !important; width: 1px !important; overflow: hidden !important; white-space: nowrap !important; }

</style> <script> 'use strict'; document.addEventListener('DOMContentLoaded', function () {

 // Zeit in ms zum betrachten der Bilder im Automatik-Modus
 const zeitZumBetrachten = 1000;
 // click-Handler auf alle Galerien legen. KÖNNTE man auch auf den Body legen und Bubbling nutzen, aber dann bekommt
 // man mit currentTarget die Galerie nicht geschenkt (und muss sie vom target mit closest(.gallery') suchen)
 document.querySelectorAll(".gallery")
         .forEach( gallery => gallery.addEventListener("click", handleGalleryClick) );
 // EIGENEN click-Handler auf den Fullview. 
 document.getElementById("gallery-fullview")
         .addEventListener("click", handleFullviewClickAndKeydown);
 // EIGENEN keydown-Handler aufs Dokument. 
 document.addEventListener("keydown", handleFullviewClickAndKeydown);
 // Klick in einer Galerie ist simpel, das behandelt alles die showInFullview Funktion, 
 // die auch vom handleFullviewClickAndKeydown zum navigieren verwendet wird.
 function handleGalleryClick(event) {
   // event.target ist das img Element oder welches HTML auch immer sonst im Thumb steckt. Suche
   // das a Element als Bezugspunkt für die Fullview-Anzeige heraus
   const clickedLink = event.target.closest("a");
   // Nicht auf einen Link geklickt? Nichts tun.
   if (!clickedLink) return;
   event.preventDefault();
   // Delegiere den Rest...
   showInFullview(clickedLink);
 }
 function showInFullview(link) {
         // der Fullscreen-Viewer
   const fullview = document.getElementById("gallery-fullview"),
         // die Galerie zum geklickten Link
         gallery = link.closest(".gallery"),
         // Das Thumbnail-Bild darin, brauchen wir für ...
         thumb = link.querySelector("img"),
         // ... den Caption-Text, der aus dem alt-Attribut generiert wird.
         caption = thumb ? thumb.alt : "";
   // Den angeklickten Link zum aria-selected Element machen
   link.parentElement.querySelectorAll("a[aria-selected]").forEach(link => link.removeAttribute("aria-selected"));
   link.setAttribute("aria-selected", "true");
   // src-Attribut im Vollbild auf das verlinkte Bild setzen und Caption in figcaption eintragen
   fullview.querySelector("img").src = link.href;
   fullview.querySelector("figcaption").textContent = caption;
   // Galerie-ID speichern für click-Handler im Fullview und Fullview einblenden (falls noch nicht passiert)
   fullview.dataset.gallery = gallery.id;
   fullview.showModal();
 }
 function handleFullviewClickAndKeydown(event) {
   const fullview = document.getElementById("gallery-fullview")
   if(!fullview) return;
   const gallery = document.getElementById(fullview.dataset.gallery);
   if(!gallery) return;
   const currentThumb = gallery.querySelector("a[aria-selected]");
   if (!currentThumb) return;
   let nextThumb,action="",stopped;
   
   if(event.type == "keydown") { 
     action = event.key; // Welche Taste wurde gedrückt?
   }
   if(event.type == "click") {
     const clickedButton = event.target.closest("button");
     // Nicht auf einen Button geklickt? Nichts tun.
     if (!clickedButton) return;
     action = clickedButton.value; // Welcher Button wurde geklickt?
   }
   switch (action) {
     case 'close':
     case 'Escape':
     case 'x':
       stopAnimations(fullview);
       fullview.close();
       fullview.dataset.gallery = null;
       gallery.querySelector("a[aria-selected]").focus();
       break;
     case 'prev':
     case 'ArrowLeft':
       // Ausführliche Version
       nextThumb = navigateDOM(currentThumb,
                               elem => elem.previousElementSibling,
                               elem => elem.tagName == "A");
       if (!nextThumb)
         nextThumb = gallery.querySelector("a:last-of-type")
       showInFullview(nextThumb);
       break;
     case 'next':
     case 'ArrowRight':
       // Kompaktversion als Einzeiler
       showInFullview(navigateDOM(currentThumb, elem => elem.nextElementSibling, elem => elem.tagName == "A") || gallery.querySelector("a:first-of-type"));
       break;
     case 'play':
     case 'r':
       // Evtl. laufende Animationen benden
       stopped = stopAnimations(fullview);
       if (!stopped.playStopped)  {
         // Mit setInterval die Bilder nacheinander zeigen (next animieren)
         fullview.play = setInterval(function() {
          showInFullview(navigateDOM(gallery.querySelector("a[aria-selected]"), elem => elem.nextElementSibling, elem => elem.tagName == "A") || 
                       gallery.querySelector("a:first-of-type"));
         }, zeitZumBetrachten);
         fullview.classList.add("play");
       }
       break;
     case 'shuffle':
     case 's':
       // Evtl. laufende Animationen benden
       stopped = stopAnimations(fullview);
       if (!stopped.shuffleStopped) {
         // Per Zufall das nächste Bilde ermitteln und anzeigen
         const allThumbs = gallery.querySelectorAll("a");
         let randomNumber,lastNumber=-1;
         fullview.shuffle = setInterval(function() {
           do {
             randomNumber = Math.floor(Math.random()*allThumbs.length);
           } while(randomNumber == lastNumber)
           showInFullview(allThumbs[randomNumber]);
           lastNumber = randomNumber;
         }, zeitZumBetrachten); 
         fullview.classList.add("shuffle");
       }
       break;
     case 'p':
       // Evtl. laufende Animationen benden
       stopAnimations(fullview);
       break;
   }

   /* Helper: Navigiere schrittweise durch's DOM, bis eine Bedingung erfüllt ist
    * "current" - Ausgangspunkt (ein HTML Elemnt)
    * Was das "nächste" Thumbnail-Element ist, legt der proceed-Callback fest.
    * Die Funktion sucht ausdrücklich nach a-Elementen - wenn andere Elemente im
    * Container sind, werden sie übersprungen. Wird kein Link mehr gefunden, gibt
    * die Funktion null zurück - um den Rest kümmere sich bitte der Aufrufer.
    */
   function navigateDOM(current, proceed, checkFound) {
     if (!current)
       return null;
     while (current = proceed(current)) {
       if (checkFound(current))
         break;
     }
     return current;
   }
   
   /* Helper: Beende evtl. laufende Animationen und gebe zurück, 
    * welche Animation beendet wurde. */
   function stopAnimations(fullviewElement) {
     let playStopped = false,
         shuffleStopped = false;
     if(fullview.play) {
       clearInterval(fullviewElement.play);
       fullviewElement.play = null;
       fullviewElement.classList.remove("play");
       playStopped = true;
     }
     if(fullviewElement.shuffle) {
       clearInterval(fullviewElement.shuffle);
       fullviewElement.shuffle = null;
       fullviewElement.classList.remove("shuffle");
       shuffleStopped = true;
     }
     return { "playStopped": playStopped, "shuffleStopped": shuffleStopped };
   }
 }
   

}); </script>

</head> <body>

Komfort-Bildwechsler

<section id="peru" class="gallery">

Peru 2007

 <a href="https://wiki.selfhtml.org/images/2/28/Peru-1.jpg">
   <img src="https://wiki.selfhtml.org/images/2/24/Peru-1-sm.jpg" alt="Peru 2007: Cusco - Blick auf Ausangate">
 </a>
 <a href="https://wiki.selfhtml.org/images/4/42/Peru-2.jpg">
   <img src="https://wiki.selfhtml.org/images/e/ea/Peru-2-sm.jpg" alt="Peru 2007: Valle Sagrado">
 </a>
 <a href="https://wiki.selfhtml.org/images/a/ab/Peru-3.jpg">
   <img src="https://wiki.selfhtml.org/images/c/c5/Peru-3-sm.jpg" alt="Peru 2007: Machu Picchu">
 </a>
 <a href="https://wiki.selfhtml.org/images/8/80/Peru-4.jpg">
   <img src="https://wiki.selfhtml.org/images/b/b0/Peru-4-sm.jpg" alt="Peru 2007: Machu Picchu - Lamas in den Ruinen">
 </a>
 <a href="https://wiki.selfhtml.org/images/3/3f/Peru-5.jpg">
   <img src="https://wiki.selfhtml.org/images/7/71/Peru-5-sm.jpg" alt="Peru 2007: Uros-Inseln im Titicaca-See">
 </a>
 <a href="https://wiki.selfhtml.org/images/4/41/Peru-6.jpg">
   <img src="https://wiki.selfhtml.org/images/5/5b/Peru-6-sm.jpg" alt="Peru 2007: Ceviche - Meeresfrüchte mit Zitronensaft">
 </a>

</section>

<section id="gardasee" class="gallery">

Gardasee 2016

 <a href="https://wiki.selfhtml.org/images/f/fb/Gardasee1.jpg">
   <img src="https://wiki.selfhtml.org/images/8/8f/Gardasee1-sm.jpg" alt="Gardasee 2016: Sonnenuntergang bei Bardolino ">
 </a>
 <a href="https://wiki.selfhtml.org/images/1/16/Gardasee2.jpg">
   <img src="https://wiki.selfhtml.org/images/6/67/Gardasee2-sm.jpg" alt="Gardasee 2016: Aperol Spritz - Entspannung für Lehrer ">
 </a>
 <a href="https://wiki.selfhtml.org/images/3/3b/Gardasee-3.jpg">
   <img src="https://wiki.selfhtml.org/images/4/40/Gardasee-3-sm.jpg" alt="Gardasee 2016: Gardaland bei Bardolino - Blick von oben">
 </a>
 <a href="https://wiki.selfhtml.org/images/e/ef/Gardasee-4.jpg">
   <img src="https://wiki.selfhtml.org/images/1/16/Gardasee-4-sm.jpg" alt="Gardasee 2016: Wasserrutsche im Gardaland ">
 </a>
 <a href="https://wiki.selfhtml.org/images/1/15/Gardasee-5.jpg">
   <img src="https://wiki.selfhtml.org/images/c/c3/Gardasee-5-sm.jpg" alt="Gardasee 2016: Sonnenuntergang bei Bardolino">
 </a>
 <a href="https://wiki.selfhtml.org/images/5/5a/Gardasee-6.jpg">
   <img src="https://wiki.selfhtml.org/images/d/d4/Gardasee-6-sm.jpg" alt="Gardasee 2016: nächtliches Handballspiel ">
 </a>
 <a href="https://wiki.selfhtml.org/images/2/2e/Gardasee-7.jpg">
   <img src="https://wiki.selfhtml.org/images/a/a4/Gardasee-7-sm.jpg" alt="Gardasee 2016: Die antike Arena in Verona - heute für Konzerte und Opern genutzt ">
 </a>

</section>

Bei einem Klick auf die Thumbnail-Vorschau erhalten Sie eine Großansicht.

<dialog id="gallery-fullview">

 <figure>
   <img alt="described by figcaption" src='data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg"%3E%3C/svg%3E'>
   <figcaption></figcaption>
 </figure>
 <button type="button" value="close">Schließen
   <svg viewBox='0 0 100 100'>
     <rect width='100' height='100' fill='var(--fill)' />
     <path d='M20,20 l60,60 m0,-60 l-60,60' fill='none' stroke='white' stroke-width='15' stroke-linecap='round'/>
    </svg>
  </button>
 <button type="button" value="play" aria-label="play/pause animation">automatisch abspielen
   <svg viewBox='0 0 200 200'>
     <rect width='200' height='200' fill='var(--fill)' />
     <path d='M60,30 l90,70 -90,70z' fill='white' stroke='white' stroke-width='30' stroke-linejoin='round' />
   </svg>
   <svg viewBox='0 0 100 100'>
     <rect width='100' height='100' fill='var(--fill)' />
     <path d='M30,20 L30,80 M70,20 L70,80' fill='none' stroke='white' stroke-width='25' stroke-linecap='round'/>
    </svg>
 </button>
 <button type="button" value="shuffle">shuffle
   <svg viewBox='0 0 376 376'>
     <rect x='0' y='0' width='100%' height='100%' fill='var(--fill)' stroke='black' stroke-width='1'/>
     <path d='M376 280l-79 68v-45h-13c-42 0-73-19-98-44 10-12 19-23 27-34 2-3 4-5 6-7 19 19 39 33 66 33h13v-38L376 280zM0 129h39c25 0 44 12 62 29 3-4 6-8 9-12 7-10 15-20 23-30 -25-23-55-40-95-40H0V129zM297 28v45h-13c-69 0-108 51-143 97 -31 41-58 76-101 76H0v53h39c69 0 108-51 143-97 31-41 58-76 101-76h13v38l79-68L297 28z' fill='white'/>
   </svg>
   <svg viewBox='0 0 100 100'>
     <rect width='100' height='100' fill='var(--fill)' />
     <path d='M30,20 L30,80 M70,20 L70,80' fill='none' stroke='white' stroke-width='25' stroke-linecap='round'/>
   </svg>
 </button>               
 <button type="button" value="prev">vorheriges Bild
   <svg width='100' height='200' viewBox='0 0 100 200' xmlns='http://www.w3.org/2000/svg'>
     <path id='left' d='M90,10 l-80,90 l80,90' fill='var(--fill)' stroke='var(--stroke)' stroke-width='15' stroke-linecap='round'/>
   </svg>
 </button>
 <button type="button" value="next">nächstes Bild
   <svg width='100' height='200' viewBox='0 0 100 200'>
     <path id='right' d='M10,10 l80,90 l-80,90' fill='var(--fill)' stroke='var(--stroke)' stroke-width='15' stroke-linecap='round'/>
   </svg>
 </button>

</dialog>

</body> </html>