XHTML SVG CSS PHP

Dr. O. Hoffmann

SVG- und PHP-Labor

Die Zeit ist Bewegung im Raum.
Joseph Joubert

Skalierbare Vektorgraphik - Animation

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.

Anfangen...

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.

Einzelattribute animiert

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.

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:

  1. values-Animation
  2. from-to-Animation (entspricht einer values Animation mit values="from;to").
  3. from-by-Animation (nur für additive Attribute oder Eigenschaften sinnvoll. Additive Animationen werden später noch besprochen, entspricht dann values="from;from+by").
  4. by-Animation (nur für additive Attribute oder Eigenschaften sinnvoll. Entspricht dann 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.)
  5. to-Animation (das Verhalten ist in SMIL im Detail definiert und recht komplex, sofern es sich nicht um eine Animation mit dem 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).
  6. Bewegung entlang eines Pfade mit 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).

Formwandler

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.

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.

Kurven Zeichnen animieren

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.

Inhalt austauschen, digitale Uhren

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.

Interaktion und Animation

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.

Text oder Graphik einblenden

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.

Transformation und Animation

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.

Bewegung entlang von Pfaden

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.

Abrollen eines Kreises oder Rades

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.

Bewegungstypen von Animationen

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).

Animationen zeitlich begrenzen

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.

Spline-Animation

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.

Mehr über Animationen?

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).