JClass Chart

PreviousNextIndex

10

Advanced Chart Programming

Outputting JClass Charts  Batching Chart Updates  Coordinate Conversion Methods

FastAction  FastUpdate  Programming End-User Interaction  Image-Filled Bar Charts

Pick  Using Pick and Unpick  Unpick

Controlling the chart in an application program is generally straightforward once you are familiar with the programming basics and the object hierarchy. For most JClass Chart objects, all the information needed to program them can be found in the API. In addition, extensive information on how they can be used can be found in the numerous example and demonstration programs provided with JClass Chart.

This chapter covers more advanced programming concepts for JClass Chart and also looks at more complex chart programming tasks.


10.1 Outputting JClass Charts

Many applications require that the user has a way to get an image or a hard copy of a chart. JClass Chart allows you to output your chart as a GIF, PNG, or JPEG image, to either a file or an output stream.

(If you have JClass PageLayout installed, you can also encode your charts as an EPS, PS, PCL, or PDF file [in addition to GIF, PNG, or JPEG]. For more information, please see the JClass PageLayout Programmer's Guide. Refer to Quest Software's web site for information on evaluating or purchasing JClass PageLayout.)

Please note that in order to enable GIF encoding, you must obtain a license from Unisys and send a copy of this license to Quest Software. Quest will send the enabling software for GIF encoding upon receipt of a valid proof of license. There are also public sources of Java image to GIF converters.

Located in com.klg.jclass.util.swing.encode, the JCEncodeComponent class is used to encode components into different image file formats. When you include this class in your program, you can call one of two methods that allow you to save the chart image as a GIF, PNG, or JPEG file, sending it to either a file or an output stream.

The parameters of the two methods are the same, except for output.

10.1.1 Encode method

The method to output to a file is:

public static void encode(JCEncodeComponent.Encoding encoding, Component component, File file)

The method to output to an output stream is the same, except that the last parameter is OutputStream output, that is ...Component component, OutputStream output)

The component parameter refers to the component to encode, that is, the chart; the encoding parameter refers to the type of encoding to use (a GIF, PNG, or JPEG; if you have JClass PageLayout installed, you can also encode your chart as an EPS, PS, PCL, or PDF file); and the output parameter refers either to the file to which to write the encoding or to the stream to which to write the encoding.

10.1.2 Encode example

To see this encode method in action, please look at the Encode example, found in the "Example & Demo Gallery" that was installed automatically with JClass Chart. This example appears in the Advanced folder.

In this example, you can alter the encoding type by selecting a different encoding type from the drop-down menu. Another option provided is your choice of file name. Also, you can right-click the example to bring up the Property Editor and further manipulate the properties of the chart.

10.1.3 Code example

The following code snippet was used to create the example above.

public void actionPerformed(ActionEvent evt) {
  int typeIndex = encTypesCB.getSelectedIndex();
  String fileName = encFileTF.getText();
  if (evt.getSource() == encButton) {
    // if encode button pressed, get the encoding type and file name
    // and use them to encoding the chart
  
    if (typeIndex >= 0 && !(fileName.equals(""))) {
      // Call chart's encoding method, but make sure to catch
      // possible exception
      try {
JCEncodeComponent.encode (JCEncodeComponent.ENCODINGS[typeIndex], chart, new File(fileName));

      } catch (EncoderException ee) {
        ee.printStackTrace();
      }
      catch (IOException io) {
        io.printStackTrace();
      }
    }
  }

10.2 Batching Chart Updates

Normally, the chart is repainted immediately after a property is set. To make several changes to a chart before causing a repaint, set the Batched property of the JCChart object to true. Property changes do not cause a repaint until Batched is reset to false.

The Batched property is also defined for the ChartDataView object. This Batched property is independent of JCChart.Batched. It is used to control the update requests sent from the DataSource to the chart.

Note: It is highly recommended that you batch around the creation or updating of multiple chart labels.


10.3 Coordinate Conversion Methods

The ChartDataView object provides methods that enable you to do the following:

The following table outlines which method or functional equivalent to use for each action.

Method

Functional equivalent

Action

dataCoordToCoord()

unmap

Converts from data coordinates to pixel coordinates

coordToDataCoord()

map

Converts from pixel coordinates to data coordinates

dataIndexToCoord()

unpick

Determines the pixel coordinates of a given data point in a series

coordToDataIndex()

pick

Determines the closest point in pixels to a given data point in a series

10.3.1 CoordToDataCoord and DataIndexToCoord

To convert from data coordinates to pixel coordinates, call the dataCoordToCoord() method. For example, the following code obtains the pixel coordinates corresponding to the data coordinates (5.1, 10.2):

Point p=c.getDataView(0).dataCoordToCoord(5.1,10.2);

This works in the same way as unmap. Note that the pixel coordinate positioning is relative to the upper left corner of the JCChart component display.

To convert from pixel coordinates to data coordinates, call coordToDataCoord(). For example, the following converts the pixel coordinates (225, 92) to their equivalent data coordinates:

JCDataCoord cd=c.getDataView(0).coordToDataCoord(225,92);

This works in the same manner as map. So, coordToDataCoord() returns a JCDataCoord object containing the X- and Y-values in the data space.

To determine the pixel coordinates of a given data point, call dataIndexToCoord(). For example, the following code obtains the pixel coordinates of the third point in the first data series:

JCDataIndex di=new JCDataIndex(3,c.getDataView(0).getSeries(0));
Point cdc=c.getDataView(0).dataIndexToCoord(di);

To determine the closest data point to a set of pixel coordinates, call coordToDataIndex():

JCDataIndex di=c.getDataView(0).coordToDataIndex(225,92,ChartDataView.PICK_FOCUSXY);

Essentially, these last two examples demonstrate that dataIndexToCoord() works in much the same way as pick and unpick. The third argument passed to coordToDataIndex() specifies how the nearest series and point value are determined. This argument can be one of ChartDataView.PICK_FOCUSXY, ChartDataView.PICK_FOCUSX, or ChartDataView.PICK_FOCUSY. For more information on the pick and unpick methods, please see Section 10.9, Using Pick and Unpick.

JCDataIndex contains the series and point value corresponding to the closest data point, and also returns the distance in pixels between the pixel coordinates and the point. coordToDataIndex() returns a JCDataIndex instance.

10.3.2 Map and Unmap

map and unmap are functionally equivalent to the coordToDataCoord() and dataIndexToCoord() methods. They are provided as convenience methods, and are more in keeping with typical Java terminology than coordToDataCoord() and dataIndexToCoord().

For Polar charts, the X- and Y-values are interpreted as (theta, r) coordinates. The X-units used will depend on the current value of angle unit. The case for Radar and Area Radar charts is similar, except that X-values will be ignored.


10.4 FastAction

The FastAction property determines whether chart actions will use an optimized mode in which it does not bother to update display axis annotations or gridlines during a chart action. Default value is false.

Using FastAction can greatly improve the performance of a chart display, because relatively more time is needed to draw such things as axis annotations or gridlines than for simply updating the points on a chart. It is designed for use in dynamic chart displays, such as charts that enable the user to perform translation or rotation actions.

The following line of code shows how FastAction can be used in a program:

c.getChartArea().setFastAction(true);

10.5 FastUpdate

The FastUpdate property optimizes chart drawing - if possible, only new data that has been added to the datasource is drawn when the chart updates, with little recalculating and redrawing of existing points. (Please see Making Your Own Chart Data Source, in Chapter 8, for a guide on how to build an updating chart data source.) However, if the new data goes outside of the current axis boundaries, then a full redraw is done.

Using FastUpdate can improve the performance of a chart display, especially with dynamic chart displays.

The following line of code shows how FastUpdate can be used in a program:

c.getDataView(0).setFastUpdate(true);

A chart using the fast update feature will not draw correctly when the chart object is placed within an JInternalFrame object or when items from a JPopupMenu overlay the chart.

Please see the FastUpdate demo, found in JCLASS_HOME/demos/chart/fastupd/, for a demonstration of this feature.

Note: This feature is not supported in Area Radar or Radar charts. For Polar charts, there is no need to check the axis bounds in the X-direction. The routines for checking axis bounds can still be used for the y-direction.


10.6 Programming End-User Interaction

An end-user can interact with a chart more directly than using the Customizer. Using the mouse and keyboard, a user can examine data more closely or visually isolate part of the chart. JClass Chart provides the following interactions:

It is also possible in most cases for the user to reset the chart to its original display parameters. The interactions described here affect the chart displayed inside the ChartArea; other chart elements, such as the header, are not affected.

Note: The keyboard/mouse combinations that perform the different interactions can be changed or removed by a programmer. The interactions described here may not be enabled for your chart.

A chart action is a user event that causes some interactive action to take place in the control. In JClass Chart, actions like zoom, translate and rotate can be mapped to a mouse button and a modifier. For example, it is possible to bind the translate event to the combination of mouse button 2 and the Control key. Whenever the user hits Control and mouse button 2 and drags the mouse, the chart will move.

10.6.1 Event Triggers

An event trigger is a mapping of a mouse operation and/or a key press to a chart action. In the example above, the trigger for translate is a combination of mouse button 2 and the Control key.

An event trigger has two parts:

Valid actions include EventTrigger.CUSTOMIZE, EventTrigger.DEPTH, EventTrigger.EDIT, EventTrigger.PICK, EventTrigger.ROTATE, EventTrigger.TRANSLATE, and EventTrigger.ZOOM.

10.6.2 Valid Modifiers

The value of a modifier is specified using java.AWT.event modifiers, as shown in the following list:

You can also specify the mouse button using one of the following modifiers:

10.6.3 Programming Event Triggers

To program an event trigger, use the setTrigger method to add the new action mapping to the collection.

For example, the following tells JClass Chart to add a zoom operation as its first trigger (first trigger denoted by 0) when Shift and mouse button are pressed:

c.setTrigger(0,newEventTrigger(Event.SHIFT_MASK,EventTrigger.ZOOM);

10.6.4 Removing Action Mappings

To remove an existing action mapping, set the trigger to null, as in the following example:

c.setTrigger(0,null);

10.6.5 Calling an Action Directly

In JClass Chart, it is possible to force some actions by calling a method of JCChart. The following is a list of the methods that can be called upon to force a particular action:

10.6.6 Specifying Action Axes

Actions like translation occur with respect to one or more axes. In JClass Chart, the axes can be set using the HorizActionAxis and VertActionAxis properties of JCChartArea, as the following code fragment illustrates:

ChartDataView arr = c.getDataView(0);
c.getChartArea().setHorizActionAxis(arr.getXAxis());
c.getChartArea().setVertActionAxis(arr.getYAxis());

Note that it is possible to have a null value for an action axis. This means that chart actions like translation do not have any effect in that direction. By default, the HorizActionAxis is set to the default X-axis, and the VertActionAxis is set to the default Y-axis.


10.7 Image-Filled Bar Charts

It is possible to use image files as chart elements within a bar chart. This is accomplished by using the Image in JCFillStyle. Image sets the image used to paint the fill region of bar charts. It takes img as a parameter, which is an AWT Image class representing the image to be used to paint image fills. If set to null, no image fill is done.

The following code fragment shows how Image can be incorporated into a program:

String imageStrings[] = {"cd.gif", "tape.gif"};
List seriesList = arr.getSeries();
Iterator iter = seriesList.iterator();
for (int i = 0; iter.hasNext(); i++) {
  ChartDataViewSeries thisSeries = (ChartDataViewSeries)
    iter.next();

  if (i < seriesLabels.length) {
    if (imageStrings[i] != null) {
      Class cl = getClass();
      URL url = cl.getResource("/examples/chart/intro/"+imageStrings[i]);
      if (url != null) {
        ImageIcon icon = new ImageIcon(url);
        thisSeries.getStyle().getFillStyle().setImage(icon.getImage());
        thisSeries.getStyle().getFillStyle().setPattern(JCFillStyle.CUSTOM_STACK);
      }
    }
  }
}

The effects can be seen in the ImageBar demonstration program (in the JCLASS_HOME/examples/chart/intro/ImageBar.java directory), which comes with JClass Chart.

Figure 39 :  The ImageBar demonstration program.

The image is clipped at the point of the highest value indicated for the bar chart.

Image only tiles the image along a single axis. For example, if the bars were widened in the above illustration, it would still tile along the vertical Y-axis only, and would not fill in the image across the horizontal X-axis. This same principle applies (though along different axes) when the bar chart is rotated 90 degrees.

Note: Image can only be used with the image formats that can be used in Java.


10.8 Pick

The pick() method is used to translate a pixel coordinate on a chart to the data point that is closest to it. The method takes a Point object containing a pixel coordinate and an optional ChartDataView object to check against, and returns the resulting data point encapsulated in a JCDataIndex object.

For pick() to work correctly, the JCChart instance must first be laid out. This is automatically done whenever a chart is drawn, such as when the snapshot() method is called. Alternately, layout can be accomplished manually by called the doLayout() method of JCChart.

Pick Methods for Polar and Radar Charts

The pick() method for Polar and Radar charts is implemented in two stages. The data point closest to the pick point is identified in a primary search, thus obeying the specified pick focus rule. In some cases (for example, Radar charts with more than one series), there may be two or more data points that have the same X- or Y-value. The primary search result may be ambiguous if the pick focus rule is PICK_FOCUS_X or PICK_FOCUS_Y. To determine which of those points is the desired one, a secondary search is carried out using the PICK_FOCUS_XY rule.

Pick Methods for Area Radar Charts

The pick behavior for Area Radar charts differs from that of Polar or Radar charts. If the user clicks on a point within a filled polygon, the search for the closest point (again, obeying the pick focus rule) is limited to the data series represented by that polygon. Pick points within a polygon have the JCDataIndex.distance variable set to 0. If the pick point is not within a filled polygon (that is, the user clicked on a point outside of the largest polygon), then the smallest distance from the pick point to the polygon is taken. As with the Polar and Radar chart types, primary and secondary searches are conducted to resolve ambiguities that may arise for PICK_FOCUS_X or PICK_FOCUS_Y.


10.9 Using Pick and Unpick

The pick method is used to retrieve an x,y coordinate in a Chart from user input and then translate that into selecting the data point nearest to it. For example, if a user clicks within a single bar within a bar chart, pick takes the coordinates of the mouse-click and selects that bar for any action within the program. Similarly, if a user clicks in an area immediately above a bar chart, pick is used to select the bar that is closest to the mouse click.

To use the pick listener, you must first set up a PICK event trigger on the chart. See Section 10.6.3, Programming Event Triggers, for more details.

Consider the following code listing (the code that comprises the DrillDown demonstration program that comes with JClass Chart, in JCLASS_HOME/demos/chart/drilldown/ ) that demonstrates how pick can be used to "drill down" to reveal more information.

Note: This example assumes that a data.class file exists that understands different data levels.

package demos.chart.drilldown;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Event;
import java.awt.GridLayout;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JEditorPane;
import javax.swing.BorderFactory;

import java.util.Iterator;
import java.util.List;

import com.klg.jclass.chart.ChartDataView;
import com.klg.jclass.chart.ChartDataViewSeries;
import com.klg.jclass.chart.EventTrigger;
import com.klg.jclass.chart.JCAxis;
import com.klg.jclass.chart.JCPickListener;
import com.klg.jclass.chart.JCPickEvent;
import com.klg.jclass.chart.JCChartStyle;
import com.klg.jclass.chart.JCLineStyle;
import com.klg.jclass.chart.JCChart;
import com.klg.jclass.chart.ChartText;
import com.klg.jclass.chart.JCDataIndex;
import com.klg.jclass.chart.JCChartArea;
import com.klg.jclass.util.swing.JCExitFrame;
import com.klg.jclass.util.legend.JCLegend;

/*
 * This demo demonstrates using pick to drill down to more
 * refined data
 */
public class DrillDown extends javax.swing.JPanel implements JCPickListener {

protected Data d = null;
protected JCChart c = null;

public DrillDown()
{
  setLayout(new BorderLayout(10,10));
  setPreferredSize(new Dimension(600,400));

  d = new Data();

  Color Turquoise = new Color(64,224,208);
  Color DarkTurquoise = new Color(0x00,0xce,0xd1);

  c = new JCChart();
  c.setTrigger(0, new EventTrigger(0, EventTrigger.PICK));
  c.setBackground(DarkTurquoise);

  JCChartArea area = c.getChartArea();
  area.getPlotArea().setBackground(Turquoise);
  area.setOpaque(true);
  area.setBorder(BorderFactory.createEtchedBorder());

  JComponent header = c.getHeader();
  header.setBackground(Turquoise);

  ((JLabel)header).setText("<html><center> <font color=black><b>Drill Down Demo</b><P>Independent Comic Book Sales 1996</center>");

  header.setBorder(BorderFactory.createRaisedBevelBorder());
  header.setVisible(true);

  JCLegend legend = c.getLegend();
  legend.setVisible(true);
  legend.setBackground(Turquoise);
  legend.setForeground(Color.black);
  legend.setBorder(BorderFactory.createLoweredBevelBorder());

  ChartDataView dataView = c.getDataView(0);
  c.setBatched(false);
  dataView.setDataSource(d);
  dataView.setChartType(JCChart.BAR);
  dataView.setHoleValue(-1000);
  dataView.getOutlineStyle().setColor(Color.darkGray);

  JComponent footer = c.getFooter();
  footer.setVisible(true);

  ((JLabel)footer).setText("<html><font color=black size=-1>  <CENTER><i>Drill Down -> Mouse Down  on Bar or Legend<P>Drill Up ->   Mouse Down on Other Area of  Graph</i></CENTER>");

  area.setDepth(10);
  area.setElevation(20);
  area.setRotation(20);

  JCAxis yAxis = area.getYAxis(0);
  yAxis.setGridVisible(true);
  yAxis.getGridStyle().getLineStyle().setColor(new Color(154,154,229));

  // Set colors for each data series
  setSeriesColor();

  // Set up pick and rotate trigger
  c.setTrigger(0, new EventTrigger(0, EventTrigger.PICK));
  c.setTrigger(1, new EventTrigger(Event.SHIFT_MASK,   EventTrigger.ROTATE));
  c.setTrigger(2, new EventTrigger(Event.META_MASK,   EventTrigger.CUSTOMIZE));
  c.setAllowUserChanges(true);

  // Add listener for pick events
  c.addPickListener(this);

  add("Center",c);
}

void setSeriesColor()
{
  // Set colors for each data series
  Color colors[] = {Color.red, Color.blue, Color.white,   Color.magenta, Color.green, Color.cyan,   Color.orange, Color.yellow};
  ChartDataView dataView = c.getDataView(0);
  List seriesList = dataView.getSeries();
  Iterator iter = seriesList.iterator();
  for (int i = 0; iter.hasNext(); i++) {
    ChartDataViewSeries series =
    (ChartDataViewSeries)iter.next();
    series.getStyle().setFillColor(colors[i]);
  }
}

/**
 * Pick event listener. Upon receipt of a pick event, it either
 * drills up or down to more general or refined data.
 */
public void pick(JCPickEvent e)
{
  boolean doLevel = false;
  boolean doUpLevel = true;
  JCDataIndex di = e.getPickResult();
  int srs = 0;

  // If clicked on bar or legend item, drill down. If clicked on
  // any other area of chart, drill up.
  if (di != null) {
    Object obj = di.getObject();
    ChartDataView vw = di.getDataView();
    srs = di.getSeriesIndex();
    int pt = di.getPoint();
    int dist = di.getDistance();

    if (vw != null && srs != -1) {
      if (srs >= 0) {
        if ((obj instanceof JCLegend) ||
           (obj instanceof JCChartArea && dist == 0))
        {
          doLevel = true;
          doUpLevel = false;
        }
        else {
          doLevel = true;
        }  
      }
    }
    else {
      doLevel = true;
    }
  }
  else {
    doLevel = true;
  }


  if (doLevel) {
    c.setBatched(true);
    if (doUpLevel) {
       d.upLevel();
    }
    else {
        d.downLevel(srs);
    }
    setSeriesColor();
    c.setBatched(false);
  }
}

public static void main(String args[])
{
  JCExitFrame f = new JCExitFrame("Basic Drilldown example");
  DrillDown tc = new DrillDown();
  f.getContentPane().add(tc);
  f.pack();
  f.setVisible(true);
}

}

When compiled and run, the DrillDown.class program displays the following:

Figure 40 :  The DrillDown demonstration program displayed.

When a bar or legend within this chart is clicked by the user, the program "drills down" to reveal more refined data comprising that bar. If an area outside of the bars is clicked upon, then the program "drills up" to reveal more general data.

pick is key to this program, determining the way the program interacts with the user. pick requires an event trigger and listener to work, as the following code fragment shows:

c.setTrigger(0, new EventTrigger(0, EventTrigger.PICK));
  c.addPickListener(this);
public void pick(JCPickEvent e)
{
  JCDataIndex di = e.getPickResult();
}

When a user clicks in the DrillDown demonstration program, the event is triggered, and the x,y coordinates are passed along to the pick event listener, which in turn takes the information and performs the indicated action. The pick() method returns a JCDataIndex, which encapsulates the point index and data series of the selected point.

It is also possible to send a pick event to objects manually. When the sendPickEvent() method is called, it sends a pick event to all objects listening for it.

10.9.1 Pick Focus

pick normally takes an x,y coordinate value, but it can take an X- or Y-value only, which is useful for specific chart types. This can be specified using the PickFocus property of ChartDataView, which specifies how distance is determined for pick operations. When set to PICK_FOCUS_XY (default), a pick operation will use the actual distance between the point and the drawn data. When set to values of PICK_FOCUS_X or PICK_FOCUS_Y, only the distance along the X- or Y-axis is used.

This is a particularly useful method within programs that display typical bar charts. In most cases it is more desirable to know which bar the user is over than which bar the user is closest to when the user clicks their mouse over a chart.

For example, a user may click over a relatively small bar in a bar chart, with the intention of raising the value of the bar displayed. If an adjacent bar in the chart is closer to the area of the mouse click along the Y-axis than the X-axis, then the adjacent bar could be selected instead of the intended target bar.

To overcome this, use PickFocus and select the axis whose values are to be reported back to the program. For example, the following line of code sets PickFocus to only report the X-coordinate of a pick event:

arr.setPickFocus(ChartDataVies.PICK_FOCUS_X);

10.10 Unpick

The unpick() method essentially functions in the opposite manner of pick: given a data series and a data point within that series, unpick returns the pixel co-ordinates of that point relative to the chart area. It takes two sets of parameters: pt for the point index, and series for the data series. For bar charts it returns the top-middle location for a given bar, and the middle of an arc for a pie chart. unpick can be used to display information at a given point in a chart, and can be used for attaching labels to chart regions.

For unpick() to work correctly, the JCChart instance must first be laid out. This is automatically done whenever a chart is drawn, such as when the snapshot() method is called. Alternately, layout can be accomplished manually by calling the doLayout() method of JCChart.


PreviousNextIndex