SMIL/Animationen steuern

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Im letzten Kapitel wurden Animationen vorgestellt, die beim Laden der Seite automatisch starteten. Sie können Animationen aber auch durch Benutzerinteraktionen oder andere Events, wie z.B dem Ende einer anderen Animation starten.

Achtung!

Nutzer des Firefox können SMIL im Frickl nicht ausprobieren, da die animate-Elemente nicht gerendert werden.
Öffnen Sie das Beispiel mit einem Klick auf Vorschau in einem neuen Tab!

Animationen durch Events steuern

Sie können Animationen auch durch Events wie ein Anklicken oder Überfahren mit der Maus auslösen. Dazu müssen Sie den Event an die id des zu animierenden Objekts anfügen und als Wert dem begin-Attribut zuweisen.

id.click
id.mouseover
SMIL-Animationen durch Events steuern ansehen …
  <text id="eins" x="50" y="50">
    Klick mich!
    <animate 
      attributeName="rotate"
      begin="eins.click" 
      dur="3"
      from="0" to="360"
      repeatCount="1"
      restart="whenNotActive" />
  </text>
  
  <text id="zwei" x="50" y="200">
    Fahr mit der Maus drüber!
    <animate 
      attributeName="font-size"
      begin="zwei.mouseover" 
      dur="1"
      to="100"
      fill="freeze" />
  </text>  	
  <text id="drei" x="50" y="400">
    Fahr mit der Maus drüber und wieder weg!
    <animate 
      attributeName="font-size"
      begin="zwei.mouseover" 
      dur="1"
      to="100"
      fill="freeze" />
    <animate 
      attributeName="font-size"
      begin="zwei.mouseout" 
      dur="10"
      from="100" to="0"
      fill="freeze" />
  </text>

Durch einen Klick auf das obere Text-Element wird eine Animation gestartet, in der die Zeichen gedreht werden.
Das mittlere und untere Text-Element werden beim Befahren mit der Maus (begin="zwei.mouseover") vergrößert. Während der mittlere Text durch fill="freeze" im animierten Endzustand bleibt, wird der untere Text beim Verlassen der Maus (begin="drei.mouseout") bis auf 0 verkleinert.

Beachten Sie: Der mouseover-Event feuert beide Animationen gleichzeitig. Eine Alternative, um beide Texte getrennt animieren zu können, wäre die mittlere Animation mittels mousemove zu aktivieren.

Animationen miteinander verknüpfen

Sie können Animationen miteinander synchronisieren, wenn Sie für begin oder end keine feste Zeitangabe, sondern eine Referenz zu einer anderen Animation (syncbase value) setzen.

id.begin+1s
id.end-1s

Dafür müssen Sie ein .end oder .begin an die id der auslösenden Animation (oder eines Eventhandler eines Objekts) anhängen. Ein optionaler Zeitzuschlag (oder auch ein negativer Wert für einen vorzeitigen Anfang) ist ebenfalls möglich.

Animationen miteinander verknüpfen ansehen …
  <circle id="kreis" cx="100" cy="300" fill="white">
    <animate id="Ani1"
             attributeName="cx" 
             to="325"
             begin="kreis.click" 
             dur="1.5s" 
			 fill="freeze"
    />
  </circle>
  <text x="50" y="30">Klick auf die weiße Kugel!</text>
  <circle cx="400" cy="250" fill="var(--red)">
    <animate id="Ani2"
             attributeName="cx" 
             to="850"
             begin="Ani1.end" 
             dur="3s" fill="freeze"
            />
    <animate id="Ani2"
             attributeName="cy" 
             to="50"
             begin="Ani1.end" 
             dur="3s" fill="freeze"
            />
  </circle>
  <circle cx="400" cy="350" fill="var(--yellow)">
    <animate id="Ani3" 
	         attributeName="cx" 
			 begin="Ani1.end" 
			 dur="3s" 
			 to="850" fill="freeze"/>
  </circle>
  <circle cx="650" cy="350" fill="var(--blue)">
    <animate id="Ani4" attributeName="cy" begin="Ani2.begin+0.5s" dur="2s" values="350; 500; 500; 350" fill="freeze"/>
  </circle>
  <circle cx="-50" cy="500">
    <animate id="Ani4" attributeName="cx" begin="Ani3.end-2s" dur="4s" to="550" fill="freeze"/>
	<animate id="Ani4" attributeName="cy" begin="Ani3.end-2s" dur="4s" to="-50" fill="freeze"/>
  </circle>

Wenn Sie auf die weiße Kugel klicken, wird sie mit begin="kreis.click" animiert. Am Ende dieser Animation mit der id="Ani1" werden weitere Animationen mit begin="Ani1.end" gestartet. Die blaue Kugel räumt mit begin="Ani2.begin+0.5s" vorzeitig ihren Platz, während kurz vor Ende [begin="Ani3.end-2s" ) eine schwarze Kugel quer über das Feld rollt.

repeat(n)

In SMIL können Animationen auch so verknüpft werden, dass eine Aktion erst nach einer gewissen Anzahl Wiederholungen einer anderen Animation ausgeführt wird.[1]

Hierfür erhält begin die id der Auslöser-Animation und repeat(n). Dies kann durch eine zusätzliche Zeitangabe noch einen offset-value erhalten.

Verknüpfung mit repeat(n) ansehen …
  <circle id="kreis" cx="100" cy="150" fill="var(--yellow)">
    <animate id="Ani1"
             attributeName="cx" 
			 dur="3s"
             values="100; 800; 100"
			 repeatCount="3"
			 fill="freeze"
    />
  </circle>

  <circle cx="200" cy="250" fill="var(--red)">
    <animate id="Ani2"
             attributeName="cx" 
             to="850"
             begin="Ani1.repeat(2)-1s" 
             dur="3s" fill="freeze"
            />
    <animate id="Ani2"
             attributeName="cy" 
             to="500"
             begin="Ani1.repeat(2)-1s" 
             dur="3s" fill="freeze"
            />
  </circle>

Die gelbe Kugel läuft an der roten Kugel vorbei, ohne dass etwas passiert. Erst in der 2. Runde wird die rote Kugel animiert. Damit es aussieht, als ob sie angestoßen wurde, wird noch eine Sekunde abgezogen (begin="Ani1.repeat(2)-1s" ).

Beachten Sie: Im IE Edge beginnt die 2.Animation nicht!

Solche verknüpften Animationen können für komplexe Infografiken und Rube-Goldberg-Maschinen verwendet werden, bei denen eine egentlich triviale Aktion durch eine Kette nacheinander ablaufender Aktionen ausgelöst wird.

Aufbauende Animationen

Bis jetzt sind wir immer von einer Animation mit einer bestimmten Dauer dur ausgegangen. SMIL erlaubt es aber auch festzulegen, wie sich Animationen verhalten, die mehrfach wiederholt werden.[2] So fällt z.B ein Ball nicht nur einmal zu Boden, sondern hüpft immer wieder hoch.

Wenn Sie einen Kreis schrittweise vergrößern wollen, gibt es mehrere Ansätze:

  • Eine Folge von n- Animationen mit animate, in denen die Werte für from="…" und to="…" manuell berechnet werden.
  • eine Animation, in dem die (manuell berechneten) Zwischenschritte mit values notiert werden.
  • eine Animation, in der der Radius jeweils um den Offset-Wert vergrößert wird und die n-mal wiederholt wird.
  • (In CSS-Animations kann dies durch die Angabe von steps(n) einfach erreicht werden.)

accumulate

Sie können die Eigenschaft accumulate einsetzen, um zu vermeiden, dass die zu animierende Eigenschaft nach jeder Wiederholung auf ihren Ursprungswert gesetzt wird.

Folgende Angaben sind möglich:

  • sum: baut auf den vorherigen Zustand auf
  • none: ersetzt den vorherigen Zustand (Standard)
schrittweise Vergrößerung mit accumulate="sum" ansehen …
  <circle id="kreis1" cx="200" cy="200" fill="var(--yellow)">
	<animate id="enlarge"
		attributeName="r" 
		begin="1"
		from="20"
		by="10"
		dur="0.5s"
		calcMode="discrete"
		repeatCount="5"
		accumulate="sum"
		fill="freeze"
    />
  </circle>
  
  <circle id="kreis2" cx="600" cy="200" fill="var(--red)">
	<animate id="enlarge2"
		attributeName="r" 
		begin="1"
		from="20"
		by="10"
		dur="0.5s"
		accumulate="none"
		calcMode="discrete"
		repeatCount="10"
		fill="freeze"	
    />
  </circle>

Beide Kreise erhalten eine Animation, die

Der rechte Kreis beginnt dabei immer wieder neu, da accumulate="none" gesetzt ist.

Der linke Kreis wird schrittweise größer, da aufgrund von accumulate="sum" der Offset-Wert zum Endwert der vorherigen Animation dazugerechnet wird.

additive

Mit der Eigenschaft additive können Sie festlegen, wie sich Werte zum Ursprungswert verhalten.

Folgende Angaben sind möglich:

  • sum: der zu setzende Wert wird zum Ursprungswert addiert
  • replace: der Ursprungswert wird durch den neuen Wert ersetzt
Attribute zur Zustandsveränderung im Vergleich ansehen …
  <circle cx="100" cy="100" r="50" fill="#c32e04">
    <animate attributeName="r" 
            begin="1s" 
            dur="2s" 
            from="50" to="100" 
            fill="freeze"/>
  </circle>
 
  <circle cx="300" cy="100" r="50" fill="#dfac20">
    <animate attributeName="r" 
            begin="1s" 
            dur="2s" 
            by="50" 
            fill="freeze"/>
  </circle>
 
  <circle cx="500" cy="100" r="50" fill="#5a9900">
    <animate attributeName="r" 
            begin="1s" 
            dur="2s" 
            from="0" to="50" 
            additive="sum" 
            fill="freeze"/>
  </circle>

Jede Animation soll dafür sorgen, dass sich der Radius innerhalb von zwei Sekunden um 50 Einheiten erhöht.
Dabei verwendet der erste Kreis die Attribute from und to, der zweite das Attribut by und der dritte from, to und additive="sum".


Dieses Beispiel wäre am einfachsten in der mittleren Variante zu realisieren.

Die Eigenschaft additive zeigt jedoch beim Einsatz von values ihren Nutzen, da ansonsten die zu animierende Eigenschaft nach jedem Zustand wieder auf ihren ursprünglichen Wert zurückspringt.

Die Eigenschaft additive in Kombination mit values ansehen …
<svg>
  <circle cx="100" cy="100" r="50" fill="#c32e04">
    <animate attributeName="r" begin="1s" dur="2s" values="0; 50; 100" fill="freeze"/>
  </circle>

  <circle cx="400" cy="100" r="50" fill="#dfac20">
    <animate attributeName="r" begin="1s" dur="2s" values="0; 50; 100" additive="sum"
      fill="freeze"/>
  </circle>

  <circle cx="700" cy="100" r="50" fill="#5a9900">
    <animate attributeName="r" begin="1s" dur="2s" values="0; 50; 100" additive="replace"
      fill="freeze"/>
  </circle>
</svg>

Die Animation des ersten Kreises ohne additive-Attribut und des dritten Kreises mit der Angabe additive="replace" verlaufen absolut gleich. Sie besitzen im Endzustand auch denselben Radius, da der Wert von r immer zuerst auf 0, dann auf 50 und zuletzt auf 100 gesetzt wird.
Die Angabe additive="sum" sorgt hingegen dafür, dass der ursprüngliche r-Wert 50 zuerst mit 0, danach mit 50 und zum Schluss mit 100 addiert wird.


Quellen

  1. CSS-Tricks: Synchronizing animations based on number of repetitions
  2. W3C: 3.3.5 The animation effect function F(t,u)