Table Of Contents

Previous topic

10. Layout

Next topic

12. Actions

This Page

11. Animation

Animationen sind zeitgesteuerte Veränderungen einer Presentation. Maongo besitzt ein Animationssystem, das es erlaubt, komplexe Animationsabläufe in XML zu definieren.

Die Animationen in Maongo sind zeitbasierend. Dies bedeutet, dass Animationen unabhängig von der Framerate, mit der die Presentation abgespielt wird, immer gleich lange dauern.

Note

Zeitlicher Ablauf einer Animation

Bei jedem Frameaufruf des Maongosystems werden in allen laufenden Animationen die aktuellen Animationswerte berechnet (zeitliche Position innerhalb der Animation, Werte der zu animierenden Eigenschaften etc.). Davon ausgehend werden auf den betroffenen Widgets die Werte gesetzt.

Soll eine Animation über einen Zeitraum von 4 Sekunden die Position eines Widgets von 0 auf 100 verändern, so bedeutet dies bei einer Framerate von 10 Bildern pro Sekunde eine Veränderung von 2,5 Pixeln pro Frame:

4 Sekunden à 10 Frames = 40 Frames; 100 Pixel / 40 = 2,5 Pixel

Sollte die Presentation mit 20 Frames pro Sekunde laufen, beträgt die Veränderung pro Frame nur 1,25 Pixel. Die Gesamtdauer der Animation bleibt unverändert.

11.1. Grundlagen

Eine einfache Animation lässt sich mit dem Element <tween /> definieren, mit dem sich Widget-Eigenschaften über einen Zeitraum hin verändern lassen.

Beispiel:

<tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>

Dieser Tween ändert die Widget-Eigenschaft Location; er bewegt das Widget im Zeitraum von einer Sekunde von Position 10,10 zu Position 100,100. Die Animation wird durch das Setzen der Widget-Property AnimationControl auf den Wert "play" gestartet.

Beispiel:

<widget>
      <property name="Interactive" value="true"/>
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>
  <action trigger="pointer-down">
    this.AnimationControl = "play";
  </action>
</widget>

Animationselemente, die in einem Widget definiert sind, laufen parallel ab, wenn die Animation auf diese Art und Weise gestartet wird. Das Widget ist somit implizit ein Animationscontainer vom Typ <parallel /> (s.u.).

Neben <tween /> gibt es weitere “Animationsbausteine”:

  • <switch /> schaltet die Widget-Eigenschaften direkt um;
  • <animation /> dient zum Aufruf einer Action in einer Animation bzw. zum Verweis auf an anderer Stelle definierte Animationen;
  • <wait /> dient zum Erzeugen einer Pause in einer Animation;
  • <iterator /> mittels eines Iterator lassen sich in einer Animation Listen mit Werten zur Verfügung stellen.

Daneben stellt Maongo zwei Elemente zur Verfügung, mit denen sich Animationen gruppieren lassen: <sequence /> und <parallel />. Animationen innerhalb einer Sequence werden nacheinander, solche innerhalb einer Parallel-Animation gleichzeitig bzw. nebeneinander abgespielt.

Beispiel:

<sequence>
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>
  <tween property="Shape" type="Shape" from="R 10,10" to="R 100,100" duration="1s"/>
</sequence>

Die beiden Tweens laufen nacheinander ab, das Widget ändert zunächst seinen Ort, dann seine Form. Die Gesamtduer der Animation ist zwei Sekunden.

Beispiel:

<parallel>
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>
  <tween property="Shape" type="Shape" from="R 10,10" to="R 100,100" duration="1s"/>
</parallel>

Die beiden Tweens laufen parallel ab, Ort und Form werden gleichzeitig geändert. Die Gesamtdauer der Animation ist eine Sekunde.

Beispiel:

<sequence>
  <parallel>
    <tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>
    <tween property="Shape" type="Shape" from="R 10,10" to="R 100,100" duration="1s"/>
  </parallel>
  <tween property="BackgroundColor" type="Color" from="red" to="blue" duration="1s"/>
</sequence>

Location und Shape werden gleichzeitig verändert, danach wird die Farbe von rot zu blau verändert. Das Beispiel zeigt auch, dass AnimationsContainer wie sequence und parallel ineinander geschachtelt werden können.

Ein weiterer AnimationsContainer ist <iterator />. Ein Iterator kommt immer dann zum Einsatz wenn innerhalb einer Animation eine Liste von Werten bzw. Widgets genutzt werden soll.

11.2. Gemeinsame Attribute

Die folgenden Attribute gelten für alle Animations-Elemente (tween, switch, animation, wait, iterator, sequence und parallel):

name (String)
Bezeichnung des Elementes. Wird name benutzt, so müssen Animationen innerhalb desselben Containers eindeutig benannt sein. Der Name kann zum Aufruf der Animation in Skripten und für Lookups innerhalb der Anwendung genutzt werden.
target (String, @, {...})

Pfad auf ein Ziel-Widget, an dem die Animation ausgeführt werden soll.

Wird in der XML-Deklaration der Animation ein target gesetzt, so gilt dies für das Animation selbst und seine Kinder; setzen die Childanimationen selbst auch ein Target, so versucht die Animationsengine, im Namensraum des Parent-Targets das Child-Target aufzulösen.

Default: Wird target nicht gesetzt, so ist das Parent-Widget der Animation das Ziel-Widget der Animation.

Besonderheit: Ein per Skript übergebenes target wirkt nur, wenn auf der Animation noch kein target gesetzt ist.

duration (String, @, {...})

Netto-Dauer der Animation, ohne Pausen, Wiederholungen, etc. Wird die duration nicht angegeben, bestimmen die Parent- oder Child-Animationen die Dauer des einzelnen Elements. Als Werte können hier alle Angaben vom Datentyp Time interpretiert werden. Siehe dazu Datentypen.

Default: 1s (eine Sekunde)

delay (String, @, {...})

Verzögerung bis zum Beginn der Animation. Eine Animation mit delay="2s" beginnt zwei Sekunden, nachdem sie gestartet wurde. Als Werte können hier alle Angaben vom Datentyp Time interpretiert werden. Siehe dazu Datentypen.

Default: 0

count (Integer, @, {...})

Anzahl der Wiederholungen einer Animation.

Default: 1

gap (String, @, {...})

Zeit zwischen zwei Wiederholungen. Als Werte können hier alle Angaben vom Datentyp Time interpretiert werden. Siehe dazu Datentypen.

Default: 0

loopitems (List, @, {...})

Liste von Objekten, über die mit den Wiederholungen iteriert wird. Legt gleichzeitig die Anzahl der Wiederholungen auf die Länge der übergebenen Liste fest.

Ist count zusätzlich gesetzt, so gilt count, und die Liste wird entsprechend verkürzt genutzt, bzw. es wird erneut von vorne iteriert, bis count Wiederholungen erreicht sind.

extdur (String, @, {...})

Die (nach außen hin sichtbare) Dauer der Animation. Diese wird entweder aus der Dauer der einzelnen Bestandteile unter Berücksichtigung von Loops und Delays/Gaps berechnet, oder kann explizit gesetzt werden, um eine interne Verteilung der Gesamtzeit auf die beteiligten Animationen zu erreichen.

Als Werte können hier alle Angaben vom Datentyp Time genutzt werden. Siehe dazu Datentypen.

Im folgenden Beispiel ist jeder einzelne Tween 4 Sekunden lang (2 Tweens mit jeweils 4 Sekunden Länge):

<sequence extdur="8">
  <tween property="Location" type="Point" from="10,10" to="100,100"/>
  <tween property="Location" type="Point" from="100,100" to="10,10"/>
</sequence>
loop (String, @, {...})

Anzahl der Wiederholungen für diese Animation.

Default: 0

Beispiel:

<sequence loop="2" >
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="2s"/>
  <tween property="Location" type="Point" from="100,100" to="10,10" duration="2s"/>
</sequence>
ft: (Action, @, {...})

f(t, dur), Animationsfunktion. Eine Animationsfunktion muss für die Übergabewerte t (aktueller Zeitpunkt) und dur (Gesamtdauer der Animation), die als Parameter übergeben werden, einen Wert zwischen 0 und 1 zurückliefern.

Als mögliche Werte stehen vorgefertigte Funktionen zur Verfügung:

LinearNone, LinearIn, LinearOut, LinearInOut, QuadIn, QuadOut, QuadInOut,
CubicIn, CubicOut, CubicInOut, QuartIn, QuartOut, QuartInOut,
QuintIn, QuintOut, QuintInOut, BounceIn, BounceOut, BounceInOut,
BackIn, BackOut, BackInOut, CircIn, CircOut, CircInOut,
ElasticIn, ElasticOut, ElasticInOut, ExpoIn, ExpoOut, ExpoInOut,
SineIn, SineOut, SineInOut

Default: LinearNone

Es können auch Referenzen auf eigene Actions übergeben werden (Beispiel 2).

Beispiel 1:

<tween property="Location" type="Point" from="10,10" to="100,100"
  duration="5s" ft="QuadEaseIn"/>

Beispiel 2:

<tween property="Location" type="Point" from="10,10" to="100,100"
  duration="5s" ft="@MyEaseIn"/>
<action name="MyEaseIn" arguments="t,dur">
  return Math.pow(t/dur, 2);
</action>

Als dritte Möglichkeit können Funktionen direkt in die Animation geschrieben werden. Dabei stehen innerhalb des Scriptes die Variablen “t”(momentaner Zeitpunkt in der Animation) und “dur”(Dauer der Gesamtanimation) zur Verfügung.

Beispiel 3:

<tween property="Location" type="Point" from="10,10" to="100,100"
   duration="5s" ft="{return (t/dur)*t;}"/>

11.3. Gruppierung mittels sequence

Die in einem <sequence />-Container enthaltenen Animationen werden nacheinander abgespielt. Wird keine absolute Dauer angegeben, entspricht die Dauer der Summe der Bruttozeiten aller Children:

<sequence>
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="1s"/>
  <tween property="Shape" type="Rectangle" from="10,10" to="100,100" duration="1s"/>
</sequence>

11.4. Gruppierung mittels parallel

Container, dessen Children gleichzeitig abgespielt werden. Die Dauer entspricht der Dauer der längsten Child-Animation. Hat ein Child keine Dauer, wird die Dauer des Containers genutzt (in diesem Fall 3 Sekunden, da die längste Child-Animation drei Sekunden lang ist):

<parallel>
  <tween property="Location" type="Point" from="10,10" to="100,100" duration="3s"/>
  <tween property="Shape" type="Rectangle" from="10,10" to="100,100" />
</parallel>

Attribute:

keine.

11.5. Animationselement tween

Veränderung einer Widget-Property über die Zeit:

<tween property="BackgroundColor" type="Color" from="#ff0000"
to="#00ffff" duration="3s"/>

Attribute:

property
Name der property, die auf dem Widget (bzw. dem als target angegebenen Widget) verändert werden soll.
type (String)

Datentyp für die from, to, by-Angaben.

Nicht jeder Datentyp kann sinnvoll getweent werden. Möglich sind beispielsweise: Integer, Number, Decimal, Point, Padding, Color, Shape. Es können nur Shapes getweent werden, die gleichartig sind (gleicher Typ / gleiche Anzahl Punkte etc.).

from (Object, @, {...})
Ausgangswert des Tweens.
to (Object, @, {...})
Endwert des Tweens.

11.6. Animationselement switch

Veränderung einer Widget-Property in Form eines einfachen Umschaltens. Besonders geeignet für den Datentyp Boolean.

<switch property="BackgroundColor" type="Color" from="#ff0000"
to="#00ffff" />

Attribute:

siehe Tween.

Ist beim Switch eine duration angegeben, so wird sie ignoriert. Ein Switch hat per Definition duration=0.

11.7. Animationselement animation

Dieser “Animationsbaustein” dient zur Integration von externen Elementen in eine Animation. Dies können Actions oder an anderer Stelle im Mad-Dokument notierte Animationen sein.

Attribute:

reference (Animation, @, {...})
Eine Animation, die an die Stelle des animation-Tags in den aktuellen Kontext eingefügt wird.
action (String, @, {...})
Eine Action. Als Werte können entweder ein Lookup auf eine im Mad definierte, benannte <action /> oder ein Script übergeben werden. Nur wenn dieses Attribut genutzt wird, wirken sich die Attribute mode bzw. duration aus.
mode (Symbol)
Dieses Attribut wirkt sich nur aus, wenn mittels action eine Action in die Animation integriert wird. Wird der mode auf “once” gesetzt, wird die Action nur einmalig aufgerufen. “onceifdefined” bewirkt, dass die action einmalig aufgerufen wird, aber nur wenn sie definiert ist. Eine nicht definierte Action wirft keinen Fehler. Wenn dieses Attribut weggelassen wird, erfolgt der Aufruf der Action auf jedem Frame innerhalb der gesetzten Dauer.
duration (Time, @, {...},INFINITE)
Dieses Attribut wirkt sich nur aus, wenn mittels action eine Action in die Animation integriert wird. Dann bestimmt es die Zeit während der diese Action aufgerufen wird. Als Sonderfall gibt es den Wert “INFINITE”. Dieser sorgt für ein endloses Laufen der Animation.

11.7.1. Aufruf von Actions

Wenn innerhalb einer Animation eine Action aufgerufen werden soll, kann dieses über das animation-Tag erfolgen.

Mittels des Attributes mode kann zwischen einem einmaligen Aufruf und einem wiederholten Aufruf unterschieden werden.

Im folgenden Beispiel wird die Action “FrameAction” für die Dauer von 50 Sekunden bei jedem Frame aufgerufen:

<animation action="@FrameAction" duration="50s" />
<action name="FrameAction" arguments="widgetref, val">
        // ...
</action>

Mittels des Attribut mode kann ein einmaliges Aufrufen der Action bewirkt werden. Wenn dieses Attribut weggelassen wird, erfolgt der Aufruf der Action auf jedem Frame innerhalb der gesetzten Dauer. Sofern eine Duration für ein animation-Tag angegeben ist, welches mittels mode auf einmalige Ausführunge geschaltet ist, wird die Duration als Wartezeit nach der Ausführung interpretiert.

Note

Bei einer einzelnen <animation> Anweisung ist die Angabe duration=”0” notwendig, damit sie ausgeführt wird. Wenn das animation-Tag bspw. in eine sequence integriert ist, ist dieses nicht notwendig.

// geht

<animation action=”@MyAction” mode=”once” duration=”0” />

// geht nicht

<animation action=”@MyAction” mode=”once” />

siehe Bug #281.

Einmaliger Aufruf einer Action in einer Sequence:

<sequence>
  <.../>
  <animation action="@MyAction" mode="once"/>
  <.../>
</sequence>
<action name="MyAction">
    // ...
</action>

Beispiel einer endlos laufenden Frameanimation:

<animation action="@MyAction" duration="INFINITE"/>
<action name="MyAction">
    // ...
</action>

Übergabewerte an die aufgerufene Action:

Die Deklaration der Action soll zwei Argumente vorsehen:

<action name="FrameAction" arguments="widgetref, val">...</action>

wobei in widgetref das aktuelle Target-Widget, in val der aktuelle Animationswert zwischen 0 und 1 übergeben wird. Die Action kann dann val nutzen, um beliebige Manipulationen am Target-Widget vorzunehmen. Für Inlinescripte “{...}” kann auf die Argumente unter diesen Namen zugegriffen werden.

11.7.2. Verweis auf andere Animationen

Erlaubt die Angabe einer Animation (Tween, Sequence, etc.), die an die Stelle des animation-Tags in den aktuellen Kontext eingefügt wird:

<widget name="widget1">
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="red" />
  <action trigger="pointer-down">
     this.AnimationControl = "play";
  </action>

  <sequence>
   <tween property="Shape" type="Rectangle" from="100,100" to="30,30"  duration="2s"/>
   // Verweis auf eine Animation welche in der Presentation definiert ist
   <animation reference="Presentation.HinHer"/>
  </sequence>
</widget>

// eingebundene Animation
<sequence name="HinHer">
   <tween property="Location" type="Point" from="0,0" to="100,100"  duration="2s"/>
   <tween property="Location" type="Point" from="100,100" to="0,0"  duration="2s"/>
</sequence>

11.8. Animationselement wait

Mittels des wait Containers kann eine Pause in laufende Animationen eingebaut werden:

<wait duration="2s" />

Im folgenden Beispiel wird zunächst die Location animiert, dann wird 5 Sekunden gewartet und anschließend wird das Shape animiert:

<sequence>
      <tween property="Location" type="Point" from="0,0" to="100,100"  duration="3s"/>
      <wait duration="5s" />
      <tween property="Shape" type="Rectangle" from="100,100" to="20,20"  duration="2s"/>
</sequence>

11.9. Animationselement iterator

Ein Iterator stellt innerhalb einer Animation eine Liste von Werten zur Verfügung die bei jedem Animationsdurchlauf auf das nächste Element weitergeschaltet wird.

Attribute:

items (List, @, {...})
Eine Liste der im Iterator enthaltenen Werte.

Im folgenden Beispiel wird nach Klick auf widget1 eine Animation gestartet, die sowohl loopitems als auch einen <iterator /> nutzt.

Als “Loopitems” der Animation sind die Childwidgets von widget2 angegeben. Damit wird festgelegt, dass die Animation zweimal loopt (da widget2 zwei Children hat); der Zugriff auf die einzelnen loopitems erfolgt über das target="item".

Innerhalb der Animation ist ein <iterator /> definiert, der über die Children von widget3 iteriert. Der Zugriff auf diese Referenzen erfolgt über den Iterator-Namen (hier myIterator).

Das folgende Beispiel führt nacheinander folgende Aktionen aus::
widget2.child1 > Shapeanimation widget3.child1 > Visible widget2.child2 > Shapeanimation widget3.child2 > Visible

widget3.child3 wird nicht verändert.

Beispiel:

<widget name="widget1">
  <property name="Interactive" value="true"/>
  <property name="Shape" value="R 20 20"/>
  <action trigger="pointer-down">
    this.AnimationControl = "play";
  </action>

  <sequence loopitems="@widget2.Children">
    <iterator name="myIterator" items="@widget3.Children"/>
    <tween target="item" property="Shape" type="Shape" from="R 20,20"
      to="R 50,50" duration="3s" />
    <switch target="myIterator" type="Object" property="Visible"
      from="true" to="false" />
  </sequence>
</widget>


<widget name="widget2">
  <property name="BackgroundColor" value="transparent"/>
  <property name="Shape" value="R 300 300"/>

  <widget name="child1"  x="100" y="50">
    <property name="Shape" value="R 20 20"/>
    <property name="BackgroundColor">red</property>
  </widget>

  <widget name="child2" x="200" y="50">
    <property name="Shape" value="R 20 20"/>
    <property name="BackgroundColor">green</property>
  </widget>
</widget>


<widget name="widget3" y="70">
  <property name="BackgroundColor" value="transparent"/>
  <property name="Shape" value="R 300 300"/>

  <widget name="child1"  x="100" y="50">
    <property name="Shape" value="R 20 20"/>
    <property name="BackgroundColor">red</property>
  </widget>

  <widget name="child2" x="200" y="50">
    <property name="Shape" value="R 20 20"/>
    <property name="BackgroundColor">green</property>
  </widget>

  <widget name="child3" x="300" y="50">
    <property name="Shape" value="R 20 20"/>
    <property name="BackgroundColor">green</property>
  </widget>
</widget>

11.10. Animationsspezifische Widget-Properties

AnimationControl (Symbol)

Erlaubt die Steuerung der auf dem Widget definierten Animation(en).

Werte: "play", "pause", "stop"

11.11. JavaScript-Syntax

Die Animation des aktuellen Widgets abspielen:

this.AnimationControl = "play";

Eine benannte Animation abspielen:

Animationreference.play(target);

Im folgenden Beispiel wird das aktuelle Widget (this) von der Animation this.moveIt bewegt:

<widget name="widget1">
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="red" />

  <action trigger="pointer-down">
    this.moveIt.play(this);
  </action>

  <sequence name="moveIt">
    <tween property="Location" type="Point" from="0,0" to="100,100"  duration="3s"/>
  </sequence>
</widget>

Um eine Animation auf einem anderen Widget auszuführen, wird dieses Widget als target im play-Aufruf der Animation übergeben:

<widget name="widget1">
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="red" />
  <action trigger="pointer-down">
    // Lookup auf das Zielwidget
    var wgt = $(this,"widget2");
    // Aufruf der Animation mit der in 'wgt' abgelegten Referenz auf "widget2"
    this.scaleIt.play(wgt);
  </action>

  <sequence name="moveIt">
    <tween property="Location" type="Point" from="0,0" to="100,100"  duration="3s"/>
  </sequence>
  <sequence name="scaleIt">
    <tween property="Shape" type="Rectangle" from="100,100" to="20,20"  duration="2s"/>
  </sequence>
</widget>


<!-- Ziel-Widget -->
<widget name="widget2" y="100">
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="green" />
</widget>

11.12. Zeitverhalten von Animationen

Die Gesamtdauer einer Animation setzt sich wie folgt zusammen:

(delay + (duration * loopcount) + (gap * (loopcount-1)))

Die Dauer von Animationen kann von “außen” (Parent-Animation) oder von innen (Child-Animation) bestimmt werden.

Ist auf einer “äußeren” Animation eine duration angegeben, welche zu kurz ist um die enthaltenen Animationen abzuspielen, wird die Animation bis zum Ende der “äußeren” duration abgespielt. Die evt. noch nicht abgespielten “inneren” Animationen werden verworfen. Sofern die “äußere” duration länger ist, als die enthaltenen Animationen, läuft die Animation einfach weiter, ohne dass Auswirkungen sichtbar werden.

Beispiele zur Illustration des Zeitverhalten:

// Animationsdauer:
// sequence undefiniert => parallel undefiniert => längster tween b: 2s
// => parallel 2s + tween c 1s => sequence ist 3 Sekunden lang
// Tween a ist bereits nach 1s zu Ende.
<sequence>
  <parallel>
    <tween name="a" property="Location" type="Point" from="10,10" to="100,100"
      duration="1s"/>
    <tween name="b" property="Shape" type="Rectangle" from="10,10" to="100,100"
      duration="2s"/>
  </parallel>
  <tween name="c" property="BackgroundColor" type="Color" from="red" to="blue"
    duration="1s"/>
</sequence>

// Animationsdauer:
// sequence 5s - tween 1s => parallel 4s => tweens a,b sind 4 Sekunden lang
<sequence duration="5s">
  <parallel>
    <tween name="a" property="Location" type="Point" from="10,10" to="100,100" />
    <tween name="b" property="Shape" type="Rectangle" from="10,10" to="100,100" />
  </parallel>
  <tween name="c" property="BackgroundColor" type="Color" from="red" to="blue"
    duration="1s"/>
</sequence>

// Animationsdauer:
// sequence undefiniert => parallel undefiniert => a,b undefiniert
// => c undefiniert => oberstes undefiniertes Element: Sequence
// => sequence 1s (Default) => parallel 0.5s ==> a,b 0.5s
// => c 0.5s
<sequence>
  <parallel>
    <tween name="a" property="Location" type="Point" from="10,10" to="100,100" />
    <tween name="b" property="Shape" type="Rectangle" from="10,10" to="100,100" />
  </parallel>
  <tween name="c" property="BackgroundColor" type="Color" from="red" to="blue" />
</sequence>

// Animationsdauer:
// sequence undefiniert => parallel undefiniert => a,b undefiniert
// => c 1s => oberstes undefiniertes Element: parallel
// => parallel 1s (Default) ==> a,b 1s
// => sequence 2s
<sequence>
  <parallel>
    <tween name="a" property="Location" type="Point" from="10,10" to="100,100" />
    <tween name="b" property="Shape" type="Rectangle" from="10,10" to="100,100" />
  </parallel>
  <tween name="c" property="BackgroundColor" type="Color" from="red" to="blue"
  duration="1s"/>
</sequence>


// Animationsdauer: 12s, dabei sind die enthaltenen Animationen nach 8s fertig
<sequence duration="12s">
  <tween property="Location" type="Point" from="0,0" to="100,100"  duration="4s"/>
  <tween property="Location" type="Point" from="100,100" to="0,0"  duration="4s"/>
</sequence>

// Animationsdauer: 4s, der zweite Tween wird nicht mehr ausgeführt.
<sequence duration="4s">
  <tween property="Location" type="Point" from="0,0" to="100,100"  duration="4s"/>
  <tween property="Location" type="Point" from="100,100" to="0,0"  duration="4s"/>
</sequence>

11.13. Beispiele

Ein einfaches Beispiel mit delay:

// der zweite Tween wird mit einer Verzögerung von 3 Sekunden gestartet
<widget>
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="red" />
  <action trigger="pointer-down">
     this.AnimationControl = "play";
  </action>

  <sequence>
   <tween property="Location" type="Point" from="0,0" to="100,100"  duration="2s"/>
   <tween property="Location" type="Point" from="100,100" to="0,0"  duration="2s"
     delay="3s"/>
  </sequence>
</widget>

Mittels gap wird eine definierte Pause zwischen den mit loop definierten Wiederholungen eingesetzt:

<widget>
  <property name="Interactive" value="true"/>
  <property name="BackgroundColor" value="red" />
  <action trigger="pointer-down">
     this.AnimationControl = "play";
  </action>

  <sequence loop="5" gap="2s">
   <tween property="Location" type="Point" from="0,0" to="100,100"  duration="2s"/>
   <tween property="Location" type="Point" from="100,100" to="0,0"  duration="2s"/>
  </sequence>

</widget>

Ein umfangreicheres Beispiel erstellt eine Bilder-Slideshow mit dem Ken-Burns-Effekt (http://en.wikipedia.org/wiki/Ken_Burns_effect):

<?xml version="1.0" encoding="ISO-8859-1"?>
<presentation width="600" height="600">
  <property name="Interactive" value="true"/>
  <action trigger="pointer-down">
    $(this,"showAnim").play(this);
  </action>
  <widget name="area" x="50" y="50" >
    <property name="Shape" value="R 400 300"/>
    <widget name="img1" x="-50" y="-50">
      <property name="Shape" value="R 800 600"/>
      <property name="Center" value="400,300"/>
      <property name="Texture" value="../images/image1.jpg"/>
    </widget>

    <widget name="img2" x="-100" y="-50">
      <property name="Shape" value="R 800 600"/>
      <property name="Center" value="400,300"/>
      <property name="Texture" value="../images/image2.jpg"/>
    </widget>

    <widget name="img3" x="-70" y="-70">
      <property name="Shape" value="R 800 600"/>
      <property name="Center" value="400,300"/>
      <property name="Texture" value="../images/image3.jpg"/>
    </widget>

    <widget name="img4" x="-200" y="-230">
      <property name="Shape" value="R 800 600"/>
      <property name="Center" value="400,300"/>
      <property name="Texture" value="../images/image4.jpg"/>
    </widget>
  </widget>

  <sequence name="showAnim">
    <parallel duration="5s" name="anim1">
      <tween target="area.img4" property="Location" type="Point"
        from="-200,-230" to="-30,-70" />
      <tween target="area.img4" property="Scale" type="Number"
        from="1" to="1.5" />
      <tween target="area.img4" property="Alpha" type="Number"
        from="1" to="0" />
    </parallel>
    <parallel duration="5s" name="anim2">
      <tween target="area.img3" property="Location" type="Point"
        from="-70,-70" to="-300,-140" />
      <tween target="area.img3" property="Scale" type="Number"
        from="1" to="1.3" />
      <tween target="area.img3" property="Alpha" type="Number"
        from="1" to="0" />
    </parallel>
    <parallel duration="5s" name="anim3">
      <tween target="area.img2" property="Location" type="Point"
        from="-100,-50" to="-170,-100" />
      <tween target="area.img2" property="Scale" type="Number"
        from="1" to="1.4" />
      <tween target="area.img2" property="Alpha" type="Number"
        from="1" to="0" />
    </parallel>
  </sequence>
</presentation>

Das komplette MAD-Dokument zum Download.

11.14. Besonderheiten bei Chartanimationen

Chartanimationen nutzen die hier beschriebenen Animationsfeatures und Sprachkonstrukte. Allerdings werden einige zusätzliche Verfahren benutzt, um sehr granular auf die Einzelelemente von Charts (Balken, Linien, Labels, etc.) zuzugreifen.

Das folgende Beispiel ist in einem PieChart definiert:

1 <sequence name="s">
2       <sequence loopitems="@AnimationElements" extdur="6" delay="0.5">
3               <iterator name="it" items="@Labels.ValueLabels.Children"/>
4               <iterator name="it2" items="@Labels.DiffLabels.Children"/>
5               <tween target="item" property="Progress"
6                 reldur="@Values[*][0]" type="Number" from="0" to="1"/>
7               <switch target="it" type="Object" property="TextFormat"
8                 from="@LabelBoldTrans" to="@LabelBoldBlue" duration="0"/>
9               <wait duration="0.1" />
10              <switch target="it2" type="Object" property="TextFormat"
11                from="@LabelBoldTrans" to="@LabelBoldBlue" duration="0"/>
12              <wait duration="0.4" />
13      </sequence>
14 </sequence>

Das Attribut loopitems wird in Zeile 2 mit dem Lookup auf @AnimationElements initialisiert. Damit stehen die “Hauptelemente” jedes Charts (hier: die Kreissegmente, in den anderen Charttypen die Balken, Säulen und Linien) in der Animation zur Verfügung, und die Anzahl der Wiederholungen der sequence ist auf die Anzahl der AnimationElements festgelegt.

In Zeile 5 wird mit target="item" auf das jeweilige Loopitem zugegriffen. In diesem Fall wird die (Winkel-)Größe des Kreissegments von unsichtbar auf den vollen darzustellenden Wert animiert (Tween der Property Progress von 0 bis 1). ** heißt die nicht AnimationProgress??? **

Interessant ist auch das Timing diese Animation: hier werden die darzustellenden Werte für das Timing benutzt, so dass ein kleiner Wert (= ein kleines Kreissegment) weniger Zeit erhält als ein großer: reldur="@Values[*][0]". Dieser Zugriff auf Values ergibt eine Liste, z.B. [32,23,12,10]. Für eine Animation, bei der jedes AnimationElement unabhängig vom Wert dieselbe Animationszeit erhält, kann reldur eine Liste [1,1,1,1,1,1,1,1] zugewiesen werden, die mindestens so lang sein sollte wie die Maximalzahl der erwarteten Werte.

Mit jeweils einem iterator werden weitere Elemente der Chartdarstellung gesteuert (Zeile 3 und 4). In diesem Fall sind in einem Container Labels zwei Labelbars definiert, deren Children per iterator in der Animation zur Verfügung gestellt werden. Mit target="it" (dem Namen des ersten Iterators) kann sodann auf die Children von @Labels.ValueLabels, mit target="it2" entsprechend auf die Children von @Labels.DiffLabels zugegriffen werden.

Mit jedem Durchlauf der in Zeile 2 definierten Sequence wird ein darin definierter iterator ein Element weitergeschaltet. In Zeile 5 und 7 wird so den einzelnen Labels ein anderes Textformat zugewiesen.

Selbstverständlich können weitere Animationselemente (wie die wait-Anweisungen in Zeile 9 und 12) die Chartanmation vervollständigen. Die beiden Anweisungen bewirken, dass zwischem dem Umschlaten der beiden Labels eine kurze Pause ist (Zeile 9), und am Ende der Gesamtsequenz für einen Balken (Balken und zwei Labels verändert) eine etwas längere Pause (Zeile 12).

Werden die Labels - wie im BarChart - direkt im Chart definiert, so ist auch ein Zugriff über die Chartproperty BarLabels möglich:

<widget type="BarChart" name="TheBarChart">
        <sequence loopitems="@AnimationElements" extdur="6" delay="0.5">
                <tween target="item" property="Progress" reldur="@Values[*][0]"
                  type="Number" from="0" to="1"/>
                <switch target="item.BarLabels[2]" type="Object" property="TextFormat"
                  from="@LabelBold" to="@LabelBoldBlue" duration="0"/>
                <switch target="item.BarLabels[3]" type="Object" property="TextFormat"
                  from="@LabelBold" to="@LabelBoldBlue" duration="0"/>
                <wait duration="0.4" />
        </sequence>
        <property name="BarLabels" value="[@HeadtextLabel,@TextLabel,@ValueLabel,@DiffLabel]"/>
        <!-- ... -->
</widget>

target="item.BarLabels[2]" schaltet hier das ValueLabel (index 2 der Liste BarLabels), target="item.BarLabels[3]" entsprechend das DiffLabel.

und das LineChart?