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.