Create Jazzy and Jazzier Bar Charts
- Skill Level Intermediate
- Supported Versions JavaFX 1.1
- Key Features Graphs, Animation, Custom title bar
- Last Updated March 2009
Learn how to create two animated bar charts with simple JavaFX applications.
Two Animated Bar Charts
The simple bar chart in the following applet shows what percent of developers use each of several standard programming languages.
The second applet shows a bar chart that has the appearance of tubes filling with liquid. We'll call this a "tube chart," to distinguish it from the first bar chart. The graph shows the price of gasoline or petrol in a few countries around the world. The animation is slowed down a bit so that you have more time to process what is happening behind the scenes.
Both charts include a custom window title with an "x" button to close the graph.
The bar charts in this article have elements in common with the line graph presented in the article "An Easy Animated Line Graph," which is described in detail for beginners. See that article for more details about how the code works.
How the Simple Bar Chart Works
The simple bar chart application (called MyBarGraph in the zipped project files) contains a simple scene in which all of the bars are animated at the same time until they reach their correct value. The scene in Main.fx contains objects that provide the following:
- The x-axis and y-axis lines with values labeled.
- A sequence variable called
bargraph, which is created from theBarclass (details follow). - A Reload button, plus the mouse events to play the timeline from the beginning.
- A custom window title plus the mouse events to move the window around on the screen.
- A custom "x" button in the window title, plus the mouse events to close the window.
The code is commented so that you can review this functionality. Including bargraph as an object in the scene is all that is required to draw and animate the bars, as defined in the Bar class.
The bargraph variable contains the data points plus other information from the Bar class, as shown in the following source code.
Main.fx
/* Percentage usages */
var bars: Integer[] = [15,20,25,15,8,7,10];
var bar_names: String[] = ["C++","C","Java","Perl","PHP","SQL","Others"];
/* instance of Bar */
var bargraph: Bar[];
for(i in [0..6]){
insert
Bar {
X: 100 + i * 50
Y: 150
height: bars[i]
txt: bar_names[i]
} into bargraph
}
The data points are initialized in the bars variable, and the bar labels are initialized in the bar_names variable. The variable values that will be used in the Bar class (defined in Bar.fx) are written to the bargraph sequence variable. Each item in this sequence includes the height of the bar, taken from the bars[] sequence, the bar labels, and X and Y values, which are bound to the x and y coordinates for the rectangle that defines the bars. These same variables are declared as instance variables in the Bar class. The values of the instance variables will only be used in case a value in the bargraph[] sequence is null.
The custom Bar class includes the timeline, the rectangle that defines the bars, and the text that will appear under each bar.
The timeline code is shown in the following code snippet from Bar.fx.
public var t = Timeline {
repeatCount: 1
keyFrames: [
KeyFrame {
time: 5s
canSkip: true
values: [
variable => height tween Interpolator.LINEAR
]
}
]
}
The values variable in the KeyFrame instance shows that the animation progresses from variable (initialized to zero) to height (the height of the bar from the bargraph[] variable) at a constant speed. The value of variable increases as the timeline progresses until it reaches the value of height. Becaue the full height of each bar is achieved in the duration specified in the KeyFrame, the taller bars are drawn faster than the shorter bars.
The vertical upwards animation is controlled by the translateY variable in the Rectangle object instance, as follows.
translateY Variable in the Rectangle Instance for Bar.fxRectangle {
translateY: bind 50 - variable * 5
By default, vertical animation occurs from top to bottom, and this order can be reversed by subtracting variable, used as the value in KeyFrame, from the starting point. The x-axis is drawn at position y=50, so the translateY variable starts at 50 and subtracts the increasing value of variable to go up instead of down. The height of the bar is multiplied by a factor of 5 to scale correctly.
How the Tube Chart Works
The tube chart has many similarities to the previous bar chart application. A custom TubeFill class is defined, which contains the timeline plus instances of the objects that will be drawn. In Main.fx, a tubes[]sequence is declared, and values that will apply to the TubeFill class are inserted.
tubes[] Variable is Populated in Main.fx
var tubes: TubeFill[];
var height: Number[] = [120.0, 100.0, 50.0, 90.0];
var name: String[] = ["India", " USA", "Brazil", "Australia"];
for(i in [0..3]){
insert
TubeFill {
translateX: -80 + i * 140
translateY: -40
fillHeight: height[i]
grad: LinearGradient {
startX: 0.0
startY: 0.0
endX: 1.0
endY: 0.0
stops: [
Stop {
color: Color.BLACK
offset: 0.0
},
Stop {
color: Color.SADDLEBROWN
offset: 0.5
},
Stop {
color: Color.BLACK
offset: 1.0
},
]
}
} into tubes
}
In this graph, a y-axis with values is drawn for each bar, so the y-axis is defined in the TubeFill class rather than in Main.fx.
For both the tubes and the liquid, a rectangle is defined for the column, with an ellipse at the top. In both cases, the ShapeSubtract class is used to cut out the portion of the rectangle that is occupied by the ellipse.
The KeyFrame instance in the timeline contains two values.
KeyFrame Instance in TubeFill.fxKeyFrame {
time: 30s
canSkip: true
values: bind [
fill => fillHeight tween Interpolator.LINEAR
op => 1.0 tween Interpolator.LINEAR
]
}
The fill => fillHeight value controls the animation of each bar to its proper height. The vertical animation is achieved by the translateY variable, defined in both the ShapeSubtract instance and the Ellipse instance defined for the liquid.
The op => 1.0 value increases the opacity of the ellipse over the timeline, which makes the ellipse invisible when the height of the bar is zero and also provides a more realistic appearance. The op variable is given its value in the ellipse instance for the liquid.
translateY Variable in the Ellipse Object Instance in TubeFill.fx
Ellipse {
translateY: bind 91 - fill
opacity: bind op
Try It
Here are some suggestions for ways that you can modify the code to experiment with the applications.
Bar Chart
- Change the animation so that the bars are drawn one at a time.
- Add data for one more bar.
Tube Chart
- Remove the
translateYvariable from theEllipseand theShapeSubtractinstances for the liquid one at a time. See how the change affects the result. - Change the color of the tubes.
- Change the opacity of the background rectangle and other objects, one at a time. See how each change affects the result.
Related Links
- Article: Create an Easy Animated Line Graph
- Sample: Drawing Basic Shapes in JavaFX
- Sample: Jigsaw Created With Boolean Shape operations
- Blog: Pet Catalog : JavaFX Example Application
- Tech Tip: Animation Along an Arbitrary Path
- Sample: Animating Shapes Along a Path
Vaibhav Choudhary
Member of Technical Staff, Sun Microsystems