You want to create a simple data-driven horizontal bar chart on a web page without using an applet or graphics library.
Use nested
HTML
tables with the width
percentages calculated
dynamically:
<table border="0"> <logic:iterate id="row" name="foo" property="bar"> <tr> <td align="right" width="20%"> <bean:write name"row" property="label"/> </td> <td align="left" width="80%"> <table width='<bean:write name="row" property="percentage"/>%' bgcolor="blue"> <tr> <td align="right"> <font color="white"> <bean:write name="row" property="percentage"/>% </font> </td> </tr> </table> </td> </tr> </logic:iterate> </table>
Displaying tables of raw numeric data may satisfy the functional requirements of your application, but outputting this information in a graph can make a tremendous difference to your end users. However, as soon as you start talking about graphics, the groans begin. Should you buy a reporting engine? What about a graphics-rendering framework? Do you need both? In many situations, if your application requirements can be met fairly by bar graphs, a combination of some clever HTML and Struts can do the work for you.
Consider a web application that displays weather forecast
information. The application needs to display a bar chart that shows
the chance of precipitation for the upcoming week.
You'll create the WeeklyWeather
class that holds the weather forecast as shown Example 4-1.
Example 4-1. JavaBean containing weather-related data
package com.oreilly.strutsckbk.ch04; import java.util.ArrayList; import java.util.List; public class WeeklyWeather { public WeeklyWeather( ) { weekForecast = new ArrayList( ); weekForecast.add(new DailyForecast("Sunday", 70)); weekForecast.add(new DailyForecast("Monday", 40)); weekForecast.add(new DailyForecast("Tuesday", 20)); weekForecast.add(new DailyForecast("Wednesday", 5)); weekForecast.add(new DailyForecast("Thursday", 50)); weekForecast.add(new DailyForecast("Friday", 40)); weekForecast.add(new DailyForecast("Saturday", 90)); } public List getWeekForecast( ) { return weekForecast; } private List weekForecast; }
The WeeklyWeather
class uses the
DailyForecast
class, shown in Example 4-2, to encapsulate the pairing of the day and the
chance of precipitation,
Example 4-2. Value object for daily forecast data
package com.oreilly.strutsckbk.ch04; public class DailyForecast { public DailyForecast(String day, int chanceOfPrecip) { this.day = day; this.chancePrecip = chanceOfPrecip; } public int getChancePrecip( ) { return chancePrecip; } public void setChancePrecip(int chancePrecip) { this.chancePrecip = chancePrecip; } public String getDay( ) { return day; } public void setDay(String day) { this.day = day; } private String day; private int chancePrecip; }
Now that the Model has been created for the application, the JSP (horizontal_chart.jsp) to render the chart can be written as shown in Example 4-3.
Example 4-3. Precipitation graph JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <html> <head> <title>Struts Cookbook - Chapter 04</title> </head> <body bgcolor="white"> <h2>Struts Cookbook Chapter 4 Examples</h2> <div align="center"> <hr /> <h3>Color Bar Chart (horizontal)</h3> <jsp:useBean id="weeklyWeather" class="com.oreilly.strutsckbk.ch04.WeeklyWeather"/> <table border="0" width="60%"> <logic:iterate id="dayEntry" name="weeklyWeather" property="weekForecast"> <tr> <td align="right" width="20%"> <bean:write name="dayEntry" property="day"/></td> <td align="left" width="80%"> <table width='<bean:write name="dayEntry" property="chancePrecip"/>%' bgcolor="#003366"> <tr> <td align="right"> <font color="white"> <bean:write name="dayEntry" property="chancePrecip"/>% </font> </td> </tr> </table> </td> </tr> </logic:iterate> </table> </div> </body> </html>
Figure 4-1 shows the resultant web page.
The horizontal chart is generated by iterating over the
weekForecast
property of the
WeeklyWeather
bean. A row of the table is
generated for each element of the weekForecast
property, with each row consisting of two columns. The first
(left-most) column holds the name of the day of the week, and the
second column displays the bars of the graph. The JSP page enables
the graphing magic by specifying a nested HTML table within the cell.
The nested table uses the chancePrecip
property of
the DailyForecast
to set the width of the table as
a percentage:
<table width='<bean:write name="dayEntry" property="chancePrecip"/>%' bgcolor="#003366">
This percentage indicates the fractional amount of space that the
table will occupy within the containing table cell. This nested table
is then filled to this percentage with the background color specified
by the bgcolor
attribute. The actual content of
this inner table is the percentage value text. By displaying the
numeric percentage along with the graphic, you can pack a lot of
information in a small space. If you didn't want to
display the raw percentage data here, you could have set the cell
contents to a nonblank space:
<td> </td>
In the Solution and in the Weekly Forecast example, the data to be graphed were in the form of a percentage value. The value was used without modification as the width percentage for the table. In many cases, the data is not a percentage but a raw scalar value. The main purpose for the chart may be to show a relative comparison of the data. You can compute the percentage value for the table width using simple arithmetic.
Continuing with the weather theme, suppose that you wanted to display the expected number of inches of rainfall per day for next week (starting with Sunday). Here is the raw forecast data from the weather service:
Day of week |
Rainfall (inches) |
---|---|
Sunday |
1.5 |
Monday |
2.0 |
Tuesday |
1.0 |
Wednesday |
0.2 |
Thursday |
0.8 |
Friday |
1.0 |
Saturday |
3.0 |
To turn these values into percentages for comparison purposes, you would use the following formula:
Percentage = (rainfall / max(rainfall)) * 100
With this formula, the day with the maximum
rainfall amount will yield a percentage of 100 percent. Since the
percentage calculation is used for presentation purposes, performing
the calculation on the JSP page is acceptable. The
JSP expression language (EL) available
with JSTL supports arithmetic. EL does not, however, provide an easy
way to calculate the maximum value. You will code this calculation to
the WeeklyForecast
Java class.
You'll want to add the
rainfallAmount
float property to the
DailyForecast
object. Then,
you'll want to add a method to the
WeeklyForecast
that calculates and returns the
maximum rainfall.
Now you can use this data to create the bar graph. Example 4-4 shows the JSP page
(horizontal_chart_jstl.jsp) to create the graph.
In addition to its calculation abilities, the JSTL
fmt:formatNumber
tag formats the text representing
the numeric value. This page shows how to use an image instead of
background color to fill the graph.
Example 4-4. Expected rainfall JSP
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean" %> <%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %> <%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt" %> <html> <head> <title>Struts Cookbook - Chapter 04</title> </head> <body bgcolor="white"> <h2>Struts Cookbook Chapter 4 Examples</h2> <div align="center"> <h3>Expected Rainfall</h3> <table border="0" width="60%"> <c:forEach var="dayEntry" items="${weeklyWeather.weekForecast}"> <tr> <td align="right" width="20%"> <bean:write name="dayEntry" property="day"/> </td> <td align="left" width="80%"> <table background="images/raincloud.gif" width="<c:out value='${(dayEntry.rainfall div weeklyWeather. maxRainfall) * 100}'/>%"> <tr> <td align="right"> <span style="{color:black;background-color:white}"> <fmt:formatNumber value="${dayEntry.rainfall}" pattern="##.0"/>" </span> </td> </tr> </table> </td> </tr> </c:forEach> </table> </div> </body> </html>
The key to making the chart work is the calculation of the width percentage using JSTL:
width="<c:out value='${(dayEntry.rainfall div weeklyWeather. maxRainfall) * 100}'/>%
The rendered bar chart is shown in Figure 4-2; it's obviously going to be a wet week.
The graphics shown in this recipe are created through a clever use of HTML. More complex graphics can be created by dynamically generating actual graphic images using graphic support provided by Java. Jason Hunter shows some of these techniques in Java Servlet Programming (O'Reilly).
If you are unfamiliar with JSTL you'll want to check out Recipe 3.1. Recipe 4.2 demonstrates how to render a more traditional vertical bar chart.
Get Jakarta Struts Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.