Saturday 12 September 2009

Week 3.2 Knowledge Experiment

Given my current limited knowledge of JavaFX, I thought it would be an interesting experiment to try and create a scene graph that contained a circle and rectangle, then on a timeline zoom them in and out repeatedly. Here's a screenshot of the end result, okay, it's nothing special and I will not win any awards for this 'experiment', but it shows you how quickly a newbie can pick up JavaFX and run with it!

You might even notice that I have some transparency involved!



So when I was thinking about doing this, my first thoughts were "hmm, I need a Thread that would periodically adjust some attributes and then cause the graph to redraw using the new values".

Almost immediately afterwards I remembered that in JavaFX you would use binding to keep the user interface in sync with some data / model. So all I needed to do is find out how to add things to a scene graph.

I must point out here, I did not use any javadoc, nor read an article, I simply used the JavaFX palette in NetBeans, then filled in the blanks. In some places I needed slightly more information, so I used the code-completion feature (ctrl+space) to learn what attributes were available... Yes, this was all guess-work.

Here's the code


package week2blog;

import javafx.scene.Scene;
import javafx.scene.Group;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;
import javafx.stage.Stage;

var sc : Number;

var tl : Timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 1s
canSkip : true
values : [sc => 0.0 tween Interpolator.EASEBOTH]},
KeyFrame {
time: 2s
values : [sc => 10.0 tween Interpolator.EASEBOTH]},
KeyFrame {
time: 5s,
values : [sc => 0.0 tween Interpolator.EASEBOTH]}
]
};

def scene : Scene = Scene {
width: 600,
height: 600,
fill: Color.LIGHTGREEN,
content: [
Group {
content: [
Circle {
centerX: 100, centerY: 100
radius: 40
fill: Color.BLACK
scaleX: bind sc
scaleY: bind sc
},
Rectangle {
x: 100
translateX: sc * 50
y: 300
width: 140, height: 90
fill: Color.PURPLE
scaleX: bind sc
scaleY: bind sc
opacity: .5
// effect:Shadow {
// color: Color.BLACK
// radius: 15
// }
}
]
}
]
}

Stage {
title : "Experiment"
scene: scene
}

tl.playFromStart();



You'll see that I discovered timeline and keyframe objects that I could use to declaratively build up my animation. The timeline is literally as it sounds - a time line, it does nothing on its own, but you add timing information into it and what you want variables to be at that time! Imagine if I said that I want my rectangle to be at the co-ordinate 0,0 at the start of the animation and 10 seconds later to be at 100,100... It would be pretty dull if it jumped from 0,0 (at the start of the animation) to 100,100 (10 seconds later), so you specify an Interpolator to say how it changes over time - tweening I believe it's called.

The obvious interpolator is the linear one, it will simply adjust the attribute from 0,0 to 100,100 linearly over 10 seconds, so in 5 seconds for example, you would be half way through the animation, meaning the values would be 50,50.


Seconds - Position
0 - 0,0 (start)
1 - 10,10
2 - 20,20
3 - 30,30
4 - 40,40
5 - 50,50
6 - 60,60
7 - 70,70
8 - 80,80
9 - 90,90
10 - 100,100


There appear to be many Interpolators, I chose the EASEBOTH, which evidently starts slowly, increasing speed and then slows back down again before completing.

One thing that was obvious, I tried to add a shadow effect and this was very slow on my MacBook - so go careful on those special effects; this is an old machine so I would expect it to look pretty good on a newer model. At the very least, give your users the option to opt out of any demanding effects.

In some cases you can consider using the cache option - this will enable re-rendering of portions of the scene graph to be quicker, but it will only cache the graphic at a specific size, or effect, so I guess you would use this for things that are statically placed, but require some effects (i.e. a button with a shadow and glow effect). You will need to trade off memory v speed if you use any caching.

As you can see, the code is pretty small - so I think I am going to like JavaFX!

Rob.

No comments:

Post a Comment