Creating pie charts with JSP is a breeze

Java Server Pages (JSP) makes it easy to read and summarize data from a database and then display the results in a pie chart. We'll show you what you need to do to tap into this functionality.

Java Server Pages (JSP) offers several simple techniques for reading transactions from a database, summarizing data, and displaying results in a pie chart. Let’s look at the details of getting these pages out the door.

What do you need?
To get started with the examples in this article, you need JDK 1.2 or higher, a relational database management system, and a JSP Web server. I tested these examples on Tomcat, and I used the com.sun.image.codec.jpegclasses that are distributed with the Sun Java 2 SDK. With this setup intact, we're ready to focus on the design.

Database design
Imagine that you work for a fictitious company that sells fresh produce, such as apples, oranges, and grapes. The owners want a pie chart showing the total sales of each product. A pie chart gives the owners a simple summary of their sales and provides a visual tool to quickly establish the products with the greatest turnover.

Listing A summarizes the two database tables used in this article. The first table (Products) contains the names of all saleable products; the second table (Sales) contains individual sales transactions per product.

The Products table has productID and productname fields. The Sales table has saleID, productID, and amount. The productID in the Sales table provides the relationship between the two tables, linking to the productID in the Products table. The Sales table’s amount field contains the cash values of each sale, which are represented by float values.

The getProducts() method (Listing B) connects to the database and stores all the product names in an array. I have set the following database rules:
  • ·        The productID is the unique, primary key for the Product table.
  • ·        The productID for the first record will be zero (0).
  • ·        All subsequent records are autonumbered, so the second record’s productID will be 1, the third record’s productID will be 2, and so on.

These database rules allow the storage of data in the products array as follows:
arr[rs.getInt("productID")] = rs.getString("productname");

Some database management systems leave it up to the programmer to maintain the integrity of the autonumbering or sequencing system. When designing your database, you'll want to find out how your database management system handles design-time rules such as autonumbering, sequences, and null or default values.

Getting total sales
Most likely, there will be a lot of records in the Sales table (since there is one record per sale), so it is necessary to make database access as quick and efficient as possible. We need only the total sales for each product.

The getSales() method (Listing C) connects to the database and returns an array that contains the total sale figures for each product. As getSales() loops through the sales transaction records, it simply stores the new sales total for each product:
int product = rs.getInt("productID");
arr[product] += rs.getFloat("amount");

The pieColor object
Each product on the pie chart needs to be displayed in a different color. To facilitate this, I have created a pieColor object (Listing D), which contains an array of Color objects:
Color pieColorArray[] = {new Color(210,60,60), new Color(60,210,60)…}

The PieColor class defines a setNewColor() method, which increments curPieColor, the index used to access the pieColorArray[]. The method also checks that the array’s index does not go out of bounds by setting the value of curPieColor to zero if it grows too large.

In effect, setNewColor() loops through the available colors and starts again with the first color when all of the colors have been used:
if(curPieColor >= pieColorArray.length)
{curPieColor = 0;}

The RenderingHints class and antialiasing
The java.awt.RenderingHints class defines several fields that are used when displaying Graphics2D images, including alpha_interpolation, dithering, and antialiasing. RenderingHints helps to determine how the image should be displayed and how (or whether) the image should be optimized.

For a smooth display, it is important to use antialiasing to create pie charts. Antialiasing is the process by which jagged computer-generated lines in an image are smoothed. The antialiasing algorithm selects the color value of a particular pixel and replaces the adjacent pixels with color values that make the original pixel look less jagged.

Figure A illustrates the effects of antialiasing. Note that the black border around the pie chart is much fuller and rounder with antialiasing.

Figure A

To set antialiasing, create a RenderingHints object and pass it to the Graphics2D setRenderingHints() method as follows:
RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,

Drawing a resizable border
The pie chart in Figure A has a border and a drop shadow. Ideally, it should be possible to change the size of the drop shadow and border areas by changing only one variable. This is achieved by declaring int border = 10 and then basing all calculations for the size of the border area on this variable:
Ellipse2D.Double elb = new Ellipse2D.Double(x_pie - border/2, y_pie - border/2, pieWidth + border, pieHeight + border);

The values x_pie and y_pie represent the top-left location of an imaginary square that surrounds the pie chart. We center the pie chart’s border by dividing the border variable by two (border/2).

Arc theory
The fillArc() method, which is inherited from the java.awt.Graphics class, provides a simple mechanism for drawing the pie "slices," or arcs:
g2d.fillArc(x_position, y_position, width, height, startAngle, sweepAngle);

The x_position and y_position integers represent the x and y coordinates of the upper-left corner of the arc to be filled. The width and height integers provide its dimensions. If the width and height values are equal, the pie chart will be round. If the width and height are not equal, the pie chart will have an oval shape.

The position of the arc’s startAngle is determined relative to zero degrees, which is located at the horizontal, 3 o’clock position. Degrees are arranged counterclockwise around the pie chart, so 90 degrees is found at 12 o’clock, 180 degrees at 9 o’clock and 270 degrees is located at the 6 o’clock position.

The fillArc() method determines the size of the arc based on the sweepAngle integer value. Arcs are drawn counterclockwise if the sweepAngle is positive and clockwise if it is negative.

Drawing the arcs
First, we use the pieColor object’s getPieColor() method to get the latest pie color and assign it to the current slice:

Next, we calculate the overall sales total by looping through the sales[] array and incrementing the sales total:
salesTotal += sales[i];

Using the sales total, it is possible to calculate the total sales for each product as a percentage of the total sales:
float perc = (sales[i]/salesTotal);

We calculate the sweepAngle (out of a total of 360 degrees) to allocate to each individual slice:
int sweepAngle = (int)(perc * 360);

After each arc is drawn, the startAngle is incremented with the current sweepAngle. This ensures that each arc starts drawing where the last arc ended, creating a seamless pie chart.

Displaying the legend
A legend offers a concise way of displaying summary figures on a pie chart. A legend should be color-coded to match the elements of the pie chart.

Figure B shows the complete pie chart and the legend, which displays product names, sales totals, and percentages in a summarized format.

Figure B

Have a slice
This article has explored the basics of pie charts by providing techniques and algorithms any programmer can use. The complete JSP for this article is included in Listing E.






Editor's Picks