Create an Easy Animated Line Graph

Representing data in graphical form is easy with the JavaFX Script programming language. This article shows how to convert data into an animated line graph. The code is described at a level of detail appropriate for beginners.

Animated Line Graph

You can easily create line graphs in the JavaFX programming language and punch them up with animation and mouseover effects.

The following applet displays a line graph of atmospheric temperatures in three different cities over a 24-hour time period. You can mouse over any data point, and the temperature value for that point is displayed.


When you run the application yourself, you will also see a window title bar.

How the Animation Works

Here's the trick that makes the animation work. A black rectangle covers the graph and moves from left to right, revealing the data points and making it appear that the lines are animated. If the color of the Scene object is changed from BLACK to GRAY, you can see the black rectangle moving to the right, as shown in Figure 1. Mouse over any of the four images to see a larger version.

How the Line Graph is Animated Figure 1: How the Line Graph is Animated

Two source files are in the application: Main.fx and PointGraph.fx. The sample includes project files for NetBeans IDE 6.5 for JavaFX 1.1. [Instructions to open the project in the NetBeans IDE]

The following sections describe in detail how this graph is created. To look up any of the classes, class variables, or class functions described here, see the Master Index to the API documentation.

About Main.fx

The Main class in Main.fx contains the following sections of code.

  • A set of variables is declared and initialized for each city, with temperature values , line color, and the city name.
Source Code: Variables in Main.fx for Each City
// 3 instance of PointGraph

var pg: PointGraph = PointGraph{
    Y: [3,1,3,5,9,12,10,6],
    color: Color.LIGHTBLUE,
    CityName: "NewYork,USA"
};
var pg1: PointGraph = PointGraph{
    Y: [12,10,14,18,20,23,14,9],
    color: Color.YELLOWGREEN,
    CityName: "Bangalore,IND"
};
var pg2: PointGraph = PointGraph{
    Y: [20, 18, 19, 24, 28, 27, 22,15],
    color: Color.ORANGE,
    CityName: "Sydney,AUS"
};

  • A Reload button is created by defining a rectangle and text. Additional code specifies that the application replays when the button is clicked.
  • A timeline is defined for the animation of the black masking rectangle, with values for speed and the type of animation. In this example, the rectangle moves at a constant speed during the duration specified, five seconds.
Source Code: Timeline for Animation of the Black Rectangle
public var t = Timeline {
    repeatCount: 1
    keyFrames: [
        KeyFrame {
            time: 5s
            canSkip: true
            values: [
                variable => 530.0 tween Interpolator.LINEAR
            ]
        }
    ]
};

  • The stage is defined, which includes variables for the window size and the location on the screen at which the window appears. Because the style variable is initialized with the value StageStyle.DECORATED, a title bar is created for the window in which the application runs. The Close, Minimize, and Maximize buttons in the title bar are generated automatically. The title is provided by the title attribute.
  • The Scene object includes all objects that appear on the screen, excluding the window title bar. Variables defined elsewhere are named in the scene, such as the variable containing the data points, and the variables for the reload button and text.

The following objects are defined within the scene:

  • A black rectangle is drawn that covers most of the scene. This is the rectangle that moves from left to right across the stage.
Source Code: The Black Rectangle
Rectangle {
    translateX: bind variable
    x: 10,
    y: 10
    width: 500,
    height: 500
    fill: Color.BLACK
    opacity: 1.0
},

  • A path is created to draw the lines for the x- and y-axes.

    Note that the variables x and y in lower case in the following figure do not correspond to the x- and y-axes, but rather describe the horizontal and vertical positions in the area defined for the stage, measured in pixels. The left top of the scene is (x=0, y=0). In the code below, the x-axis is drawn from (x=10, y=300) to (x=450, y=300), and the y-axis is drawn from (x=10, y=300) to (x=10, y=10).
Source Code: Path Object for the X and Y axes
Path {
    translateX: 50
    translateY: 0
    stroke: Color.WHITE
    strokeWidth: 2
    opacity: 0.4
    elements: [
        MoveTo {
            x: 10.0,
            y: 300.0
        },
        HLineTo {
            x: 450.0
        },
        MoveTo {
            x: 10.0,
            y: 300.0
        },
        VLineTo {
            y: 10.0
        }, 
    ]
},

  • A group is created with a for loop to add the axis labels.

    The num variable, used as the counter in the for loop, is also used to create the x location for the text, and it is used again to determine the text that is displayed. For example, for the x-axis, if num=2 in the sequence, the horizontal location for the text is x=125, and the text that is displayed is 6.
Source Code: Adding the Axis Labels
content: for(num in [0..7]) {[
/* Add the x-axis labels */
    Text {
        fill: Color.WHITE
        font: Font {
            size: 10
        }
        x: num * 60 + 5
        y: 320
        content: "{3*num}"
    },
/* Add the y-axis labels */
    Text {
        fill: Color.WHITE
        font: Font {
            size: 10
        }
        x: -5
        y: 320 - num * 50
        content: "{5*num}-"
        }
    ]
}

About PointGraph.fx

PointGraph.fx contains the code for the data points and lines.

  • Script variables are declared and initialized for the display of temperature during mouseovers and to enumerate the fixed values along the x-axis.
Source Code: Script Variables in PointGraph.fx
/* Variable for showing temperature */
public var labelX = 0;
public var labelY = 0;
public var labelOpacity = 0;
public var labelText: String;
/* X Axis */
public var X: Integer[]=[0,3,6,9,12,15,18,21];

The PointGraph class extends the CustomNode class,which includes overriding the create function. Y is declared as an instance variable. It is a sequence to match the declaration in Main.fx, from which it derive its values.

Source Code: The PointGraph Class and Instance Variables
public class PointGraph extends CustomNode {

    public var Y: Integer[];
    public var num: Integer;
    public var color: Color;
    public var CityName: String;

The PointGraph class contains the following objects:

  • A Rectangle class that defines the rectangle that appears when a viewer mouses over a data point.
Source Code: The Mouseover Rectangle to Display the Temperature
Rectangle {
    x: bind labelX,
    y: bind labelY,
    opacity: bind labelOpacity
    width: 40,
    height: 15
    arcHeight: 5
    arcWidth: 5
    fill: Color.BLACK
    stroke: Color.GRAY
    strokeWidth: 1
},

  • A Text class that defines the formatting for the text that appears in the rectangle on mouseover.
Source Code: Formatting for the Text to Appear on Mouseover
Text {
    fill: Color.WHITE
        font: Font {
        size: 12
    name: "Arial Bold"
    }
    x: bind labelX + 10,
    y: bind labelY + 12,
    opacity: bind labelOpacity
    content: bind labelText
}

  • A Text class that sets the formatting, location, and content to display the name of the city on the graph.

    Notice that the vertical position is determined by calculating a value that is relative to the first temperature in the sequence for that city. For example, in Main.fx, the first Y value for New York is 3, and the x-axis is located at y=300, so the vertical location of the city name is y=300-3*10=270.
Source Code: The Name of City Displayed on the Graph
Text {
    fill: Color.WHITE
    font: Font {
        size: 10
    }
    x: 10,
    y: 300 - Y[0] * 10
    content: CityName
}

  • A group with a for loop that creates a circle of the appropriate color for each data point and places it at the appropriate location.

    The for loop uses a sequence slice: for(num in [0..X.size() - 1]). The built-in size() function counts the number of items in the sequence. In this case, the sequence enumerated for X has eight items. Because the sequence starts at 0, the sequence ranges from 0 to 7. The for loop equates to for(num in [0..7]). The size() function has the same result operator sizeof. Therefore, another way to write the for loop is for(num in [0..sizeof X - 1]). For more information about sequence slices, see Learning the JavaFX Script Programming Language.

    The circles have a radial gradient to give them more of a 3D appearance. This Group object also contains the functions for the the event handlers to show and hide the label when the mouse moves over or away from the data points.
Source Code: Creating Circles for the Data Points
Group {
    content: for(num in [0..X.size() - 1]) { [
        Circle {
            centerX: X[num] * 20.0,
            centerY: 300 - Y[num] * 10.0
            radius: 6
            fill: RadialGradient {
            centerX: 0.25
            centerY: 0.25
            stops: [
                Stop {
                    color: color
                    offset: 0.0
                },
                Stop {
                    color: Color.BLACK
                    offset: 1.0
                },
            ]
        }
        onMouseMoved: function( e: MouseEvent ):Void {
            labelX = X[num] * 20;
            labelY = 300 - Y[num] * 10;
            labelOpacity = 1;
            labelText = "{Y[num]} C";
        }
        onMouseExited: function( e: MouseEvent ):Void {
            labelOpacity = 0;
        }
    } ]
}
                        
  • A group that contains a for loop with a Path object to connect lines to the data circles.
Source Code: Lines Connecting the Data Points
Group {
    content: for(num in [0..(X.size() - 2)]) { [
        Path {
            fill: null
            stroke: color
            strokeWidth: 2
            elements: [
                MoveTo {
                    x: X[num] * 20.0,
                    y: 300 - Y[num] * 10.0
                },
                LineTo {
                    x: X[
                    num  +  1] * 20.0,
                    y: 300 - Y[
                    num  +  1] * 10.0
                },
            ]
        }
    ] }
}

Open and Run the Project in the NetBeans IDE

  1. Download the example and extract the zip file.

  2. Copy the PointGraph folder to the NetBeans projects directory.

    • For a default Windows installation. The NetBeans project folder is located in My Documents\NetBeansProjects

    • For a default Mac OS X installation. The NetBeans project folder is located in your-user-name/NetBeansProjects

      Note: With a new NetBeans installation, you must open or create a project before the NetBeansProjects folder is created.
  3. In the NetBeans IDE, click File > Open Project and select the sample.

Related Links

 

English
日本語
한국어
简体中文
русский
Português do Brasil