January 06, 2010

Simple animation in JavaFX

Having two weeks off during the Christmas holidays gives you some time to create something in JavaFX. I had already used JavaFX before, but animations were a part I didn't yet have any experience in. So I was thinking of remaking a simple banner application that a client once needed for his website. That version was written in Flash and was created by a third party. You can have a look at that animation at http://vi.be.

The application is quite simple. It reads in an XML-file which contains a list of banners. Each banner has an image, a title, a description and a URL. After the XML-file has been read, it displays the banners one after another. The transition between two different banners is done by using a simple fading out/fading in animation. Doing this animation in JavaFX is simple.

First I create a variable to hold the current opacity and bind this to the opacity of the banner. The SingleBanner class used below is nothing more than a CustomNode in which the image, the title and the description are placed.

var bannerOpacity = 1.0;

insert SingleBanner {
banner : banner // the POJO containing all banner info
visible : false // initially all banners are invisible
opacity : bind bannerOpacity // bind the opacity variable to the banner

// when the mouse is hovering over the banner, pause the timeline
onMouseEntered : function(event : MouseEvent) {
timeline.pause();
}
onMouseExited : function(event : MouseEvent) {
timeline.play();
}
} into banners;


To do the actual animation in JavaFX, we need to create a Timeline. A Timeline does nothing more than perform actions at specified "keyframes". You can execute this Timeline once, a few times or even infinitely. Here's the code for our Timeline:

var timeline : Timeline = Timeline {
repeatCount : Timeline.INDEFINITE
keyFrames: [
at (4.75s) {
bannerOpacity => 1.0
},
at (4.85s) {
bannerOpacity => 0.0 tween Interpolator.EASEOUT
}
at (5.0s) {
bannerOpacity => 1.0 tween Interpolator.EASEIN
}
]
}


The syntax is easy to understand and you can clearly see what the Timeline does. 4.75 second after the Timeline was started, it will assign 1.0 to the variable bannerOpacity. Between 4.75 and 4.85 seconds the opacity will be brought down to zero using an EaseOut interpolation. Finally, the opacity will be brought back up to 1.0 with an EaseIn interpolation. The trick is now to make the current banner invisble when the opacity reaches 0. At the same time, the next banner in the array will be made visible. We can do that easily using a replace trigger.

var bannerOpacity = 1.0 on replace {
if (bannerOpacity == 0.0) {
counters[index].active = false;
if (index + 1 >= sizeof(banners)) {
index = 0;
} else {
index++;
}
counters[index].active = true;
}
}

var index = 0;
var banner = bind banners[index] on replace oldBanner {
oldBanner.visible = false;
banner.visible = true;
}


That's all that is required to do some simple animation. The code for the project can be downloaded here. There are only two problems that I couldn't resolve:

  • I have not yet found a way how to open a URL from within JavaFX. This can be achieved with: AppletStageExtension.showDocument(banner.link, "_new");

  • In browser mode the loading of the images takes a long time. In desktop mode it seems to go a lot quicker.



Below you can have a look at the banner application itself.