Markus Seidl: Abspielen von Videos auf einer HTML Slideshow (JavaScript)

Hallo Liebe Community,

ich hoffe ich finde hier Hilfe, weil mit Google komme ich diese mal nicht wirklich weiter.

Ich habe von den W3Schools einen HTML Code für eine Slideshow übernommen. Jetzt würde ich das so gerne so erweitern, das damit auch Videos angezeigt werden können.

Aber immer wenn ich den JavaScript Teil (nach x[slideIndex - 1].style.display = "block" oder x[slideIndex - 1].style.display = "block") so anpasse, damit dort ein Play oder Stop steht, wird entweder wahlweise alles angehalten, oder nur das Bild vom Anfang des Videos angezeigt, aber nicht abgespielt.

Für mich stellt sich die Frage, geht es überhaupt, und wenn ja, wo muss ich das Play und Stop hinsetzen, damit das Video abgespielt wird. Hier mein derzeitiger Code:

<title>Slideshow</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
    .mySlides {
        display: none;
    }

    .this-content {
        z-index: -1;
    }

    body {
        overflow: hidden;
        margin: 0;
    }

    #myProgress {
        width: 100%;
        margin-top: -4px;
        position: absolute;
        background-color: #C0C0C0;
    }

    #myBar {
        height: 4px;
        background-color: #009440;
    }
</style>

<body>
    <div class="this-content">

        <video class="mySlides" style="width:100%" data-timeout=5000><source src="Slides/video.mp4" type='video/mp4'></video>
        <img class="mySlides" src="Slides/Folie1(30).JPG" style="width:100%" data-timeout=5000>

    </div>

    <div id="myProgress">
        <div id="myBar"></div>
    </div>
    <script>
        var progressBarTimeout = 0;
        var progressBarWidth = 1;
        var progressBarRefreshRate = 50;
        var i = 0;
        var id;
        var slideIndex = 0;

        move();
        carousel();
        function carousel() {
            var i;
            var x = document.getElementsByClassName("mySlides");
            for (i = 0; i < x.length; i++) {
                x[i].style.display = "none";
				console.log(x[i].data-timeout);
            }
            slideIndex++;
            if (slideIndex > x.length) { slideIndex = 1 }
            x[slideIndex - 1].style.display = "block";

            progressBarTimeout = x[slideIndex - 1].dataset.timeout;
            progressBarWidth = 0;
            setTimeout(carousel, x[slideIndex - 1].dataset.timeout);
        }

        async function move() {
            msPerFrame = 1000 / progressBarRefreshRate;
            timestampLastStop = null;
            timestampNextStop = null;
            var elem = document.getElementById("myBar");

            timestampLastStop = Date.now();
            timestampNextStop = timestampLastStop + msPerFrame;
            while (true) {
                frames = progressBarTimeout / msPerFrame;
                result = await sleep(timestampNextStop - Date.now());
                result = null;
                timestampLastStop = timestampNextStop;
                timestampNextStop = timestampLastStop + msPerFrame;
                progressBarWidth++;
                elem.style.width = ((progressBarWidth / frames) * 100) + "%";
            }
        }

        function sleep(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }
    </script>
</body>
</html>

Gruß

Markus Seidl

  1. Hallo Markus,

    Ein "stop" gibt es für Videos nicht. Nur play und pause.

    Dass das Video nicht losläuft, ist eine Paranoia-Funktion der Browser. Da sich massenhaft Leute beschwert haben, deren PC im Büro plötzlich losplärrte oder -stöhnte, weil ein Autoplay-Video Ton hatte, ist ein automatisches Starten von Videos nur noch zulässig, wenn das Video stummgeschaltet ist. Das erreichst Du mit dem muted Attribut.

    Die Alternative ist ein Button "Slideshow starten" oder so, der die Slideshow startet - der Benutzer muss einmalig mit der Seite interagiert haben, damit ein automatisches Starten von Medien möglich ist. Da reicht schon ein Klick ins Nichts - ein "Starten" Button ist aber deutlich netter.

    Und dann sollte das funktionieren.

    Teil 1: Wegblenden (wo display:none gesetzt wird) - da prüfst Du, ob das DOM Element eine pause Methode hat und rufst sie bei Vorhandensein auf.

    Teil 2: Einblenden (wo display:block gesetzt wird) - da prüfst Du auf die play-Methode und rufst die auf.

    Es ist dafür etwas übersichtlicher, wenn Du das aktuelle Slide-Objekt in eine Variable legst.

    var i;
    var x = document.getElementsByClassName("mySlides");
    for (i = 0; i < x.length; i++) {
      var slide = x[i];
      slide.style.display = "none";
      if (slide.pause)
        slide.pause();
    }
    
    slideIndex++;
    if (slideIndex > x.length) { slideIndex = 1 }
    
    var slide = x[slideIndex - 1];
    slide.style.display = "block";
    if (slide.play) {
      slide.currentTime = 0;
      slide.play();
    }
    
    progressBarTimeout = slide.dataset.timeout;
    progressBarWidth = 0;
    setTimeout(carousel, progressBarTimeout);
    

    Grundsätzlich ist dieses Beispiel mal wieder ein Fall von "W3Fools". Dieser Code ist für sich allein wohl verwendbar, aber sobald auf der Seite mehr Script unterwegs ist, kollidiert alles miteinander. Da muss Modularisierung her; ich fürchte nur, deine JavaScript-Kenntnisse sind nicht wirklich hinreichend, um das zu verstehen. Aber schau mal ins Selfhtml WIKI, unter Modularisierung. Speziell: Kapselung im Funktions-Scope. Das ist nicht ganz trivial, man muss dafür ein paar Feinheiten von JS verstehen, aber es lohnt sich wenn man viel Script auf eine Seite bringen will.

    Dein Progress-Bar ist etwas, dass Du am besten ganz schnell wieder entfernst. Es gibt 3 Alternativen:

    • transition-Attribut in CSS
    • animation-Attribut in CSS (ist aufwändiger)
    • Javascript-Steuerung mit requestAnimationFrame (auch aufwändig)

    Aber NICHT mit setTimeout, und nicht mit der Annahme, du hättest 50 Hertz Bildwiederholrate. Die hast Du auf Computern eigentlich nie. Ein Desktop hat eher 60, und moderne Geräte auch 100 oder 120. CSS Animationen und requestAnimationFrame berücksichtigen das.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hallo Rolf,

      Dass das Video nicht losläuft, ist eine Paranoia-Funktion der Browser. Da sich massenhaft Leute beschwert haben, deren PC im Büro plötzlich losplärrte oder -stöhnte, weil ein Autoplay-Video Ton hatte, ist ein automatisches Starten von Videos nur noch zulässig, wenn das Video stummgeschaltet ist. Das erreichst Du mit dem muted Attribut.

      aber auch das kann man in einigen Browsern, z.B. Firefox und seinen Verwandten, per Konfiguration unterbinden, so dass auch stumme Videos nicht automatisch starten dürfen.

      Live long and pros healthy,
       Martin

      --
      Klein φ macht auch Mist.
      1. Hallo Martin,

        oh. Würde da ein Start-Button helfen?

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hi,

          oh. Würde da ein Start-Button helfen?

          ja, es geht ja nur um das automatische Starten ohne Benutzer-Interaktion.

          Live long and pros healthy,
           Martin

          --
          Klein φ macht auch Mist.
    2. Lieber Rolf,

      Es ist dafür etwas übersichtlicher, wenn Du das aktuelle Slide-Objekt in eine Variable legst.

      var i;
      var x = document.getElementsByClassName("mySlides");
      for (i = 0; i < x.length; i++) {
        var slide = x[i];
        slide.style.display = "none";
        if (slide.pause)
          slide.pause();
      }
      

      das geht noch übersichtlicher:

      document
        .getElementsByClassName("mySlides")
        .forEach(slide => {
      
          slide.style.display = "none";
      
          if (slide.pause) {
            slide.pause();
          }
        });
      

      Und anstatt mit style.display herumzufummeln, sollte man lieber ein hidden-Attribut setzen oder entfernen. Das kann man dann mit CSS als display:none oder display:block ausweisen:

      document
        .getElementsByClassName("mySlides")
        .forEach(slide => {
      
          slide.setAttribute("hidden", "hidden");
          // slide.removeAttribute("hidden");
      
          if (slide.pause) {
            slide.pause();
          }
        });
      

      Liebe Grüße

      Felix Riesterer

      1. Tach!

        document
          .getElementsByClassName("mySlides")
          .forEach(slide => {
        

        document.getElementsByClassName() gibt eine HTMLCollection zurück, die keine forEach-Methode hat. Besser nimmt man document.querySelectorAll(), da ist das Ergebnis eine NodeList, die zwar auch nicht alle Array-Methoden hat, aber zumindest ein forEach kennt.

        dedlfix.

      2. Hallo Felix,

        der Code von Markus sah so alt (und zusammengekupfert) aus, dass ich von vielen Erläuterungen zu modernem JS Abstand genommen habe. Ich weiß nicht mal, wo ich da hätte anfangen müssen, es wäre uferlos geworden.

        Man könnte einwenden: wer async verwendet, ist eh in 2016 angekommen und hat den IE abgehängt. Aber ich würde angesichts des Gesamtkunstwerks wetten, dass Markus den Sinn von "async" nicht oder nicht richtig verstanden hat und diesen Pseudoprogressbar ebenfalls irgendwoher kopiert hat. Wobei Tante Google die verwendeten Variablen nicht findet…

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hallo Rolf B,

          Tatsächlich habe ich den Quelltext kopiert, habe ich aber auch nicht anders gesagt :)

          "Ich habe von den W3Schools einen HTML Code für eine Slideshow übernommen"

          Den habe ich etwas umgebaut, damit ich das Timing der Slides über Data-Timeout setzen kann. Ich gebe auch gerne zu, dass weder JavaScript noch JS irgendwie mein Fall sind. Ich bin eher in der Ecke Powershell (Core, .Net) unterwegs. Und mein Problem könnte ich leicht lösen, wenn ich einen Windowsrechner hätte, auf dem die automatisch startende Präsentation angezeigt werden müsste.

          Allerdings arbeite ich mit einem Raspberry PI und HTML + JavaScript oder JS sind halt meine einzige Möglichkeiten, die ich habe, um aus einem Netzwerkordner eine HTML Präsentation automatisiert zu erstellen.

          @all: Erstmal danke für den ganzen Input. Ein Start Button ist halt kontraproduktiv, weil die Präsentation jeden Tag einfach von selbst starten soll.

          Derzeit wird ein entsprechendes Verzeichnis täglich geprüft, ob etwas geändert wurde. Wenn sich etwas geändert hat, dann wird eine indext.html mit Powershell zusammengebaut, welche alle Bilder enthält. Der Vorteil: Man muss einfach nur ein Bild reinlegen am Ende des Bildnamens ein z.B. (30) eintragen, und das Bild wird dann für 30 Sekunden in der Slideshow am nächsten Tag angezeigt.

          ich werde morgen einfach mal probieren Eure Änderungsvorschläge einzufügen. Vielen Dank erstmal :)

          Gruß

          Markus Seidl

          1. Hallo Markus,

            danke für die Erklärungen zu deinem Umfeld.

            Ein Start Button ist halt kontraproduktiv, weil die Präsentation jeden Tag einfach von selbst starten soll.

            Ja, aber leider sind die Browser so. Immerhin ist es derzeit noch so, dass gemutete Videos autostarten dürfen.

            .net Core sollte auch auf einem Raspberry laufen - hast Du damit schon mal dein Glück versucht?

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hallo zusammen,

              ich bitte um Entschuldigung für die späte Rückmeldung, möchte jetzt aber hier noch den positiven Vollzug der Tipps melden.

              Nachdem ich das Video "muted" gesetzt habe, lief es dann auch klaglos. Das Timing auf dem Raspberry um das Video zurückzusetzen lässt zu wünschen übrig, aber damit kann man leben (entweder sieht man am Anfang des Videos noch kurz das Ende vom vorherigen Durchlauf, oder man sieht am Ende wieder das erste Bild), das wird dann gegebenfalls mal etwas, woran ich mich mache, wenn ich dazu wieder Lust habe.

              Ich möchte mich für alle Kommentare bedanken.

              Gruß

              Markus Seidl

            2. .net Core sollte auch auf einem Raspberry laufen - hast Du damit schon mal dein Glück versucht?

              Grüß dich Rolf

              Ja, läuft wirklich drauf, allerdings kann ich damit keine grafischen Inhalte darstellen. Soll heißen, bisher gab es keinen Zugriff auf X oder Wayland (das war eines der ersten Dinge die ich Anfangs geprüft habe.

              Über Mono dürfte das gehen, allerdings hatte ich mich nicht weiter mit entsprechenden Entwicklungsumgebungen unter Linux beschäftigt. Und mit Powershell wollte ich das eigentlich nicht machen (Keine Ahnung wie gut das geht).

              Ich lasse mich gerne eines Besseren belehren, da ich gerne mit .Net programmiere, als auf Java/Script und Webseiten ausweichen zu müssen. Für das Konzept tauge ich einfach nicht 😀

              Gruß

              Markus Seidl

              1. Hallo Markus,

                hmpf, ja, das hab ich gar nicht gewusst.

                .net 6 will MAUI mitbringen, sozusagem ein portables Xamarin. Für .net 5 gibt's nur 3rd Party Zeugs, und Paul Knopf möchte Dich an Qt anbinden: https://github.com/qmlnet/qmlnet

                Rolf

                --
                sumpsi - posui - obstruxi