Table of Contents
OpenLaszlo applications have a fluid, dynamic feel that allow you to guide the user's experience. This fluidity is achieved with animators, which change the value of an object's attribute over a specified time duration. In this tutorial we'll start by showing the code for some short applications that allow you to see the essential simplicity of coding with animators. A little further down there are interactive examples that are a little more complicated but allow you to see animation in action.
Note that when we refer to animation in LZX applications, we mean anything that changes over time. This usually means something visible, but not always. For example, one might animate output volume of an audio file. You can animate the opening and closing of tabs and windows, the positions of items on the screen, and so forth.
For example, the following application defines an animator for a window that moves it to a position of x=100 over 1 second
               (1000 milliseconds). The animator is an instance of lz.animator, and is defined by using the <animator>
               
                tag.
            
Example 24.1. A simple animator
<canvas height="50" width="100%">
    <view width="80" height="30" bgcolor="red" onclick="go.doStart()">
        <text align="center" valign="middle">Click Me!</text>    
        <animator name="go" attribute="x" to="100" duration="1000" start="false"/>
    </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
    * Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
    * Use is subject to license terms.                                            *
    * X_LZ_COPYRIGHT_END ****************************************************** -->
                  
               An animator starts with the current value of an attribute unless otherwise specified.  
               In the next example the application defines an animator for a window that first moves the window to a position 
               of x="50", and then animates the window to a position of x="100" over 1 second.
               
            
Example 24.2. Specifying starting conditions
<canvas height="50" width="100%">
    <view width="80" height="30" bgcolor="red" onclick="go.doStart()">
        <text align="center" valign="middle">Click Me!</text>    
        <animator name="go" attribute="x" from="50" to="100" duration="1000" start="false"/>
    </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
    * Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
    * Use is subject to license terms.                                            *
    * X_LZ_COPYRIGHT_END ****************************************************** -->
                  
               Animators, by default, change an object's attribute by easing in and out of the from and 
               to values. Running the above sample applications shows a window that  accelerates in and out of its 
               position. This nonlinear behavior can be minimally controlled with the use of the motion attribute. 
               For example, the following  code shows a window which moves linearly across the screen, in contrast to examples above. 
               The values for the motion tag are: easeboth, easein, easeout, and linear.
               
            
Example 24.3. Linear movement
<canvas height="50" width="100%">
    <view width="80" height="30" bgcolor="red" onclick="go.doStart()">
        <text align="center" valign="middle">Click Me!</text>    
        <animator name="go" attribute="x" to="100" duration="1000" motion="linear" start="false"/>
    </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
    * Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
    * Use is subject to license terms.                                            *
    * X_LZ_COPYRIGHT_END ****************************************************** -->
                  
               Animators, like views, can be named so that they can be controlled later via scripts. This next example shows a common practice
               to activate an animator when a view is clicked, rather than when a view is first instantiated. Animators can be initially
               dormant by setting start="false", and then activated on demand by calling its start() method.
               
            
Example 24.4. Controlling animation with a script
<canvas height="100" width="100%">
  <view bgcolor="red" width="100" height="100" onclick="this.myAnimator.doStart()">
    <animator name="myAnimator" attribute="x" to="100" duration="1000" start="false"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  Animators can also animate objects relative to their current values. This means that the goal of the animator is actually the "to" value plus the objects's current value. Starting with the example above, and including relative="true" to the set of attributes, creates a view that animates 100 pixels to the right every time it is clicked.
Example 24.5. Relative animation
<canvas height="100" width="100%">
  <view bgcolor="red" width="100" height="100" onclick="this.myAnimator.doStart()">
    <animator name="myAnimator" attribute="x" to="100" duration="1000" start="false" relative="true"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  More than one animator can be added to an object, and the set will be processed simultaneously. The code below shows an object moving diagonally by using both "x" and "y" animators.
<canvas height="100" width="100%">
  <view bgcolor="red" width="100" height="100">
    <animator attribute="x" to="100" duration="1000"/>
    <animator attribute="y" to="100" duration="1000"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->To process the two animators above sequentially, i.e. one after the
               other, you use the <animatorgroup>
               
                tag,
               explained below.
            
Inside Animators, the "this" keyword refers to the animator, and "parent" refers to the view or node it is nested in.
The following examples illustrate various uses of the <animator>
                  
                   and <animatorgroup>
                  
                   tags.  Notice that below each
                  example there are "Test" and "Reset" buttons. The Test button causes
                  the animation code to be executed; the Reset button brings the
                  examples back to their initial state. Use these examples to see how
                  different animation techniques compare to each other.
               
These applications rely on the support file animation_library.lzx.
The following example shows the effect of animating the
                  opacity, rotation,
                  height, width, and
                  x and y placement of
                  simple views.  Click on any red square to see the animation of the
                  named attribute, or press "test" to see them all at once.
               
Example 24.6. Basic Animation
<canvas width="100%" height="200" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial1" height="600" width="${parent.width}" visible="true">
    <ruler name="rlr" height="3000" y="0"/>
    <view height="30"/>
    <view height="120" y="30">
      <view x="50">
        <boxtitle label="opacity"/>
        <boxtitle label="rotation"/>
        <boxtitle label="width"/>
        <boxtitle label="height"/>
        <boxtitle label="x"/>
        <boxtitle label="y"/>
        <simplelayout axis="x" spacing="51"/>
      </view>
      <view y="20">
        <box id="B1" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="opacity" to=".5" duration="500" start="false"/>
        </box>
        <box id="B2" x="150" onclick="this.anm.doStart()">
          <animator name="anm" attribute="rotation" to="45" duration="500" start="false"/>
        </box>
        <box id="B3" x="250" onclick="this.anm.doStart()">
          <animator name="anm" attribute="width" to="99" duration="500" start="false"/>
        </box>
        <box id="B4" x="350" onclick="this.anm.doStart()">
          <animator name="anm" attribute="height" to="100" duration="500" start="false"/>
        </box>
        <box id="B5" x="450" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" to="500" duration="500" start="false"/>
        </box>
        <box id="B6" x="550" onclick="this.anm.doStart()">
          <animator name="anm" attribute="y" to="50" duration="500" start="false"/>
        </box>
      </view>
      <simplelayout axis="y" spacing="5"/>
    </view>
    
    <!-- The TEST and RESET buttons -->
    <view x="50" y="150" width="${parent.width - 50}">
      <button x="50" onclick="B1.anm.doStart(); B2.anm.doStart(); B3.anm.doStart(); B4.anm.doStart(); B5.anm.doStart(); B6.anm.doStart();">Test</button>
      <button onclick="B1.setAttribute('opacity', 1); B2.setAttribute('rotation', 0); B3.setAttribute('width', 49); B4.setAttribute('height', 49); B5.setAttribute('x', 450); B6.setAttribute('y', 0); this.parent.P2.setAttribute('display', ' ');">Reset</button>
      <simplelayout axis="x"/>
    </view>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                     The following example shows the difference between relative and
               absolute animation. By default, relative is set
               to false, which means that animation of an attribute is
               calculated relative to that attribute's initial value.  When
               relative is set to true, the
               animation is relative to the value of that attribute when the animator
               is invoked.  Click on each of the red squares a few times to see the
               difference.
            
Example 24.7. Basic Animation
<canvas width="100%" height="200" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- RELATIVE ANIMATION EXAMPLE -->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="300" y="0"/>
    <view height="30"/>
    <view height="120">
      <view y="40" visible="true">
        <view>
          <text>Absolute</text>
            <box id="B7" x="50" onclick="this.anm.doStart()">
              <animator name="anm" attribute="x" to="200" duration="500" start="false"/>
            </box>
          </view>
          
          <view>
            <text>Relative</text>
              <box id="B8" x="50" onclick="this.anm.doStart()">
                <animator name="anm" attribute="x" to="200" duration="500" start="false" relative="true"/>
              </box>
            </view>
          <simplelayout axis="y" spacing="5"/>
        </view>
      </view>
      
      <!-- The TEST and RESET buttons -->
      <view x="50" y="150">
        <button text="Test" x="50" onclick="B7.anm.doStart();B8.anm.doStart()"/>
        <button text="Reset" onclick="B7.setAttribute('x', 50);B8.setAttribute('x', 50);"/>
      <simplelayout axis="x"/>
    </view>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  The from attribute indicates the starting
               value from which the animation is to begin. If the object is not at
               that value, it first assumes it and then begins the animation.  In the
               example below, the animated attribute is x,
               the horizontal placement. The from value in
               each case is 200, and the to value
               is 100. Before the specified animation begins, the object
               first moves by setting its x value to
               100.  In the absolute case, the object animates to
               x=100, where x is calculated relative
               to the object's initial value.  In the second case, the
               object moves until x=100, where x is
               calculated relative to its value at the start of the animation.
            
Example 24.8. Using the "from" attribute
<canvas width="100%" height="200" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="300" y="0"/>
    <view height="30"/>
    <view height="120" y="40">
      <view>
        <text>absolute</text>
        <box id="B9" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" from="200" to="100" duration="500" start="false"/>
        </box>
      </view>
      
      <view>
        <text>relative</text>
        <box id="B10" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" from="200" to="100" duration="500" start="false" relative="true"/>
        </box>
      </view>
      <simplelayout axis="y" spacing="5"/>
    </view>
  </view>
  
  <!-- The TEST and RESET buttons -->
  <view x="50" y="150">
    <button text="Test" x="50" onclick="B9.anm.doStart();B10.anm.doStart()"/>
    <button text="Reset" onclick="B9.setAttribute('x', 50); B10.setAttribute('x', 50); this.parent.P2.setAttribute('display', ' ');"/>
    <simplelayout axis="x"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  The motion attribute allows you to specify
               whether the animation accelerates ("ease out"), decelerates ("ease
               in"), both accelerates and decelerates ("ease both"), or is at a
               constant rate (linear).
            
Example 24.9. Using the "motion" attribute
<canvas width="100%" height="300" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="300" y="0"/>
    <view height="30"/>
    <view height="200" y="40">
      <view>
        <text>easeboth</text>
        <box id="B11" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" to="600" duration="1000" start="false" motion="easeboth"/>
        </box>
      </view>
      
      <view>
        <text>easein</text>
        <box id="B12" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" to="600" duration="1000" start="false" motion="easein"/>
        </box>
      </view>
      
      <view>
        <text>easeout</text>
        <box id="B13" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" to="600" duration="1000" start="false" motion="easeout"/>
        </box>
      </view>
      
      <view>
        <text>linear</text>
        <box id="B14" x="50" onclick="this.anm.doStart()">
          <animator name="anm" attribute="x" to="600" duration="1000" start="false" motion="linear"/>
        </box>
      </view>
      <simplelayout axis="y" spacing="5"/>
    </view>
  </view>
  
  <!-- The TEST and RESET buttons -->
  <view x="50" y="260">
    <button text="Test" x="50" onclick="B11.anm.doStart(); B12.anm.doStart(); B13.anm.doStart(); B14.anm.doStart()"/>
    <button text="Reset" onclick="B11.setAttribute('x', 50); B12.setAttribute('x', 50); B13.setAttribute('x', 50); B14.setAttribute('x', 50); this.parent.P2.setAttribute('display', ' ');"/>
    <simplelayout axis="x"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  
               In OpenLaszlo applications you can achieve the same result by using XML tags or JavaScript APIs. The examples above have demonstrated
               how to use the <animator> tag.  Alternatively
               you can use the lz.node.animate() method in script statements. The following example contrasts tag and script approaches to animating views.
               
            
Example 24.10. The "bounce effect"
<canvas width="100%" height="390" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="350" y="0"/>
    <view height="30"/>
    <view height="200" y="40">
      <box id="B15" x="50" onclick="this.ax1.doStart(); this.ax2.doStart()">
        <animator name="ax1" attribute="x" to="400" duration="1000" motion="easeout" start="false"/>
        <animator name="ax2" attribute="x" to="300" duration="1000" motion="easein" start="false"/>
      </box>
      
      <box id="B16" x="50" onclick="this.ax1.doStart(); this.ax2.doStart()">
        <animator name="ax1" attribute="x" to="400" duration="1000" motion="easein" start="false"/>
        <animator name="ax2" attribute="x" to="300" duration="1000" motion="easeout" start="false"/>
      </box>
      <view height="10"/>
      <box id="B17" x="50" onclick="this.bounce()">
        <method name="bounce">
          this.animate("x",400,1000,false,{motion:'easeout'});
          this.animate("x",300,1000,false,{motion:'easein'});
        </method>
      </box>
      <box id="B18" x="50" onclick="this.bounce()">
        <method name="bounce">
          this.animate("x",400,1000,false,{motion:'easein'});
          this.animate("x",300,1000,false,{motion:'easeout'});
        </method>
      </box>
      <box id="B19" x="50" onclick="this.bounce()">
        <method name="bounce">
          this.animate("x",400,1000,false,{motion:'easein'});
          this.animate("x",300,1000,false,{motion:'easeout'});
        </method>
      </box>
      <simplelayout axis="y" spacing="10"/>
    </view>
  </view>
  
  <!-- The TEST and RESET buttons -->
  <view x="50" y="350">
    <button text="Test" x="50" onclick="B15.ax1.doStart(); B15.ax2.doStart(); B16.ax1.doStart(); B16.ax2.doStart(); B17.bounce(); B18.bounce(); B19.bounce();"/>
    <button text="Reset" onclick="B15.setAttribute('x', 50); B16.setAttribute('x', 50); B17.setAttribute('x', 50); B18.setAttribute('x', 50); B19.setAttribute('x', 50); this.parent.P2.setAttribute('display', ' ');"/>
    <simplelayout axis="x"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  The indirect attribute allows you to reverse
               the direction in which an animation occurs while still arriving at the
               same result.  In the example below, the
               indirect attribute is set to true
               for the animation on B23.  This causes the
               animation to go to the left, rather than the right, disappearing off
               the canvas, as it were, and reappearing on the right.  Setting the
               indirect attribute to true in
               animating the rotation attribute changes the
               sense of the apparent motion from clockwise to counterclockwise.  Try
               setting indirect to true on other
               properties — such as height, width, opacity — to see the
               effect.
            
Example 24.11. Indirect attribute
<canvas width="100%" height="290" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="250" y="0"/>
    <view height="30"/>
    <view height="200" y="40">
      <view height="10"/>   
      <box id="B22" x="50" onclick="this.anm.doStart()">
        <animator name="anm" attribute="x" to="500" duration="1000" start="false"/>
      </box>
      <box id="B23" x="50" onclick="this.anm.doStart()">
        <animator name="anm" attribute="x" to="500" duration="1000" start="false" indirect="true"/>
      </box>
  
      <simplelayout axis="y" spacing="10"/>
    </view>
  </view>
  <!-- The TEST and RESET buttons -->
  <view x="50" y="250">
    <button text="Test" x="50" onclick="B22.anm.doStart();B23.anm.doStart()"/>
    <button text="Reset" onclick="B22.setAttribute('x', 50); B23.setAttribute('x', 50); this.parent.P2.setAttribute('display', ' ');"/>
    <simplelayout axis="x"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  The <animatorgroup>
               
                tag allows you to
               combine the actions of several animators on a single object. The
               animators can be set to operate simultaneously or sequentially.  In
               the example below, animatorgroups are used to combine animations on
               the x and y attributes
               of the two red views. Notice that the x
               attribute of B20 has been set to linear motion
               instead of the default easeboth.  In the case of
               B21 the motion of the y
               animation has been set to easeout.  By clicking the
               
               
               "test" button you can see how these simple changes to the animator
               parameters cause distinctly different movements.
            
The <animatorgroup>
               
               
               process attribute allows you to specify whether
               the animators within an <animatorgroup> should be
               processed sequentially or simultaneously. By default the actions are
               performed simultaneously.  To see the difference, edit the example
               below by specifying process="sequential".
            
Example 24.12. Animator groups
<canvas width="100%" height="400" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="400" width="${parent.width}" visible="true">
    <ruler name="rlr" height="350" y="0"/>
    <view height="30"/>
    <view height="200" y="40">
      <view height="150" x="50">
        <box id="B20" onclick="this.anm.doStart()">
          <animatorgroup name="anm" start="false" process="simultaneous">
            <animator attribute="x" from="0" to="300" duration="1000" motion="linear"/>
            <animator attribute="y" from="0" to="100" duration="1000"/>
          </animatorgroup>
        </box>
      </view>
      <view height="150" x="350">
        <box id="B21" onclick="this.anm.doStart()">
          <animatorgroup name="anm" start="false" process="simultaneous">
            <animator attribute="x" from="0" to="300" duration="1000"/>
            <animator attribute="y" from="0" to="100" duration="1000" motion="easeout"/>
          </animatorgroup>
        </box>
      </view>
      <simplelayout axis="y" spacing="10"/>
    </view>
  </view>
  <!-- The TEST and RESET buttons -->
  <view x="50" y="350">
    <button text="Test" x="50" onclick="B20.anm.doStart(); B21.anm.doStart()"/>
    <button text="Reset" onclick="B20.setAttribute('x', 0);B20.setAttribute('y', 0); B21.setAttribute('x', 0);B21.setAttribute('y', 0); this.parent.P2.setAttribute('display', ' ');"/>
    <simplelayout axis="x"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  Animatorgroups can be contained within animatorgroups, allowing for the encapsulation of more complex behavior. This next example illustrates that point by having the view return back to its original position. The return animates the object along both the x and y axes simultaneously after its initial movements on them separately.
Example 24.13. animatorgroup-2
<canvas height="210" width="100%">
  <view bgcolor="red" width="100" height="100" onclick="this.outeranimatorgroup.doStart()">
    <text align="center" valign="middle">Click Me!</text>    
    <animatorgroup name="outeranimatorgroup" process="sequential" start="false">
      <animator attribute="x" to="100" duration="1000"/>
      <animator attribute="y" to="100" duration="1000"/>
      <animatorgroup process="simultaneous" duration="1000">
        <animator attribute="x" to="0"/>
        <animator attribute="y" to="0"/>
      </animatorgroup>
    </animatorgroup>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  Note that in the code above there was no duration set for the x and
               y animators of the interior <animatorgroup>.
               Attributes such as duration,
               x, y,
               width, etc. can be defined in an
               <animatorgroup> and these values will be adopted by
               every subanimator unless they already have that attribute defined for
               themselves. If, as in the example above, a
               duration value is assigned to an animated
               group, it does not necessarily mean that the animatorgroup will be
               confined to that amount of time.  It means that every subanimator may
               use that duration. If process='simultaneous' and each
               subanimator uses the group duration as their
               value then the length of total time for all subanimators would equal
               the duration time for the animatorgroup
            
You can animate any attribute that can be modified at runtime. For example, the following example shows the effect you can get by animating a layout. Because layout encompasses several attributes we have simplified this example by having the layout return to its initial state — there is no "reset" button.
Example 24.14. Animating Layout
<canvas width="100%" height="185" bgcolor="0xE5E1B0">
  <!-- INCLUDES That provide framework for the example -->
  <include href="animation_library.lzx"/>
  
  <!-- The EXAMPLE itself-->
  <view id="tutorial2" height="200" width="${parent.width}" visible="true">
    <ruler name="rlr" height="150" y="0"/>
    <view height="30"/>
    <view height="60" y="40">
      <view id="V01" x="50">
        <borderedbox/>
        <borderedbox/>
        <borderedbox/>
        <borderedbox/>
        
        <simplelayout name="lyt" axis="x" spacing="5">
          <animatorgroup name="anm" start="false" process="sequential">
            <animator attribute="spacing" from="5" to="50" duration="1000"/>
            <animator attribute="spacing" from="50" to="-49" duration="1000"/>
            <animator attribute="spacing" from="-49" to="5" duration="1000"/>
          </animatorgroup>
        </simplelayout>
      </view>
    </view>
    
    <!-- The TEST button -->
    <view x="50" y="150">
      <button text="Test" x="50" onclick="V01.lyt.anm.doStart()"/>
    </view>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  Now that you've seen how animation works you can explore animating all different kinds of attributes. Here is a hint: try giving a view a "hidden" attribute, say "charm" that is constrained to the value of other attributes, and then animating "charm."
For example, often, you need a there-and-back animation. This can be a bother, since the obvious way to do it requires two animators, and adjusting properties within an animator group can be tricky.
A simple workaround is to use an animated value as the square root of the destination value. This gives you that kind of there-and-back behavior with a single animator.
Example 24.15. compound behavior in single animator
<canvas height="50" width="100%">
  <view width="30" height="30" bgcolor="red" x="${225 - (this.sqrtx * this.sqrtx)}">
    <attribute name="sqrtx" value="-15"/>
    <animator attribute="sqrtx" from="-15" to="15" duration="3000" repeat="Infinity"/>
  </view>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  You can animate a group of images by specifying the directory from which to load the images. All the files in that directory will be used for the animation.
The following example uses the eight png files in resources/spinner/ 
                 for the animation.
            
Example 24.16. Multiframe animation
<canvas height="180" width="100%">
    <resource name="spinner_rsc" src="resources/spinner/"/> 
    
    <simplelayout axis="y"/> 
    
    <view name="spinner" x="50" y="4" resource="spinner_rsc"/> 
    
    <button>play 
        <handler name="onclick"> 
            canvas.spinner.play(); 
        </handler> 
    </button> 
    
    <button>stop 
        <handler name="onclick"> 
            canvas.spinner.stop(); 
        </handler> 
    </button> 
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
    * Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
    * Use is subject to license terms.                                            *
    * X_LZ_COPYRIGHT_END ****************************************************** -->
                  Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.