Programming Animations in FX

I've been trying to refactor the animation support in FX lately and discussed it with Brian Goetz while he was here, and here's the current state. These changes will be checked in to the OpenJFX repository shortly. Note: this about programming animations, not tool-support. I assume a tool will produce data structures that describe canned animations, not code like this.

My goal is to make it possible for the programmer to specify the required behavior and still be able to actually understand what his code is doing.

Animations are fundamentally updates. They assign values to properties (or invoke processes that do such) at certain time instants.

The traditional animation loop

while (animationIsRunning) {
    // update stuff
    wait(interval);
}

is easy to understand, but it has several drawbacks:

  1. It requires a dedicated thread - introducing data synchronization issues
  2. It doesn't handle jitter - "update stuff" can take variable amounts of time at each iteration, making the animation look choppy.
  3. Since the time consumed by "update stuff" is included in the loop, the animation will exhibit different behavior based on the speed of the processor.

FX provides a time iterated for loop which (I think) is as easy to understand but overcomes these limitations:

println("before the animation");

for (i in [1..10] dur 10000) {
     // update stuff
}

println("after the animation");

The above loop describes a discrete animation which executes every second for 10 seconds. In addition, the loop body is always executed in the current thread. However the loop still blocks until all 10 iterations are complete. Currently, this is implemented with the Event Queue Hack, but proper support for continuations could be provided via code generation by the FX compiler. Since the loop blocks, it can be intuitively incorporated into a larger sequential process, e.g;

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          for (i in [0..100] dur 1000) {
               x = i;
          }
          for (i in [0..100] dur 1000 {
               y = i;
          }
     }
}

The above moves the rectangle from (0, 0) to (100, 0) over 1 second, and then moves it from (100, 0) to (100, 100) over 1 second, when you click the mouse on the rectangle.

Now, sometimes we want animations to run in parallel. For this case, a nearly identical construct is provided, namely the update trigger:

trigger on (i = [1..10] dur 10000) {
      // update stuff
}

println("after the trigger, but the animation is still running");

In this case the body of the trigger is executed 10 times, once per second. However, unlike the for loop, the code after the trigger executes in parallel with the trigger's body. The body of the trigger is still executed in the same thread, however, when the timer triggers it:

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          trigger on (i = [0..100] dur 1000) {
               x = i;
          }
          trigger on (i = [0..100] dur 1000) {
               y = i;
          }
     }
}

In this example, the animations of x and y occur in parallel and the the rectangle moves diagonally from (0, 0) to (100, 100) over 1 second.

In the case of discrete animations such as these the "frame rate" for the loop body is duration/(sizeof input-1). For cases where an animation is conceptually continuous, a better approach is often to use a predefined (high) frame rate and interpolate between the values for each frame using some interpolation function. The syntax is open to discussion but here's how that works right now:

Rect {
     fill: green
     height: 50
     width:  50
     var x = 0
     var y = 0
     x: bind x
     y: bind y
     onMouseClicked: operation(e) {
          trigger on (i = [0, 100] dur 1000 motion LINEAR) {
               x = i;
          }
          trigger on (i = [0, 100] dur 1000 motion LINEAR) {
               y = i;
          }
     }
}

LINEAR is a predefined function that performs linear interpolation (you can plug in your own instead). The interpolation function is of the form

function<T> (inputValues:T\*, elapsedTimeAsUnitInterval: Number): T

As a shorthand for animating individual properties a form of the the assignment statement is also provided:

x = [0, 100] dur 1000 motion LINEAR;
y = [0, 100] dur 1000 motion LINEAR;

which is equivalent to the two triggers above in onMouseClicked().

Finally, for the case where the for loop actually doesn't do anything:

for (i in [0, 1] dur 1000) {
     // don't do anything
}

we have a shorthand called "wait"

wait(1000);

Below are a few test cases for these constructs:

  1. Video Poker
    Standalone
    FXPad
  2. Motorola Intro
    Standalone
    FXPad
  3. Simple Path Animation
    FXPad
Comments:

Check out this fisheye animation component for Flex:

http://demo.quietlyscheming.com/fisheye/TileExplorer.html

From this blog entry:

http://www.quietlyscheming.com/blog/2006/04/25/new-component-2d-fisheye-v02/

Posted by Ryan de Laplante on August 11, 2007 at 04:37 AM PDT #

At the bottom of this page are links to all kinds of interesting animation components for Flex.

http://www.quietlyscheming.com/blog/

Posted by Ryan de Laplante on August 11, 2007 at 04:45 AM PDT #

Is there a CLDC version available for download somewhere yet? I have been working intermittently on a project for a little while now, which could leverage such a thing to allow users to create their own content for the app.

Posted by Joel Schnall on August 15, 2007 at 08:45 AM PDT #

This all looks great! I really would like to learn this, though I have no idea were to start. I have no programing skills, but I really want to learn this! Can anybody give me any pointers were to start or simple tutorials to get me up and running? Thank you.

Posted by Chris Phillips on August 18, 2007 at 07:48 AM PDT #

Nice Article

Posted by sohbetkanallari on August 24, 2008 at 11:55 PM PDT #

<a href="http://www.yapitec.com" title="Dübel - Hırdavat - El Aletleri" target="_blank">Dübel - Hırdavat - El Aletleri</a>

Posted by dübel on December 30, 2008 at 09:28 PM PST #

http://geciktirici.seksmarketim.biz

Posted by Geciktirici on December 30, 2008 at 09:31 PM PST #

NOTE: It seams like that such feature is not present in the final JavaFX release 1.0

Posted by Mike on January 20, 2009 at 03:27 AM PST #

http://www.smsmatbaa.com

Posted by matbaa on June 22, 2009 at 03:04 AM PDT #

thank you
http://www.tavlaoynasana.com

Posted by Tavla Oyna on July 02, 2009 at 11:54 AM PDT #

nice article
thank you
http://www.erozyon.info

Posted by Erozyon on July 02, 2009 at 11:54 AM PDT #

It seams like that such feature is not presen

Posted by onlynpara on April 02, 2010 at 09:34 AM PDT #

It seams like that such feature is not presen

Posted by hitbedava on April 02, 2010 at 09:34 AM PDT #

Below are a few test cases for these constructs:

Posted by agrisevdasi on April 02, 2010 at 09:35 AM PDT #

Simple and Nice example !

Posted by شات on December 15, 2010 at 03:56 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

user12610627

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today