JavaScript/Tutorials/Web Animations/Animationen synchronisieren

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Im diesem Kapitel stellen wir Ihnen einen Bildwechsler vor, in dem die Bilder nacheinander ein- und wieder ausgeblendet werden. Dabei wird nicht ein Element animiert, sondern alle in der Galerie enthaltenen Bilder, sodass die Animation mehrfach eingesetzt und synchronisiert werden muss.

Überblendung

Beim Überblenden passiert im Grunde nichts anderes, als dass man bei zwei übereinander liegenden Bildern zuerst das untere mit voller Deckkraft darstellt, und das zweite völlig transparent deckungsgleich darüber. In der Animation erhöhen Sie nun die Deckkraft des zweiten Bildes, dass es das darunterliegende Bild immer mehr und schließlich ganz überdeckt.

Dazu bedient man sich der CSS-Eigenschaft opacity, die die Deckkraft (Opazität) eines Elements steuert. Je höher der Wert, desto weniger durchsichtig ist ein Element. Dabei darf der Wert für opacity Dezimalwerte zwischen 0.0 und 1.0 annehmen, stellt also den Prozentwert dar (20% Transparenz entsprächen dann 80% Deckkraft, also opacity:0.8).

HTML und CSS

Die HTML-Struktur unseres Bildwechslers haben wir aus dem CSS-Tutorial übernommen. Das Bild wird zusammen mit einer figcaption-Bildunterschrift innerhalb eines figure-Elements platziert.

Beispiel ansehen …
  <div id="gallery">
    <figure>
      <img src="Berge1.jpg" alt="">
      <figcaption>Bild 1 </figcaption>
    </figure>
    <figure>  
      <img src="Berge2.jpg" alt="">
      <figcaption>Bild 2 </figcaption>
    </figure></div>
#gallery {
  position: relative;
}

#gallery figure {
  position: absolute; 
  left: 0; 
  top: 0; 
}
Damit das zweite Bild genau über dem ersten zu liegen kommt, muss es absolut positioniert werden. Damit sein Bezugspunkt aber nicht die linke obere Ecke des Browserfensters, sondern das vorherige Bild wird, wurde das direkte Elternelement der figure-Elemente (hier das div mit der id gallery) relativ positioniert. Dadurch ändert sich die "Nullmarke" für absolut positionierte Kindelemente (in diesem Fall die figure-Elemente). Nun können die Bilder mittels top:0 und left:0 passgenau übereinander gelegt werden, was für das Überblenden unverzichtbar ist.

JavaScript

Beispiel ansehen …
document.addEventListener('DOMContentLoaded', function () {
 
  var fader = document.querySelector('#gallery figure:last-of-type');
      fader.animate([{
          opacity: '0'
      }, {
          opacity: '1'
      }
      ], {
          duration: 2000,
          direction: 'alternate',
          iterations: Infinity
      });
	
});
Mit document.querySelector('#gallery figure:last-of-type') wird das letzte figure-Element des div mit der id gallery selektiert und mit Element.animate() animiert.
Die Animation ändert die Deckkraft des zweiten figure-Elements von 0 auf 1, sodass es innerhalb von 2 Sekunden von durchscheinend auf volle Deckkraft wechselt. Durch die Angabe 'alternate' bei direction wird nach jedem Durchlauf die Richtung geändert. Über das Schlüsselwort Infinity der iterations-Eigenschaft wird festgelegt, dass die Animation unendlich oft wiederholt wird.

Laden des JavaScripts

Vielleicht ist ihnen schon aufgefallen, dass das JavaScript speziell strukturiert ist. Der Code mit der Animation ist in einer anonymen Funktion "verpackt". Sie wird einer anderen Funktion (hier addEventListener) als Argument übergeben, um im Falle eines bestimmten Ereignisses ausgeführt zu werden. Der Sinn dieser Struktur ist der, dass auf der einen Seite die verwendeten lokalen Variablen und Funktionen vor anderen JavaScript-Programmen verborgen werden, und dass auf der anderen Seite erst nach dem vollständigen Laden des Dokuments unser Programm ausgeführt wird.

Hauptartikel: JavaScript/Tutorials/Namensraum
Beispiel ansehen …
document.addEventListener('DOMContentLoaded', function () {
 
  document.querySelector('#interaktiv').addEventListener('click', klickverarbeitung);
 
  //your JS-Code
  ...
	  
});
An das Document-Objekt als Ausgangspunkt des Elementbaums wird mit der addEventListener-Methode ein Event-Handler angehängt.
Wenn das DOM aufgebaut ist, feuert das DOMContentLoaded-Ereignis und ruft unsere anonyme Funktion auf, die unser JavaScript-Script enthält.

Fader mit mehreren Bildern

Nachdem nun der Mechanismus des Überblendens geklärt ist, kann das Konzept ausgeweitet werden, um mehrere Bilder in einer Slideshow anzuzeigen. Dazu werden im Dokument einfach mehrere Bilder definiert, durch die sich das Script hindurcharbeiten muss. Bei der aufgerufenen Animation ändern sich nur Verzögerung vor dem Start und dann die Wartezeit nach der Animation, damit die Bilder passend ein- und wieder ausgeblendet werden.

Beispiel ansehen …
  // Auswahl des Bildwechslers und seiner Kindelemente
  var changer = document.querySelector( '#gallery' ),
      children = changer.querySelectorAll( 'figure'),	
      aniÜbergang = 1000,
      aniDur = 1000,	  
      dauer = (aniÜbergang + aniDur),
      aniStartDelay = aniÜbergang,
      aniEndDelay = (children.length -1)* (dauer);

  // figure-Elemente werden in absteigender Schleife durchlaufen
  for (var i = children.length - 1; i >= 0; i--) {
      children[i].animate([{
            opacity: '1'
        }, {
            opacity: '0'
        }
        ], {
            duration: aniDur,
            delay: aniStartDelay,
            endDelay: aniEndDelay,
            fill: 'forwards',	
            iterations: 1
        });
    var gesamt = aniDur + aniStartDelay + aniEndDelay;
    aniStartDelay = aniStartDelay + dauer;
    aniEndDelay = aniEndDelay - dauer;
Die Bildergalerie mit der id gallery wird mit querySelector selektiert. Anschließend werden mit querySelectorAll alle figure-Elemente ausgesucht.

Da diese absolut positioniert sind, liegt das im Markup letzte figure-Element oben. In einer Schleife werden diese dann absteigend so animiert, dass sie nach einer Verzögerung innerhalb von 1s (1000 Millisekunden) ausgeblendet werden, sodass das darunterliegende Bild sichtbar wird.

Die Verzögerung (delay) und das Warten nach der erfolgten Animation (endDelay) sind so getaktet, dass die Bilder nacheinander zu sehen sind und alle Animationen gleichzeitig beendet sind, damit es bei einer Wiederholung nicht zu Rucklern kommt.
Beachten Sie: Wenn Sie die Animation mehrfach wiederholen, indem Sie den Wert von iterations vergrößern oder das Schlüsselwort Infinity einsetzen, gerät die Taktung außer Kontrolle und die Bilder werden nur noch unregelmäßig angezeigt.

Der Grund dafür ist, dass die Angaben von delay und endDelay nur zu Beginn und am Ende der Animation wirken, nicht jedoch zwischen den Wiederholungen.

Deshalb werden wir im folgenden Beispiel einen anderen Ansatz verfolgen.

mehrere Animationen zeitversetzt starten

Im letzten Beispiel haben Sie gesehen, dass es mit der Web Animations API noch nicht möglich ist, eine Animation zeitversetzt für mehrere Elemente zu verwenden, indem die Timing Options verändert werden.

Allerdings ist es möglich, das KeyframeEffect Object entsprechend zu verändern, sodass die einzelnen Bilder passend eingeschoben werden.

Keyframes takten

Alle Bilder sollen anfangs ausgeblendet sein und nacheinander für einen gleichen Zeitraum, der in der Variable intervall festgelegt ist, eingeblendet werden. Also müssen die einzelnen keyframes abhängig von der Anzahl der Bilder, die sich über children.length ermitteln lässt, getaktet werden.

Anders als bei CSS-Animation erhalten die keyframes keine Wegpunkte oder Prozentangaben vorangestellt, sondern werden über die offset-Eigenschaft eingestellt. Mit ihr werden den einzelnen keyframes Wegpunkte zugewiesen. Start ist dabei immer 0, Ende 1, dazwischenliegende Werte müssen innerhalb dieser Spanne sein.

KeyframeEffect-Object mit variablen Werten ansehen …
var keyframes = [
  { opacity: 0 },
  { opacity: 1, offset: 1 / children.length * 1 / 3 },
  { opacity: 1, offset: 1 / children.length * 2 / 3 },
  { opacity: 0, offset: 1 / children.length },
  { opacity: 0 }
];

for (var index = 0; index < children.length; index++) {
  children[index].animate(keyframes, { 
    duration: intervall * children.length,
    delay: index * intervall,
    iterations: Infinity 
  });
}
In einem keyframeEffect-Objekt werden mehrere keyframes festgelegt: Alle Bilder sind anfangs ausgeblendet. Jedes Bild wird im ihm zustehenden Anteil eingeblendet. Bei einem Drittel der Zeit ist es voll sichtbar, bei zwei Dritteln beginnt die Ausblendung.
In einer Schleife werden alle figure-Elemente animiert. Die Dauer dur ergibt sich aus der Multiplikation von Intervalldauer und Anzahl der Bilder aus children.length. Mit delay werden die Animationen nacheinander passend ausgeführt.

Da jedes Bild innerhalb seines Intervalls eingeblendet wird, erscheint zwischen den Bildern immer wieder der Hintergrund.

Feinabstimmung

Um die Lücke zwischen den Einblendungen verschwinden zu lassen, müssen die einzelnen Animationen länger dauern. so muss das nächste Bild schon eingeblendet werden, wenn das vorherige noch sichtbar ist. Um dies zu erreichen, müssen die Wegpunkte verschoben werden. Am einfachsten gelingt dies durch eine Teilung der Gesamtdauer durch eine Zahl, die kleiner als die Gesamtanzahl der Bilder ist.

eine sanfte Überblendung ansehen …
var keyframes = [
  { opacity: 0 },
  { opacity: 1, offset: 1 / (children.length - 2) * 1 / 3 },
  { opacity: 1, offset: 1 / (children.length - 2) * 2 / 3 },
  { opacity: 0, offset: 1 / (children.length - 2) },
  { opacity: 0 }
];

for (var index = 0; index < children.length; index++) {
  children[index].animate(keyframes, { 
    duration: intervall * children.length,
    delay: index * intervall,
    iterations: Infinity 
  });
}
Da bei (children.length-1) noch ein bisschen grau erscheint, wird der offset-Wert durch (children.length-2) geteilt.


Nun haben wir einen Bildwechsler, der selbständig durchläuft. Allerdings ist es nur schwer möglich, die verschiedenen Animationen zu steuern. Im folgenden Kapitel stellen wir Ihnen einen Komfort-Bildwechlser vor, der neben einer fortlaufenden Reihenfolge auch eine Zufallsauswahl ermöglicht und bequem gesteuert werden kann. Dabei sollen verschiedene Arten des Einschwebens und Überblendens ermöglicht werden.