![]() ![]() ![]() |
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
, theJCEncodeComponent 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; theencoding
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 theoutput
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 theJCChart
object totrue
. Property changes do not cause a repaint untilBatched
is reset tofalse
.The
Batched
property is also defined for theChartDataView
object. ThisBatched
property is independent ofJCChart.Batched
. It is used to control the update requests sent from theDataSource
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:
- Convert from data coordinates (x and Y-data values) to pixel coordinates (where these data coordinates appear on screen) and vice versa.
- Determine the pixel coordinates of a given data point in a series, or the closest point to a given set of pixel coordinates.
The following table outlines which method or functional equivalent to use for each action.
Method
Functional equivalent
Action
Determines the pixel coordinates of a given data point in a series
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
Point p=c.getDataView(0).dataCoordToCoord(5.1,10.2);dataCoordToCoord()
method. For example, the following code obtains the pixel coordinates corresponding to the data coordinates (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 theJCChart
component display.To convert from pixel coordinates to data coordinates, call
JCDataCoord cd=c.getDataView(0).coordToDataCoord(225,92);coordToDataCoord()
. For example, the following converts the pixel coordinates (225, 92) to their equivalent data coordinates:This works in the same manner as
map
. So,coordToDataCoord()
returns aJCDataCoord
object containing the X- and Y-values in the data space.To determine the pixel coordinates of a given data point, call
JCDataIndex di=new JCDataIndex(3,c.getDataView(0).getSeries(0));dataIndexToCoord()
. For example, the following code obtains the pixel coordinates of the third point in the first data series:
Point cdc=c.getDataView(0).dataIndexToCoord(di);To determine the closest data point to a set of pixel coordinates, call
JCDataIndex di=c.getDataView(0).coordToDataIndex(225,92,ChartDataView.PICK_FOCUSXY);coordToDataIndex()
:Essentially, these last two examples demonstrate that
dataIndexToCoord()
works in much the same way aspick
andunpick
. The third argument passed tocoordToDataIndex()
specifies how the nearest series and point value are determined. This argument can be one ofChartDataView.PICK_FOCUSXY
,ChartDataView.PICK_FOCUSX
, orChartDataView.PICK_FOCUSY
. For more information on thepick
andunpick
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 aJCDataIndex
instance.
10.3.2 Map and Unmap
map
andunmap
are functionally equivalent to thecoordToDataCoord()
anddataIndexToCoord()
methods. They are provided as convenience methods, and are more in keeping with typical Java terminology thancoordToDataCoord()
anddataIndexToCoord()
.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 isfalse
.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
c.getChartArea().setFastAction(true);FastAction
can be used in a program:
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
c.getDataView(0).setFastUpdate(true);FastUpdate
can be used in a program: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 aJPopupMenu
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:
- moving the chart
- zooming into or out of the chart
- rotation (only for bar or pie charts displaying a 3D effect)
- adding depth cues to the chart
- interactively change data points (using the pick feature)
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:
- the modifier, which specifies the combination of meta keys and mouse buttons that will trigger the action
- the action, which specifies the combination of chart action that will occur
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
c.setTrigger(0,newEventTrigger(Event.SHIFT_MASK,EventTrigger.ZOOM);0
) when Shift and mouse button are pressed:
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:
- Translation -
translateStart()
,translate()
,translateEnd()
- Rotation -
rotateStart()
,rotate()
,rotateEnd()
- Zoom -
zoomStart()
,zoom()
,zoomEnd()
- Scale -
scale()
- Reset -
reset()
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
ChartDataView arr = c.getDataView(0);HorizActionAxis
andVertActionAxis
properties ofJCChartArea
, as the following code fragment illustrates:
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 theVertActionAxis
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
inJCFillStyle
.Image
sets the image used to paint the fill region of bar charts. It takesimg
as a parameter, which is an AWTImage
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
String imageStrings[] = {"cd.gif", "tape.gif"};Image
can be incorporated into a program:
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 aPoint
object containing a pixel coordinate and an optionalChartDataView
object to check against, and returns the resulting data point encapsulated in aJCDataIndex
object.For
pick()
to work correctly, theJCChart
instance must first be laid out. This is automatically done whenever a chart is drawn, such as when thesnapshot()
method is called. Alternately, layout can be accomplished manually by called thedoLayout()
method ofJCChart
.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 isPICK_FOCUS_X
orPICK_FOCUS_Y
. To determine which of those points is the desired one, a secondary search is carried out using thePICK_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 forPICK_FOCUS_X
orPICK_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.
c.setTrigger(0, new EventTrigger(0, EventTrigger.PICK));
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.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. Thepick()
method returns aJCDataIndex
, 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 thePickFocus
property ofChartDataView
, which specifies how distance is determined for pick operations. When set toPICK_FOCUS_XY
(default), a pick operation will use the actual distance between the point and the drawn data. When set to values ofPICK_FOCUS_X
orPICK_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
arr.setPickFocus(ChartDataVies.PICK_FOCUS_X);PickFocus
and select the axis whose values are to be reported back to the program. For example, the following line of code setsPickFocus
to only report the X-coordinate of a pick event:
10.10 Unpick
The
unpick()
method essentially functions in the opposite manner ofpick
: 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, andseries
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, theJCChart
instance must first be laid out. This is automatically done whenever a chart is drawn, such as when thesnapshot()
method is called. Alternately, layout can be accomplished manually by calling thedoLayout()
method ofJCChart
.
![]() ![]() ![]() |