Dr. O. Hoffmann
Die Zeit ist Bewegung im Raum.
Joseph Joubert
Eine Animation ist die Visualisierung eines Bewegungsablaufes oder allgemeiner die zeitabhängige Darstellung einer zeitabhängigen Änderung einer visuell erfaßbaren Größe. Das menschliche Auge zusammen mit dem Gehirn ist eher drauf optimiert, überhaupt Bewegungen oder Änderungen wahrzunehmen, als den genauen Zeitverlauf zu analysieren oder auch nur mehrere bewegte Objekte gleichzeitig zu analysieren. Anders das menschliche Gehör, mit welchem das Gehirn sehr präzise Frequenzschwankungen wahrnehmen kann, der Mensch hat ein sehr gutes Empfinden für Musik und Rhythmik. Daher läßt sich das Gehirn bei mit dem Auge wahrgenommenen Zeitabläufen viel einfacher täuschen als bei Geräuschen. Darauf beruhen im Grunde alle Arten von Animationen. In der Regel werden nur einzelne Bilder mit Momentaufnahmen gezeigt, die im langsam wahrnehmenden Gehirn zu einer Bewegung zusammengesetzt werden. Bei Fernsehen oder Kino reichen dafür bereits 25 oder 24 Bilder pro Sekunde, mit etwas gutem Willen reicht auch bereits die Hälfte. Irgendwo darunter merkt eigentlich jeder, daß er mit Einzelbildern getäuscht wird.
Pixelgraphikformate wie MPEG, MNG, GIF arbeiten nach dem gleichen Schema wie Film oder Fernsehen, mit Einzelbildern. SVG geht anders vor, es wird nicht festgelegt, wie die Bewegung erzeugt wird, vielmehr wird beschrieben, wie sie abläuft. Das nennt sich dann auch deklarative Animation. Erst dem Darstellungsprogramm obliegt die Aufgabe, dem Gehirn des Nutzers Bewegung nahezubringen. Existierende Darstellungsprogramme werden das auch wieder mit einer Abfolge von Einzelbildern realisieren, aber vielleicht wird es ja einmal Programme geben, die es anders machen - SVG legt sich da nicht fest, ist also ein Format, welches so gut auch für zukünftige Entwicklungen geeignet ist. Ein Nachteil der Nutzung von Einzelbildern wird auch elegant umgangen: hat man mehrere bewegte Objekte, so muß man die alle in eine Bilderfolge packen. Bei SVG hingegen wird nur beschrieben, welche Parameter sich wie ändern sollen, was für jeden einzelnen Parameter einen eigenen Zeitablauf bedeuten kann. So lassen sich sehr einfach auch komplexe Vorgänge mit zahlreichen bewegten Parametern beschreiben, wobei die Größe der Datei je nach Problem geradezu unglaublich klein bleiben kann. Mit einer SVG-Datei von unter 10kB ist es problemlos möglich, schnelle Bewegungsabläufe von mehreren Parametern zu beschreiben, die sich in Milliarden von Jahren nicht wiederholen werden. Andererseits können mit einer Einzelbilderfolge natürlich Millionen von Einzelpixeln auf einmal animiert werden. Auch das ist prinzipiell mit SVG möglich, dafür würden dann Einzelbilder in einem Pixelgraphikformat wie JPEG oder PNG entsprechend gegeneinander ausgetauscht. Hinzu kommt bei SVG noch die Möglichkeit, mehrere Bilderfolgen teiltransparent zu überlagern oder gegeneinander zu transformieren.
Im digitalen Zeitalter mag es natürlich sein, kontinuierliche Vorgänge oder sonstige nicht diskrete Objekte künstlich in Stücke zu hacken, damit geht natürlich oft ein Informationsverlust einher, der gleich bei der Digitalisierung passiert, wonach der übrigbleibende Rest dann vor weiteren Verlusten bewahrt werden kann, bei analogen Daten ist der Verlust hingegen meist schleichend mit Kopiervorgängen oder einfach durch den Lauf der Zeit, dafür behalten kontinuierliche Vorgänge und Objekte aber auch ihren kontinuierlichen Charakter. Mit SVG könnten beide Vorteile mit neuen Techniken genutzt werden - digitale Speicherung und analoge Darstellung etwa von Animationen - ein klarer Qualitätsgewinn gegenüber den derzeitigen Einzelbild-basierten Verfahren. Vielleicht ist ja bereits das nächste Zeitalter wieder ein analoges mit neuen Techniken und Methoden, schon seit langer Zeit kann man etwa in klassischen Oszilloskopen kontinuierliche Vorgänge auch kontinuierlich darstellen, Quantenzustände in zukünftigen Quantencomputern haben sowohl diskrete als auch analoge Aspekte. So oder so, weil in SVG die Animation eine beschriebene Bedeutung hat, bleibt die Bedeutung und Information erhalten, egal mit welcher Technik die Darstellung vorgenommen wird.
Für Animationen greift SVG zu einem guten Teil auf Methoden des Standards SMIL zurück und teilt sie mit diesem. Animationen sind sehr einfach zu erstellen mit dafür vorgesehenen speziellen Elementen. Nahezu alle Attribute oder Eigenschaften nahezu aller SVG-Elemente lassen sich animieren.
Für einen definierten Zeitablauf ist festgelegt, daß bei SVG 1.1 der
Dokumentbeginn vorliegt, wenn das svg
-Element samt Inhalt komplett interpretiert
ist und die Darstellung unmittelbar bevorsteht. Das entspricht in SVG tiny 1.2 der
Voreinstellung des Attributes timelineBegin
des
Elementes svg
gleich onLoad ist.
Der andere mögliche Wert ist onStart, das ist ein etwas früherer Zeitpunkt,
wenn die Startmarkierung des svg
-Elementes komplett interpretiert und verarbeitet
worden ist.
Ferner hat SVG tiny 1.2 eines neues Attribut snapshotTime
ebenfalls des Elementes svg
, mit dem man angeben kann, welcher Zeitpunkt genommen
werden soll, wenn das Darstellungsprogramm ein Vorschaubild zeigt. Der Wert ist eine Zeitangabe, etwa in
Sekunden. Der Inhalt zu dem Zeitpunkt sollte dann besonders repräsentativ sein.
Opera bietet ein Vorschaubild an, dies Attribut spielt da aber leider keine Rolle (getestet bis Version 10alpha).
Für SVG 1.1 oder auch Programme, die Animation noch ignorieren, wird das nicht helfen, da
kann aber der statische Wert von Attributen und Eigenschaften gewählt werden. Für Programme,
die Animation korrekt interpretieren, kann man dann den Wert zum Zeitpunkt 0 einfach mit einem
zusätzlichen Animationselement setzen.
Mit dem set
-Element kann der Wert eines Attributes einmalig geändert werden.
Besonders geeignet für einmalige Zustandsänderungen oder
als diskrete Reaktion auf eine Nutzerinteraktion.
Die Änderung erfolgt zeitlich diskret ohne Zwischenstufen.
Mit dem animate
-Element kann darüber
hinaus jeweils ein Einzelattribut animiert werden.
Änderungen zwischen verschiedenen Werten können
diskret oder kontinuierlich erfolgen.
Darüberhinaus gibt es weitere angebbare Feinheiten in der Art der
Animation. Zur Animation von Farbveränderungen ist das Element
animateColor
vorgesehen, für Transformationen
das Element animateTransform
.
Neben der Animation von Einzelattributen kann mit animateMotion
auch
ein komplexeres Objekt bewegt werden, wobei das Bewegungsmuster gar
über das der animierten Transformation eines Gruppenelementes hinausgeht
und die Bewegung entlang eines beliebigen Pfades ermöglicht.
Dabei ist zu beachten, daß bei Mozilla/Gecko die Interpretation des Elementes animateColor
absichtlich manipuliert wird, damit sind bei Mozilla/Gecko also keine Animationen durchführbar.
Stattdessen können Autoren für dieses Darstellungsprogramm stattdessen auch animate
verwenden.
Das erste Beispiel zeigt die
Animation von Einzelattributen mit
dem Element animate
(Quelltext zur
Animation von Einzelattributen).
Mittels xlink:href
kann angegeben werden, auf welches Element sich die
Animationsangaben beziehen. Alternativ kann das Animationselement auch vom betroffenen
Element umschlossen sein, wie in folgenden Beispielen noch zu sehen sein wird.
Das Attribut attributeName
gibt an, welches Attribut des
betroffenen Elementes animiert werden soll. Nahezu alle Attribute können
nach bestimmten Regeln animiert werden.
attributeType
ist entweder XML, CSS oder
auto, je nachdem, ob es um ein XML-Attribut geht oder um eine
CSS-Eigenschaft.
Bei auto wird erst nach einem
CSS-Attribut gesucht und sofern das nicht vorhanden ist, das entsprechende
XML-Attribut verwendet. Da CSS XML überschreibt,
ergibt sich damit die Möglichkeit einer
sehr feinen Einstellung und interessanter Kombinationen.
Sofern gar kein CSS zur Dekoration verwendet werden soll, kann das Attribut auch weggelassen werden.
Mittels der Attribute
from
und to
kann angegeben werden, von welchem Wert zu welchem die Animation laufen soll.
Mit by
statt to
können
relative Änderungen erreicht werden. Alternativ kann auch mit dem Attribut
values
eine
Semikolon-separierte Liste von Werten angegeben werden, die durchlaufen werden sollen.
Insgesamt stehen damit sechs Animationstypen zur Verfügung:
values
-Animation mit values
="from;to").values
="from;from+by").values
="0;by" mit
additive
="sum".
Bei Transformationen gilt die Zuordnung zu einer values
-Animation prinzipiell genauso,
verschiedene Programme setzen das aber nicht korrekt um.)set
-Element handelt.
Bei set
ist immer to
zu verwenden, weder values
, from
noch
by
und zusammen mit set
ist das Verhalten bei
den Betrachtungsprogrammen korrekt.
Bei allen anderen Animationselementen sollte der Dokumentautor das definierte Verhalten in
SMIL
genau verstanden haben. Dennoch gibt es derzeit (Mai 2009) kein mir bekanntes
Darstellungsprogramm, welches to-Animationen unter allen Umständen richtig darstellt,
bei nicht additiven Attributen gibt es zudem auch noch Lücken in älteren Versionen von SMIL).animateMotion
.
animateMotion
kann zwar auch die
vorherigen Animationstypen verwenden, es kann allerdings auch auf verschiedene Weise ein
Pfad angegeben werden, entlang dem sich ein Objekt bewegen kann.
Mittels dur
wird die zeitliche Länge der Animation angegeben, ohne Zeiteinheit in
Sekunden, ebenso bei der Einheit s. Es gibt zahlreiche weitere Möglichkeiten, auf
die ich hier nicht weiter eingehen möchte, da man in der Regel mit der
Angabe in Sekunden auskommt. Es gibt auch den Wert indefinite, was aber in der
Regel nur sinnvoll ist, um eine Animation zu verhindern oder zu stoppen.
Mittels repeatCount
wird angegeben, wie oft die Animation
wiederholt werden soll, der Wert braucht nicht ganzzahlig sein und kann auch den
Wert indefinite annehmen, was in dem Falle bedeutet, daß die Animation immer
weiter fortgesetzt wird, solange dies nicht ein davon unabhängiges Ereignis beendet.
Mit dem Attribut fill
(nicht zu verwechseln mit der gleichnamigen
Eigenschaft zur Füllfarbe von zu malenden Elementen) wird
festgelegt, was passiert, wenn die Animation zuende ist. Bei freeze wird der letzte
Wert der Animation beibehalten, bei remove wird auf den Ausgangswert
zurückgesprungen, beziehungsweise es bleibt nur der Effekt von Animationen mit niedrigerer
Priorität sichtbar oder der Wert, der ohne Animation verfügbar ist.
Das zweite Beispiel zeigt eine weitere
Animation von Einzelattributen
(Quelltext zur
zweiten Animation von Einzelattributen)
mit dem Element animate
. Recht eindrucksvoll ist zu sehen, daß durch
verschiedene teilerfremde Werte für dur
eine Wiederholung
des gesamten Animationsablaufs praktisch vermieden werden kann.
Innerhalb der Lebensdauer des Rechners wird sich die Animation nicht
komplett identisch wiederholen. Als neues Attribut lernen wir begin
kennen, damit kann man den Startzeitpunkt der Animation festlegen.
Wenn nicht anderweitig unterbunden, bleibt das animierte Objekt solange
statisch, bis das begin
-Ereignis eingetreten ist.
Wert des begin
-Attributes
ist eine Semikolon-separierte Liste von Zeitpunkten oder Ereignissen
oder der Wert indefinite, bei dem die Animation anderweitig gestartet
werden muß. Der einfachste Fall ist die Angabe eines Zeitpunktes
relativ zum Beginn der Animation, also etwa
begin
="2s".
Alternativ zu repeatCount
kann auch direkt die
Zeit angegeben werden, wie lange wiederholt werden soll, also zum
Beispiel repeatDur
= "15s".
Mit end
kann auch eine Zeit angegeben werden,
nach der die Animation beendet werden soll. Sind mehrere dieser
Attribute angegeben, so beendet jeweils der kleinste daraus ermittelte
Zeitpunkt die Animation, der größer als oder gleich
begin
ist. Wie bei
begin
kann auch bei end
eine
Semikolon-separierte Liste von Zeitpunkten oder
Ereignissen oder der Wert indefinite angegeben werden.
Animationsbegrenzung
mit repeatDur
(Quelltext zur
Animationsbegrenzung mit repeatDur
).
Zu animierbaren Einzelattributen gehören auch die Pfade, die beliebig kompliziert aussehen können, wodurch sich bereits mit einfachsten Mitteln recht interessante Effekte erzielen lassen. Im englischen Sprachraum wird das auch morphing genannt, oder auf deutsch in etwa Formwandlung, kann man recht häufig auch bei Pixelgrapik sehen, wo etwa ein Gesicht in ein anderes verwandelt wird. Oder aber es wird deformiert, was dann eher warping oder Verformung genannt würde - etwa zu sehen bei dem java-applet in meiner Selbstdarstellungsrubrik. Als erstes Beispiel dazu ändern wir nur die abgerundeten Ecken eines Rechtecks und bekommen so einen Übergang zu einer Ellipse: Animierter Formwandler Rechteck - Ellipse (Quelltext zum Formwandler).
Bei Pfaden geht das prinzipiell ähnlich, ist aber leider mit
Opera 8 nicht immer nachvollziehbar, obgleich die Animation von Pfaden
auch zu SVG-tiny gehört. Da scheint es beim Opera 8 einen
Fehler oder eine Lücke zu geben, die in Opera 9.0 nahezu beseitigt ist,
lediglich bei elliptischen Bögen hat auch Opera 9.0 noch Probleme, die
in einer Vorversion schon mal behoben waren. In späteren Opera-Versionen
funktionieren die Animationen. Das adobe-plugin hat allerdings
auch bei elliptischen Bögen Probleme mit korrekter Animation.
Wie dem auch sei, hier sind ein paar Beispiele, wo neben der
Liniendicke auch Pfade beziehungsweise Polygone animiert werden:
Animierter Formwandler kubische Kurve (Quelltext zum
Formwandler kubische Kurve),
Animierter Formwandler Polygon (Quelltext zum
Formwandler Polygon).
Animierter Formwandler quadratische Kurve (Quelltext zum
Formwandler quadratische Kurve).
Animierter Formwandler quadratische Kurve 2 (Quelltext zum
Formwandler quadratische Kurve 2).
Animierter Formwandler kubische Kurve 2 (Quelltext zum
Formwandler kubische Kurve 2).
Wichtig dabei zu wissen ist, daß sich die Struktur der Pfadangabe nicht ändern
darf, lediglich die Zahlenwerte. Die durch Buchstaben definierten Malanweisungen bleiben also
die gleichen und von gleicher Anzahl. Auch die Anzahl der Zahlenwerte bleibt gleich, nur ihre
Werte können animiert werden.
Wird das Polygon als Pfad aus geraden Linien formuliert, kann dies interessanter Weise
auch Opera 8 animieren, warum auch immer:
Animierter Formwandler Polygon als Pfad (Quelltext zum dritten
Formwandler). Die beteiligten Polygone werden zufällig ausgewählt, es lohnt sich
also, die Datei mehrfach aufzurufen.
Animierter Formwandler quadratischer Kurvenzug
Animierter Formwandler quadratischer Kurvenzug 2
Animierter Formwandler kubischer Kurvenzug.
Wichtig bei Pfadanimationen ist, daß in SVG 1.1 immer dieselbe Abfolge von Buchstaben in jedem Animationswert und dem statischen Wert gegeben sein muß. In SVG tiny 1.2 ist das etwas abgemildert, dort sind diskrete Animationen immer möglich und bei kontinuierlichen darf auch zwischen relativen und absoluten Angaben gewechselt werden. Wenn die Abfolge falsch ist, findet keine Animation statt, es wird dann auch nicht etwa automatisch auf eine diskrete Animation umgeschaltet. Die Animation der Pfade von Polygonen und Polylinien erfolgt analog zu Pfadanimationen.
Durch Animation eines der Attribute stroke-dasharray
oder stroke-dashoffset
läßt sich auch erreichen,
daß es so aussieht, als werde eine Kurve gezeichnet. Dazu sollte allerdings
bekannt sein, wie lang die Kurve ist. Was bei Kurven aus geraden Linien einfach ist,
kann allerdings bei gekrümmten Kurven auf Numerik hinauslaufen. Die
Spezifikation sieht eigentlich vor, daß der Autor die Länge auch mit
dem Attribut pathLength
schätzen kann, worauf dann
eine Skalierung erfolgen soll - funktionieren tut das aber wohl nur mit Opera 9 und sonst
keinem mir verfügbaren Darstellungsprogramm (Opera 8, Adobe, KSVG, Mozilla/Gecko).
Bei der Animation von stroke-dasharray
jedenfalls kann man so vorgehen, daß
man erstmal einen Wert abschätzt, der sicher länger als die Kurve ist, nehmen wir mal
an, das sei 'g', ist ferner 'p' die (sicherheitshalber mit pathLength
spezifizierte)
Länge, so kann man schreiben: values
="0,g;p,g", soll die
Geschwindigkeit animiert werden, so
kann man natürlich auch noch diverse Zwischenwerte angeben. Das funktioniert so weit mit
Opera 9.
Zur Animation mit stroke-dashoffset
geht man wie folgt vor:
Als stroke-dasharray
jedenfalls ist zweimal die Kurvenlänge anzugeben,
dieselbe einmal für stroke-dashoffset
. Animiert wird dann letzteres
von der vollen Kurvenlänge nach 0,
um den Effekt zu erreichen. Bei geschickter Schätzung fällt es auch nicht auf, wenn
die Kurvenlänge nicht genau getroffen ist. Abschätzen kann man die auch bequem
mit einem provisorischen stroke-dasharray
, welches man als Maßstab
für die Länge nimmt.
Animation des Zeichnens von
Kurven (Quelltext zum Zeichnen
von Kurven).
Bei dem roten Quadrat ist die Länge genau bekannt, bei der blauen Kurve nur
geschätzt. Zudem wird bei der blauen Kurve die Form des Linienendes animiert, wobei es
sich zwangsläufig um einen diskreten Wechsel handelt.
Beim grünen Quadrat sollte eigentlich die Kurvenlänge animiert
werden, was der Betrachter daran erkennen sollte, daß sich vom stroke-dasharray die Längen
ändern. Auch die Animation von stroke-dasharray
selbst beim magenta ist irgendwie
außer Opera 9 keinem anderen Darstellungsprogramm zu entlocken - schade eigentlich,
da steckt eine Menge Potential drin, stattdessen sieht man nur Fehler der anderen Darstellungsprogramme,
KSVG 1 kann es immerhin mit set
auch richtig animieren.
Jedenfalls stroke-dashoffset
scheint ohne Einschränkungen bereits animierbar zu sein, wenn der Autor die Pfadlänge
kennt.
Auch das xlink:href
-Attribut ist animierbar, was es
leicht ermöglicht, Inhalte in einer Animation auszutauschen, seien es
nun rein graphische Elemente oder auch Text:
Binäre digitale Uhr (Quelltext zur binären
digitalen Uhr),
Dezimale digitale Uhr (Quelltext zur dezimalen
digitalen Uhr).
Mit den Interaktionsmöglichkeiten aus dem nächsten Abschnitt
läßt sich das leicht zu einer Stopuhr ausbauen:
Digitale Stopuhr (Quelltext zur dezimalen
digitalen Stopuhr).
Start und Stop kann mit verschiedenen Ereignissen
erreicht werden: Klicken oder Aktivieren des
entsprechenden Knopfes, beziehungsweise Verwendung
der Taste b für Beginn/Start und e für Ende/Stop.
Ebenfalls möglich ist die Verwendung des gelben Knopfes
für beides: drücken für Start, loslassen für Stop.
Mittels PHP kann eine Uhr auch relativ einfach gestellt werden. Wie das gemacht wird, wird bei der analogen Uhr erläutert (Menüpunkt weitere Beispiele, analoge Uhr).
Als Alternative kann etwa die Eigenschaft display
diskret animiert
werden, um einen ähnlichen Effekt zu erzielen, dazu werden die jeweils
nacheinander erscheinenden Objekte an der gleichen Stelle platziert und
display
dann von none auf block
gewechselt, wenn das jeweilige Objekt erscheinen soll. Ähnlich funktioniert
es mit der Eigenschaft visibility
.
Die Anwendung der digitalen Uhr kann verallgemeinert werden und man gelangt dann zu
einer Anwendung von xlink:href
als diskrete Animation von nicht
animierbaren Attributen und Eigenschaften. Dazu führt man die notwendigen
Elemente wieder im defs
-Element an und referenziert dann wieder mit use
das jeweilige Element mit den gewünschten Eigenschaften oder Attributwerten.
Für die Interaktion sind in SVG zahlreiche Ereignisse vordefiniert,
die auch ohne die generelle Funktion des Dokumentes durch Skripte
beeinträchtigen zu müssen, eine Manipulation des Nutzers
ermöglichen. Nehmen wir dazu als erstes ein einfaches Beispiel.
Durch Anklickern der kleinen blauen Kreise kann der Durchmesser des
großen Kreises halbiert werden. Verwendet werden dazu entweder
set
, animate
oder animateTransform
.
Interaktion per Klick
(Quelltext zu Interaktion per Klick).
Probleme beim adobe plugin und bei Opera 8 hängen mit dem Attribut end
zusammen, sofern möglich ist also für solch ältere Programme die
Verwendung von dur
vorzuziehen.
Neben click gibt es zahlreiche weitere Ereignisse, einige Beispiele werden hier
ausprobiert, als da sind: mouseover, mouseout, mousedown,
mouseup, mousemove, activate, welches bei welchem
Knopf steht im Element title
des jeweiligen Knopfes.
(mit Opera 8 ist nur click zuverlässig, Opera 9 kann immer noch
kein activate, sonst funktioniert dieses Beispiel schon recht schön, adobe
hat manchmal Problem mit mouseup:
Interaktion per Ereignis
(Quelltext zu Interaktion per Ereignis).
Es gibt noch weitere Ereignisse, die ich hier nicht weiter betrachten will.
Zu beachten ist auch wiederum, daß Mozilla/Gecko Interaktion gezielt sabotieren, indem sie sie an diese
an die Interpretation von Skripten koppeln, was nichts miteinander zu tun hat - man kann also nicht davon
ausgehen, daß neuere Versionen von Darstellungsprogrammen von Mozilla/Gecko eine deklarative Interaktion
zulassen.
In diesem Beispiel wird es schon etwas spannender mit dem Attribut begin
:
Manipulierbare Animation
(Quelltext zur manipulierbaren Animation)
Die fünf gezeigten Ellipsen bekommen jeweils ein id
-Attribut.
Über Ereignisse wie id.activate; id.click als Werte für das
begin
-Attribut kann auf die Animation eingewirkt werden.
click und einige andere Ereignisbeschreibungen von SVG beziehen sich auf ein
Hilfsmittel wie die Maus, während activate ein
hardware-unspezifisches Ereignis ist, welches nicht genau festlegt, wie der
Nutzer die Funktion aktiviert. Das ist als Alternative zu click immer schön,
damit der Nutzer nicht auf eine Maus angewiesen ist. Es gibt zahlreiche andere
Möglichkeiten, Ereignisse zu definieren, etwa accessKey(?)
für ein Tastatur-Ereignis, ein id.repeat(?) für den Zugriff
auf Wiederholungen.
Wir sehen hier auch animateTransform
im Einsatz - in diesem
Falle, um die beiden großen Kreise um den Mittelpunkt des Bildes zu drehen.
Mittels des Attributes type
muß angegeben werden, welche Transformation
animiert werden soll - in dem Falle rotate.
Gucken wir mal noch ein bißchen nach den Attributen begin
und end
:
Manipulierbare Animation
(Quelltext zu einer weiteren manipulierbaren Animation).
Anklickern der großen Kreise bewirkt eine Animation des
Durchmessers des jeweiligen Kreises. Diese kann mit den kleinen
Knöpfen links unten beendet werden, beziehungsweise
mit dem untersten wird die Drehung der beiden großen
Kreise aktiviert. Durch Angaben wie begin
="id.activate+2s"
wird der Beginn gegenüber dem Ereignis verzögert, in dem
Falle um 2 Sekunden. Die Angaben zu end
scheinen zumindest Opera 8
etwas zu verwirren - bis zum kompletten Absturz des Programmes! Das
war mit end
eigentlich nicht gemeint (wenn ein beendeter Kreis beginnt,
nur noch heftig zwischen zwei Größen hin und her zu
springen, schnell die Animation stoppen und sich anschnallen ;o)
Mit dem Attribut
restart
="always", "whenNotActive"
oder "never" kann beeinflußt werden, ob die Animation
neu gestartet werden kann.
Die kleinen Knöpfe rechts unten arbeiten mit einer anderen Methode, mit einem Verweis,
der die Animation startet. Das besondere dabei ist, daß bei abermaligem Drücken
des gleichen Knopfes die Historie der bisherigen Animation seit dem letzten Drücken
des Knopfes wiederholt wird.
Mit den Tasten a und b wird gezeigt, wie accessKey(?) angewendet wird, das
ändert jeweils die Füllfarbe eines großen Kreises, eventuell
erst nachdem die Graphik durch Reinklicken den Fokus bekommen hat.
Einfacheres Beispiel zum restart
: Klicke auf einen der Kreise, um einen Neustart
der jeweiligen Animation zu versuchen:
Animation wieder starten
(Quelltext zu einer Animation wieder starten).
Der rote Kreis kann nicht wieder gestartet werden, der magenta Kreis nur, wenn er nicht mehr aktiv ist (also wenn er rechts
angekommen ist) und der blaue kann immer wieder gestartet werden.
Opera 8 ignoriert das Attribut offenbar ebenso wie KSVG 1, Opera 9 und das adobe-plugin können es.
Mit Verweisen kann auch einfach Text ein- und ausgeblendet werden. Dafür reichen
zwei set
-Animationen für zum Beispiel Attribute wie
opacity
,
visibility
oder
display
.
Anklickern des großen Kreises blendet den Text ein, Anklickern
des Rechteckes mit Text drin blendet den Text wieder aus. Das ist gut zu gebrauchen, um
bei komplexeren Bildern oder Informationen ergänzende Textinformationen
einzublenden:
Einblenden von Text
(Quelltext zum
Einblenden von Text).
Natürlich kann auch Graphik eingeblendet werden. Es ginge auch
auch mit einem Ereignissen wie mouseover und mouseout wie oben bereits besprochen.
Zu beachten ist bei der Anwendung des a
-Elementes, daß es immer nur genau ein
Ziel gibt, weil der Wert eines id
-Attributes pro Dokument nur einmal angegeben werden
kann und das Ziel eines Verweises in SVG immer eindeutig ist. Es ist also nicht möglich,
mit dem a
-Element mehrere ganz unabhängige Aktionen auszulösen.
Dazu wäre so etwas wie begin
="id.begin" zu
verwenden, wie in einem
der nächsten Abschnitte noch sinngemäß erläutert werden wird.
Transformationen können animiert werden, nur matrix leider nicht,
Skalierung, Drehung, Neigung und Translation funktionieren aber:
Animierte Transformationen Drehung und Skalierung
(Quelltext zu animierten Transformationen).
Viel ist dazu ansonsten nicht zu sagen, aber aufgepaßt, ohne weitere
Angaben überschreiben sich Angaben zur Transformation, wenn sie auf
dasselbe Element bezogen sind, wie das zu umgehen ist, werden wir weiter unten
noch sehen. Die simpelste Methode ist jedenfalls, für jede animierte
Transformationseigenschaft ein eigenes g
-Element zu verwenden.
Ist generell additive
="replace" gesetzt, wird das gesamte
transform
-Attribut durch die Animation überschrieben, ist es sum,
so wird die Animation hinten dran multipliziert. Weil besonders das Verhalten bei sum
und mit dem Attribut accumulate
mit dem Wert sum
den Programmanbietern und teilweise auch den Leuten, die die SVG-Spezifikationen schreiben,
offenbar mehrheitlich unklar geblieben ist, kann man sich in solchen komplizierteren Fällen
auf das Verhalten der Darstellungsprogramme nicht verlassen. In diesem Bereich versuche ich schon seit
Jahren auf die SVG-Arbeitsgemeinschaft einzuwirken, was die Situation in SVG1.2 bereits deutlich
verbessert hat. to-Animationen sind noch immer unklar, daher für animateTransform
zu vermeiden.
Ich denke, an dieser Stelle haben wir uns erst mal eine kleine Erholung verdient.
Wir versuchen es mit Karussellfahren
per animateMotion
(Quelltext zu animateMotion
).
Neben vielen anderen kleinen Animationen folgt das Gesicht vor allem dem ebenfalls eingezeichneten
Pfad und orientiert sich relativ zu diesem wegen des Attributes
rotate
="auto".
Alternativ kann auch ein fester Winkel angegeben werden oder auto-reverse, was gegenüber
auto einer Drehung um 180 Grad entspricht.
animateMotion
nutzt die übliche Pfaddefinition die dann mit path
oder mpath
angegeben wird. Alternativ sind auch Angaben mit
from, to, by
und values
erlaubt.
Gleichzeitig gucken wir uns mit der Nase der Figur auch zur Wiederholung animateColor
an.
Statt animateColor
kann auch das Element animate
verwendet werden,
um Farbanimationen
anzugeben. Farben können ebenfalls mit set
gesetzt werden.
Egal wie der Pfad definiert wird, mit keyPoints
ist es möglich, den Pfad in
beliebig viele Einzelstücke zu unterteilen und das Verhalten mit entsprechend vielen
keyTimes
(siehe weiter unten) und entsprechenden
calcMode
zu steuern. Etwa das adobe-plugin und Opera 8 ignorieren keyPoints
komplett oder teilweise.
Ein interessanter Effekt ergibt sich, wenn ein Pfad entlang seiner eigenen Punktspiegelung bewegt wird,
so ist der aktuelle Punkt immer der Nullpunkt:
Punktgespiegelte Bewegung
(Quelltext zur punktgespiegelten Bewegung).
Zwei kubische Pfade sind die Punktspiegelungen voneinander.
Der eine Pfad bewegt sich entlang des anderen, was zur Folge
hat, daß der aktuelle Punkt jeweils der Nullpunkt ist.
Nun kann die Scheindrehung der beiden Pfade um den Nullpunkt auch durch eine überlagerte Drehung näherungsweise kompensiert werden:
Punktgespiegelte Bewegung mit kompensierter Scheindrehung
(Quelltext zur punktgespiegelten Bewegung mit kompensierter Scheindrehung).
Je weniger rund der Pfad ist, desto schlechter ist natürlich die Näherung.
Um das Abrollen eines Kreises oder Rades auf einem Weg darzustellen (dessen Krümmungsradius überall kleiner als der Radius des Kreises ist, kann man recht einfach zwei Bewegungen überlagern, einmal die Drehung des Rades um die eigene Achse und dann die Bewegung entlang des Weges. Ist r der Radius des Rades zum Berühungspunkt mit dem Weg, so ist der Umfang U = 2 π r. Die Zeit für eine komplette Drehung muß nun genauso groß wie die Translation um U entlang des Weges sein, damit der Eindruck des Abrollens entsteht.
Ist der Weg gerade, so ist dies recht einfach zu realisieren:
Abrollen auf geradem Weg
(Quelltext zum Abrollen auf geradem Weg).
Hier wird einfach eine by-Animation für die Translation verwendet, wobei als Wert der dreifache Umfang des Kreises
verwendet wird und auch die dreifache Animationsdauer. Die Animation wird wiederholt.
Durch eine negative Anfangszeit startet das Rad im sichtbaren Bereich.
Rollt das Rad in oder auf einem Kreis ab, so ist dies offenbar rein mit Drehungen realisierbar, wobei das Verhältnis
der Radien die Animationsdauern bestimmt. Je nachdem, ob das Rad innen oder außen rollt, ändert sich auch das
Vorzeichen der Drehung des Rades relativ zur Richtung der Rolldrehung:
Abrollen auf einem Kreis
(Quelltext zum Abrollen auf einem Kreis).
Die beiden Räder rollen gegenläufig um, eines innen, eines außen.
Auch das Abrollen entlang eines beliebigen Pfades ist möglich. Zu dem Zwecke wird dann zum einen animateMotion
verwendet, zum anderen sollte die Länge des Pfades bekannt sein, um die Animationsdauer für die Bewegung entlang
des Pfades relativ zur Drehung des Rades korrekt angeben zu können. Man kann die Länge des Pfades relativ einfach und
genau schätzen, indem man sich mit stroke-dasharray
einen Maßstab bastelt.
Über das Verhältnis der Pfadlänge zum Radumfang ergibt sich dann wieder das Verhältnis der Animationsdauern:
Abrollen auf einem kubischen Pfad
(Quelltext zum Abrollen auf einem kubischen Pfad).
Die Laufrichtung wird natürlich durch den gewählten Pfad bestimmt. Auf welcher Seite das Rad rollt, bestimmt sich
durch rotate
auto oder auto-reverse.
Bei der Bestimmung des Kreisumfanges ist wie gesagt der Radius vom Kreismittelpunkt zum Pfad relevant.
Punkte außerhalb des Radius führen dann gegebenenfalls eine rückläufige Schleife aus.
Ganz praktisch kommt das etwa bei Eisenbahnrädern vor, die auf Schienen laufen:
Abrollen eines Eisenbahnrades auf einem kubischen Pfad
(Quelltext zum Abrollen eines Eisenbahnrades auf einem kubischen Pfad).
Die Schleifen sind deutlich erkennbar an den kleinen roten Kreisen und den Enden der längeren Speichen des Rades.
Beim Abrollen eines Pfades wird die Situation komplizierter:
Abrollen eines kubischen Pfades
(Quelltext zum Abrollen eines kubischen Pfades):
Ein kubischer Pfad wird entlang seiner Punktspiegelung bewegt,
was zur Folge hat, daß der aktuelle Punkt jeweils der Nullpunkt ist.
Eine überlagerte Drehung sorgt für einen Effekt,
als würden sich der Pfad drehen, allerdings bleibt dabei
der Nullpunkt immer gleich.
Wenn nun wiederum dies entlang eines geraden Pfades bewegt wird,
entsteht in etwa der Eindruck, als rolle der kubische Pfad entlang des geraden Pfades ab.
Da der Zeitablauf für die Drehung und die Bewegung entlang des Pfades aber etwas
unterschiedlich ist, paßt der Effekt nicht genau - um so schlechter, je mehr
der Pfad von einem Kreis abweicht.
Als nächstes sollten wir uns die verschiedenen Möglichkeiten
einmal genauer ansehen, wie Bewegungen beschrieben werden können.
Dazu nutzen wir einfache einfallslose Animationen, mit gleichem Start- und
Zielpunkt:
Verschiedene Bewegungstypen
(Quelltext zu verschiedenen Bewegungstypen).
Die Gruppe mit gelben Rahmen A-C zeigt vor allem, daß man mit from, to, by
die gleiche
Animation mit verschiedenen Kombinationen dieser Parameter erreichen kann. Verwendet man
hingegen values
, kommt es darauf an, was dort für Werte drinstehen. Es kommt auch
auf den calcMode
an - für einfache Animationen ist die Voreinstellung
linear, nur für
animateMotion
ist sie paced - dabei wird überall der
gleiche Betrag für die Geschwindigkeit angenommen. Bei discrete, dargestellt
in den Beispielen D bis F mit grünem Rand, werden diskrete Sprünge zwischen den
values
-Werte ausgeführt.
Typisch für diskrete Animationen sind Änderungen
von Attributwerten, die nicht in Zahlen ausdrückbar sind, also von sich aus eine
quantisierte Natur haben. Bei diesen ist die diskrete Animation ohnehin Voreinstellung und
einzige Möglichkeit. Auch bei Zahlenwerten kann natürlich ein diskreter Sprung
erwünscht sein, was so auch einstellbar ist. Nun gibt es auch Attribute oder Eigenschaften wie
fill
oder stroke
, bei denen kann
beide Möglichkeiten auftreten können, insbesondere auch eine Mischung. Korrektes Verhalten
im Falle eine Mischung wäre hier, daß das Darstellungsprogramm die Situation analysiert und
calcMode
discrete automatisch festlegt. Weil dies in der
Praxis aber bei diversen Darstellungsprogrammen nicht funktioniert und stattdessen diverser Unsinn
angeboten wird, sollte der Autor discrete in solche einem Falle explizit vermeiden, um
eine definierte Animation zu bekommen.
Wann bei diskreter Animation gesprungen wird oder wann bei einer kontinuierlichen Animation die jeweils
angegebenen Werte dargestellt werden, kann mit dem keyTimes
festgelegt werden -
das sind relative Angaben zwischen 0 und 1 entsprechend Anfang und Ende der Animation.
Die Liste muß monoton steigend sein und mit 0 beginnen. Bei kontinuierlicher Animation muß sie auch
mit 1 enden. Bei diskreter Animation kann sie mit 1 enden, was in der Praxis aber wieder zu wunderlichen
Ergebnissen für diskrete Animation in real existierenden Programmen führen kann, weswegen man
1 für diskrete Animation meiden sollte.
Wenn das Attribut keyTimes
verwendet
wird, ist für jeden values
-Wert genau ein
keyTimes
-Wert vorzusehen. Wegen der Monotonie
der Zeit nach unserem heutigen klassischen Verständnis des Universums sollte auch die
keyTimes
-Liste streng monoton sein. Bestenfalls kann das streng dabei gestrichen werden.
Nicht monoton ansteigende Listen sind fehlerhaft und wird das Darstellungsprogramm nicht umsetzen können.
Das liegt eher an der Raum-Zeit-Struktur des Universums als an SVG oder dem Darstellungsprogramm.
G bis I mit rotem Rand zeigen uns Animationen mit verschiedenen keyTimes
für einen
linearen Animationsverlauf.
Mit linear ist eigentlich gemeint, daß die Geschwindigkeit zwischen zwei
values
-Werten gleich bleibt, nicht über die ganze Animation.
Über die keyTimes
wird festgelegt, welcher Anteil an der Gesamtzeit auf
einen Verlauf zwischen zwei values
-Werten entfällt.
J zeigt einen
paced-Verlauf, Angaben zu keyTimes
werden ignoriert
und die Geschwindigkeit soll über den ganzen Verlauf
gleich bleiben. Nützlich ist das vor allem bei komplizierteren Kurven, für deren
genauen Verlauf man recht unregelmäßige Angaben machen müßte, was
die jeweiligen Längen der Kurvenstücke angeht. paced vermeidet da weitgehend
ein in der Regel unerwünschtes Ruckeln der Animation ohne größere
Rechenkunststückchen des Autors zu erfordern - wenn das nichts ist!
Ohne Kurven oder sonstwie unregelmäßige values
in mehreren Parametern
ist paced eher langweilig für Autoren. paced
verlangt jedenfalls zum einen eine Interpolation zwischen den angegebenen Werten, zum anderen,
daß irgendwie ein sinnvoller Abstand zwischen den angegebenen Werten definiert, so definiert ist,
daß dies eine gleichmäßige Änderung zur Folge hat. Solche Abstände kann man
einfach bei Skalaren (einzelnen Werten) und bei Vektoren angeben (Vektoren haben eine Betrag/Läge und
eine Richtung). Für andere Objekte wie Listen oder gar Pfade gibt es keine in diesem Zusammenhang
allgemein sinnvolle Definition eines Abstandes.
Bei exotischeren Attributen finden sich dazu in SVG1.1 (erste Ausgabe) keine Angaben, für Transformationen sind sie im allgemeinen falsch!
In SVG1.2 und der zweiten Ausgabe von SVG1.1 ist das inzwischen auf mein Bemühen hin sinnvoll ergänzt und korrigiert worden.
Autoren sollten bei Listen paced gar nicht angeben, weil es unsinnig ist. Bei Transformationen sind
meist die älteren Darstellungsprogramme fehlerhaft ebenso wie die Spezifikation SVG1.1 (erste Ausgabe), weshalb auch dafür von paced abzuraten ist.
Sinnvolles Verhalten kann
ein Autor bei Attributen mit kompliziertem Aufbau seiner Werte, etwa bei
animierten Pfaden, eher durch Angabe von keyTimes
erreichen als durch
eine paced-Animation.
Bislang hatten wir alles mit fill
="freeze" laufen lassen.
K zeigt fill
="remove". Um den gleichen Endwert
zu erreichen, wird der statische Wert
nach unten gelegt. L bis O beschäftigen sich mit den Attributen
additive
="sum" oder "replace"
und accumulate
="sum" oder "none".
Mit ersterem werden relative Änderungen angegeben, relativ zum statischen
Anfangswert oder auch relativ zu anderen Animationen. accumulate
setzt bei
Wiederholungen mit repeatCount
oder repeatDur
nicht beim Anfangswert, sondern beim Endwert mit der Wiederholung ein,
nicht anzuwenden zusammen mit einer to-Animation,
wenn keine Zahl für repeat angegeben ist oder wenn sich das zu animierende
Attribut nicht für additive Operationen eignet.
Die additive
Summe kann zum Beispiel sinnvoll eingesetzt werden, wenn
bei animateTransform
mehrere Transformationen für ein Element
ausgeführt werden sollen. Ohne weitere Angabe oder mit additive
replace würde nur die letzte angegebene animateTransform
sichtbar sein, weil die vorherige überschrieben wird, sonst werden die
animierten Transformationen jeweils in der Reihenfolge ihrer Priorität hinten
an die Transformationsliste angefügt.
Dazu dieses
Beispiel: additive
sum
(Quelltext zu
additive
sum),
links oben wird überschrieben (replace), rechts unten werden beide
Transformationen animiert. Sowohl die statische skewX-Anweisung als auch
die Rotation wird mit replace überschrieben und tritt oben links nicht mehr
in Erscheinung, anders beim Beispiel unten rechts, wo beide erhalten bleiben,
zusätzlich zur zuletzt ausgeführten Skalierung.
Man beachte jedoch, daß besonders by- und to-Animationen mit animateTransform
mit Problemen belastet sind, die Teilweise an den Spezifikationen liegen, teilweise auch
an den Darstellungsprogrammen.
Alternativ können multiplikative Transformationen erreicht werden,
wenn für jede Transformation ein eigenes g
-Element
angelegt wird, die dann ineinander verschachtelt werden.
Die Animationen
kann man natürlich auch hintereinander ausführen, was allerdings
nicht die gleiche Animation ist, was uns aber noch ein Beispiel für die
Ereignissteuerung liefert. Mittels id.begin oder id.end optional jeweils + Zeit
als Werte für das begin
-Attribut oder auch das
end
-Attribut
kann man da interessante Regeln formulieren, was relativ
zu wem beginnen soll. Bei id.repeat(?), wobei ? eine ganze, nicht negative
Zahl darstellt, hat Opera 8 offenbar eine Lücke oder einen Fehler, dies
ist dort nicht nachzuvollziehen, bei Opera 9 oder dem adobe-plugin schon.
Beispiel: Ereignisse
und korrelierte Animationen
(Quelltext zu Ereignisse und korrelierte Animationen).
Besonders die Ereignissteuerung mittels id.begin und id.end eignet sich
hervorragend, um verschiedene Bewegungstypen zu mischen, was sonst
kaum zu realisieren wäre - so kann man etwa an eine lineare
Bewegung eines Parameters unmittelbar eine paced- oder discrete- Bewegung
desselben Parameters anschließen lassen.
Die additive
Summe kann auch bei animateColor
hilfreich
sein, wenn es darum geht, jeden Farbkanal einzeln zu animieren. Bei jeder Animation wird jeweils nur ein
Kanal mit Werten von null verschieden animiert, die anderen beiden Kanäle bleiben bei der Animation null
und werden von anderen additiven Animationen der gleichen Form behandelt - durchaus auch mit anderem
Zeitablauf: Farbkanäle einzeln animieren
(Quelltext zu einzeln animierten Farbkanälen).
Mittels min
und max
kann die
minimale und maximale Animationsdauer angegeben werden. Um das
komplett zu verstehen, muß sich der geneigte Leser allerdings die
betreffende Stelle in der
SMIL-Animations-Spezifikation durchlesen.
Mittels der beiden wird die Animationsdauer eingegrenzt, wenn die berechnete
Animationsdauer nicht innerhalb des Intervalles min
und
max
liegt, wird sie korrigiert.
Weicht die zum Beispiel durch dur
,
end
, repeatDur
oder
repeatCount
gegebene
Animationsdauer von dem Intervall zwischen min
und
max
ab, so erfolgt eine
Korrektur. Ist sie kleiner als min
, hat das keinen
direkten Einfluß auf die Darstellung. Im Zeitbereich zwischen dem Ende der
Animation und dem min
-Wert verhält sich
die Animation visuell wie vom fill
-Wert vorgegeben, ist per
Definition aber weiterhin aktiv.
Ist die berechnete Animationsdauer länger als max
,
so wird sie auf max
begrenzt.
Auf das damit ausgezeichnete Element haben
min
und max
folgende Auswirkungen: Das Element soll gegebenenfalls nur
den Zustand gemäß fill
bis zum Erreichen des Zeitpunktes min
annehmen, falls die Animation vorher vorbei ist.
Das tut aber jedes Element einer Animation in SVG. Wenn die Animation allerdings
genutzt wird, um eine andere zu starten oder zu stoppen, gilt die korrigierte Zeit.
Beim Überschreiten von max
wird die Animation des Elementes beendet.
Meine Beobachtung ist nun, daß Opera 8 und auch adobe-plugin
min
und max
komplett ignorieren, Opera 9.0 interpretiert sie meist falsch, was bei 9.50 weitgehend behoben wurde.
Hier einfach mal ein Beispiel:
Der blaue Kreis hat dur
="10s" und
min
="20s",
der gelbe hat dur
="30s" und
max
="20s"
Links oben sollte sich nach Ende der jeweiligen Animation die Farbe des
jeweiligen Kreises auf eingeblendet werden, zusätzlich sollte sich nach
20s der unterste Kreis zu rot färben. Wegen der jeweiligen Wahl von
min
und max
sollten also alle Kreise links oben zum gleichen Zeitpunkt
bunt werden:
Animationsdauer begrenzen
(Quelltext zur Begrenzung der
Animationsdauer).
Eine andere sinnvolle Anwendung kann gegeben sein, wenn man gar nicht weiß, wann
eine Animation zuende ist, etwa weil sie per Interaktion beendet werden soll, man aber auf jeden
Fall möchte, daß andere Animationen durch diese innerhalb eines bestimmten Zeitbereiches
gestartet oder beendet werden sollen - schade, daß das von einigen
Darstellungsprogrammen einstweilen ignoriert wird, immerhin zeigen die Modifikationen
von Opera 8 nach 9, daß daran gearbeitet wird. Mit Batik/Squiggle und Opera 9.50 ist das alles
durchaus gut nutzbar.
Hier noch ein interaktives Beispiel:
Dauer einer interaktiven Animation begrenzen
(Quelltext zur Begrenzung der Dauer einer interaktiven Animation).
Die Höhe eines Rechtecks kann mit einem Klick auf
den Startknopf vergrößert werden, was mit einem
Klick auf den Stopknopf abgebrochen werden kann.
Es startet 1s nach dem Klick auf den Startknopf.
Die Dauer ist 40s, min
ist 20s, max
ist 30s, die mit diesen Zeiten verknüpften Größen sind grau markiert.
Dies bedeutet:
1. Die Animation kann mit einem Klick auf den
Startknopf gestartet werden, auch wiederholt, weil dies
vom Dokument nicht verhindert wird.
2. Falls die Animation gestartet wird und nicht vor ihrem
Ende neue gestartet wird, so endet sie irgendwo zwischen
den Werten für
min
und max
.
3. Falls der Stopknopf nach Erreichen des Wertes für
max
oder nie betätigt wird, wurde die Animation
bereits bei max
angehalten und nichts weiter passiert.
4. Falls der Stopknopf zwischen
min
und max
betätigt wird,
hält die Animation unmittelbar an.
5. Falls der Stopknopf vor Erreichen des Wertes für min
betätigt wird, dauert die Animation an und wird erst
beim Wert für min
angehalten.
Beim calcMode
gibt es einen weiteren Wert namens
spline. Neben den keyTimes
sind dann zu den values
entsprechend viele
keySplines
anzugeben,
die bestimmen, wie sich die Geschwindigkeit auf einem Kurvenstück zwischen zwei
keyTimes
ändert.
Dazu wird die Notation einer Bézierkurve genutzt, bei der
Anfangs- und Endpunkt bei (0 0) und (1 1) liegen, entsprechend dem Anfang und
dem Ende der Bewegung zwischen zwei keyTimes
,
es sind dann also nur die beiden
Kontrollpunkte anzugeben. keySplines
="0 0 1 1"
entspricht einer gleichbleibenden Geschwindigkeit (siehe Typ 1 in folgender Animation),
"0 1 0 1" einer starken Beschleunigung zu Beginn und einem langsamen
Ende (Typ 2), "1 0 1 0" hingegen einem langsamen Anfang und einem
schnellen Ende (Typ3).
Alle Werte müssen zwischen 0 und 1 liegen.
Bewegungstyp spline
(Quelltext zum Bewegungstyp
spline).
Eine graphische Repräsentation wie in der Spezifikation kann da für den
Anfang sinnvoll sein, im hiesigen Bereich Kurven kann dafür ja der Kurvenzeichner etwas
modifiziert werden, um sich das Verhalten zu veranschaulichen.
Jetzt interessiert uns natürlich, wie wir die Kontrollpunkte der Bézierkurve
berechnen können. Die Zeitabhängigkeit der Variable ist ja in relativen
Einheiten anzugeben, nennen wir sie s(z), wobei
die Zeit z aus [0, 1] ist und der s aus [0, 1] und u wieder unser Laufparameter aus [0, 1] für den spline.
Mit der Notation aus dem Kurvenabschnitt (11a,b) bekommen wir für die Kontrollpunkte:
P(0) = (z(0),s(0)) = (0,0) und P(3) = (z(1),s(1)) = (1,1)
(1a) P(1) = P(0) + dc(0)/du/3
(1b) P(2) = P(3) - dc(3)/du/3
Wir haben einen zeitabhängige
Variable k(t), und t Zeit in absoluten Koordinaten, die mit
(s,z) wie folgt korreliert ist:
(2a) k = q s(u) + k0
(2b) t = p z(u) + t0
wobei q und p konstante Skalierungsfaktoren sind und r0 und t0 konstante Startwerte.
Genauer ist q die Länge eines Intervalles zwischen den beiden betroffenen
values
,
während p die Länge eines Intervalles zwischen den beiden betroffenen
keyTimes
ist multipliziert mit der Animationslänge
dur
, entsprechend ist
k0 der frühere der beiden beteiligten values
und t0 ist begin plus dur
multipliziert mit
dem früheren Wert der beiden beteiligen keyTimes
.
Bereits hier sieht man einen Haken bei den relativen Angaben für die Kontrollpunkte,
die ja laut Spezifikation ebenfalls Komponenten im Bereich [0, 1] haben müssen.
Es sind keine Kurvenstücke darstellbar, die ein Extremum haben. So müssen
also values
und keyTimes
so gewählt werden, daß Minima und Maxima
der Kurve auf ein Werten für values
fallen, sonst gibt es ganz
große Probleme mit den splines!
Das ist für die Zeitkomponente sinnvoll, nicht aber unbedingt für die
values
-Komponente. Für die Zeitkomponente
würde in meinen Augen gar die Forderung reichen, daß z(u) monoton ist,
alles andere macht die Angelegenheit nur unnötig kompliziert für den Autor
und für das Darstellungsprogramm auch nicht einfacher.
Funktionierendes Beispiel: Ist etwa
begin
="10s" keyTimes
="0;1" und
dur
="20s" so ist
t(z) = dur
z + begin
= 20s z + 10s.
Für values
="100; 400" ist
k(t) = 300 s(z(u)) + 100
Da v(t) = dk/dt die Geschwindigkeit des animierten Objektes ist, stehen die Kontrollpunkte also für die Geschwindigkeit und dv/dt ist dann die Beschleunigung, die somit in SVG implizit über die Bézierkurve zur Verfügung steht. Sie kann mit Gleichung (9) aus dem Abschnitt Kurven berechnet werden, womit sich auch Forderungen aufstellen lassen, wie die Beschleunigung einer Kurve aussehen soll, woraus sich dann die Kontrollpunkte ergeben.
Werden solche kleinen Stücke per values
-Attribut aneinander
gefügt, so möchte man
vermutlich am gemeinsamen Endpunkt eine stetige Geschwindigkeit haben, also keinen Sprung
in der Geschwindigkeit. Nennen wir die Kontrollpunkte des ersten Kurvenstückes P(i,0) und die
der Folgekurve P(i,1), möchte man also haben:
(3) v(P(2,0)) = v(P(1,1))
Das ist einfach erreichbar, wenn die q und p für beide
Bereiche gleich sind. Es ergibt dann offenbar
(4) P(1,1) = (1,1) - P(2,0)
Beispiel
keySplines
=
".75 .25 .2 .9; .8 .1 .3 .4; .7 .6 .1 .1; .9 .9 .24 .75"
keyTimes
= "0; .33333; 0.66667; 1"
values
="0; 120; 240; 360;"
Sind die Angaben in values
und keyTimes
nicht zueinander passend, so kürzen sich
die p und q gerade nicht heraus und man muß genauer überlegen. Das hängt
direkt damit zusammen, daß keine Extrema in der Mitte eines Kurvenstückes zwischen
zwei values
dargestellt werden können.
An sich sollte man jetzt das Extremum exakt bestimmen,
also einen Wert für values
einfügen und in der
Umgebung die values
eng genug wählen, damit die
momentane Beschleunigung innerhalb eines Kurvenstückes klein bleibt gegenüber der
mittleren im values
-keyTimes
-Kasten.
Nennen wir analog die Skalierungsfaktoren p(0), p(1), q(0), q(1), so bekommt man immerhin
noch brauchbare Resultate, wenn gilt p(0)/p(1) = q(0)/q(1).
Das ist bei geeigneter Wahl der s(u) und z(u) immer hinzubekommen.
Es kann sinnvoll sein, mittels z(u) den Zeitverlauf zu verbiegen,
wenn nicht z=u gewählt wird.
Mit
I(0)= values(zweiter Wert) - values(erster Wert)
I(1)= values(dritter Wert) - values(zweiter Wert)
J(0)= keyTimes(zweiter Wert) - keyTimes(erster Wert)
J(1)= keyTimes(dritter Wert) - keyTimes(zweiter Wert)
ergibt sich zum Beispiel Komponentenweise für die Kontrollpunkte P(i,1) mit einem Faktor f
(5a) Pz(1,1)=f (1-Pz(2,0)) J(1)/J(0)
(5b) Ps(1,1)=f (1-Ps(2,0)) I(1)/I(0)
Dabei ist f ungleich 0 so zu wählen, daß Pz(1,1) und Ps(1,1) immer im Bereich [0, 1] liegen.
Ist die Geschwindigkeitsänderung innerhalb
eines Kurvenstückes klein und die p(i) und q(i) benachbarter Kurvenstücke
sehr ähnlich, weicht also der Wert für keySplines
kaum von "0 0 1 1" ab, so
wird es keine Probleme mit der Fortsetzung der Kurven geben, wenn f=1 gewählt wird.
Beispiel: t = p u + t0
Nehmen wir an, t laufe von 0 bis 1, weil wir die Zeitdauer über das
dur
-Attribut bestimmen
und den Zeitnullpunkt über begin
.
Haben wir ferner n+1 Werte von 0 bis n. Für den i-ten Wert erhalten wir dann
die keyTimes
i/n und
t(i) = u/n + i/n
die Zeitwerte für die keySplines
ergeben sich so unmittelbar zu
Pz(i,1) = 1/3 und Pz(i,2) = 2/3
Für die Ortswerte erhält man
k0 = k(i) und q = k(i+1) - k(i) und somit
Ps(i,1) = ds(0)/du/3
Ps(i,2) = 1- ds(1)/du/3
Wegen ds/du = dk/dt dt/du = 1/n dk/dt
Man achte bei k(t) auf stetige Differenzierbarkeit und darauf, daß alle Extrema
auf einem Wert für values
liegen.
Anwendungsbeispiele gibt es unter 'weitere Beispiele', 'Bewegung'.
Folgender kleiner keySpline-Tester macht Vorschläge, bei denen das f
von oben möglichst bei 1 liegt, Vorrang hat aber immer das Intervall-Kriterium, ohne
welches die Animation gar nicht funktioniert. Von 1 abweichende Werte bedeuten immer eine
Beschleunigung, die ja auch erwünscht sein kann.
Es wird getestet und visualisiert, wie zwei Zeitintervalle mit keySplines
zusammenpassen, links ist z=0, rechts z=1, unten der minimale s-Wert, oben der maximale.
Die schwarze Kurve entspricht den eingegebenen Werten, die rote einer stetig differenzierbaren
Fortsetzung vom ersten zum zweiten Kurvenstück, magenta zeigt umgekehrt einen Vorschlag,
wie aus dem zweiten Kurvenstück das erste fortgesetzt werden kann, es bleibt dem Nutzer
unbenommen, an P(1,1) noch einen entsprechenden Faktor f dranzumultiplizieren und erneut zu testen.
Durch Betätigen des blauen
Knopfes werden die drei Animationen in Form einer Rotation getestet, die beiden Vorschläge
folgen der schwarzen Originaleingabe mit kurzer Verzögerung:
keySpline-Tester.
(funktioniert so leider nicht bei allen Darstellungsprgrammen, daher hier eine Alternative, wenn sich nicht alle
drei Kreise nach Klick auf den blauen Kreis bewegen: keySpline-Tester 2)
In der URI können verschiedene Dinge angegeben werden, die sich an die
SVG-Notation anlehnen. dur
ist die Animationsdauer in Sekunden,
values
entsprechend die Werte, über die die Animation gehen soll.
keyTime ist der mittlere Wert der drei keyTimes
, erster und dritter
werden automatisch auf 0 beziehungsweise 1 gesetzt. Werden mehr als zwei splines verwendet, muß dann
entsprechend umskaliert werden. Dann kommen die keySplines
, Komponenten der
Einzelstücke sind hier anders als bei SVG zwingend mit Kommata zu separieren, die beiden splines
wie bei SVG auch mit einem Semikolon. Ist eine Richtungsumkehr beabsichtigt, liegt also für
den mittleren Wert ein Extremwert vor, ist es übrigens sinnvoll, ds/dz = 0 für diesen Umkehrpunkt zu realisieren,
sonst ergeben sich da meist sehr unphysikalische Bewegungsmuster (im folgenden Abschnitt gibt es dafür
aber ein sinnvolles Beispiel). Aus dem Grunde sollte auch dz/ds = 0
vermieden werden und auch die keyTimes
exakt 0 und 1 und zusammenfallende
values
.
Gut, über Animationen kann man noch viel schreiben, weitere Beispiele sind in den nächsten
Abschnitten Bewegung, Numerik und weiteren zu finden. Es gibt inzwischen auch eine zweisprachige
(englisch/deutsch) systematische
Übersicht über mögliche animierbare Attribute mit Beispielen von mir, die sowohl als
Sammlung als auch zum Testen von Darstellungsprogrammen genutzt werden kann:
Beispiele und systematischer Test von SVG-Animationen.
Hier wollte ich aber noch das kleine
Fraktal-Ballett vorstellen (Quelltext zum Fraktal-Ballett).
Es gibt ja auch Programme, mit denen man SVG erzeugen kann. Meist muß
man danach erstmal mal den Quelltext etwas aufräumen und die Animationen
gegebenenfalls per Hand ergänzen. Ein Versuch von mir mit Inkscape, bei dem
sich das Aufräumen sehr in Grenzen hielt:
Portrait des Autors animiert (Quelltext zum animierten Portrait des Autors).
Tatsächlich ist der Werdegang des Portraits etwas komplizierter:
Ursprünglich wurde es mit einer Digitalkamera aufgenommen und
dann mit Gimp geringfügig modifiziert. Die modifizierte Pixelgraphik wurde
mit Inkscape geladen. Inkscape nutzt als Unterprogramm Potrace, mit welchem
aus Pixelgraphik Pfade in Vektorgraphik erstellt werden können, die
somit beliebig skalierbar werden und einem Comic ähneln, also je nach
Einstellung stark abstrahiert sind. Potrace gibt es für zahlreiche Betriebssysteme
und auch als eigenständiges Programm und hat da einige Möglichkeiten,
nach denen die Datenreduktion stattfinden kann. Ein derartiges Bild wird
dann mit Inkscape bei Bedarf weiterverarbeitet, etwa mit der Option Vereinfachung
von Pfaden, um die Abstraktion noch weiter voranzutreiben und als pures SVG abgespeichert.
Diese nunmehr Vektorgraphik räumt man mit einem Texteditor auf,
macht die Farbangaben tauglich für SVG-tiny und ergänzt die
Animationen - und fertig ist das Portrait im Format SVG, welches ja auch
ein bißchen an den guten Andy Warhol erinnert ;o)
Auf besonderen Wunsch gibt es auch noch einen Fußballplatz. Diese Vorlage und die Informationen auf
dieser Seite sollten reichen, um damit ganze Spielzüge zu animieren:
Fußballspiel, teilweise bereits animiert (Quelltext zum Fußballspiel).