FlotJFExamplesWeb is a web project built to illustrate how to use FlotJF together with Flot. Flot is a pure JavaScript plotting library for jQuery while FlotJF is a Java Framework to generate the JSON data for use with Flot.
FlotJF was built to simplify the process of generating graphs with J2EE applications using Flot.
Check out the running version here:
http://flotjfexamplesweb.appspot.com/
Screenshots
|
|
|
ExampleGraph1.java |
ExampleGraph2.java |
ExampleGraph3.java |
|
|
|
ExampleGraph4.java |
ExampleGraph5.java |
ExampleGraph6.java |
Getting FlotJFExamplesWeb
The best way is to build it from source and import it to IDE of choice. See instructions under
Building:
https://github.com/dunse/FlotJFExamplesWeb/blob/master/README.md
To just checkout the running examples, download
https://github.com/downloads/dunse/FlotJFExamplesWeb/FlotJFExampleWeb-0.2-SNAPSHOT.war and deploy it to application server of choice.
After deployment open
http://hostname/context-root/ (For Tomcat the default would be
http://localhost:8080/FlotJFExampleWeb-0.2-SNAPSHOT/)
The Application
The application is quite simple. There is a static landing page (index.html) which has links to all the examples. These examples are displayed using example.jsp which we will take a look at first.
example.jsp
At the top of example.jsp we have some Java code to create session scope variables which we will use when calling the backend system for the correct data.
exampleId is passed from index.html using number 1 to 4. (If not set it default to 1, or we would get a
NullPointerException).
poll is either set or not set. If not set it is
null which we programmatically check later in the code.
<%
String exampleId = request.getParameter("id");
String poll = request.getParameter("poll");
String tooltip = request.getParameter("tooltip");
if (exampleId == null) {
exampleId = "1";
}
%>
In the HEAD section the jQuery and Flot scripts needs to be included. Line 15 and 17 are the main scripts that are required while 16 is optional to support Internet Explorer 6 and 7.
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>FlotJF Example <%=exampleId %></title>
<link rel="stylesheet" media="screen" href="stylesheets/main.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<!--[if lte IE 8]><script src="javascripts/flot/excanvas.min.js" type="text/javascript" charset="UTF-8"></script><![endif]-->
<script src="javascripts/flot/jquery.flot.js" type="text/javascript" charset="UTF-8"></script>
<script src="javascripts/flotjf.tooltip.js" type="text/javascript" charset="UTF-8"></script>
</head>
Line 22 is the <div> container which will be used to draw the graph on screen. We named it
placeholder which will be used to reference this object from the JavaScript code.
The custom size set bye the
style argument cannot be bigger than the <iframe> that has been specified in index.html.
<body id="example">
<h2>Example <%=exampleId %></h2>
<div id="placeholder" style="width:95%;height:400px;" ></div>
This determine if tooltips should be used. If
tooltip is set
useTooltip() inside flotjf.tooltip.js is called to bind the necessary events to handle this.
<% if (tooltip != null) { %>
useTooltip();
<% } %>
In the first section of the JavaScript we define
data which will hold the JSON data object fetched from the backend server. This
data variable is populated using the
getGraph() function. This in turn uses jQuery to perform a HTTP POST request to the /GetGraph URI to retrieve the JSON data.
In the code below the 'GetGraph' gets translated to /GetGraph by jQuery.
{example: <%=exampleId %>} will add one request parameter to the HTTP call named
example using the
exampleId from line 2.
The response from the HTTP POST call is passed back into
data and can be used by other parts of the JavaScript and Flot.
var data = [];
function getGraph() {
$.post('GetGraph',{example: <%=exampleId %>},
function(response) {
data = response
} )
return data;
}
Next we setup the plot. Below we first get the GraphOptions using HTTP POST in the same way as the GetGraph, which we then pass to
$.plot to create a new graph.
Important to note is the
async:false which disable asynchronous calls while initiating the graph. This is to ensure
options and
data have values before first use.
// setup plot
var options = [];
var updateInterval = 3000;
$.ajaxSetup({async:false});
$.post('GetGraphOptions',{example: <%=exampleId %>},
function(response) {
options = response
} )
var plot = $.plot($("#placeholder"), getGraph(), options);
The
update() function is used to draw the graph. This is done in three steps.
- setData() which retrieves the data using getGraph() function described above.
- setupGrid() to adjust the grid to the new data.
- draw() the graph(plot) on the screen.
If
poll was passed as a request parameter,
setTimeout() will create a timer which will call
update() every 3seconds (
updateInterval = 3000ms on line 39) to update the graph with new data from the backend server.
function update() {
plot.setData(getGraph());
plot.setupGrid();
plot.draw();
<% if (poll != null) { %>
setTimeout(update, updateInterval);
<% } %>
}
Finally we call
update() to initiate the drawing of the graph for the first time and set jQuery to use asynchronous calls again.
update();
$.ajaxSetup({async:true});
The above will of couse not do anything without the backend servlets which we will look closer at next.
GetGraph.java
This is one of the servlet which is used to retrieve
data by the frontend JavaScript. Servlet mapping is defined in web.xml as /GetGraph.
/**
* Servlet implementation class GetGraph
*/
public class GetGraph extends HttpServlet {
In the below code we process the HTTP POST request starting by extracting the request scope parameter
example. Then we set the response content type to
application/json so the client will interpret the response correctly.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String example = request.getParameter("example");
response.setContentType("application/json");
PrintWriter out = response.getWriter();
The rest of the code is to print the
data in the response body based on the
example parameter.
switch (Integer.valueOf(example)) {
case 1:
out.println(ExampleGraph1.getGraph());
GetGraphOptions.java
The same as for GetGraph.java, the servlet mapping declaration of /GetGraphOptions is located in web.xml.
/**
* Servlet implementation class GetGraphOptions
*/
public class GetGraphOptions extends HttpServlet {
Again, the same as for GetGraph.java with the minor difference that the response body consist of the
options from
getGraphOptions().
out.println(ExampleGraph1.getGraphOptions());
ExampleGraph1.java
ExampleGraph1 will return a simple graph with one data series based on
sin().
We start by creating a new
Chart object which is the container for
options and
data.
Next we create both X and Y Axis from the
Axis class. Flot use the same options for both axis which is why we use the common class
Axis.
In this example we use the default options so we just add the axis to the
chart object which will make them visible on the graph.
public static String getGraphOptions() {
Chart chart = new Chart();
Axis yAxis = new Axis();
chart.addYAxis(yAxis);
Axis xAxis = new Axis();
chart.addXAxis(xAxis);
return chart.printChartOptions();
}
When creating a data series we use the
PlotData object. The
PlotData constructor takes two optional arguments, Label and Colour. In this example we want to use the default colour and therefore we pass
null. Using
null to set properties will set them to the default value.
Next we create 100 data points using
addPoint(x,y). The
addPoint() method takes two arguments of type
Object to make it as flexible as Flot itself. In this example however we use simple data types
int and
double.
Last we create the
Chart object and add the data serie which will populate
data and then print it in JSON format using
printChart() method.
public static String getGraph() {
PlotData sinPlot = new PlotData("sin(x)", null);
int i = 0;
while( i++ < 100 ) {
sinPlot.addPoint(i, Math.sin(i));
}
Chart chart = new Chart();
chart.addElements(sinPlot);
return chart.printChart();
}
ExampleGraph2.java
ExampleGraph2 will return a simple graph with two data series based on
sin() and
cos() using two y axis.
Here we add a second y axis and use
setPosition() to define location of the axis (valid locations are "bottom", "top", "left" or "right").
Axis yAxisRight = new Axis();
yAxisRight.setPosition("right");
chart.addYAxis(yAxisRight);
To use the right y axis, simply call the
setRightYAxis() on the dataseries.
PlotData cosPlot = new PlotData("cos(x)+5", null);
cosPlot.setRightYAxis();
ExampleGraph3.java
ExampleGraph3 will return a multi-type graph with three data series representing line, dot and bar series.
To change the type from default line, just call
setBarOptions() or
setPointOptions().
// Flot use Line as default type. To change the type, just call the helper method use<Type>.
sqrtPlot.setBarOptions();
cosPlot.setPointOptions();
ExampleGraph4.java
ExampleGraph4 is a bit more advanced where we use the
poll parameter to update the graph every 3 seconds.
Here we set
max property on the y axis which will lock the maximum to 550 instead of the default dynamic setting.
The x axis is set to
time mode which by default automatically scales the axis depending on the range of the data series. In this case we use 5 minutes range which defaults to 30 second ticks.
Axis yAxis = new Axis();
yAxis.setMax(550L);
chart.addYAxis(yAxis);
Axis xAxis = new Axis();
xAxis.setMode("time");
chart.addXAxis(xAxis);
This
getGraph() method is a bit more advanced to illustrate the use of realtime updates of the graph.
First we create two Calendar objects, one using local time and one UTC. Flot only use UTC which means the time must be adjusted before Flot process it.
Variable
timeSpan will be used to limit the returned data series x range to 5 minutes.
public static String getGraph() {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+0000"));
Calendar localCal = Calendar.getInstance();
// Timespan in seconds
Integer timeSpan = 300;
Since we are simulating a realtime graph the highest x value must be current time while startTime 5 minutes (timeSpan) earlier. We use time in milliseconds since it makes data manipulation easier and Flot expect this format.
On line 34 we adjust the endTime to compensate for the limitation of Flot only supporting UTC. This is by adjusting the time in milliseconds by the offset between UTC and local timezone. In Flot this will make sure the time is presented as it would be using the local timezone.
Long endTime = cal.getTimeInMillis();
// Adjust endTime
endTime += localCal.getTimeZone().getOffset(cal.getTimeInMillis());
Long startTime = endTime-(timeSpan*1000);
PlotData sinPlot = new PlotData("rand(x)", null);
The next few lines is using a Java's Random class to create a identical sequences of number which we navigate through using a subset of the time in milliseconds. The sole purpose is to simulate retrieval data from a persistent layer such as a database where we end up with a realtime feel on the client side.
// Create new random generator using seed 1
Random rand = new Random(1);
// Create sequence based on time to be used to retrieve numbers from random seed
int startIntSeed = (int)Math.floor((startTime % 10000000) / 1000);
// Forward to the current next random number
for (int seq = 0; seq < startIntSeed; seq++) {
rand.nextInt(500);
}
ExampleGraph5.java
ExampleGraph5 shows the use of colour and opacity graident.
We start by defining we want a Bar series. Then specify the options such as width (0.8 = 80%) and the line width (0 = no border lines).
Next we define a three colors to use as a gradient, blue, red then blue. This is all that is requied to create a gradient based on colour. We also use
setColors() to set another level of gradient using opacity 0.8 to 0.1 in order to show how it can be used..
sqrtPlot.setBarOptions();
sqrtPlot.getBars().setBarWidth(0.8);
sqrtPlot.getBars().setLineWidth(0);
Colors colors = new Colors("#afefef", "#ff5522","#afefef");
colors.setColors(new Gradient(0.8,null), new Gradient(0.1, null));
sqrtPlot.getBars().setFillColor(colors);
ExampleGraph6.java
ExampleGraph6 shows the use of tooltips (Based on Example 3).
In the Java code the only requirement is to specify that the grid is
hoverable.
// Enable interaction with grid. (In this case for tooltip)
Grid grid = new Grid();
grid.setHoverable(true);
chart.addGrid(grid);
This alone will not make tooltip appear so we borrow some code from one of the Flot examples,
http://people.iola.dk/olau/flot/examples/interacting.html
The only change to notice is on line 15 where we put the
bind into a function so we can control whether to use tooltips or not from
example.jsp (line 26).
function showTooltip(x, y, contents) {
$('<div id="tooltip">' + contents + '</div>').css({
position : 'absolute',
display : 'none',
top : y + 5,
left : x + 5,
border : '1px solid #fdd',
padding : '2px',
'background-color' : '#fee',
opacity : 0.80
}).appendTo("body").fadeIn(200);
}
var previousPoint = null;
function useTooltip() {
$("#placeholder").bind(
"plothover",
function(event, pos, item) {
$("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2));
if (item) {
if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex;
$("#tooltip").remove();
var x = item.datapoint[0].toFixed(2), y = item.datapoint[1]
.toFixed(2);
showTooltip(item.pageX, item.pageY, item.series.label
+ " of " + x + " = " + y);
}
} else {
$("#tooltip").remove();
previousPoint = null;
}
});
}