[Index] [Introduction] [Installation] [Package] [Component] [Chart] [Axis] [Utility] [Applet] [Servlet] [Appndx A] [Appndx B] [API]

FRAMES   NO FRAMES   NO FRAMES INDEX


KavaChart Standalone Application Cookbook

This chapter shows several ways to use KavaChart within a standalone Java application. This tutorial anticipates that you have significant experience using the Java language. Although all the examples here use simple standalone applications, the concepts are equally relevant for applets or other classes. For more general overview information, consult the Package, Component, Chart, and Axis links at the top and bottom of this page.

These examples can be found in the javachart.chart.standalone package directory, even though they're not in a formally defined package. The Java Bean example uses techniques that can be seen in various source files in javachart.beans.chart, especially javachart.beans.chart.ChartWriter, which also uses KavaChart bean customizers to manipulate charts in a standalone application.

In general, KavaChart requires only a java.awt.Graphics class to create actual chart drawings. This permits KavaChart to be used with both lightweight and heavyweight components, and with heavily customized graphical components as well as basic AWT components. In addition, KavaChart doesn't impose any sort of event handling model, allowing it to be used with the widest possible range of user interface approaches. 


Example 1 - basics and compilation

Our first example extends java.awt.Frame to build a very simple, non-interactive chart:

Step 1 - create a standalone program that draws a Frame. The following program draws an empty window (Frame) with a size of 400 pixels by 400 pixels:

import java.awt.*;

public class myChart extends Frame {
   public static void main(String[] args){
      myChart app = new myChart();
      app.setSize(400, 400);
      app.setVisible(true);
   }
}
Step 2 - create a KavaChart class for use with this program, and set the size to be the same as the Frame. While we're creating a BarChart for this example, you could just as easily use any other subclasses of javachart.chart.Chart, such as LineChart or PieChart. This superclass contains most of the useful methods for building charts and for accessing the various constituent chart elements.
import javachart.chart.*;
BarChart chart = new BarChart("sample");
chart.resize(400, 400);
Step 3 - override the Frame's paint method to do something (slightly) interesting. While our chart isn't complete yet, this is where we'll want to do the drawing. Frame (and most other graphics classes) use the paint method whenever they need to draw themselves.
public void paint(Graphics g){
   chart.paint(g);
}
Step 4 - add some data. With this step, we have a fully functional program for drawing a BarChart. The following source code is the complete myChart.java file:
import java.awt.*;
import javachart.chart.*;

public class myChart extends Frame {

   BarChart chart = new BarChart("sample");

   public static void main(String[] args){
      double[] myData = {123, 432, 223, 345};
      myChart app = new myChart();
      app.setSize(400, 400);
      app.setVisible(true);
      app.chart.resize(400, 400);
      app.chart.addDataset("important numbers", myData);
   }

   public void paint(Graphics g){
      chart.paint(g);
   }
}
Step 5 - compile myChart.java. If you're using the JDK from JavaSoft, you'd have to a) make sure the "javachart" directory is part of your CLASSPATH environment (e.g. "set CLASSPATH=C:\javachart" for Windows), and b) execute the command "javac myChart.java". If you're using some other development environment, such as VisualAge, JBuilder, Cafe, or J++, the steps are similar: make sure javachart is in your CLASSPATH and execute compilation. Alternatively, you may want to import the entire javachart directory tree into

Step 6 - run your program. If you're using JavaSoft's JDK, this would be done with the following command: "java myChart". Note that if your program was part of a Java package, such as javachart.standalone, you'd have to run "java javachart.standalone.myChart". If you're running with a reasonably current Microsoft operating system, you can also use a command like "jview myChart" to use Microsoft's JVM.


Example 2 - a reusable chart Panel

Our next example uses a very similar approach, but creates a reusable subclass of Panel that can be added to any other Java component, with only a few minor changes:

Step 1 - create a standalone program that will 1) create a reusable ChartPanel class, and 2) place that Panel into a Frame:

import java.awt.*;

public class ChartPanel extends Panel {
        public static void main(String[] args){
                Frame myFrame = new Frame("Title Bar");
                ChartPanel myPanel = new ChartPanel();
                myFrame.add(myPanel);
                myFrame.setSize(400, 400);
                myFrame.setVisible(true);
        }
}
Step 2 - add a method to initialize a simple chart. A few things to note: 1) we intentionally placed the chart definition outside the intialization method to ensure the chart object is available elsewhere, such as from paint() for drawing, or from an external class, to change various chart properties. 2) we use the initialization method to change a couple of chart properties as well as to install some sample data. The initialization method sets a direct property, the chart's LegendVisibility, which is available for all Chart subclasses. We also set a title string for this chart by acquiring the chart's Background (chart.getBackground()) and then setting the Background's title string. This hierarchical approach to managing chart properties can seem confusing at first, but ultimately provides a well organized and modular mechanism for managing a lengthy list of properties.
   public BarChart chart = new BarChart("sample");

   protected void initChart(){
      double[] sampleData = {123, 432, 345, 432};
      chart.addDataset("Banana Sales", sampleData);
      chart.setLegendVisible(true);
      chart.getBackground().setTitleString("Sample Chart");
   }
Step 3 - override the Panel's paint method to draw a chart whenever this panel paints itself. We'll add a new twist this time, though. First, we'll override the update method, to eliminate update's default clearing and the resultant flicker. Second, we'll use a special KavaChart paint method. This method creates an off-screen image buffer (using Panel's createImage method) that will actually take the chart drawing. By drawing to the off-screen image buffer, and then drawing the buffer in a single operation, we'll have smooth, flicker free drawing:
public void update(Graphics g){
   paint(g);
}

public void paint(Graphics g){
        chart.paint(this, g);
}
Our total ChartPanel class can be used by any other graphics class with a few simple lines:
ChartPanel myChartPanel = new ChartPanel();
myChartPanel.initChart();
add(myChartPanel);
myChartPanel.chart.getBackground().setTitleString("a totally new title");
etc.
The finished ChartPanel looks like this:
import java.awt.*;
import javachart.chart.*;

public class ChartPanel extends Panel {
   public BarChart chart = new BarChart("sample");

   protected void initChart(){
      double[] sampleData = {123, 432, 345, 432};
      chart.addDataset("Banana Sales", sampleData);
      chart.setLegendVisible(true);
      chart.getBackground().setTitleString("Sample Chart");
   }

   public void update(Graphics g){
      paint(g);
   }

   public void paint(Graphics g){
      chart.paint(this, g);
   }

   public static void main(String[] args){
                Frame myFrame = new Frame("Title Bar");
                ChartPanel myPanel = new ChartPanel();
                myPanel.initChart();
                myFrame.add(myPanel);
                myFrame.setSize(400, 400);
                myFrame.setVisible(true);
   }
}

Example 3 - a reusable lightweight chart panel

Our next example is nearly identical, except that it uses lightweight Swing components. Because of KavaChart's flexible architecture, it can be used easily with either Swing or AWT environments:

Step 1 - create a standalone program that will 1) create a reusable ChartPanel class, and 2) place that JPanel into a JFrame:

public class ChartPanel extends JPanel {
        public static void main(String[] args){
                JFrame myFrame = new JFrame("Title Bar");
                ChartPanel myPanel = new ChartPanel();
                myFrame.getContentPane().add(myPanel);
                myFrame.setSize(400, 400);
                myFrame.setVisible(true);
        }
}
Step 2 - add a method to initialize a simple chart. This is identical to the previous AWT example.
   public BarChart chart = new BarChart("sample");

   protected void initChart(){
      double[] sampleData = {123, 432, 345, 432};
      chart.addDataset("Banana Sales", sampleData);
      chart.setLegendVisible(true);
      chart.getBackground().setTitleString("Sample Chart");
   }
Step 3 - override the JPanel's paint and update methods to draw a chart whenever this panel paints itself. Again, this is identical to the AWT modifications:
public void update(Graphics g){
   paint(g);
}

public void paint(Graphics g){
        chart.paint(this, g);
}
Like the AWT version, the lightweight ChartPanel class can be used by any other graphics class with a few simple lines:
ChartPanel myChartPanel = new ChartPanel();
myChartPanel.initChart();
add(myChartPanel);
myChartPanel.chart.getBackground().setTitleString("a totally new title");
etc.
The finished ChartPanel looks like this:
import javax.swing.*;
import javachart.chart.*;

public class ChartPanel extends JPanel {
   public BarChart chart = new BarChart("sample");

   protected void initChart(){
      double[] sampleData = {123, 432, 345, 432};
      chart.addDataset("Banana Sales", sampleData);
      chart.setLegendVisible(true);
      chart.getBackground().setTitleString("Sample Chart");
   }

   public void update(Graphics g){
      paint(g);
   }

   public void paint(Graphics g){
      chart.paint(this, g);
   }

   public static void main(String[] args){
                JFrame myFrame = new JFrame("Title Bar");
                ChartPanel myPanel = new ChartPanel();
                myPanel.initChart();
                myFrame.getContentPane().add(myPanel);
                myFrame.setSize(400, 400);
                myFrame.setVisible(true);
   }
}

Example 4 - using KavaChart Beans

Our next example demonstrates how to use KavaChart beans to create a standalone application containing a chart. While our ChartPanel example above could be used as a Java Bean, it's not particularly useful in this context. This is largely because a) it has no useful properties exposed at a top level and b) because the chart's underlying data is self-contained and contrived. KavaChart beans include a customizer for each chart type, providing GUI access to most chart properties. They also include a plug-in data source model and a set of data source beans that permit you to easily separate data management from visual display management. Our initial example uses no data source, and relies on built-in sample data contained within the bean:

Step 1 - create a standalone program the draws a Frame containing our bean. This time we'll use a PieChart. The following program draws a charting Frame with a size of 400 pixels by 400 pixels:

import java.awt.*;
import javachart.beans.chart.*;

public class ChartFrame extends Frame {
        public static void main(String[] args){
                ChartFrame app = new ChartFrame();
                app.setSize(400, 400);
                app.add(new PieChart());
                app.setVisible(true);
        }
}
Note that the bean automatically takes care of issues like resizing, double buffering, repainting, string rotations, etc. This simplification has tremendous value in many applications.

Step 2 - add a data source to our bean. KavaChart includes a variety of data source beans in source code form. Your application's data acquisition requirements are likely very different from the next user's application. However, by modifying or subclassing one of the KavaChart data beans, you can easily create your own data bean that will work with any KavaChart charting bean. In this example, we'll simply add a bean that simulates data inputs.

import java.awt.*;
import javachart.beans.chart.*;
import javachart.beans.data.*;

public class ChartFrame extends Frame {
        public static void main(String[] args){
                ChartFrame app = new ChartFrame();
                app.setSize(400, 400);
                PieChart chart = new PieChart();
                DataFeedSimulator dataFeed = new DataFeedSimulator();
                dataFeed.addDataFeedListener(chart);
                app.add(chart);
                app.setVisible(true);
        }
}
In this program, each time our dataFeed receives a data update, it sends it to any chart beans that may be listening. As you run this program, you will notice that in addition to automatic management of repainting, etc., this chart's data changes from time to time. In fact, if you create your own data bean in place of DataFeedSimulator, every time your data changes, the chart will change automatically to display your new data.


Example 5 - modifying chart properties directly

KavaChart includes a myriad of chart properties that can be modified by reaching into the hierarchy of elements. The following method illustrates one set of modifications:
private setup(Chart chart){
                chart.setLegendVisible(true);
                Plotarea plt = chart.getPlotarea();
                plt.setLlX(0.11);
                plt.setLlY(0.10);
                plt.setUrY(0.75);
                plt.setUrX(0.75);
                plt.getGc().setFillColor(Color.lightGray);
                
                chart.getXAxis().setGridVis(true);
                chart.getYAxis().setGridVis(true);
                chart.getXAxis().setLabelFormat(Gc.COMMA_FORMAT);
                chart.getYAxis().setLabelFormat(Gc.COMMA_FORMAT);
                chart.getXAxis().setLabelPrecision(4);
                chart.getYAxis().setLabelPrecision(4);

                chart.getBackground().setTitleFont(new Font("Helvetica", 1, 16));
                chart.getBackground().setTitleString("QSK19 High Response JWAC Type III Data");

                chart.getXAxis().setTitleString("Power (bhp)");
                chart.getYAxis().setTitleString("Turbine Corporate Flow Parameter()");
}
A few things are worth noting in this method. First, some general properties are set at the top level, such as setting the chart's legend visibility. You can review most of these properties in the API documentation for javachart.chart.Chart. Properties specific to individual chart types can be found in the API documentation for those chart types.

Second, you'll notice that many of the properties we're setting in this sample are for chart elements below the top level. For example, we're setting the color of our chart's plotarea to light gray. First, we obtain the Plotarea class:

                Plotarea plt = chart.getPlotarea();
But a cursory examination of the Plotarea class reveals that Plotarea doesn't contain a color property. This is stored in the Plotarea's Gc class. After obtaining the Gc class, we're finally able to set the color:
                plt.getGc().setFillColor(Color.lightGray);
Although this level of indirection may seem confusing at first, in the end it generally improves the organization of your applications.

Similarly, you'll find that calls to chart.getYAxis() don't actually return an Axis, but an AxisInterface. The price of a little abstraction permits your application to deal with Axes, SpeedoAxes, DateAxes, LabelAxes, and anything else you might want to dream up in a uniform way. In this case, we obtain the X and Y axes to set grid visibility properties, labelling properties, and titles.


Example 6 - creating charts from serialized data

KavaChart also permits you to serialize chart definitions and re-instantiate the chart using the serialized data. This has many potential uses, but it also lets you create a chart definition interactively with KavaChart bean customizers, and then read those chart definitions into an application.

Consider our previous standalone application using a chart bean:

public class ChartFrame extends Frame {
        public static void main(String[] args){
                ChartFrame app = new ChartFrame();
                app.setSize(400, 400);
                app.add(new PieChart());
                app.setVisible(true);
        }
}
The chart bean was installed using "new PieChart()". We could also add a method like this to read the chart definition from a file:
private ChartBean newChart(String fileName){

        ChartBean bean = null;

        InputStream is = this.getClass().getResourceAsStream(fileName);
        if (is == null) {
                System.err.println("Could not locate the chart data at " + fileName);
        }
        try {
                ObjectInputStream ois = new ObjectInputStream(is);
                bean = (ChartBean) ois.readObject();
        } catch (Exception ex) {
                System.err.println("trouble reading from serialized data: "+ex);
        }
        return bean;
}
With our newChart method, we can simply replace "new PieChart()" with something like this:
                app.add(newChart("graph.obj"));
to read a file named "graph.obj" into our application. The real value of this is the ability to pre-modify any chart attribute interactively, without any coding, using a commercial IDE, the BDK from JavaSoft, or our own javachart.beans.chart.ChartWriter application. With this paradigm, you can create template charts of all varieties for your application, and simply read them as required, connecting your own DataFeed to complete the picture. This has the potential of tremendous simplification for all sorts of applications requiring charting functionality.


Example 7 - adding mouse interactions

Although KavaChart doesn't presume to manage mouse or keyboard events, it contains key functionality to translate simple event information into rich chart information. The key to this is KavaChart's javachart.chart.DisplayList class. Given a pixel location, this class will identify all of the charting elements at that location.

By default, display list processing is disabled, and must be enabled with the Chart method "setUseDisplayList". Setting this property to "true" causes Chart subclasses to record information about the current chart for subsequent requests. The display list is cleared and regenerated each time a chart is redrawn.

Any pixel location may correspond to many chart elements. For example, one location on a Bar chart could contain a Bar, a Legend, a Plotarea and a Background. KavaChart's DisplayList class fills a Vector with charting elements at a particular location in the same order they're drawn. This means the last element in the Vector is the top-most item.

Since your application may not be interested in every element, individual chart elements (Bar, Axis, Plotarea, etc.) also include a "setUseDisplayList" method. Setting this property to "false" for any element in a chart prevents that element from appearing in the DisplayList.

The following method could be used to process any sort of MouseEvent. It's similar to the code found in the sample SimpleLine.java:

        public doMouseEvent(MouseEvent e){
                LineChart chart;
                int i;
                Vector  list;
                Point   pickpt;
                Object  myObj;
                Datum   myDat;
                
                chart = (LineChart) chart;
                pickpt = new Point (e.getX(), e.getY());
                list = new Vector();
                if (chart.getDisplayList().contains(pickpt,list)){
                        System.out.println("got a pick...");
                        for(int j=0;j < list.size();j++){
                        myObj = list.elementAt(j);
                        if(myObj instanceof Dataset)
                                System.out.println("got a dataset...");
                        if(myObj instanceof Line)
                                System.out.println("got a Line...");
                        if(myObj instanceof Plotarea)
                                System.out.println("got a plotarea...");
                        if(myObj instanceof Background)
                                System.out.println("got a Background...");
                        if(myObj instanceof Axis)
                                System.out.println("got an Axis...");
                        if(myObj instanceof Datum){
                                System.out.println("got a datum, setting to 0");
                                myDat = (Datum) myObj; //coerce myObj to Datum
                                myDat.setY(0.0);
                        }
                }
        }
In SimpleLine.java this method overrides the (deprecated, but simple) event handler in SimpleLine's Frame superclass. Consider what this event does if the event is a MOUSE_DOWN. The location of the mouse click is passed into the chart's display list:
                        if (chart.getDisplayList().contains(pickpt,list)){
If the DisplayList class reports back "true", it has found items corresponding to this location, and fills our Vector with these chart elements. We report that items are available, and then traverse the Vector, identifying the various items:
                                System.out.println("got a pick...");
                                for(int j=0;j < list.size();j++){
                                        myObj = list.elementAt(j);
                                        if(myObj instanceof Dataset)
                                                System.out.println("got a dataset...");
                                        if(myObj instanceof Line)
                                                System.out.println("got a Line...");
                                        ...
We're just reporting what we find, using the instanceof operator. Although this is a trivial usage for simplicity's sake, this can be a very powerful mechanism, permitting you to launch various editors, execute hyperlinks, modify data, etc. based on your application requirements and the type of object you're dealing with. In our example, we're just reporting what we find, unless you happen to click a line vertex, which corresponds to a specific observation, or Datum class. In this case, we set the Datum's Y value to 0.0 to make a visible change in the chart.

While this isn't a complicated procedure, it illustrates the potential power this model provides. KavaChart objects can be dealt with individually, while retaining complete chart coherency. For example, if we were to change LineChart to PieChart (or any other kind of chart) this sample code would still behave properly. Similarly, if we had a GUI editor attached to Datum classes, we wouldn't need to know anything about the underlying chart to edit individual data points.


Example 8 - highlighting chart items

Once we've considered what sort of mouse interactions we want to process, it's common practice to highlight an item to provide users with some feedback before confirming (with a double-click, for example) that an item should receive some sort of edit.

KavaChart provides a javachart.chart.Highlighter class to give the basic functionality required for this sort of interaction. To retain KavaChart's flexibility in dealing with different sorts of Graphics classes (lightweight vs. heavyweight components, etc.) Highlighter doesn't actually do any highlighting, but it does provide you with pixel locations for any selected object. Instantiate a Highlighter class like this:

        myHighlighter = new Highlighter(chart.getGlobals());
To the handleEvent example above, we'd add something like this to indicate a selection:
        setSelection(myHighlighter.getHighlightPoints(myObj), myObj);
where "setSelection" is a local management method for actually drawing the highlight points returned by the Highlighter class.

You can find sample application code for managing selection highlighting in Highlight.java, in the standalone directory. This example includes code for setting an initial selection (setSelection) adding to a selection (addSelection) and for clearing a list of selected objects (clearSelectList).

While Highlight.java contains useful code for managing selections, the repaint mechanism is intentionally simplified. A more sophisticated application would forgo regenerating the entire chart for each repaint, and instead rely on an off screen image buffer version of the chart until the chart actually changes. This wouldn't make much difference in the small sample chart, but could make a significant difference in a chart with thousands of data points.


Example 9 - using server-push and KavaChart beans

Standard KavaChart applets rely on "client-pull" to retrieve data over a network. That is, by using URL dataset definitions, the applet will contact your server via http periodically to update its information. While this is convenient and adequate for many applications, it suffers from 2 distinct drawbacks. First, the overhead of negotiating a new http connection can be significant. This is particularly significant if your data changes frequently. Creating a new http connection, say, every second to update your chart's data could become a major drain on server resources, particularly if many users are viewing the charts simultaneously.

Second, your applet is running asynchronously from data changes. If your applet is set to update every 30 seconds, it might well be 30 seconds late in displaying some important data change. For some kinds of information, this doesn't matter. Some information is extremely time critical, however.

For charts that deal with time sensitive data, a much better approach is to permit the server to trigger updates instead of waiting for the client to request updates. This approach is generally called "server-push". In this case, our client application opens a socket to the server, which remains open waiting for additional information to arrive.

One of the KavaChart datafeed beans is specifically designed to deal with this situation. The SocketListener bean opens a socket to a specified server, using a specified port, and listens for lines of data. Like all other datafeed beans, SocketListener then sends update notifications to any DataFeedListener that has registered with the datafeed bean. Here's what the body of our app looks like:

        public SocketChart(){
                ChartBean chart = new LineChart();
                SocketListener data = new SocketListener();
                data.addDataFeedListener(chart);
                add(chart);
                setSize(500, 300);
                setVisible(true);
        }
Pretty easy. We're just using SocketListener defaults (open a socket to localhost, and listen to port 830), so no additional setup is required. SocketListener (and Java) takes care of the details of Socket i/o and reading lines of incoming data.

The server side isn't quite as easy to deal with, since it involves creating a server application that listens for connections and sends updates from your original data source. Fortunately, Java provides some nice facilities here, so we furnished a simple server application that just happens to work with our standalone client app. In the "misc" directory, you'll find an application called Broadcaster that does the trick. Broadcaster sends out sine and cosine curves, so you can see that we're really getting some recognizable data at our client. Step one, then is to launch Broadcaster:

java Broadcaster
The next step is to launch our client, which can also be found in the misc directory:
java SocketChart
You will see some notification from Broadcaster that a connection was established, and SocketChart starts to plot sine and cosine waves that correspond to incoming data. Our SocketListener bean is set up to send a maximum of 50 observations, so it will start scrolling the data when it reaches 50 data points.

What happens now if we launch a second copy of SocketChart? You'll see that the new copy of SocketChart updates right along with the old copy. In fact, you can have as many copies of SocketChart running as you can stand to see. Each one will respond to updates coming from the single Broadcast application.

This is a very powerful paradigm for creating custom charts with real time data. With very little burden on your server, you can service a large number of clients, each one reflecting the latest changes in data as they arrive. Also, because of the multi-threaded nature of KavaChart's data model, your client application is completely "alive" for editing, resizing, highlighting, etc., while it awaits more incoming data.

We implemented this example with an application instead of an applet, but the approach is the same for an applet. Keep in mind, though, that Java's SecurityManager might prevent an applet from opening sockets to a machine other than the one serving KavaChart classes.


Example 10 - building a SimpleDataFeed subclass

Using KavaChart beans most effectively may require creating a data feed bean to acquire data from your source and send it to a KavaChart bean. With the utility superclass SimpleDataFeed, this is a fairly straightforward process. While you could also hard-code your data source to each chart instance, the abstraction and simplicity afforded by the bean model is well worth the effort.

The first step is to create the code that actually aquires your data. Since we don't have any particularly meaningful data sources in KavaChart, we'll just write some code to generate a sine wave and cosine wave. We can create the Datasets directly (as many of the examples in javachart.beans.data do), but for our situation, it's easier to just create an array of values and let SimpleDataFeed take care of the dirty work. We'll use the protected arrays xArray and yArray to build our data with this method:

        private void buildMyData(){
                if(xArray == null)
                        xArray = new double[2][100];
                if(yArray == null)
                        yArray = new double[2][100];
                for(int i=0;i< xArray[0].length;i++){
                        xArray[0][i] = (double)i;
                        yArray[0][i] = Math.sin(((double)(i+iteration)/20));
                        xArray[1][i] = (double)i;
                        yArray[1][i] = Math.cos(((double)(i+iteration)/20));
                }
                iteration++;
        }
The next step will be to give our bean a Thread, so that it can send out data periodically. In our example, let's send out a data update every tenth of a second:
        public void run(){
                while(true){
                        try{
                                buildMyData();
                                updateDatasets();
                                fireEvent();
                                Thread.sleep(100);
                        }catch(Exception e)
                        { 
                                System.out.println("killed"); 
                        }
                }
        }
A couple of things are going on here. First, buildMyData() updates the values in our x and y data arrays. Then we call updateDatasets() to transfer the information in these arrays into an actual DataEvent. Finally, we send the data to any interested ChartBeans with a fireEvent() call. The complete bean is located in javachart/standalone/WaveMaker.java.

Now, to actually see the chart in action, we'll use a LineChart bean and our WaveMaker bean to show an animated sine/cosine wave form. Here's the complete code (located in javachart/standalone/WaveViewer.java):

        public WaveViewer(){
                ChartBean chart = new LineChart();
                SimpleDataFeed data = new WaveViewer();
                data.addDataFeedListener(chart);
                add(chart);
                setSize(800, 300);
                setVisible(true);
        }
Note that this data bean can now be deployed with any kind of chart. Try a BarChart or AreaChart as an example. 
[Index] [Introduction] [Installation] [Package] [Component] [Chart] [Axis] [Utility] [Applet] [Servlet] [Appndx A] [Appndx B] [API]