SMIL/Animationen steuern
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.
Inhaltsverzeichnis
Achtung!
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
<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.
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.
<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.
<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"
).
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 aufnone
: ersetzt den vorherigen Zustand (Standard)
<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
- den Radius mit by um 10 erhöht.
- per calcMode="discrete" schrittweise abläuft
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 addiertreplace
: der Ursprungswert wird durch den neuen Wert ersetzt
<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.
<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
- ↑ CSS-Tricks: Synchronizing animations based on number of repetitions
- ↑ W3C: 3.3.5 The animation effect function F(t,u)
- Codepen; Amelia Bellamy-Royds: accumulate vs additive in SVG/SMIL animation
- O Reilly: kap 19x2 Using SVG/SMIL Animation
- metamorphant: The Algorithmic metamorphant Part 3: Animating with SVG and SMIL
- css-tricks: A Guide to SVG Animations (SMIL): Additive & Accumulative Animations: additive and accumulate