Chris Oliver's Weblog
- All
- F3
- JavaFX
- Programming
Key-Frame Animation
It's unfortunate that OpenJFX currently isn't a real open-source project. As such, it gives the appearance that progress isn't being made with JavaFX Script. Nevertheless, evolution has occurred, albeit internally.
I've worked on replacing the animation framework in JavaFX with something more complete and consistent. This was always intended to happen. The presently available animation mechanism (the "dur" operator) was a temporary solution added to F3 more than a year ago, was never thought to be an adequate solution, and clearly isn't to anyone who has ever actually tried to use it.
The supported animation idiom is now that of "Key Frame" animation, as in traditional animation and visual design tools. My view (after significant research) is that this same idiom is also the most effective technique for describing animations programmatically. The concept is that you describe the animated state transitions of your "scene" by declaring start and end "snapshots" of state at certain points in time, and declare interpolation functions to calculate the in-between states.
Given this input the system can automatically perform the animation, stop it, pause it, resume it, reverse it, or repeat it when requested. Thus it is a "declarative" animation technique.
Programmatically such "snapshots" consist of specifying the values for JavaFX variables - local variables and instance variables.
Here are some examples:
- Simple A very simple example, which demonstrates simultaneous animation of the rotation, scale, and fill color of a rectangle. Ball Consists of three concurrent repeating animations: one for the x coordinate of the ball, one which animates the y coordinate, and the one which animates the scale to create a "bounce" effect. See line 65 for the animations.
- Motomaxxve Consists of only one keyframe animation whose "position" is bound to a Slider, such that you can manually "play" it by moving the slider. Left-click on the content will play it forward, Right-click will reverse it. One interesting point is that the text animations are dynamically generated.
- EG Consists of several animations (fade, slide): one of which is a kind of ticker-tape view of the presenters at the 2007 "Entertainment Gathering" at the Getty Museum. The others support a slide show view.
- Poker Video poker game. Consists of two animations: 1 for the deal, and 1 for the draw, each of which animates the bet, turning over the cards, and scoring (if you have a winning hand).
You'll want to take a look at the examples for reference as you read the below, I think.
Time Literals
Since time is fundamental to animation, I've added time "literals" to the language. These are instances of the following primitive class:
public class Time extends java.lang.Comparable {
public attribute millis: Integer;
public attribute seconds: Number;
public attribute minutes: Number;
public attribute hours: Number;
public operation toMillis():Integer;
public operation add(other:Time):Time;
public operation subtract(other:Time):Time;
public operation multiplyBy(n:Number):Time;
public operation divideBy(n:Number):Time;
public operation equals(other): Boolean;
}
Numeric Literals with one of the suffixes (h, m, s, ms) are interpreted as Time literals, e.g:
2s == Time {seconds: 2}; // true
Relational operators and arithmetic operators other than % are overloaded for Time types:
2.5s < 5000ms; // true
2.5s * 3 == 7.5s; // true
Timelines
A KeyFrame describes a set of end states of various properties of objects at a certain time instant relative to the start of the animation, together with interpolation specifications to calculate the in-between values relative to the previous frame. Lack of an interpolation specification indicates a "discrete" animation, meaning the value of the property instantaneously transitions to the value given in the key frame at the time instant of the key frame. A Timeline is an object that contains a list of key frames, together with operations to control the overall animation, to start it, stop it. repeat it, etc.
Timelines are instances of the following class:
public class Timeline {
public attribute keyFrames: KeyFrame*;
public attribute repeatCount: Number;
public attribute autoReverse: Boolean;
public operation start();
public operation stop();
public operation pause();
public operation resume();
public operation reverseNow();
public attribute position: Number?; // unit time interval
}
where KeyFrame is:
public class KeyFrame {
public attribute time: Time;
public attribute keyValues: InterpolatedLValue*;
public attribute action: function()?;
public attribute timelines: TimeLine*; // included timelines
}
InterpolatedLValue has the following definition:
public class InterpolatedValue {
public attribute value: Object;
public attribute interpolate: function(values:Object*, unitTimeInterval:Number):Object?;
}
public class InterpolatedLValue extends InterpolatedValue {
public attribute target: &Object;
}
InterpolatedValue describes a pair (<value>, <interpolation_function>).
InterpolatedLValue describes a triple (<target property>, <value>, <interpolation function>).
Properties
Specification of the target property required adding "pointers" to the JavaFX script language. Pointer types are declared with the "&" symbol (as in the target attribute above), and pointer instances are obtained with the unary "&" operator and dereferenced with the unary "*" operator, as in C, e.g:
var x = 2;
var px = &x;
*px == 2; // true
*px = 3;
x == 3; // true
Properties in JavaFX are pointers to local variables or object attributes. In cases where these are "sequences" a pointer to an element of such a sequence is also a valid property.
Syntax
Although KeyFrame animations are normal JavaFX objects, special syntax is provided to make it easier to express than is possible with the standard object-literal syntax.
The "tween" operator is a a literal constructor for InterpolatedValue.
100 tween LINEAR;
is equivalent to
InterpolatedValue { value: 100, interpolate: LINEAR:Number }
The "=>" operator provides a literal constructor for a list of InterpolatedLValues:
var x = 2;
x => 100 tween LINEAR;
is equivalent to the following
var x = 2;
InterpolatedLValue {target: &x, value: 100, interpolate: LINEAR:Number};
However, you can also apply "=>" to a whole set of object properties using an object-literal like notation rather than just single property or variable, for example like this:
var rect = Rect {};
rect => {height: 400 tween EASEBOTH, width: 500, fill: blue tween LINEAR, clip: { shape: Rect => {height: 500, width: 600} };
The second line above is equivalent to this:
[InterpolatedLValue {
target: &rect.height
value: 500
interpolate: EASEBOTH:Number
},
InterpolatedLValue {
target: &rect.width
value: 500
interpolate: null
},
InterpolatedLValue {
target &rect.fill
value: blue:Color
interpolate: LINEAR:Color
},
InterpolatedLValue {
target: &((Rect)rect.clip.shape).height
value: 500
interpolate: null
},
InterpolatedLValue {
target: &((Rect)rect.clip.shape).width
value: 600
interpolate: null
}]
Finally, the "at" and "after" operators are literal constructors of KeyFrame objects:
var x = 2;
var rect = Rect {...};
at (2s) {
x => 2 tween LINEAR;
rect => {width: 400 tween EASEBOTH, fill: red tween EASEBOTH};
trigger {
println("at 2 seconds...");
}
}
after (5s) {
x => 100 tween EASEBOTH;
}
The "trigger" clause allows you to associate an arbitrary callback with the key frame.
The time specified by "at" is relative to the start of the Timeline. The time specified by "after" is relative to the previous key frame.
The first example above is equivalent to:
KeyFrame {
time: 2s
action: operation() { println("at 2 seconds..."); }
keyValues:
[InterpolatedLValue {
target &x
value: 2
interpolate: LINEAR:Number
},
InterpolatedLValue {
target: &rect.width
value: 400
interpolate: EASEBOTH:Number
},
InterpolatedLValue {
target: &rect.fill
value: red:Color
interpolate: EASEBOTH:Color
}]
}
Timelines and KeyFrames may be composed hierarchically - a KeyFrame may use the "include" operator to include any number of Timelines, in which case the key frames that make up the included timelines are merged into the containing timeline at the time instant of the key frame. The above "Ball" example demonstrates this, reproduced here:
var ax = Timeline {
// x
keyFrames:
[at (0s) {
x => 0;
},
at (10s) {
x => 700 tween LINEAR;
}]
autoReverse: true
repeatCount: INFINITY
}
var ay = Timeline {
// y
repeatCount: INFINITY
keyFrames:
[at (0s) {
y => 0;
},
at (2.2s) {
y => 375 tween SPLINE(0, 0, .5, 0);
},
at (2.25s) {
y => 375;
},
at (4.5s) {
y => 0 tween SPLINE(0, 0, 0, 0.5);
}]
}
var sxy = Timeline {
// scale x y
repeatCount: INFINITY
keyFrames:
[at (2.15s) {
sx => 1;
sy => 1;
},
at (2.25s) {
sx => 1.2 tween LINEAR;
sy => .7 tween LINEAR;
},
at (2.5s) {
sy => 1 tween LINEAR;
sx => 1 tween LINEAR;
},
at (4.5s) {
sx => 1;
sy => 1;
}]
}
var clip = Timeline {
repeatCount: INFINITY
keyFrames:
at (0s) {
include ax, ay, sxy;
}
}
In the above example, the "clip" timeline combines the other three animations. Playing "clip" will play all the animations simultaneously (yet still taking into account each ones individual repeat behavior).
Posted at 10:22AM Dec 20, 2007 by Christopher Oliver in JavaFX | Comments[32]
the "dur" operator was simple and clean that was it's beauty. Dont understand me wrong i like the Flash keyFrames i like the Flash as a tool for creating animations ( flex is good microsoft silverlight has a nice solution too ) and all they are keyframe oriented i like them but i like love the dur operator :) one line and u have it and it work ! :) so .. if you ask me ok make them keyFrame oriented if there is nice design tool but leave the "dur" too .. I like coding by hand.
Posted by JOKe on December 20, 2007 at 12:00 PM PST #
I'm not convinced by this approach. Too complicated to be productively usable, and the code itself is not very readable. And pointers - you gotta be kidding me! Is this still supposed to be a productive and easy to use language? You guys can do better then that!
Posted by Snowflake on December 20, 2007 at 01:34 PM PST #
Snowflake,
Pointers are not visible to the user - if you look at the examples.
It's a necessary implementation detail, however.
The examples given weren't necessarily designed to demonstrate the simplicity of the animation syntax, but rather the generality and credibility of it.
I've added an even simpler example, which shows an expression of a reversing, simultaneous scale, rotation, and color animation.
I personally, don't see how to make it easier than that. If you do, please let me know.
Try clicking on the rectangle while the animation is running.
Posted by Chris Oliver on December 20, 2007 at 03:17 PM PST #
It's good for you to admit you're not doing open source. The question is WHY???
You're pretty much undermining Sun overall open source effort by now doing this on a highly visible, yet far-from-baked project. I'm pretty sure it's actually hurting other open source projects at Sun.
Posted by John Doe on December 21, 2007 at 12:17 AM PST #
Hi Chris
Looks like a nice enhancement to the language. The one thing I can imagine wanting is to use some sort of symbol inside of at() or after(), in order to identify steps in a timeline by name (or some logical/conceptual identifier) instead of using an explicit time. I need to play around with the current proposal to see if that's meaningful or not; just that having some action take place at a certain time seems a little odd. It would seem I would need a lot of testing to determine when the right point is to have an action take place.
Nice work, as always--thanks for the demos.
Regards
Patrick
Posted by Patrick Wright on December 21, 2007 at 12:35 AM PST #
Chris
Another question related to development of the language--I'm following the compiler group mailing list, and while they are trying to figure out how to implement the "original" F3 language, I'm wondering how these new changes will be scheduled in. Is the plan to develop the interpreter in concert with the compiler, or to let the interpreter advance beyond the compiler? Seems your work with the interpreter shows it's one mechanism to experiment with new features, which is a plus.
Thanks
Patrick
Posted by Patrick Wright on December 21, 2007 at 01:57 AM PST #
@John Doe
If you think I'm personally responsible for the fact that OpenJFX hasn't become a true open-source project, you're mistaken. That's the opposite of my personal recommendation.
On the plus side, the openjfx compiler project is a true open-source project, as is the new Java scene-graph project.
Hopefully, in the near future these will replace the current open-jfx binary code base.
Posted by Chris Oliver on December 21, 2007 at 11:25 AM PST #
@Patrick,
You can use variables in place of time literals:
var t1 = 0s;
var t2 = 1s
var t3 = 2s;
at (t1) {...}
at (t2) {...}
at (t3) {...}
Or any expression:
after (t3-t2) {...}
Posted by Chris Oliver on December 21, 2007 at 11:30 AM PST #
One recommendation from the peanut gallery: call them something other than pointers and use different symbols. People will mock the language for having "pointers" even though they're a different beast than their C counterparts.
Posted by 76.21.13.66 on December 21, 2007 at 09:48 PM PST #
Chris,
great work the demos are well done. I like the Key-Frame animation as well. However I also like the old "dur" operator. Are you going to deprecate it? Perhaps we could keep it to do simpler stuff...
Posted by Adam Bien on December 27, 2007 at 11:52 AM PST #
Concerning your Time class...
FIRST:
In my latest project we introduced a special time-literals into proprietary query language. And I think it was safer than yours.
Java class was as simple as:
final class Time {
private final long millis;
...
}
I think that your time should have constructor Time (hour:Number , minute:Number, second:Number, millis:Integer)
each of parameter may be possitive or negative and...
there should be possilbe to use them as
1.5h (one and half hour) equiv to Time(hour:1.5)
-2.2m (minus 2minutes and 12seconds) equiv to Time(minute: -2.2);
and it should allow
3h15m10s200t which should mean 3hours and 15 minutes and 10 seconds and 100 milliseconds... (t stands for millis because I could not propose better letter) and should be equiv to Time(3,15,10,200);
The latest form should not allow real values except in the last part, say:
3h15.5m is possible and equiv of Time(hour:3, minute:15.5);
while 3h15.5m10s is not allowed...
Number of hours is not limited.
Number of minutes is in [0..60) only if we have Nh.
Number of seconds is in [0..60) only if we have Nh and\or Mm
Number of millis is in [0...999] only if we have Nh and\or Mm and\or Ss.
Thus 1001s is possible, 10h20s is possible, while 10h100s is not.
But once Time instance is created its value becomes long and original information (literal presentation) should not be available in form other than long. This will exclude bad practice to use getHour(), getMinute(), etc. for presentation purposes. The only exception may be toString() which may normalize long to full NhMmSsTt presentation. Concerning additional methods I would exclude them -- because Time would be a pure wrapper over long; compare Long, Integer, Double, Float has no any operation except conversion to mother type and string; so do Time; it should not have any operations. However +, -, /, %, etc should be acceptable for them.
SECOND:
Another option may be not to have time type at all and have only seconds (real number, accurately transformed into Java's millis thru all the code when calling to Java). And then we should just to have special "extension" to Number literal which may be hh:mm:ss.SSS or mm:ss.SSS while ss.SSS will be just a usual variant of this literal. In this case it would look very natural. I think the second solution is more corespondent to KISS nature of JavaFX. (actually this solution would be similair to Excel sense of time interval and dates -- in Excel it is number of days, when number is not integer then it includes time).
THIRD:
May be even better than SECOND :)
We treat time as JavaFX's Integer (Java's long)
var t = 12345; // 12345 millis;
var t2 = 12.345; // 12 millis NOT 12 sec + 345 millis!!! actually this is incorrect, so form with only dot is not acceptable.
var t3 = 0:12.345; // 0 minutes 12 seconds and 345 millis
t is absolute equiv of t3.
Idea is to have a special format for Integer (in contrast to SECOND)
The bad outcome of this syntax may be that it may conflict ternary operator ( a ? b : c )
In all 3 variants I suggest to have simple wrapper over long and nothing more.
Thanks,
Alex.
Posted by Alexander Zynevich on January 10, 2008 at 12:37 PM PST #
hi chris,
I try to run this demo. they run fine in javafx pad.
but when i try to run the ode in netbeans. i get error like,
""[Error in file:/C:/Users/dhaval/Documents/NetBeansProjects/Banner/src/banner/Main.fx:85: Encountered "s" at line 85, column 31.
""]
the line it points is
[[
" [at (0s) { "
]]
please replay
thanks.
Posted by dhaval on January 10, 2008 at 06:27 PM PST #
Hi Chris,
I'm very very happy to see that
keyframe animation will be
supported in JavaFX!
I'd like to suggest adding an
attribute for the number of frames
(at 24 frames per second),
since animators, both digital
and traditional, tend to think
in frames ... at 24 fps.
Also, it looks like the base time unit
in the code snippet appears to
be a millisecond. I'd recommend
making the base time unit
1/6th of a millisecond. This was
the choice that was made for Maya,
a popular 3D animation package.
The reasoning behind this choice
is that with 6000 base time units
per second, its easy to represent
24 frames per second, as each
frame would have 250 units of time.
Otherwise, with 1 ms as your
base time unit, 1 frame at 24 fps
would be ... 41.6666666...
a bit messier ...
1/6th of a ms works like magic!
cheers!
John
Posted by John on January 23, 2008 at 08:50 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by Dizi izle on February 19, 2008 at 12:36 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by Redtube on February 19, 2008 at 12:36 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by porno on February 19, 2008 at 12:37 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by 89.com on February 19, 2008 at 12:37 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by 89 on February 19, 2008 at 12:38 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by Youporn on February 19, 2008 at 12:39 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by Youtube on February 19, 2008 at 12:39 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by sex on February 19, 2008 at 12:40 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by seks on February 19, 2008 at 12:40 PM PST #
Those asking for the release, read Chris' comments here The summary: Hopefully Feb 2007 here
Posted by Filim indir on February 19, 2008 at 12:41 PM PST #
The animation syntax does cover a substantial new set of cases, which is great. I've spent the last few weeks doing a variety of things with OpenLaszlo, and I'd say that jfx and laszlo have things to learn from each other.
I was a little disturbed by some of the notes on the openjfx compiler wiki - specifically the mention that bindings are "overused". Without a thorough definition by the writers, it's a very big question mark.
If bindings are "overused" because of performance concerns, that is an issue for the jfx runtime, NOT for the language. If they are overused because they are perceived as being difficult to understand, that is an issue with training materials.
The whole point of declarative languages is to say what you mean, not how to get there. The more mature a declarative language gets, the more it is able to accomplish its tasks without annoying the user about details that are necessary to derive proper performance.
In my opinion bindings are underutilitized in the jfx. A specific and critical laszlo feature missing from jfx is the lz state.
A state packages up behaviors, attribute sets, animations, and even content into a named unit that can be applied to any node, and switched on and off at will. Because they are classes, lz states can get complex in their definitions, and states can have states as well (giving us a nice higher order means of expression). A state is effectively a dynamic mixin to an object.
lz implements them by simply instantiating everything in the state trees but removing them from actually process unless the state apply attribute is true. And the apply attribute on the state is, of course, fully bindable.
To relate this back to animation (and your post), I note that an animation can be placed in an lz state. When the state is applied, all animations in that state are triggered. If a state is removed, all animations are stopped and removed (along with everything else in the state).
So if we have a picture we want to show the user, we can define two different states for that picture -- thumbnail and view. In the thumbnail state we put an event handler (or action) that applies the view state, then removes the thumbnail state. The thumbnail state also has width and height set to small sizes. The view state contains an animation that sets the width and height to the size of the actual image, over some duration.
You're probably familiar with this already, but on the off chance you're not, have a look at openlaszlo. Try to ignore the documentation (which is generally excellent but fails to introduce the declarative stuff early enough), and go straight to states and constraints.
jfx becomes a much stronger language with something like states, and general problem of controlling animation is MUCH easier with them as well.
Posted by Ross Judson on March 01, 2008 at 11:22 AM PST #
One other short note: jfx is a very "vertical" language, particularly with the code formatting choices you've made. Given that, I hope you will put a spin button the splitter in JavaFXPad so the preview and code can be side-by-side. This would be particularly effective on a wide-screen monitor, which I suspect a good deal of your audience use.
Posted by Ross Judson on March 01, 2008 at 11:26 AM PST #
Long shot here - are you the same Chris Oliver who wrote assorted programs for the Sinclair ZX Spectrum?
Posted by Gerard on March 19, 2008 at 12:58 AM PDT #
pagerank kazan, site ekle, link ekle, url ekle, add url, add link, add site, site submit
Posted by ali on May 10, 2008 at 10:56 PM PDT #
htmlkodlar, webmaster araçları, htmlkod
Posted by kemal on May 10, 2008 at 11:02 PM PDT #
toplist site ekle, link ekle, url ekle
Posted by husnü on May 10, 2008 at 11:03 PM PDT #
toplist site ekle, link ekle, url ekle
Posted by husnü on May 10, 2008 at 11:06 PM PDT #
toplist site ekle, link ekle, url ekle
Posted by kodmarker on May 13, 2008 at 10:11 AM PDT #
http://www.kodmarker.tr.gg/
Posted by MUDİX on May 13, 2008 at 10:12 AM PDT #