Приглашаем посетить
Брюсов (bryusov.lit-info.ru)

3.4 Business graphics with Java applets

Table of Contents

Previous Next

3.4 Business graphics with Java applets

3.4.1 A Java function to display indices of stock exchanges

Most scientific graphs are formula or mathematical model based. This means that graph data can be, more or less, generated or predicted with good accuracy. Business graphs, on the other hand, are more challenging. These types of graphs are more data based and full of unpredictable features. The indices of share markets, foreign exchange rates, business sales, or even daily temperatures are just some of the examples in this category. It may not be easy to find a mathematical model to fit them. The importance of business graphs is not the symmetry, smoothness, or even the beauty of the curve, it is based on real data and is an indispensable tool for decision making in the real world. For example, if business sales or production is down for three consecutive months, a careful analysis of related graphs such as supply, marketing, advertising, production costs, etc., may provide the answers and, in many cases, can help to make business decisions.

As the final part of this chapter, we are going to develop some Java programs dedicated to business graphs or graphics. At an elementary level, the basic requirements for a good Java program for business graphs are as follows:

  • Multiple curves can be drawn and displayed easily.

  • Data points can be highlighted so that consecutive changes on intervals are visible.

  • Each curve can have a name attached to it.

  • The program should be flexible.

  • The program should be fully automated and user-friendly.

Suppose you have been asked to develop a Web page including a chart displaying the share indices of "Dow Jones," "Nikkei," and "Hang Seng" daily. In order to achieve flexibility and user-friendliness, the following XHTML <div> division element may be a good starting point:



Listing: ex03-09.txt - Indices For Stock Exchanges

 1: <div style="font-size:22pt; text-align:center;font-weight:bold">
 2:     Daily Indices Of Share Market<br />(Thursday)<br />
 3:   <applet code="Graphs02.class" width=600 height=350>
 4:     <param name="xTitle" value="Days">
 5:     <param name="yTitle" value="Index Value">
 6:     <param name="NumberOfCurve" value="3">
 7:     <param name="NumberOfData" value="4">
 8:     <param name="Data1" value="Hang Seng,10723,10733,10643,10745">
 9:     <param name="Data2" value="Nikkei,11352,11114,11218,11147">
10:     <param name="Data3" value="Dow Jones,10249,10209,10382,10176">
11:     <param name="NmberOfLabel" value="5">
12:     <param name="labelName" value="Mon,Tue,Wed,Thu,Fri">
13:   </applet>
14: </div>

This Web page or division element activates a Java applet called Graphs02.java (see later) showing the indices "Hang Seng," "Nikkei," and "Dow Jones" on four days of a week. The values of xTitle and yTitle in lines 45 are strings displayed on the x- and y-axes. The value of NumberOfCurve is 3, which means that three curves are defined and they are Data1, Data2, and Data3 representing the three different indices. The value of NumberOfData is 4 indicating that each share index contains a set of five numeric data. Consider the third curve (see line 10):



<param name="Data3" value="Dow Jones,10249,10209,10382,10176">

The first value of this curve represents the name of the curve, which in this case is "Dow Jones." The numeric data after that are the indices for Monday, Tuesday, Wednesday, and Thursday respectively. If you run this example on a browser, you will see a picture as shown in Fig. 3.17.

Figure 3.17. Stock exchange indices I

graphics/03fig17.jpg


As you can see from Fig. 3.17, the name of each curve and current value are displayed. The five label names are displayed below the x-axis. Also, the maximum and minimum values of the data appear on the y-axis. If you replace lines 710 by the statement



<param name="NumberOfData" value="5">
<param name="Data1" value="Hang Seng,10723,10733,10643,10745,10710">
<param name="Data2" value="Nikkei,11352,11114,11218,11147,10963">
<param name="Data3" value="Dow Jones,10249,10209,10382,10176,10185">

you will add more data to each curve. That is, the share indices for Friday are included. A screen shot of this new page is shown in Fig. 3.18.

Figure 3.18. Stock exchange indices II

graphics/03fig18.jpg


As you will find out, the Java program to display the indices is quite flexible and can be applied to many graphical presentation applications. For example, it can be used to display daily temperature or weather data, monthly company sales, and many other applications. Another advantage of using the <div> element is that you can use CSS position properties to put the applet window anywhere on the Web page.

In this section, you will learn how to build this application step by step. The program is based on a Java function called myDrawLines() which is a modification of the Coor01.java program in section 3.3.4. This function has more general input arguments and the calling syntax is



Listing: ex03-10.txt - Calling Syntax Of Java Function myDrawLines()

 1: public void myDrawLines(
 2:    int xA, int xB, int yA, int yB,
 3:    double xMin, double xMax, double yMin, double yMax,
 4:    int noData, double[] xData, double[] yData, Color lineColor,
 5:    int drawType, Color typeColor, int sizeX, int sizeY,
 6:    boolean labelF, Boolean dataF String labelS,
 7:    Color labelC,int labelOx, int labelOy,
 8:    Graphics gg)

The arguments in line 2 define the bounding box in the applet window, line 3 specifies the bounding box of the data, and line 4 provides details about the data:

noData

Number of data to draw.

xData[]

Array to store the x-coordinates.

yData[]

Array to store the y-coordinates.

lineColor

Determine the drawing color.


The arguments in line 5 are used to determine the joining type (or highlights) at each of the data points. There are four joining types available, specified by the value of the variable, drawType. The value of drawType can be one of the following:

1: Draw circles at each data point.

2: Draw filled circles.

3: Draw rectangles.

4: Draw filled rectangles.

For example, the input for the arguments in line 5, "3,new Color(255,0,0),20,30," draws a red rectangle with size 20 x 30 pixels bounding each data point. The final arguments in lines 78 determine the curve name and location offsets. Consider the input



true, true, "My Curve", new Color(0,0,255), 10, 20

The first true value will display a blue text "My Curve" at the end of the curve with offsets 10 pixels right and 20 pixels down. The second true will display the data value at the same time. A false value for the variable labelF means no display at all.

Now, let's take a look at the program fragment of Graphs01.java listed in ex03-11.txt.



Listing: ex03-11.txt - Code Fragment For Graphs01.java

24:  public void myDrawLines(int xA, int xB, int yA, int yB,
25:    double xMin,double xMax, double yMin, double yMax,
26:    int noData,double[] xData, double[] yData, Color lineColor,
27:    int drawType, Color typeColor,int sizeX, int sizeY,
28:    boolean labelF, boolean dataF, String labelS,
29:    Color labelC,int labelOx, int labelOy, Graphics gg)
30:  {
31:    Graphics2D g = (Graphics2D) gg;
32:    int ii, x1,y1, halfX, halfY;
33:    double[] xDraw = new double[noData];
34:    double[] yDraw = new double[noData];
35:    double xStart, yStart;
36:
37:    // Step 1: Connecting all the data points with a line
38:    for (ii =0;ii<noData;ii++)
39:    {
40:      xDraw[ii]=myScale(xA,xB,xMin,xMax,xData[ii]);
41:      yDraw[ii]=myScale(yA,yB,yMin,yMax,yData[ii]);
42:    }
43:
44:    g.setColor(lineColor);
45:    xStart= xDraw[0];
46:    yStart =yDraw[0];
47:    for (ii=1;ii<noData;ii++)
48:    {
49:      Line2D.Double myLine = new Line2D.Double(xStart,yStart,
50:                                               xDraw[ii],yDraw[ii]);
51:      g.draw(myLine);
52:      xStart = xDraw[ii];
53:      yStart = yDraw[ii];
54:    }
55:
56:    // Step 2: Highlight each data point depending on the drawType
57:    if ((drawType > 0) &&(drawType <5) )
58:    {
59:
60:     halfX = sizeX/2;
61:     halfY = sizeY/2;
62:     for(ii=0;ii<noData;ii++)
63:     {
64:       x1 = (int) myScale(xA,xB,xMin,xMax,xData[ii]);
65:       y1 = (int) myScale(yA,yB,yMin,yMax,yData[ii]);
66:       g.setColor(typeColor);
67:       if (drawType ==1)
68:          g.drawOval(x1- halfX,y1-halfY,sizeX,sizeY);
69:       else if(drawType ==2)
70:          g.fillOval(x1- halfX,y1-halfY,sizeX,sizeY);
71:       else if (drawType ==3)
72:          g.drawRect(x1- halfX,y1-halfY,sizeX,sizeY);
73:       else if (drawType ==4)
74:          g.fillRect(x1- halfX,y1-halfY,sizeX,sizeY);
75:     }
76:    }
77:
78:    // Step 3: Display the name of the curve
79:    if (labelF == true)
80:    {
81:       x1 = (int) myScale(xA,xB,xMin,xMax,xData[noData -1]);
82:       y1 = (int) myScale(yA,yB,yMin,yMax,yData[noData -1]);
83:       g.setColor(labelC);
84:       g.drawString(labelS,x1+labelOx,y1-labelOy);
85:       if (dataF == true)
86:       {
87:         g.drawString(""+ (int) yData[noData -1],x1+labelOx,y1+15);
88:       }
89:    }
90: }

Apart from the class name Graphs01, the first 23 lines are the same as those in Coor01.java containing the usual myScale() function. Apart from the slightly complicated input arguments, this function is not that difficult to read. Basically, the function is divided into three parts (or steps). The first part (lines 3754) converts all the points into the applet window coordinates xDraw[] and yDraw[] using the two bounding boxes {xA,xB,yA,yB} and {xMin,xMax,yMin,yMax}. The for-loop in lines 4754 is used to draw a line connecting all the coordinates.

The second part (lines 5676) is to highlight all data points. First, the data point is converted into the applet coordinate (x1,y1) as illustrated in lines 6364. A condition if statement is used to determine what kind of connection type the user wants to apply. For example, if the drawType is 2, the statement in line 69 will be executed:



g.fillOval(x1- halfX,y1-halfY,sizeX,sizeY);

This statement draws a filled circle (or oval) at (x1-halfX,y1-halfY) position with dimensions sizeX and sizeY. The variables halfX and halfY are used to make sure that the circle is drawn with its center point at coordinates (x1,y1). A simple for-loop draws a small circle bounding each data point. The third part (lines 7889) is to display the identity of the curve. If the value of labelF is true, the name of the curve is displayed. If the dataF variable is true, the value of the final data value will be displayed as well.

As a test driver for this function, we consider the following paint() function as the continuation of the Java program Graphs01.java.



Listing: Continuation Of The Java Program Graphs01.java

91:
92:  public void paint(Graphics gg)
93:  {
94:   Graphics2D g = (Graphics2D) gg;
95:   double xxMax, xxMin, yyMax, yyMin;
96:   int xxA, xxB, yyA, yyB, noData;
97:
98:   xxA = 20; xxB = 320; yyA = 240; yyB=40;
99:   xxMin = 0; xxMax = 6; yyMin = 100; yyMax = 500;
100:
101:   // Draw data lines with circles
102:   double[] xData={1,2,3,4,5,6};
103:   double[] yData={120,370,460,405,270,300};
104:   String curveName="myCurve01";
105:   noData = 6;
106:   g.setStroke(new BasicStroke(2));
107:   g.setFont(new Font("Arial",Font.BOLD,14));
108:   myDrawLines(xxA,xxB,yyA,yyB,xxMin,xxMax,yyMin,yyMax,
109:           noData,xData,yData,new Color(255,0,0),
110:           1,new Color(0,100,0),15,15, 34
111:           true,true,curveName,new Color(255,0,255),15,0,gg);
112:
113:   // Draw data lines with rectangle
114:   double[] x1Data={1,2,3,4,5,6,7,8,9};
115:   double[] y1Data={230,175,367,280,120,229,101,460,410};
116:   curveName="myCurve02";
117:   noData = 9;
118:   g.setStroke(new BasicStroke(2));
119:   myDrawLines(xxA,xxB,yyA,yyB,xxMin,xxMax,yyMin,yyMax,
120:           noData,x1Data,y1Data,new Color(0,0,200),
121:           3,new Color(100,0,0),15,15,
122:           true,true,curveName,new Color(255,0,255),15,0,gg);
123:  }
124: }

This testing function paint() contains two curves. After the details of the two bounding boxes in lines 9899, the first curve is defined. This curve is called "myCurve01" with a set of six data points. The curve is drawn in red on the applet window with green circles around the points (see lines 109110). The name and last value are displayed following the instruction as in line 111. The second curve is defined and drawn by the statements in lines 113122. Since there is no parameter reading from the calling Web page (not yet), all you need is the following XHTML code (e.g., ex03-12.htm) to include this applet:



<applet code="Graphs01.class" width=600 height=300></applet>

You can run the applet and a screen shot of this example is shown in Fig. 3.19.

Figure 3.19. ex03-12.htm

graphics/03fig19.gif


3.4.2 Automation and more interaction with Web pages

To write a successful applet, the applet must be able to work with a Web page and take parameters from users. In the early example ex03-03.htm, you learned how to set up parameters for Java inside a Web page such as



<applet code="xxxx.class" width=xxx heigh=xxx>
     <param name="ParamterName01" value="ParameterValue 01">
     <param name="ParamterName02" value="ParameterValue 02">
</applet>

In Java, the parameters can be retrieved by the function getParameter(). For example, the value of ParameterName01 can be obtained by the statement



parameterSt = getParameter("ParameterName01");

In this section, we go beyond this parameter setting and retrieval technique. As a starting point, we are going to handle parameters returned by a Web page such as ex03-13.htm below.



Example: ex03-13.htm - Display Daily Indices Of Stock Exchanges

 1: <?xml version="1.0" encoding="UTF-8"?>
 2: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
 3: "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
 4: <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
 5: <head><title>Indices of Share Market  ex03-13.htm</title></head>
 6: <body>
 7:  <div style="font-size:22pt; text-align:center;font-weight:bold">
 8:      Daily Indices Of Share Market<br />(Friday)<br /><br />
 9:   <applet code="Graphs02.class" width=600 height=350>
10:    <param name="xTitle" value="Days">
11:    <param name="yTitle" value="Index Value">
12:    <param name="NumberOfCurve" value="3">
13:    <param name="NumberOfData" value="4">
14:    <param name="Data1" value="Hang Seng,10723,10733,10643,10745">
15:    <param name="Data2" value="Nikkei,11352,11114,11218,11147">
16:    <param name="Data3" value="Dow Jones,10249,10209,10382,10176">
17:    <param name="NumberOfLabel" value="5">
18:    <param name="labelName" value="Mon,Tue,Wed,Thu,Fri">
19:   </applet>
20:  </div>
21: </body>
22: </html>

In this page, we have put all data values and the name of the curve into one <param>. This arrangement may save a lot of XHTML coding and increase readability. By putting all data values together as in lines 1416, some careless data errors can be eliminated. To handle multiple parameter values of this kind, you need to use the string and substring features of Java. Also, in order to automate the Java program and make it more flexible and user-friendly, we are going to modify Graphs01.java into a more flexible, automatic, and powerful class Graphs02.java by adding the following features and functions:

• Global Variables

Define the bounding boxes to be used by all functions.

myFindMinMax()

Find the minimum and maximum values from all data.

mySetColor()

Set color for each curve automatically.

mySetFrame()

Define the bounding boxes for data and applet window, draw the x,y-axes, and label them in a fully automatic way.

myDrawGraphs()

Organize above and call the myDrawLines() function to draw all the curves.

myGetArgs()

More interaction with the XHTML page and get all parameters.


With all these modifications, you will have an example one step closer to a more mature Java program. In particular, the myGetArgs() function is the main connection between your Web pages and the Java program.

Apart from the class name, the first 90 lines of Graphis02.java are the same as those in Graphs01.java containing the functions myRescale(), ranColor(), and myDrawLines(). The remaining Java coding is listed and explained step by step below:



Listing: ex03-12.txt - Code Fragment For Graphs02.java

 91:  //Global Variables
 92:  double     xxMax, xxMin, yyMax, yyMin;
 93:  int        xxA, xxB, yyA, yyB;
 94:  int        noData,noCurve;
 95:  String[][] tData;
 96:  String[]   labelSt;
 97:  Color[]    curveColor;
 98:  int        segNumber, baseLine;
 99:  double     minData, maxData;
100:  String     xTitle,yTitle;
101:
102:  public void myFindMinMax()
103:  {
104:   int ii,jj; double tTmp;
105:   maxData = (double) Integer.parseInt(tData[0][1]);
106:   minData = maxData;
107:   for(jj=0;jj<noCurve;jj++)
108:   {
109:    for (ii=1;ii<=noData;ii++)
110:    {
111:      tTmp= (double) Integer.parseInt(tData[jj][ii]);
112:      if (maxData < tTmp)
113:          maxData = tTmp;
114:      if (minData > tTmp)
115:          minData = tTmp;
116:    }
117:   }
118:  }
119:
120:  public void mySetColor()
121:  {
122:    int ii;
123:    curveColor= new Color[noCurve];
124:    if (noCurve == 3)
125:    {
126:     curveColor[0] = new Color(255,0,0);
127:     curveColor[1] = new Color(255,255,0);
128:     curveColor[2] = new Color(0,255,0);
129:    } else {
130:     for(ii=0;ii<noCurve;ii++)
131:     {
132:      curveColor[ii] = ranColor();
133:     }
134:    }
135:  }
136:

First, we have some global variables. After declaring the variables for the bounding boxes in lines 9293, all data for the curves are stored into one 2D array of string tData[][]. The labels on the x-axis are stored in the array labelSt. Each curve may have a different color and therefore the color for each curve is stored in the array of color curveColor[]. The titles for the x- and y-axes are stored in variables xTitle and yTitle. The myFindMinMax() function in lines 102118 is to look through all the data in array tData[][] to find the minimum and maximum data (i.e., minData and maxData). These two will be marked on the y-axis. The mySetColor() function is used to set the color for each curve automatically. In this case, if exactly three curves are displayed, the colors will be red, yellow, and green (see lines 124129). If not, the color of each curve will be randomly picked as illustrated in lines 130133.

Next, you need a facility to define the bounding boxes automatically. Consider the Java code below:



Listing: Continuation of Graphs02.java  The mySetFrame() Function

137:  public void mySetFrame(Graphics gg)
138:  {
139:    int ii;
140:    Graphics2D g = (Graphics2D) gg;
141:
142:    Dimension d = getSize();
143:    int xDiff = d.width/(segNumber*2);
144:    int yDiff = d.height/(segNumber +3);
145:    xxA = 10; xxB = d.width - 60;
146:    yyA = d.height - 40; yyB = yDiff;
147:
148:    g.setColor(new Color(200,200,200) );
149:    g.fillRect(0,0,d.width,d.height);
150:    g.setFont(new Font("Arial",Font.BOLD,14));
151:
152:    double dataDiff = (maxData - minData)/segNumber;
153:    xxMin = 0; xxMax = segNumber+1;
154:    yyMin = minData - dataDiff; yyMax = maxData + dataDiff;
155:
156:   int ix0 = (int) myScale(xxA,xxB,xxMin,xxMax,xxMin);
157:   int ix1 = (int) myScale(xxA,xxB,xxMin,xxMax,xxMax);
158:   int iy0 = (int) myScale(yyA,yyB,yyMin,yyMax,yyMin);
159:   int iy1 = (int) myScale(yyA,yyB,yyMin,yyMax,yyMax);
160:   int iMin = (int) myScale(yyA,yyB,yyMin,yyMax,minData);
161:   int iMax = (int) myScale(yyA,yyB,yyMin,yyMax,maxData);
162:      baseLine = iy0;
163:   g.setStroke(new BasicStroke(2));
164:   g.setColor(Color.blue);
165:   g.drawString(xTitle,ix1-10,iy0+20);
166:   g.drawString(yTitle,ix0+10,iy1-10);
167:   g.drawString(""+(int) minData,ix0+15,iMin-5);
168:   g.drawString(""+(int) maxData,ix0+15,iMax-5);
169:
170:   g.setColor(Color.black);
171:   g.drawLine(ix0+xDiff,iy0,ix1,iy0);
172:   g.drawLine(ix0+xDiff,iy0,ix0+xDiff,iy1);
173:   g.drawLine(ix0+xDiff-5,iMin,ix0+xDiff+5,iMin);
174:   g.drawLine(ix0+xDiff-5,iMax,ix0+xDiff+5,iMax);
175:
176:   for (ii=1;ii<=segNumber;ii++)
177:   {
178:     int xAxis = (int) myScale(xxA,xxB,xxMin,xxMax,ii);
179:     g.drawLine(xAxis,iy0-5,xAxis,iy0+5);
180:     g.drawString(labelSt[ii],xAxis-15,iy0+25);
181:   }
182: }
183:

This function is to set the bounding boxes on the applet window and the data. The statement in line 142 gets the dimension of the applet window defined by the calling Web page. The width and height of the applet window are stored in the properties d.width and d.height. The bounding box on the applet window is defined in lines 145146. Then the window is filled with a gray color. The bounding box of the data is defined in lines 152154. The x- and y-axes are defined by the statements in lines 156161. The statements in lines 165168 display the titles of the x- and y-axes. The minimum and maximum data values are drawn at the same time. Lines 170174 are used to draw the x- and y-axes. Finally, the for-loop in lines 176182 draws all the labels on the x-axis.

The actual drawing function is myDrawGraphs() and is listed below:



Listing: Continuation of Graphs02.java  The myDrawGraphs() Function

184:  public void myDrawGraphs(Graphics gg)
185:  {
186:   Graphics2D g = (Graphics2D) gg;
187:   int ii,jj;
188:   double[] xData;
189:   double[] yData;
190:   String tmpSt;
191:
192:   xData = new double[noData];
193:   yData = new double[noData];
194:   for(ii=0;ii<noData;ii++)
195:   {
196:     xData[ii]=ii+1;
197:   }
198:
199:   myFindMinMax();
200:   mySetFrame(gg);
201:
202:   g.setStroke(new BasicStroke(3));
203:   for(jj=0;jj<noCurve;jj++)
204:   {
205:    tmpSt = (String) tData[jj][0];
206:    for(ii=0;ii<noData;ii++)
207:    {
208:     yData[ii]= (double) Integer.parseInt(tData[jj][ii+1]);
209:    }
210:    g.setStroke(new BasicStroke(2));
211:    g.setColor(Color.red);
212:    myDrawLines(xxA,xxB,yyA,yyB,xxMin,xxMax,yyMin,yyMax,
213:           noData,xData,yData,
214:           curveColor[jj],1,new Color(0,100,0),10,10,
215:           true,true,tmpSt,new Color(0,0,255),15,0,gg);
216:   }
217:  }
218:

This function declares two arrays xData[] and yData[] storing the x- and y-coordinates of each curve. The for-loop in lines 194197 fills the array xData[]. After finding the minimum and maximum values of all data, the mySetFrame() function in line 200 is called to draw the axis and necessary labels. The double for-loop in lines 203216 extracts the data of each curve from the array tData[][] into array yData[]. When the data of one curve are extracted, a function call to myDrawLines() draws the curve onto the applet window as illustrated in lines 212215. When all the curves are drawn, all the graphs will appear on the applet window.

To get the parameters from the Web page, you use the function myGetArgs() listed below:



Listing: Continuation of Graphs02.java  The myGetArgs() Function

219:  public void myGetArgs()
220:  {
221:   String tmpSt, tmpSt2;
222:   int ii,jj, index2, tmp2;
223:
224:    xTitle = getParameter("xTitle");
225:    yTitle = getParameter("yTitle");
226:    noCurve= Integer.parseInt(getParameter("NumberOfCurve"));
227:    noData= Integer.parseInt(getParameter("NumberOfData"));
228:    segNumber= Integer.parseInt(getParameter("NumberOfLabel"));
229:
230:    //Extracts all labels on x-axis
231:    labelSt=new String[segNumber+1];
232:    tmpSt2 = getParameter("labelName");
233:    index2=0; labelSt[0]="";
234:    for(jj=1;jj<segNumber;jj++)
235:    {
236:      tmp2 = tmpSt2.indexOf(',',index2);
237:      tmpSt = tmpSt2.substring(index2,tmp2);
238:      labelSt[jj] = tmpSt.trim();
239:      index2 = tmp2 +1;
240:    }
241:    tmp2 = tmpSt2.indexOf(',',index2);
242:    if (tmp2 > index2)
243:        tmpSt = tmpSt2.substring(index2,tmp2);
244:    else
245:        tmpSt= tmpSt2.substring(index2);
246:    labelSt[jj]= tmpSt.trim();
247:
248:    //Extract all data from each curve
249:    tData = new String[noCurve][noData+1];
250:    for (ii=1;ii<=noCurve;ii++)
251:    {
252:      tmpSt2 = getParameter("Data"+ii);
253:      index2=0;
254:      for(jj=0;jj<noData;jj++)
255:      {
256:        tmp2 = tmpSt2.indexOf(',',index2);
257:        tmpSt = tmpSt2.substring(index2,tmp2);
258:        tData[ii-1][jj] = tmpSt.trim();
259:        index2 = tmp2 +1;
260:      }
261:      tmp2 = tmpSt2.indexOf(',',index2);
262:      if (tmp2 > index2)
263:        tmpSt = tmpSt2.substring(index2,tmp2);
264:      else
265:        tmpSt= tmpSt2.substring(index2);
266:      tData[ii-1][jj]= tmpSt.trim();
267:    }
268:  }
269:

First, this function uses the getParameter() function to get the input data (see lines 224228) including the strings for the x,y-axes titles (xTitle and yTitle), number of curves (noCurve), number of data for each curve (noData), and number of labels on the x-axis (segNumber). Lines 230246 extract all labels on the x-axis. If you have a parameter on the Web page



<param name="labelName" value="Mon,Tue,Wed,Thu,Fri">

the string tmpSt2 in line 232 stores the entire value "Mon,Tue,Wed,Thu,Fri." Starting from index2=0, the indexOf() function used in line 236 will return the first appearance of the comma (i.e., ",") in the string tmpSt2 to tmp2. The substring() function in line 237 extracts the string between index2 and tmp2 (i.e., "Mon"). After trimming all the white spaces using the function trim() in line 238, these data are assigned to string array labelSt[]. Next, you assign the comma position as the current position and continue the for-loop in lines 234240 until the last label. The if statement in lines 242246 says that if the original string contains more data than required, the next data before the next comma are extracted. If the last required data are the end data of the string, the end data are extracted.

Very similar ideas are used to read all the curve data and store them into the 2D array tData[][] in lines 248267. That is, after the double for-loop, all the data of each curve are stored in tData[][] as strings.

The final part of this Java program is quite simple and is listed below:



Listing: Continuation of Graphs02.java  The init() and paint() Function

270:  public void init()
271:  {
272:     myGetArgs();
273:     mySetColor();
274:  }
275:
276:  public void paint(Graphics gg)
277:  {
278:     myDrawGraphs(gg);
279:  }
280: }

The init() function first calls myGetArgs() to get the parameters from the Web page. It then sets up the color for each curve by a function call to mySetColor(). The paint() function simply calls the drawing function myDrawGraphs() to draw and display all curves on the applet window.

With Graphics02.java, you can now run the Web page ex03-13.htm and you should see the same result as in Fig. 3.17. If you add one more data in example ex03-13.htm as described at the beginning of section 3.4.2 and call the new example ex03-14.htm you should see the same result as in Fig. 3.18.

In order to demonstrate the flexibility of this program Graphs02.class, we consider a Web page (ex03-15.htm) displaying a daily temperature chart for major cities. This page contains the <div> element:



Listing: ex03-13.txt - Web Page Fragment For Example ex03-15.htm

 1: <div style="font-size:22pt; text-align:center;font-weight:bold">
 2:     Daily Temperature Chart For<br />Major Cities<br /><br />
 3:  <applet code="Graphs02.class" width=600 height=350>
 4:    <param name="xTitle" value="Days">
 5:    <param name="yTitle" value="Temperature">
 6:    <param name="NumberOfCurve" value="4">
 7:    <param name="NumberOfData" value="7">
 8:    <param name="Data1" value="Hong Kong,31,29,33,30,31,34,32">
 9:    <param name="Data2" value="Tokyo,19,23,22,17,19,22,16">
10:    <param name="Data3" value="New York,24,21,19,22,25,19,24">
11:    <param name="Data4" value="London,14,11,16,15,10,8,11">
12:    <param name="NumberOfLabel" value="7">
13:    <param name="labelName" value="Mon,Tue,Wed,Thu,Fri,Sat,Sun">
14:   </applet>
15: </div>

This Web page is easy to read and a screen shot of this example is shown in Fig. 3.20. Thanks to the conditional statements in lines 241246 and 261265, another feature of Graphs02.class is that you can draw previous data by just changing the value of NumberOfData.

Figure 3.20. ex03-15.htm

graphics/03fig20.gif


To demonstrate yet another feature of Graphs02.class, consider a chart showing the product sales of a company around the world. The <div> element of this Web page (ex03-16.htm) is listed below:



Listing: ex03-14.txt - Web Page Fragment For Example ex03-16.htm

 1: <div style="font-size:22pt; text-align:center;font-weight:bold">
 2:   Company Product Sales<br />Around The World<br /><br />
 3: <applet code="Graphs02.class" width=600 height=350>
 4: <param name="xTitle" value="Months">
 5: <param name="yTitle" value="Sales Millions">
 6: <param name="NumberOfCurve" value="3">
 7: <param name="NumberOfData" value="12">
 8: <param name="Data1" value="Singapore,11,19,13,6,15,19, 21,16,25,25,12,13">
 9: <param name="Data2" value="Tokyo,51,43,50,51,43, 55,41,63,55,35,72,33">
10: <param name="Data3" value="Paris,31,36,43,46,31,33,28,46,47,27, 51,23">
11: <param name="NumberOfLabel" value="12">
12: <param name="labelName" value="Jan,Feb,Mar,Apr,May,
13:    Jun,Jul,Aug,Sep,Oct,Nov,Dec">
14: </applet>
15: </div>

This page is very similar to example ex03-15.htm. You may have also noticed that the curve data in lines 810 contain some white spaces. This example will work well on the browser since we have used the trim() function to trim off the white spaces in the myGetArgs() function (see lines 238, 246, 258, and 266 of Graphs02.java). The program will generate errors if trim() is not used. A screen shot of this example is shown in Fig. 3.21. Apart from these features, no other protection against user errors on the Web page is employed. For a more professional program, more protection coding is needed.

Figure 3.21. ex03-16.htm

graphics/03fig21.jpg


3.4.3 Displaying bar and pie charts

The program Graphs02.class provides a framework for building more graphics functionalities. For example, you can put bar chart and pie chart functionalities into the class by adding the bar and pie drawing routines (or functions). This arrangement will take advantage of the existing functions already in the class.

Consider the structure of the class Graphs02.java below:

myScale()

Mapping the x,y-axes into the applet window.

ranColor()

Generating random color.

myDrawLines()

A general routine to draw lines.

• Global Variables

Define bounding box parameter as global.

myFindMinMax()

Find the minimum and maximum data.

mySetColor()

Set up color for each curve.

mySetFrame()

Draw x,y-axes and associated labels.

myDrawGraphs()

Organize functions above to draw curves.

myGetArgs()

Get parameters from Web page.


A bar chart and a pie chart routine can be added after the function mySetFrame() to form a new class called Graphs03.java. To complete this new class, all you have to do is to modify the two functions myDrawGraphs() and myGetArgs() to accept the new bar and pie chart functions.

Now change the class name in Graphs02.java to Graphs03 and save it as Graphs03.java. Insert the following bar chart function myBarChart() after the function mySetFrame() (i.e., at line 183 in Graphs02.java):



Listing: ex03-15.txt - The Bar Chart Function In Graphs03.java

 1:  public void myBarChart(int xxA, int xxB, int yyA, int yyB,
 2:    double xxMin,double xxMax, double yyMin, double yyMax,
 3:    int noData,double[] xData, double[] yData, int baseLine,
 4:    Color barColor, boolean showText, Color textColor, Graphics gg)
 5:  {
 6:   Graphics2D g = (Graphics2D) gg;
 7:   int xi1,yi1,ii,offSet, halfOff;
 8:
 9:   g.setFont(new Font("Arial",Font.BOLD,14));
10:   for(ii=0;ii<=noData;ii++)
11:   {
12:     g.setColor(barColor);
13:     xi1 = (int) myScale(xxA,xxB,xxMin,xxMax,xData[ii]);
14:     yi1 = (int) myScale(yyA,yyB,yyMin,yyMax,yData[ii]);
15:     offSet = (xxB - xxA)/(noData *2);
16:     halfOff = offSet/2;
17:
18:     g.setPaint(
19:        new GradientPaint(xi1,yi1,ranColor(),
20:         xi1+halfOff,baseLine-yi1,ranColor(),true) );
21:
22:     Rectangle2D.Double myRect = new Rectangle2D.Double(xi1-halfOff,
23:                                    yi1,offSet,baseLine-yi1);
24:     g.fill(myRect);
25:
26:     if (showText == true)
27:     {
28:       g.setColor(textColor);
29:       g.drawString(""+ (int) yData[ii],xi1-halfOff,yi1  10);
30:     }
31:  }
32: }

This function draws a long rectangle (or bar) at each position stored in the arrays xData[] and yData[]. The x,y-positions are first converted to applet window coordinates (xi1,yi1) in lines 1314. Then the width of the rectangle is calculated and stored in variable offSet (see line 15). To define the bar, you can use the Java2D rectangle shape as illustrated in lines 2223. The variable halfOff equals half of the offset to make sure that the bar is drawn evenly along the labels. The values of the baseLine and yi1 are measured from the top of the applet window to the x-axis and the bar respectively. The difference between these two values is the height of the bar itself. The fill() function in line 24 draws the filled rectangle. In order to make this example more interesting, random gradient colors are used to draw each bar. The GradientPaint() function in lines 1920 smoothly changes one color to another from one coordinate to another coordinate. Finally, if the value of the showText variable is true, the data associated with each bar are displayed at the top.

Another function called myPieChart() is also added right after the bar chart function myBarChart() to draw a complete pie on the applet window. This function is listed in ex03-16.txt.



Listing: ex03-16.txt - The Pie Chart Function In Graphs03.java

 1:  public void myPieChart( int noData,double[] xData,double[] yData,
 2:    boolean showText, Color textColor, Graphics gg)
 3:  {
 4:   Graphics2D g = (Graphics2D) gg;
 5:   double sum;
 6:   int ii, ang1, ang2, sizeB, sizeP, rTmp;
 7:   Color[] pieColor1, pieColor2;
 8:
 9:   pieColor1 = new Color[noData];
10:   pieColor2 = new Color[noData];
11:   g.setFont(new Font("Arial",Font.BOLD,14));
12:
13:   Dimension d = getSize();
14:   xxA = 0; xxB = d.width; yyA = d.height; yyB = 0;
15:   sizeB = (int) ( (yyA - yyB)/(noData*2) );
16:   sizeP = (int) ((yyA -yyB) * 0.9);
17:   rTmp =  (int) ((xxB-xxA) *0.4);
18:   if (sizeP > rTmp)
19:         sizeP = rTmp;
20:
21:   sum = 0.0f;
22:   for(ii=0;ii<noData;ii++)
23:   {
24:     sum = sum + yData[ii];
25:   }
26:
27:   ang1 = 20;
28:   for (ii=0;ii< noData;ii++)
29:   {
30:     pieColor1[ii] = ranColor();
31:     pieColor2[ii] = ranColor();
32:     g.setPaint( new GradientPaint(0,0,pieColor1[ii],
33:                 sizeB,sizeB,pieColor2[ii],true) );
34:     ang2 = (int) (360 * yData[ii]/sum +0.6);
35:     g.fill(new Arc2D.Double(20,20,sizeP,sizeP,ang1,ang2,Arc2D.PIE) );
36:     ang1 = ang1 + ang2;
37:
38:     if (showText == true)
39:     {
40:      int iiTmp = (int) (10000*yData[ii]/sum +1);
41:      g.fillRect((xxB-xxA)/2,ii*(sizeB+20)+20,sizeB,sizeB);
42:      g.setColor(Color.black);
43:      g.drawString(" "+labelSt[ii+1]+" - ("+ (double) iiTmp/100.0 + "% )",
44:                    (xxB-xxA)/2 + sizeB+10,ii*(sizeB+20)+35);
45:     }
46:   }
47: }

This function draws a complete pie using the data xData[] and yData[]. If the value of the variable showText is true, the text associated with each pie is displayed with the TextColor (see line 2). Since we don't want to draw the x,y-axes, the input arguments in lines 12 are simpler. As mentioned in section 3.3.3, the following Java2D shape function can be used to draw a pie at position (x1,y1):



Arc2D.Double(x1,y1,sizeX,sizeY,ang1,ang2,Arc2D.PIE)

where variables sizeX and sizeY are the dimensions of the box bounding the pie. The pie is drawn from angle ang1 to angle ang2. In order to calculate the angles of the pie chart, each yData[] is converted to a percentage. The percentage can be calculated by the individual data yData[ii] divided by the total sum of yData[] data. When you multiply the percentage by 360, you have the running angle (i.e., ang2) of the pie as in line 34. With the starting angle ang1, the pie is defined and drawn in line 35. If the value of the variable showText is true, a rectangle (see line 41) together with the label and percentage of the pie is drawn (see lines 4344). The color of each pie is governed by the random gradient color in lines 3233.

To incorporate these two functions into the class and to distinguish it from the curve situation, you may need to add an integer variable graphType at the global variable section of the class. When the value of graphType is 1, the class draws lines. If graphType is 2 or 3, a bar chart or a pie chart is drawn. Now, consider the myDrawGraphs() function (see lines 184217 of Graphs02.java). First, you may need to locate the functions myFindMinMax() and mySetFrame() and perform the following changes:



if ((graphType ==1)||(graphType==2))
{
  myFindMinMax();
  mySetFrame(gg);
}

This if statement makes sure that the x,y-axes are drawn when a curve or a bar chart is required. All you have to do next is to replace the function call to myDrawLines() (see lines 212215 in Graphs02.java) according to a situation depending on the value of variable graphType, e.g.,



if (graphType ==1)
{
  myDrawLines(xxA,xxB,yyA,yyB,xxMin,xxMax,yyMin,yyMax,
       noData,xData,yData,
       curveColor[jj],1,new Color(0,100,0),10,10,
       true,true,tmpSt,new Color(0,0,255),15,0,gg);
}
if (graphType ==2)
{
  myBarChart(xxA,xxB,yyA,yyB,xxMin,xxMax,yyMin,yyMax,
       noData,xData,yData,baseLine,new Color(0,0,255),
       true,new Color(0,0,255),gg);
if (graphType ==3)
{
  myPieChart(noData,xData,yData,
             true,new Color(0,0,255),gg);
}

Finally, the function myGetArgs() can be modified by the following Java code:



Listing: ex03-17.txt - The myGetArgs() Function In Graphs03.java

 1:  public void myGetArgs()
 2:  {
 3:   String tmpSt, tmpSt2;
 4:   int    ii,jj, index2, tmp2;
 5:
 6:   graphType = Integer.parseInt(getParameter("GraphType"));
 7:   if ( (graphType>0) && (graphType <4))
 8:   {
 9:    if (graphType ==1)
10:    {
11:      noData= Integer.parseInt(getParameter("NumberOfData"));
12:      noCurve= Integer.parseInt(getParameter("NumberOfCurve"));
13:      xTitle = getParameter("xTitle");
14:      yTitle = getParameter("yTitle");
15:      segNumber= Integer.parseInt(getParameter("NumberOfLabel"));
16:    }
17:    if (graphType==2)
18:    {
19:      noData= Integer.parseInt(getParameter("NumberOfData"));
20:      noCurve = 1;
21:      xTitle = getParameter("xTitle");
22:      yTitle = getParameter("yTitle");
23:      segNumber= Integer.parseInt(getParameter("NumberOfLabel"));
24:    }
25:    if (graphType==3)
26:    {
27:      noData= Integer.parseInt(getParameter("NumberOfData"));
28:      noCurve = 1;
29:      segNumber= noData;
30:    }
31:
32:    //Extracts all labels on x-axis
33:    labelSt=new String[segNumber+1];
34:      ====  ====  ====  ====  ====  ====  ====  ====  ====
35:      ====  ====  ====  ====  ====  ====  ====  ====  ====
36:        The Corresponding Original Statements are here
37:      ====  ====  ====  ====  ====  ====  ====  ====  ====
38:      ====  ====  ====  ====  ====  ====  ====  ====  ====
39:    }
40:  }

First, this function gets the parameter of GraphType from the calling Web page and stores the value into integer variable graphType (see line 6). Then the parameters are read into the class according to the value and requirement of graphType. Lines 1115 get the parameters for displaying the curves. Lines 1724 and 2530 are the requirements for displaying the bar and pie chart respectively. The remaining part starting from line 32 is the same as the corresponding statements in the myGetArgs() function in the Java program Graphs02.java.

For a bar chart test page, let's consider a page (e.g., ex03-17.htm) with the following <div> division element:



Listing: ex03-18.txt - Code Fragment For Example ex03-17.htm

 1: <div style="font-size:22pt; text-align:center;font-weight:bold">
 2:   Bar Chart: Company Product Sales<br />(Singapore Office)<br /><br />
 3: <applet code="Graphs03.class" width=600 height=350>
 4: <param name="GraphType" value="2">
 5: <param name="xTitle" value="Months">
 6: <param name="yTitle" value="Sales Millions">
 7: <param name="NumberOfData" value="12">
 8: <param name="Data1" value="Singapore,11,19,13,6,15,19, 21,16,25,25,12,13">
 9: <param name="NumberOfLabel" value="12">
10: <param name="labelName" value="Jan,Feb,Mar,Apr,May,
11:    Jun,Jul,Aug,Sep,Oct,Nov,Dec">
12: </applet>
13: </div>

At line 4 of this page, a new parameter called GraphType is added. The value of this parameter is 2, indicating that a bar chart is drawn. Since the format of this example is the same as previous examples, the remaining statements in this page are easy to read. A screen shot of this example is shown in Fig. 3.22.

Figure 3.22. ex03-17.htm

graphics/03fig22.jpg


For a pie chart testing page, consider a page (e.g., ex03-18.htm) with the following division <div> element:



Listing: ex03-19.txt - Code Fragment For Example ex03-18.htm

 1: <div style="font-size:22pt; text-align:center;font-weight:bold">
 2:     Pie Chart: Company Product Sales<br />
 3:     (First 6 Months In Singapore Office)<br /><br />
 4:  <applet code="Graphs03.class" width=600 height=350>
 5:   <param name="GraphType" value="3">
 6:   <param name="NumberOfData" value="6">
 7:   <param name="Data1" value="Singapore,11,19,13,6,15,19">
 8:   <param name="labelName" value="Jan,Feb,Mar,Apr,May,Jun">
 9:  </applet>
10: </div>

The GraphType in line 5 indicates that the pie chart function is called and a complete pie is displayed according to the parameters in lines 68. A screen shot of this example is shown in Fig. 3.23.

Figure 3.23. ex03-18.htm

graphics/03fig23.jpg


Again, the Java program Graphs03.java is just a demonstration example to show how to build a more complex Java applet to incorporate some presentation graphics such as business curves, bar charts, and pie charts. The concepts and skills can be extended to develop more challenging and practical Web applications.

Java is a rich subject and capable of almost anything. Only a few practical and selected topics are presented here. For further study, readers are advised to read some dedicated texts or to visit the official site of Java (www.javasoft.com) for more tutorials, examples, libraries, and other resources.

    Table of Contents

    Previous Next