Tuesday, April 7, 2009

Add Effects to the right Container!

WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.


The Flubber application I described earlier has an old stop-watch style timer with second and minute hands:



Making the clock hand move was trivial using value binding and a rotation transform on the hand graphics object:


transforms: Rotate {
angle: bind (360.0 / 60 * minutes) - 90.0
}

Since we are using a binding expression, setting the minutes variable anywhere (and yes, assigning to it!) will cause the hand angle to be recomputed and the graphics updated.

Anyway - once we had the clock moving, the first thing we wanted to do was improve the look of the clock by adding a drop
shadow. That was trivial; all we had to add was this:


effect: DropShadow {
offsetX: 5
offsetY: 5
color: Color.BLACK
radius: 10
}


That looked pretty good:




But look what happened when we let the timer run... Where is the light source?




What's happening here is that the drop shadow is rotating with the hand. Not what we want.
We were all learning JavaFX that day, so we hacked it, using the following code:


effect: DropShadow {
offsetX: bind Math.sin(Math.toRadians(handAngle + 45)) * 5.0
offsetY: bind Math.cos(Math.toRadians(handAngle + 45)) * 5.0
color: Color.BLACK
radius: 10
}


Now, the drop shadow offset moves along with the rotation such that the shadow always appears in the right place.
It worked, and we moved on.



Now that I understand JavaFX and the scenegraph a bit better I realize that this approach is wrong - there's a much simpler solution!
We don't want to apply the drop shadow to the Path object directly, since the path is what we are rotating with our minute angle.
Instead, we should simply move the effect out to the surrounding parent. That will apply the drop shadow after the shape
has been rotated.
Doing that, we can set our drop shadow initialization back to the original simple 5,5 delta, and we get exactly the result we want:



So, think about which node you apply effects to! And by the way, the effects framework is really fun to play with - you should definitely
explore javafx.scene.effect.* !


No comments:

Post a Comment