Chapter 15. Programming Using the BIRT Charting API

This chapter describes the basic requirements of a charting application and demonstrates how to use the BIRT charting API to create a new chart and modify an existing chart definition. The BIRT chart engine provides the BIRT charting API. Classes and interfaces in this API support:

• Writing Java applications to generate many types of charts, such as bar charts, line charts, pie charts, scatter charts, and stock charts.

• Customizing the properties of a chart to fit the users’ requirements.

• Modifying an existing chart item in a BIRT report design or adding a chart to an existing report design.

This chapter shows how to customize an existing chart and create a new chart within a BIRT application. Use of the charting API in a stand-alone application is beyond the scope of this book. For examples of completed charting applications, download the BIRT samples from the BIRT web site.

This chapter discusses only the most important of the more than 400 classes and interfaces in the BIRT charting API. For information about the complete set of charting API classes and interfaces, see the online Javadoc. To view the Javadoc, open the online help and navigate to BIRT Charting Programmer Reference→Reference→API Reference.

About the chart engine contents

Downloading and extracting the chart engine archive file from the Eclipse BIRT download page creates the following three folders:

• ChartRuntime, which contains the Eclipse plug-ins required to run, render, and edit charts

• ChartSDK, which contains everything you need to create charting applications, including the following components:

• All the chart run-time plug-ins and an example plug-in providing sample charting applications including a chart viewer

• Documentation in the form of online help, context-sensitive help for the user interface components, and Javadoc for the charting API

• Source code for all the BIRT chart engine packages

• DeploymentRuntime, which contains the JAR files that you need to run a charting application outside Eclipse

About the environment for a charting application

The minimum requirements for creating a basic charting application are:

• The BIRT charting run-time engine

• The BIRT run-time engine, for an application that runs within the BIRT report context

• Java Development Kit 1.5.0 or later

• Deployment Java archive (.jar) files

To develop or run a Java application that incorporates a BIRT chart, you need to include certain JAR files in the Java CLASSPATH. To be certain that the CLASSPATH includes all the JAR files your application needs, include the following files in the CLASSPATH:

• All the JAR files in DeploymentRuntime/ChartEngine

• Any custom extension plug-in JAR files that you use

Typically, a charting application does not use the functionality from every JAR file in the ChartEngine folder, but having extra JAR files in the CLASSPATH does not affect the performance or size of an application, so the easiest technique is to include them all.

Configuring the chart engine run-time environment

An application using the BIRT chart engine can run either in the context of the BIRT report engine or as a stand-alone application. To deploy charts in a BIRT report, use the BIRT report engine. A stand-alone application does not use the BIRT report engine. Either application produces and consumes charts within itself or passes the chart structure and data to another application. To configure the BIRT chart engine environment, set one and only one of the following two system environment variables:

• STANDALONE

Create this variable if the application has no need for any extension plug-ins. The variable does not require a value.

• BIRT_HOME

Create this variable if the application requires the BIRT chart extension plug-ins. Set the value to the directory containing the BIRT report engine plug-ins.

You can set whichever of these two environment variables you need on the command that runs the application. For example, to set the STANDALONE variable, use a command similar to the following one:

java -DSTANDALONE ChartingAp

If running this command produces an error about an inability to load OSGi, the application is not stand-alone. Instead it requires the BIRT_HOME variable to be set to the location of the run-time engine folder. Use a command line argument similar to the following one to set the variable:

-DBIRT_HOME="C:/birt-runtime-2_6_0/ReportEngine"

To test a charting application in the Eclipse workbench, set these variables in Run→Open Run Dialog→Java Application→Arguments→VM Arguments.

Verifying the environment for a charting application

Listing 15-1 illustrates the most basic charting application it is possible to write. The output of this program is a file called myChart.chart, which contains several hundred lines of XML code. This code defines a basic chart with no data, no labels, no series, and no titles. Although this output does not represent a useful chart, compiling and running the program verifies that the environment is configured correctly for a charting application.

Listing 15-1 Basic charting application


import java.io.*;
import org.eclipse.birt.chart.model.*;
import org.eclipse.birt.chart.model.impl.*;

public class MyFirstChartProg {

   public static void main( String[ ] args ) {
      Chart myChart = ChartWithAxesImpl.create( );
      Serializer si = SerializerImpl.instance( );
      try {
         si.write( myChart, new FileOutputStream( new File
            ( "C:\myChart.chart" ) ) );
      } catch ( IOException e ) { e.printStackTrace( ); }
   }
}

About the charting API and the chart structure

The chart element in a report design extends the basic BIRT report item through the org.eclipse.birt.report.model.api.ExtendedItemHandle class, so supports the same standard properties and functionality as all other report items. To access the chart item using the design engine API, call the ExtendedItemHandle.getProperty( ) method with an argument of chart.instance. This call returns an org.eclipse.birt.chart.model.Chart object. All chart types implement this interface through one of the classes, ChartWithAxesImpl, ChartWithoutAxesImpl, and DialChartImpl from the org.eclipse.birt.chart.model.impl package. Cast the Chart object to the appropriate class to change its properties.

ChartWithAxesImpl is the most commonly used chart class. This class supports area, bar, bubble, cone, difference, Gantt, line, pyramid, scatter, stock, and tube charts. ChartWithoutAxesImpl supports pie and radar charts. DialChartImpl supports meter charts. Many of these chart types provide subtypes. For example, a bar chart has stacked, percent stacked, and side-by-side subtypes that affect the appearance of a multi-series bar chart.

About chart visual components

The key visual components of a chart are moveable areas known as blocks that are defined by the interface org.eclipse.birt.chart.model.layout.Block. Blocks include the plot, title, and legend areas. A charting application can change the location of the title and legend areas with respect to the plot area.

About chart data

The key data component of a chart is the series. The series controls the set of values to plot and how to group those values. Charts display the values from series as data points in a chart with axes and as slices or pointers in a chart without axes. A charting application can define series values statically as a data set or dynamically as a query. The chart engine also provides extension points to support custom data set types.

Understanding static data

The chart engine requires placing all data in an object that implements the chart org.eclipse.birt.chart.model.data.DataSet interface before generating the chart. The following interfaces in the org.eclipse.birt.chart.model.data .impl package extend the DataSet interface:

• BubbleDataSet

• DateTimeDataSet

• DifferenceDataSet

• GanttDataSet

• NumberDataSet

• StockDataSet

• TextDataSet

Each interface has a corresponding implementation class that supplies a static create method to initialize a data structure. For example, the following code creates a static NumberDataSet for a series in a chart:

NumberDataSet seriesOneValues =
   NumberDataSetImpl.create( new double[ ]{ 15, 23, 55, 76 } );

The chart engine does not support sorting or grouping on a static data set. A chart displays one data point for every value in a static data set in the order provided.

Understanding dynamic data

The chart engine supports sourcing data from a dynamic source, which includes BIRT data sets and java.sqlResultSet objects. In these cases, the binding phase generates the chart data sets based on the expressions defined in the model for each series in the chart. After completing this phase, each Chart series binds to one of the chart data sets listed in the static data section.

A series is a set of plotted values in a chart. BIRT uses a series definition object to define what data a series contains. For example, row["month"] populates a series with the month column from a BIRT data set bound to a chart. This series definition object results in a run-time series that is bound to a supported chart data set type when the chart generates.

BIRT also supports defining groups and sorting in a series definition. When using these features, BIRT creates additional run time series as necessary, each with its own chart data set.

For example, if a BIRT report contains a data set having three columns, such as the product name, amount sold, and month sold, you can create a bar chart to display the data. The category series contains the product and the value series contains the amount. Using the category series as the x-axis and the value series as the y-axis, the chart model produces two run-time series when generating the chart. You can add the month to the y-axis series to group the data and produce multiple run-time series. The category series and the value series can contain up to twelve run-time series, one for each month.

All run-time series for a chart must have the same number of data points. To get the run-time series for a series, call the getRunTimeSeries( ) method for the specific series definition. Listing 15-2 gets a run-time series and sets the first bar series to have a riser type of triangle.

Some chart types use nested SeriesDefinitions objects. For example, a pie chart creates a top-level series definition that stores category series information. This top-level series definition also contains another nested series definition that stores the information for the value series.

Listing 15-2 Getting a run-time series


function beforeGeneration( chart, icsc )
{
   importPackage(
      Packages.org.eclipse.birt.chart.model.attribute );

   var xAxis = chart.getBaseAxes( )[0];
   var yAxis = chart.getOrthogonalAxes( xAxis, true )[0]
   var seriesDef = yAxis.getSeriesDefinitions( ).get( 0 )
   var runSeries = seriesDef.getRunTimeSeries( );
   var firstRunSeries = runSeries.get( 0 );
   firstRunSeries.setRiser( RiserType.TRIANGLE_LITERAL );
}

Using the charting API to create a new chart

To create a chart instance object for use in a stand-alone application or a report design, use a static method of one of the chart implementation classes. Depending on which chart implementation object you use, you can either create a chart with or without axes. The following line of code creates a chart with axes:

ChartWithAxes newChart = ChartWithAxesImpl.create( );

Modifying chart properties

Each of the available chart implementations provides a set of properties. The properties of the chart define everything about a stand-alone chart. Chart properties do not define the integration of a chart object into a chart element in a report design, such as binding a data set to a chart and a chart’s ultimate display size. A section later in this chapter describes how to set up a chart as an element in a report design.

The BIRT chart engine API supports changing chart properties. All charts have the properties that the Chart interface provides, such as dimension, which sets the appearance of the chart as two-dimensional, two-dimensional with depth, or three-dimensional, and plot, which is the area that contains the chart itself.

The ChartWithAxesImpl class implements the ChartWithAxes interface, which provides properties related to x-, y-, and for some chart types, z-axes.

The ChartWithoutAxesImpl class implements the ChartWithoutAxes interface, which provides properties for pie slices. The DialChartImpl class implements the ChartWithoutAxes and DialChart interfaces. DialChart supports the superimposition property that meter charts use.

Each interface provides getter and setter methods for its properties, and other methods if necessary. For example, for the dimension property, the Chart interface provides getDimension( ), setDimension( ), isSetDimension( ), and unsetDimension( ) methods.

Understanding simple and complex properties

Some properties, like dimension, are simple properties that take a single value. Some simple properties accept a restricted set of values that the class defines as static fields. Use the Javadoc to find these values.

Other properties, such as a chart’s plot or title are complex. A getter method for a complex property returns an object. For example, the Chart.getTitle( ) method returns an org.eclipse.birt.chart.model.layout.TitleBlock object. The chart interfaces do not provide setter methods for complex properties. When code changes the properties of a complex property, the changes take effect on the chart immediately.

Some properties, such as the horizontal spacing of elements within a plot, use values based on the current units of measurement. Call the Chart.setUnits( ) method to set the units that you prefer.

Listing 15-3 shows how to set simple and complex properties and the units of measurement.

Listing 15-3 Getting and setting chart properties


// Simple properties
// Set a chart's appearance to two-dimensional
chart.setDimension( ChartDimension.TWO_DIMENSIONAL_LITERAL );

// Set the units of measurement for the chart
chart.setUnits( UnitsOfMeasurement.PIXELS_LITERAL.getLiteral( ) );

// Complex properties
// Set the chart's title
chart.getTitle( ).getLabel( ).getCaption( ).setValue( "Europe" );
// Rotate the text in the chart's title
chart.getTitle( ).getLabel( ).getCaption( ).getFont( )
   .setRotation( 5 );

// Set chart block properties
chart.getBlock( ).setBackground( ColorDefinitionImpl.WHITE( ));
chart.getBlock( ).setBounds( BoundsImpl.create( 0, 0, 400, 250 ));

Setting plot properties

All charts have a plot property, which specifies the area in a Chart object that contains the chart itself. The plot is an object that implements the org.eclipse .birt.chart.model.layout.Plot interface. Plot defines horizontal and vertical spacing and the client area, which contains the rendering of the chart. The client area is itself a complex property that defines properties such as the background color and outline of the rendered chart. Plot provides all the properties defined by the Block interface in the same package, such as the background and outline. When setting values for a property that multiple components provide, determine the best class on which to modify the property based on the characteristics of all the classes.

To set properties of the plot, first get a Plot object from the chart instance object. Then, use a setter method of a component of the Plot object. Listing 15-4 illustrates how to get the chart plot and modify its properties.

Listing 15-4 Getting chart plot and modifying its properties


Plot plot = chart.getPlot( );
plot.getClientArea().setBackground( ColorDefinitionImpl.CREAM( ));
plot.setHorizontalSpacing( plot.getHorizontalSpacing( ) + 10 );
plot.getOutline( ).setVisible( true );

Setting legend properties

All charts have a legend property, which is the area in a Chart object that contains the chart legend. For a chart without axes, the legend identifies the slices on a pie chart or pointers on a meter chart. For a chart with axes, the legend identifies the series that display values on the x-axis. For a chart with multiple y-series, the legend displays separate sections for each series. Typically, if there is only one x-axis group and one y-series, do not make the legend visible.

The legend is an object that implements the org.eclipse.birt.chart.model .layout.Legend interface, which extends the Block interface. Legend provides all the Block properties, plus properties specific to Legend, such as position, title, text, and values. The default position of the legend is to the right of the plot area. Within this position, change the location of the legend by setting its anchor property.

To set properties of the chart legend, first get a Legend object from the chart instance object. Then, use a setter method of a component of the Legend object. To set properties of legend lines, use a LineAttribute object from the Legend object. Listing 15-5 illustrates how to get the chart legend and modify its properties.

Listing 15-5 Getting and setting legend properties


Legend legend = chart.getLegend( );
legend.getText( ).getFont( ).setSize( 16 );
legend.getInsets( ).set( 10, 5, 0, 0 );
legend.setAnchor( Anchor.NORTH_LITERAL );

// Set the attributes of the legend's outline
legend.getOutline( ).setVisible( false );
LineAttributes lia = legend.getOutline( );
lia.setStyle( LineStyle.SOLID_LITERAL );

Setting axes properties

A chart with axes always has at least two axes, the primary base axis and the axis orthogonal to the base axis. A primary base axis is a category axis, which displays values of any data type and is typically an x-axis. A chart can have more than one primary base axis. Every base axis has at least one axis that is orthogonal to it. An orthogonal axis is a value axis, which displays numeric values and is typically a y-axis.

The org.eclipse.birt.chart.model.component.Axis interface supports both category and value axes.

To set the properties of one or more axes of a chart, cast the Chart object to a type of ChartWithAxes, as shown in the following statement:

cwaChart = ( ChartWithAxes ) chart;

To access a category axis, call the ChartWithAxes.getPrimaryBaseAxes( ) method. This method returns an array. If there is only one primary base axis, get the first element of the array, as shown in the following code:

Axis xAxisPrimary = newChart.getPrimaryBaseAxes( )[0];

To access the value axis for a single value-axis chart, call the method, getPrimaryOrthogonalAxis( ). For a chart having multiple value axes, access the list of axes by calling getOrthogonalAxes( ).

Listing 15-6 illustrates the technique for getting the axes of a chart and setting their properties.

Listing 15-6 Getting category and value axes and setting their properties


Axis xAxisPrimary = cwaChart.getPrimaryBaseAxes( )[0];
xAxisPrimary.getLabel( ).getCaption( ).getFont( ).setRotation(45);
xAxisPrimary.setType( AxisType.TEXT_LITERAL );
xAxisPrimary.getMajorGrid().setTickStyle(TickStyle.BELOW_LITERAL);
xAxisPrimary.getOrigin( ).setType(IntersectionType.VALUE_LITERAL);
xAxisPrimary.getTitle( ).setVisible( false );

Axis yAxisPrimary =
   cwaChart.getPrimaryOrthogonalAxis( xAxisPrimary );
yAxisPrimary.getMajorGrid( ).setTickStyle(TickStyle.LEFT_LITERAL);
yAxisPrimary.setType( AxisType.LINEAR_LITERAL );
yAxisPrimary.getScale( ).setMax( NumberDataElementImpl.create
   ( 1000 ) );
yAxisPrimary.getScale( ).setMin( NumberDataElementImpl.create(0));
yAxisPrimary.getTitle( ).getCaption( ).setValue( "Sales Growth" );
yAxisPrimary.setFormatSpecifier
   ( JavaNumberFormatSpecifierImpl.create( "$" ) );

Using series

All charts use series to define the data values to represent. Series objects contain a list of values to plot on the chart. To instantiate a Series object, call the static create( ) method on org.eclipse.birt.chart.model.component.impl .SeriesImpl. Define the set of values for a series either with a dynamic query that accesses an external data source or with a static data set that is a list of values. A query on the series definition object supports grouping and sorting of the data.

The series for an x-axis or for the values that control the number of sectors in a pie can contain non-numeric data values, such as dates or text values. For example, these series can contain the quarters in a range of years, or product codes or countries.

The series for a y-axis or for the values that control the size of the sectors in a pie chart must hold numeric values. These series are implementations of specific subinterfaces of the Series interface. Each chart type uses its own series type, to control the chart represents the values. For example, a BarSeries object has riser and riser outline properties to control the appearance of the bars.

Series definition objects provide access to the series objects for the chart and standard properties such as the palette of colors in which to display pie sectors, bars, and other markers. To instantiate a SeriesDefinition object, call the static org.eclipse.birt.chart.model.data.impl.SeriesDefinitionImpl.create( ) method. To add a series to a series definition, get the collection of series and add the series to that collection. To set the color of a series, get a SeriesPalette object and call its shift( ) method.

A series definition supports multiple series. The series do not all have to be the same type. For example, a line chart can use the same axes as a bar chart. Typically, a chart displays extra series on a y-axis, not on an x-axis.

Listing 15-7 illustrates how to get a series definition from an axis and how to change a property of the series.

Listing 15-7 Getting a series definition and setting a property


SeriesDefinition seriesDefX = SeriesDefinitionImpl.create( );
seriesDefX = ( SeriesDefinition )
   xAxisPrimary.getSeriesDefinitions( ).get( 0 );
seriesDefX.getSeriesPalette( ).shift( 1 );

Adding a series to a chart

To display values on a chart, add category and value series to a newly created chart or modify the series on an existing chart. For a chart with axes, associate series with both category and value axes.

Creating a category series

On a chart with axes, the category series is the set of values that the category axis displays. On a chart without axes, the category series defines the number of sectors in a pie chart or the number of pointers on a meter chart. To create a category series, use the static create( ) method of the SeriesImpl class, as shown in the following line:

Series seriesCategory = SeriesImpl.create( );

Creating an orthogonal series

The orthogonal series specifies the representation of the values in the value series. On a chart with axes, the orthogonal series is the set of values that display on the y-axis, for example, appearing as bars, bubbles, stock barsticks or candle-sticks. On a chart without axes, the orthogonal series sets the size of slices in a pie or the position of a pointer on a meter chart. A chart can have multiple orthogonal series of the same or differing types.

The orthogonal series classes are subclasses of the SeriesImpl class, and are located in the org.eclipse.birt.chart.model.type.impl package. The following classes are available:

• AreaSeriesImpl

• BarSeriesImpl

• BubbleSeriesImpl

• DialSeriesImpl

• DifferenceSeriesImpl

• GanttSeriesImpl

• LineSeriesImpl

• PieSeriesImpl

• ScatterSeriesImpl

• StockSeriesImpl

The BarSeriesImpl class supports bar, cone, pyramid, and tube chart types.

To create an orthogonal series, use the static create( ) method of the series class. The following line shows an example of creating a bar series:

BarSeries barSeries2 = ( BarSeries ) BarSeriesImpl.create( );

Setting series properties

A category series supports only the properties defined by the SeriesImpl class. A value series supports additional properties defined by the relevant subclass of SeriesImpl. For example, a bar series supports bar stacking and outlines on the risers. A pie series supports slice outlines and exploded slices.

To set the properties of a series, use getter and setter methods of the appropriate series objects, as shown in Listing 15-8, which sets properties on BarSeries and LineSeries objects.

Listing 15-8 Setting the properties of a bar series and line series


LineSeries ls1 = ( LineSeries ) LineSeriesImpl.create( );
ls1.getLineAttributes( ).setColor( ColorDefinitionImpl.RED( ) );
BarSeries bs1 = ( BarSeries ) BarSeriesImpl.create( );
bs1.getLabel( ).setVisible( true );
bs1.getLabel( ).getCaption( ).setValue( "Q2" );

Associating data with a series

Create either a query or a data set, and add that object to the series data definition. To create a query, use the static create( ) method of the org.eclipse.birt.chart.model.data.impl.QueryImpl class. To create a data set, use the static create( ) method on a subclass of DataSetImpl. The data set type must match the type of values that the axis displays. For example, a category axis displaying date-and-time data values requires a data set of class DateTimeDataSet. Similarly, a bar series requires a numeric data set, of class NumberDataSet. Some series require multiple sets of data. For example, a stock series requires four sets of data, high, low, open, and close. Either add four queries in that order to the series, or add a StockDataSet to the series. Listing 15-9 adds queries and data sets to line, bar, and stock series.

Listing 15-9 Setting a query and a data set on category series


// Setting a query on a category series
Series seriesCategory = SeriesImpl.create( );
Query query = QueryImpl.create( "row["CATEGORY"]" );
seriesCategory.getDataDefinition( ).add( query );

// Setting a data set on a category series
Series seBase = SeriesImpl.create( );
DateTimeDataSet dsDateValues =
   DateTimeDataSetImpl.create( new Calendar[ ]{
   new CDateTime( 2011, 12, 21 ),
   new CDateTime( 2011, 12, 20 ),
   new CDateTime( 2011, 12, 19 ),
   new CDateTime( 2011, 12, 18 ),
} );
seBase.setDataSet( dsDateValues );

Listing 15-10 illustrates how to create a second value series, set some of its properties, assign data to the series, and add the series to an axis.

Listing 15-10 Creating a series, setting properties, and adding it to an axis


SeriesDefinition seriesDefY = SeriesDefinitionImpl.create( );
seriesDefY.getSeriesPalette( ).update( ColorDefinitionImpl
   .YELLOW( ) );
BarSeries barSeries2 = ( BarSeries ) BarSeriesImpl.create( );
barSeries2.setSeriesIdentifier( "Q2" );
barSeries2.setRiserOutline( null );
barSeries2.getLabel( ).setVisible( true );
barSeries2.setLabelPosition( Position.INSIDE_LITERAL );

// Assign data to the series
Query query2 = QueryImpl.create( "row["VALUE2"]" );
barSeries2.getDataDefinition( ).add( query2 );
seriesDefY.getSeries( ).add( barSeries2 );
// Add the new series to the y-axis
yAxisPrimary.getSeriesDefinitions( ).add( seriesDefY );

Adding a series definition to a chart

After setting the properties of a SeriesDefinition object, add the object to the chart. For a chart without axes, add the series definitions directly to the chart object’s collection of series definitions. The first series definition in the collection defines the category series and the second one defines the orthogonal series. For a chart with axes, add the series definition to each Axis object’s collection of series definitions as shown in Listing 15-11.

Listing 15-11 Adding series definitions to a pie chart and a chart with axes


ChartWithoutAxes cwoaPie = ChartWithoutAxesImpl.create( );
cwoaPie.getSeriesDefinitions( ).add( sd );
PieSeries sePie = ( PieSeries ) PieSeriesImpl.create( );
sePie.setDataSet( seriesOneValues );
sePie.setSeriesIdentifier( "Cities" );
sd.getSeriesDefinitions( ).add( sdCity );

xAxisPrimary.getSeriesDefinitions( ).add( sdX );
yAxisPrimary.getSeriesDefinitions( ).add( sdY1 );
yAxisPrimary.getSeriesDefinitions( ).add( sdY2 );

Setting up the default aggregation for the chart

A chart plots every value that it receives unless an org.eclipse.birt.chart .model.data.SeriesGrouping object defines the type of aggregation to perform. Set up aggregation on the category series to define the value on which to aggregate and the type of aggregation, as shown in Listing 15-12. The chart builder user interface displays the available aggregation types. All orthogonal series use the aggregation type specified by the category series grouping by default.

Listing 15-12 Defining aggregation on the category series


SeriesGrouping grouping = sdX.getGrouping( );
grouping.setEnabled( true );
grouping.setGroupType( DataType.TEXT_LITERAL );
grouping.setGroupingUnit( GroupingUnitType.STRING_LITERAL );
grouping.setGroupingInterval( 0 );
grouping.setAggregateExpression( "Sum" );

Changing the aggregation for secondary value series

Every value series uses the same aggregation expression to aggregates values to display unless the application changes the aggregation by setting up a SeriesGrouping specific to the series. Change only the grouping properties that differ from the default grouping, as shown in Listing 15-13.

Listing 15-13 Defining aggregation on a value series


SeriesGrouping groupingY2 = sdY2.getGrouping( );
groupingY2.setEnabled( true );
groupingY2.setAggregateExpression( "Average" );$

Adding a chart event handler

Two kinds of chart event handlers are available to a charting application: a Java event handler or a JavaScript event handler.

Adding a Java chart event handler

To add a Java event handler, create a separate Java class file containing the event handler method or methods. The process for creating a Java event handler class is identical to the process for creating a Java event handler class for any other report item, as described in the chapters on scripting with Java and scripting for charts. The class must include a function for every event handler method of the chart.

To register a Java class in the charting application code, use the setScript( ) method of the chart instance object, as shown in the following statement:

chart.setScript
   ( "com.MyCompany.eventHandlers.ChartEventHandlers" );

The string argument passed to the setScript( ) method is the fully qualified name of the Java class. Do not include the .class extension in the class name.

Adding a JavaScript chart event handler

To add a JavaScript event handler, code the script as one long string and pass that string to the setScript( ) method of the chart instance object. For example, the statement in Listing 15-14 passes a string to chart.setScript( ) containing event handler script for the beforeDrawDataPointLabel event handler. Line breaks in the JavaScript code are indicated by backslash n ( ), and quotes within the script are indicated by a backslash quote ( " ). The JavaScript code consists of several strings concatenated together to form a single string. This technique helps make the script more readable.

Listing 15-14 Adding an event handler script to a bar chart


cwaBar.setScript ( "function beforeDrawDataPointLabel"
   + "(dataPoints, label, scriptContext)"
   + "{val = dataPoints.getOrthogonalValue( );"
   +    "clr = label.getCaption( ).getColor( );"
   +    "if ( val < -10 ) clr.set( 32, 168, 255 );"
   +    "else if ( ( val >= -10 ) & ( val <=10 ) )"
   +    "clr.set( 168, 0, 208 );"
   +    "else if ( val > 10 ) clr.set( 0, 208, 32 );}")

Using a chart item in a report design

A Java program can open an existing BIRT report design file and alter the content of the report before displaying or saving the report. The chapter on programming BIRT describes how to open a report design file using the BIRT engine and model APIs. This section describes how to use the BIRT charting API to modify an existing chart element in the report design and to create a new chart element. The following sections contain code examples for each step in the process.

Accessing an existing chart item

To get a chart report item from a report design, first perform the following steps using the BIRT core and model APIs, as described earlier in this book:

• On a DesignConfig object, set the BIRT home property to the directory that contains the report engine.

• Start the platform using the configuration object, a design engine factory, and a design engine.

• Use the design engine to create a session handle object.

• Create a design handle object for a report design from the session handle.

• Use the design handle object to access the chart element in the design.

Next, retrieve a Chart object from the chart item. This Chart object supports accessing the BIRT chart engine classes and using BIRT’s charting API.

Listing 15-15 illustrates the process of getting a chart report item. This code assumes that the chart is the first report item in a list and that the list is the first report item in the report.

Listing 15-15 Getting a ReportDesignHandle object and a Chart object


DesignConfig dConfig = new DesignConfig( );
dConfig.setBIRTHome( "C:/birt-runtime-2_6_0/ReportEngine" );
IDesignEngine dEngine = null;
ReportDesignHandle dHandle = null;

try {
   Platform.startup( dConfig );
   IDesignEngineFactory dFactory = ( IDesignEngineFactory )
      Platform. createFactoryObject( IDesignEngineFactory.
      EXTENSION_DESIGN_ENGINE_FACTORY );
   dEngine = dFactory.createDesignEngine( dConfig );
   SessionHandle sessionHandle =
      dEngine.newSessionHandle( ULocale.ENGLISH );
   dHandle = sessionHandle.openDesign( reportName );
} catch ( BirtException e ) {
   e.printStackTrace( );
   return;
}
ListHandle li = ( ListHandle )
   dHandle.getBody( ).getContents( ).get( 0 );
ExtendedItemHandle eihChart1 = ( ExtendedItemHandle )
   li.getSlot( 0 ).getContents( ).get( 0 );
Chart chart = ( Chart ) eihChart1.getProperty( "chart.instance" );

Creating a new chart item

Before creating a new chart item in a report design, a charting application performs all the steps to start up the platform and design engine, as described in the previous section. Next, the application creates the Chart object as described earlier in this chapter. Creating a new chart object for use in a report design is identical to creating a chart for a stand-alone application. Finally, the application creates a chart element and sets up the properties required to link the chart object to the element by performing the following tasks. These tasks relate to the appearance and behavior of a chart inside a report design. If the chart is not deployed in a report, the tasks in this section are not required.

• Getting an ElementFactory object

The ElementFactory object supports creating a new report element.

• Setting the chart type and creating sample data

The chart type and sample data provide a guide to the appearance of a chart element in a report design in BIRT Report Designer.

• Getting an ExtendedItemHandle object

The ExtendedItemHandle object is similar to a standard report item handle. The item handle associates the chart object with the report item instance in the report design. The handle is also the object that binds to a data set.

• Setting the chart.instance property on the report item

The chart.instance property of the report item identifies the chart instance object and links the report item to the chart instance object.

• Getting a data set from the report design

A chart must bind to data in order to have meaning. The report design provides access to one or more data sets that the report developer defined. The program can create a data set and add it to the design.

• Binding a chart to the data set

To bind a chart to a data set, specify the data set as a property of the extended item handle object.

• Setting any other report item properties

• Adding the new chart to the report design

The last step is to add the chart to the report design by adding the extended item handle object to the report design.

• Optionally saving the report design

An application program that creates or modifies a BIRT report design can save the new or modified report design.

The following sections describe these tasks in more detail and provide code examples for every step.

Getting a design engine element factory object

Creating a chart item in a report design requires an ElementFactory object. To get an ElementFactory object, use the getElementFactory( ) method of the ReportDesignHandle object, as shown in the following line of code:

ElementFactory ef = dHandle.getElementFactory( );

The chapter on programming with the BIRT APIs provides more information about using the Design Engine APIs and how to place a new item in a report design.

Setting the chart type and subtype

A chart’s type and subtype determine the appearance of the chart in BIRT Report Designer. In conjunction with sample data, these properties provide a realistic rendering of the chart item in the report design’s layout window and in the chart wizard. To ensure that the appearance of this rendered chart is as accurate as possible, set the chart’s type so that it matches the series type set on the axis. Many types, such as bar, Gantt, line, and stock, are available for a chart with axes. Charts without axes can be dial, pie, or radar types only.

The bubble, dial, difference, Gantt, and pie classes each support only a single type. The other chart types have multiple subtypes. Set the chart type and subtype by using the Chart methods setType( ) and setSubType( ) respectively. These methods take a single String argument. Table 15-1 shows the available values for chart types and the valid subtypes for each chart type. Because cone, pyramid, and tube charts are merely different representations of a bar chart, they have the same subtypes as a bar chart.

Table 15-1 Chart type and subtype properties

image

image

Listing 15-16 shows how to set a chart type and subtype:

Listing 15-16 Setting a chart’s type and subtype


ChartWithAxes cwaBar = ChartWithAxesImpl.create( );
cwaBar.setType( "Bar Chart" );
cwaBar.setSubType( "Side-by-side" );

Creating sample data

This section describes an optional step in the creation of a chart. Sample data provides visual information in BIRT Report Designer about a chart’s appearance. If you omit the code in Listing 15-17, the chart renders correctly when the report generates, but the designer’s layout window does not display sample values.

Listing 15-17 Adding sample data to a chart


SampleData sdt = DataFactory.eINSTANCE.createSampleData( );
BaseSampleData sdBase =
   DataFactory.eINSTANCE.createBaseSampleData( );
sdBase.setDataSetRepresentation( "A" );
sdt.getBaseSampleData( ).add( sdBase );

OrthogonalSampleData sdOrthogonal =
  DataFactory.eINSTANCE.createOrthogonalSampleData( );
sdOrthogonal.setDataSetRepresentation( "1" );
sdOrthogonal.setSeriesDefinitionIndex( 0 );
sdt.getOrthogonalSampleData( ).add( sdOrthogonal );
newChart.setSampleData( sdt );

Getting an extended item handle object

A chart report item extends from the design engine’s ReportItemHandle class by further extending the ExtendedItemHandle class. Use the ElementFactory object to create this object by using the newExtendedItem( ) method of the ElementFactory object, as shown in the following line of code:

ExtendedItemHandle chartHandle =
   ef.newExtendedItem( null, "Chart" );

Setting up the report item as a chart

Set the chart.instance property of the report item object to contain the chart instance object. Get the report item from the extended item handle object, as shown in Listing 15-18.

Listing 15-18 Associating a chart object with an extended item handle


ExtendedItemHandle chartHandle =
   ef.newExtendedItem( null, "Chart" );

try {
   chartHandle.getReportItem( ).setProperty
      ( "chart.instance", newChart );
} catch( ExtendedElementException e ) {
   e.printStackTrace( );
}

Preparing a data set and data columns

The new chart item still does not have access to data from the report design. The chart item uses data rows from a data set and column bindings that define how to apply values from data set columns to the chart. The names of the column bindings must match the column names used in the chart’s series objects.

To access a data set, create a data set or get an existing data set from the report design. Next, set up the columns to bind to the chart by instantiating org.eclipse.birt.report.model.api.elements.structures.ComputedColumn objects. A ComputedColumn object contains an expression that accesses columns from a data set. The code in Listing 15-19 gets the first data set in the report design.

Listing 15-19 Accessing a data set and preparing columns


DataSetHandle dataSet =
   ( DataSetHandle ) dHandle.getDataSets( ).get( 0 );
ComputedColumn col1 = StructureFactory.createComputedColumn( );
col1.setName( "VALUE1" );
col1.setExpression( "dataSetRow["QUANTITYORDERED"]") ;
col1.setDataType(
   DesignChoiceConstants.COLUMN_DATA_TYPE_INTEGER );
ComputedColumn col2 = StructureFactory.createComputedColumn( );
col2.setName( "VALUE2" );
col2.setExpression( "dataSetRow["PRICEEACH"]" );
col2.setDataType( DesignChoiceConstants.COLUMN_DATA_TYPE_FLOAT );
ComputedColumn col3 = StructureFactory.createComputedColumn( );
col3.setName( "CATEGORY" );
col3.setExpression( "dataSetRow["PRODUCTLINE"]");
col3.setDataType( DesignChoiceConstants.COLUMN_DATA_TYPE_STRING );

Binding the chart to the data set

Use the extended item handle to bind the chart to the data set and data columns, as shown in Listing 15-20.

Listing 15-20 Binding a data set and columns to the chart item


try {
   chartHandle.setDataSet( dataSet );
   extendedItemHandle.addColumnBinding( col1, true );

   extendedItemHandle.addColumnBinding( col2, true );
   extendedItemHandle.addColumnBinding( col3, true );
}
catch ( SemanticException e ) {
   e.printStackTrace( );
}

Set any other report item properties

The extended report item supports all the properties provided by the org.eclipse.birt.report.model.api.ReportItemHandle class. These properties include a bookmark, dimensions, and a theme. For example, to set the dimensions of the chart report item, use code as shown in Listing 15-21.

Listing 15-21 Setting chart item properties


try {
   extendedItemHandle.setHeight( "250pt" );
   extendedItemHandle.setWidth( "400pt" );
} catch ( SemanticException e ) {
   e.printStackTrace( );
}

Adding the new chart to the report design

After setting the properties of the chart and binding the chart to data, add the new chart to the report design. Listing 15-22 adds the chart item to the footer of an existing list item.

Listing 15-22 Adding the chart item to the report design


ListHandle li =
   ( ListHandle ) dHandle.getBody( ).getContents( ).get( 0 );
try {
   li.getFooter( ).add( chartHandle );
}
catch ( ContentException e3 ) { e3.printStackTrace( ); }
catch ( NameException e3 ) { e3.printStackTrace( ); }

Saving the report design after adding the chart

The report design file on disk does not yet contain the chart report item. Typically, you save the modified report design with a new name in order not to overwrite the original report design file.

try {
   dHandle.saveAs( "./Test_modified.rptdesign" );
}
catch ( IOException e ) { e.printStackTrace( ); }
dHandle.close( );

Putting it all together

The code in Listing 15-23 uses many of the techniques illustrated in this chapter in a complete Java application that creates a chart report item.

Listing 15-23 Adding a chart to the report design


import java.io.IOException;

import org.eclipse.birt.chart.model.ChartWithAxes;

import org.eclipse.birt.chart.model.attribute.Anchor;
import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.DataType;
import org.eclipse.birt.chart.model.attribute.GroupingUnitType;
import org.eclipse.birt.chart.model.attribute.IntersectionType;
import org.eclipse.birt.chart.model.attribute.LineAttributes;
import org.eclipse.birt.chart.model.attribute.LineStyle;
import org.eclipse.birt.chart.model.attribute.MarkerType;
import org.eclipse.birt.chart.model.attribute.TickStyle;

import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl
   .ColorDefinitionImpl;
import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;

import org.eclipse.birt.chart.model.component.impl.SeriesImpl;

import org.eclipse.birt.chart.model.data.BaseSampleData;
import org.eclipse.birt.chart.model.data.DataFactory;
import org.eclipse.birt.chart.model.data.OrthogonalSampleData;
import org.eclipse.birt.chart.model.data.Query;
import org.eclipse.birt.chart.model.data.SampleData;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.SeriesGrouping;

import org.eclipse.birt.chart.model.data.impl
   .NumberDataElementImpl;
import org.eclipse.birt.chart.model.data.impl.QueryImpl;
import org.eclipse.birt.chart.model.data.impl
   .SeriesDefinitionImpl;

import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;

import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.layout.Plot;

import org.eclipse.birt.chart.model.type.LineSeries;

import org.eclipse.birt.chart.model.type.impl.LineSeriesImpl;

import org.eclipse.birt.core.exception.BirtException;

import org.eclipse.birt.core.framework.Platform;

import org.eclipse.birt.report.engine.api.EngineConfig;

import org.eclipse.birt.report.model.api.DataSetHandle;
import org.eclipse.birt.report.model.api.DesignConfig;
import org.eclipse.birt.report.model.api.ElementFactory;
import org.eclipse.birt.report.model.api.ExtendedItemHandle;
import org.eclipse.birt.report.model.api.IDesignEngine;
import org.eclipse.birt.report.model.api.IDesignEngineFactory;
import org.eclipse.birt.report.model.api.ListHandle;
import org.eclipse.birt.report.model.api.PropertyHandle;
import org.eclipse.birt.report.model.api.ReportDesignHandle;
import org.eclipse.birt.report.model.api.SessionHandle;
import org.eclipse.birt.report.model.api.StructureFactory;
import org.eclipse.birt.report.model.api.activity
   .SemanticException;

import org.eclipse.birt.report.model.api.command.ContentException;
import org.eclipse.birt.report.model.api.command.NameException;

import org.eclipse.birt.report.model.api.elements
   .DesignChoiceConstants;
import org.eclipse.birt.report.model.api.elements.structures
   .ComputedColumn;
import org.eclipse.birt.report.model.api.extension
   .ExtendedElementException;
import org.eclipse.birt.report.model.api.extension.IReportItem;

import com.ibm.icu.util.ULocale;

/*************************************************************
 * Read a BIRT report design file, add a chart and write a
 * new report design file containing the added chart.
 * Run this application with the following command line:
 * java ChartReportApp origDesign modifiedDesign
 ************************************************************/

public class ChartReportApp
{
   private static String birtHome =
      "C:/birt-runtime-2_6_0/ReportEngine";
   private static String reportName = "./test.rptdesign";
   private static String newReportDesign = "./test_new.rptdesign";

   /************************************************************
   * Get the report design name and the name of the modified
   * report design from the command line if the command line has
   * any arguments.
   * Create an instance of this class, create a new chart,
   * write a new design file containing both the original and
   * the new chart
   *************************************************************/

   public static void main( String[ ] args )
   {
      if( args.length > 0 ) {
         reportName = args[0];
      }
      if( args.length > 1 ) {
         newReportDesign = args[1];
      }

      ReportDesignHandle dHandle = createDesignHandle(reportName);

      // create an instance of this class
      ChartReportApp cra = new ChartReportApp( );

      // Call the build method of this class.
      cra.build( dHandle, newReportDesign );
   }

   /********************************************************
    * The report design handle object is the entry point to
    * the report.

    * Create a report design handle object based on the
    * original design file by performing the following steps:

    * 1) Start the platform using the configuration object
    * 2) Create a design engine factory object from the platform
    * 3) Create a design engine using the factory object
    * 4) Create a session handle object from the design engine
    * 5) Create a design handle object from the session handle

    * The resulting design handle object is the entry point
    * to the report design and thus to the chart.
    *********************************************************/

   private static ReportDesignHandle createDesignHandle
      ( String reportName )
   {
      EngineConfig config = new EngineConfig( );
      config.setBIRTHome( birtHome );
      DesignConfig dConfig = new DesignConfig( );
      dConfig.setBIRTHome( birtHome );
      IDesignEngine dEngine = null;
      ReportDesignHandle dHandle = null;
      try {
         Platform.startup( config );
         IDesignEngineFactory dFactory =
            ( IDesignEngineFactory ) Platform.createFactoryObject(
            IDesignEngineFactory.EXTENSION_DESIGN_ENGINE_FACTORY );
         dEngine = dFactory.createDesignEngine( dConfig );
         SessionHandle sessionHandle =
            dEngine.newSessionHandle( ULocale.ENGLISH );
         dHandle = sessionHandle.openDesign( reportName );
      }
      catch(BirtException e) {
          e.printStackTrace();
      }
      return dHandle;
   }

   /***********************************************************
   * Build a chart
   ***********************************************************/

   public void build
      ( ReportDesignHandle dHandle, String newDesignName )
   {
      // Create a new chart instance object
      ChartWithAxes newChart = ChartWithAxesImpl.create( );

      // Set the properties of the chart
      newChart.setType( "Line Chart" );
      newChart.setSubType( "Overlay" );

      newChart.getBlock().setBackground(
         ColorDefinitionImpl.WHITE() );
      newChart.getBlock().setBounds(
         BoundsImpl.create( 0, 0, 400, 250 ) );

      Plot p = newChart.getPlot();
      p.getClientArea().setBackground(
         ColorDefinitionImpl.create( 255, 255, 225 ));
      newChart.getTitle().getLabel().getCaption()
         .setValue( "Europe" );

      Legend lg = newChart.getLegend( );
      LineAttributes lia = lg.getOutline( );
      lg.getText().getFont().setSize( 16 );
      lia.setStyle( LineStyle.SOLID_LITERAL );
      lg.getInsets().set( 1, 1, 1, 1 );
      lg.getOutline().setVisible( false );
      lg.setAnchor( Anchor.NORTH_LITERAL );

      Axis xAxisPrimary = newChart.getPrimaryBaseAxes( )[0];
      xAxisPrimary.setType( AxisType.TEXT_LITERAL );
      xAxisPrimary.getMajorGrid().setTickStyle(
         TickStyle.BELOW_LITERAL );
      xAxisPrimary.getOrigin().setType(
         IntersectionType.VALUE_LITERAL );
      xAxisPrimary.getTitle().setVisible( false );

      Axis yAxisPrimary = newChart.getPrimaryOrthogonalAxis(
         xAxisPrimary );
      yAxisPrimary.getMajorGrid().setTickStyle(
         TickStyle.LEFT_LITERAL );
      yAxisPrimary.getScale().setMax(
         NumberDataElementImpl.create( 160 ));
      yAxisPrimary.getScale().setMin(NumberDataElementImpl
         .create( -50 ));
      yAxisPrimary.getTitle().getCaption()
         .setValue( "Sales Growth" );

      // Create sample data.
      SampleData sdt =
         DataFactory.eINSTANCE.createSampleData();
      BaseSampleData sdBase =
         DataFactory.eINSTANCE.createBaseSampleData();
      sdBase.setDataSetRepresentation("A");
      sdt.getBaseSampleData().add( sdBase );

      OrthogonalSampleData sdOrthogonal =
         DataFactory.eINSTANCE.createOrthogonalSampleData();
      sdOrthogonal.setDataSetRepresentation( "1");
      sdOrthogonal.setSeriesDefinitionIndex(0);
      sdt.getOrthogonalSampleData().add( sdOrthogonal );
      newChart.setSampleData(sdt);

      // Create the category series.
      Series seCategory = SeriesImpl.create();

      // Set the data value for X-Series.
      Query query = QueryImpl.create( "row["CATEGORY"]" );
      seCategory.getDataDefinition().add( query );

      // Create the primary data set
      LineSeries ls1 = ( LineSeries ) LineSeriesImpl.create();
      ls1.setSeriesIdentifier( "Q1" );

      // Set dthe ata value for Y-Series 1.
      Query query1 = QueryImpl.create( "row["VALUE1"]/1000" );
      ls1.getDataDefinition().add( query1 );
      ls1.getLineAttributes().setColor(ColorDefinitionImpl.RED());
      for ( int i = 0; i < ls1.getMarkers( ).size( ); i++ )
      {
         ( ls1.getMarkers( ).get( i ) ).setType(
            MarkerType.TRIANGLE_LITERAL );
      }
      ls1.getLabel().setVisible( true );

      LineSeries ls2 = (LineSeries) LineSeriesImpl.create( );
      ls2.setSeriesIdentifier( "Q2" );

      // Set the data value for Y-Series 2.
      Query query2 = QueryImpl.create( "row["VALUE2"]" );
      ls2.getDataDefinition().add( query2 );
      ls2.getLineAttributes().setColor(
         ColorDefinitionImpl.YELLOW() );
      for ( int i = 0; i < ls2.getMarkers( ).size( ); i++ )
      {
         ( ls2.getMarkers( ).get( i ) ).setType(
            MarkerType.CIRCLE_LITERAL );
      }
      ls2.getLabel().setVisible( true );

      SeriesDefinition sdX = SeriesDefinitionImpl.create();
      sdX.getSeriesPalette().shift( 0 );

      // Set default grouping.
      SeriesGrouping grouping = sdX.getGrouping( );
      grouping.setEnabled( true );
      grouping.setGroupType( DataType.TEXT_LITERAL );
      grouping.setGroupingUnit( GroupingUnitType.STRING_LITERAL );
      grouping.setGroupingInterval( 0 );
      grouping.setAggregateExpression( "Sum" ); //$NON-NLS-1$
      xAxisPrimary.getSeriesDefinitions().add( sdX );
      sdX.getSeries().add( seCategory );

      SeriesDefinition sdY1 = SeriesDefinitionImpl.create();
      sdY1.getSeriesPalette().shift( 0 );
      sdY1.getSeries().add( ls1 );
      yAxisPrimary.getSeriesDefinitions().add( sdY1 );

      SeriesDefinition sdY2 = SeriesDefinitionImpl.create();
      sdY2.getSeriesPalette().shift( 0 );
      sdY2.getSeries().add( ls2 );
      yAxisPrimary.getSeriesDefinitions().add( sdY2 );

      // Change the aggregation for Y-Series 2.
      SeriesGrouping groupingY2 = sdY2.getGrouping( );
      groupingY2.setEnabled( true );
      groupingY2.setAggregateExpression( "Average" );//$NON-NLS-1$

      // Get a chart implementation object and set its
      // chart.instance property
      ElementFactory ef = dHandle.getElementFactory( );
      ExtendedItemHandle extendedItemHandle =
         ef.newExtendedItem( null, "Chart" );

      try{
         IReportItem chartItem =
            extendedItemHandle.getReportItem( );
         chartItem.setProperty( "chart.instance", newChart );
      } catch( ExtendedElementException e ) {
            e.printStackTrace( );
      }

      // Get a data set and bind it to the chart.
      DataSetHandle dataSet = ( DataSetHandle )
         dHandle.getDataSets( ).get( 0 );
       ComputedColumn col1 =
         StructureFactory.createComputedColumn( );
       col1.setName( "VALUE1" );
       col1.setExpression( "dataSetRow["QUANTITYORDERED"]") ;
       col1.setDataType(
         DesignChoiceConstants.COLUMN_DATA_TYPE_INTEGER );
       ComputedColumn col2 =
         StructureFactory.createComputedColumn( );
       col2.setName( "VALUE2" );
       col2.setExpression( "dataSetRow["PRICEEACH"]" );
       col2.setDataType(
         DesignChoiceConstants.COLUMN_DATA_TYPE_FLOAT );
       ComputedColumn col3 =
         StructureFactory.createComputedColumn( );
       col3.setName( "CATEGORY" );
       col3.setExpression( "dataSetRow["PRODUCTLINE"]");
       col3.setDataType(
         DesignChoiceConstants.COLUMN_DATA_TYPE_STRING );

      try {
         extendedItemHandle.setDataSet( dataSet );
         extendedItemHandle.addColumnBinding(col1, true);
         extendedItemHandle.addColumnBinding(col2, true);
         extendedItemHandle.addColumnBinding(col3, true);
         extendedItemHandle.setHeight( "250pt" );
         extendedItemHandle.setWidth( "400pt" );
      } catch ( SemanticException e ) {
            e.printStackTrace( );
      }

      // Add the chart to the report design
      ListHandle li =  (ListHandle) dHandle.getBody( )
         .getContents( ).get( 0 );
      try {
            li.getFooter( ).add( extendedItemHandle );
         } catch ( ContentException e3 ) {
            e3.printStackTrace( );
         } catch ( NameException e3 ) { e3.printStackTrace( ); }

      // Save the report design that now contains a chart
      try {
         dHandle.saveAs( newDesignName );
      } catch ( IOException e ) { e.printStackTrace( ); }
      dHandle.close( );
     Platform.shutdown( );
     System.out.println( "Finished" );
   }
}

Using the BIRT charting API in a Java Swing application

The BIRT charting API does not rely on the BIRT design engine or the BIRT report engine, nor does it process a BIRT report design file. You can use the BIRT charting API to generate a chart in any Java application.

The program shown in Listing 15-24 uses the BIRT charting API to build a chart in a Java Swing application. nor does it process a BIRT report design file.

Listing 15-24 Java Swing charting application



import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;

import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;

import java.util.HashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.eclipse.birt.chart.api.ChartEngine;

import org.eclipse.birt.chart.device.IDeviceRenderer;
import org.eclipse.birt.chart.device.IUpdateNotifier;

import org.eclipse.birt.chart.exception.ChartException;

import org.eclipse.birt.chart.factory.GeneratedChartState;
import org.eclipse.birt.chart.factory.Generator;

import org.eclipse.birt.chart.model.Chart;
import org.eclipse.birt.chart.model.ChartWithAxes;

import org.eclipse.birt.chart.model.attribute.AxisType;
import org.eclipse.birt.chart.model.attribute.Bounds;
import org.eclipse.birt.chart.model.attribute.IntersectionType;
import org.eclipse.birt.chart.model.attribute.LegendItemType;
import org.eclipse.birt.chart.model.attribute.Position;
import org.eclipse.birt.chart.model.attribute.TickStyle;

import org.eclipse.birt.chart.model.attribute.impl.BoundsImpl;
import org.eclipse.birt.chart.model.attribute.impl
   .ColorDefinitionImpl;

import org.eclipse.birt.chart.model.component.Axis;
import org.eclipse.birt.chart.model.component.Series;

import org.eclipse.birt.chart.model.component.impl.SeriesImpl;

import org.eclipse.birt.chart.model.data.NumberDataSet;
import org.eclipse.birt.chart.model.data.SeriesDefinition;
import org.eclipse.birt.chart.model.data.TextDataSet;

import org.eclipse.birt.chart.model.data.impl.NumberDataSetImpl;
import org.eclipse.birt.chart.model.data.impl
   .SeriesDefinitionImpl;
import org.eclipse.birt.chart.model.data.impl.TextDataSetImpl;

import org.eclipse.birt.chart.model.impl.ChartWithAxesImpl;

import org.eclipse.birt.chart.model.layout.Legend;
import org.eclipse.birt.chart.model.layout.Plot;

import org.eclipse.birt.chart.model.type.BarSeries;

import org.eclipse.birt.chart.model.type.impl.BarSeriesImpl;

import org.eclipse.birt.core.framework.PlatformConfig;

/*
 * The selector of charts in Swing JPanel.
 */

public final class SwingChartingApp extends JPanel implements
      IUpdateNotifier,
      ComponentListener
{
   private static final long serialVersionUID = 1L;
   private boolean bNeedsGeneration = true;
   private GeneratedChartState gcs = null;
   private Chart cm = null;
   private IDeviceRenderer idr = null;
   private Map contextMap;

   /*
    * Create the layout with a container for displaying a chart
    */
   public static void main( String[ ] args )
   {
      SwingChartingApp scv = new SwingChartingApp( );
      JFrame jf = new JFrame( );
      jf.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
      jf.addComponentListener( scv );
      Container co = jf.getContentPane( );
      co.setLayout( new BorderLayout( ) );
      co.add( scv, BorderLayout.CENTER );

      Dimension dScreen = Toolkit.getDefaultToolkit( )
         .getScreenSize( );
      Dimension dApp = new Dimension( 800, 600 );
      jf.setSize( dApp );
      jf.setLocation( ( dScreen.width - dApp.width ) / 2,
         ( dScreen.height - dApp.height ) / 2 );
      jf.setTitle( scv.getClass( ).getName( ) + " [device="
         + scv.idr.getClass( ).getName( ) + "]" );//$NON-NLS-1$
      jf.setVisible( true );
   }

   /*
    * Connect with a SWING device to render the graphics.
    */
   SwingChartingApp( )
   {
      contextMap = new HashMap( );
      try
      {
         PlatformConfig config = new PlatformConfig( );
         config.setProperty( "STANDALONE", "true" ); //$NON-NLS-1$
            //$NON-NLS-2$
         idr = ChartEngine.instance( config ).getRenderer(
            "dv.SWING" );//$NON-NLS-1$
      }
      catch ( ChartException ex )
      {
         ex.printStackTrace( );
      }
      cm = createBarChart( );
   }
      /* Build a simple bar chart */
      public static final Chart createBarChart( )
      {
         ChartWithAxes cwaBar = ChartWithAxesImpl.create( );

         /* Plot */
         cwaBar.getBlock( )
            .setBackground( ColorDefinitionImpl.WHITE( ) );
         cwaBar.getBlock( ).getOutline( ).setVisible( true );
         Plot p = cwaBar.getPlot( );
         p.getClientArea( ).setBackground(
               ColorDefinitionImpl.create( 255, 255, 225 ) );
         p.getOutline( ).setVisible( false );

         /* Title */
         cwaBar.getTitle( ).getLabel( ).getCaption( )
            .setValue( "Bar Chart" );

         /* Legend */
         Legend lg = cwaBar.getLegend( );
         lg.getText( ).getFont( ).setSize( 16 );
         lg.setItemType( LegendItemType.CATEGORIES_LITERAL );

         /* X-Axis */
         Axis xAxisPrimary = cwaBar.getPrimaryBaseAxes( )[0];
         xAxisPrimary.setType( AxisType.TEXT_LITERAL );
         xAxisPrimary.getMajorGrid( )
            .setTickStyle( TickStyle.BELOW_LITERAL );
         xAxisPrimary.getOrigin( )
            .setType( IntersectionType.VALUE_LITERAL );
         xAxisPrimary.getTitle( ).setVisible( true );

         /* Y-Axis */
         Axis yAxisPrimary = cwaBar
            .getPrimaryOrthogonalAxis( xAxisPrimary );
         yAxisPrimary.getMajorGrid( )
            .setTickStyle( TickStyle.LEFT_LITERAL );
         yAxisPrimary.setType( AxisType.LINEAR_LITERAL );
         yAxisPrimary.getLabel( ).getCaption( ).getFont( )
            .setRotation( 90 );

         /* Data Sets */
         TextDataSet categoryValues = TextDataSetImpl
            .create( new String[]{ "Item 1", "Item 2", "Item 3"} );
         NumberDataSet orthoValues = NumberDataSetImpl
            .create( new double[]{ 25, 35, 15 } );

         /* X-Series */
         Series seCategory = SeriesImpl.create( );
         seCategory.setDataSet( categoryValues );

         SeriesDefinition sdX = SeriesDefinitionImpl.create( );
         sdX.getSeriesPalette( ).shift( 0 );
         xAxisPrimary.getSeriesDefinitions( ).add( sdX );
         sdX.getSeries( ).add( seCategory );

         /* Y-Series */
         BarSeries bs = (BarSeries) BarSeriesImpl.create( );
         bs.setDataSet( orthoValues );
         bs.setRiserOutline( null );
         bs.getLabel( ).setVisible( true );
         bs.setLabelPosition( Position.INSIDE_LITERAL );

         SeriesDefinition sdY = SeriesDefinitionImpl.create( );
         yAxisPrimary.getSeriesDefinitions( ).add( sdY );
         sdY.getSeries( ).add( bs );
         return cwaBar;
      }

   public void regenerateChart( )
   {
      bNeedsGeneration = true;
      repaint( );
   }

   public void repaintChart( )
   {
      repaint( );
   }

   public Object peerInstance( )
   {
      return this;
   }
   public Chart getDesignTimeModel( )
   {
      return cm;
   }

   public Object getContext( Object key )
   {
      return contextMap.get( key );
   }

   public Object putContext( Object key, Object value )
   {
      return contextMap.put( key, value );
   }

   public Object removeContext( Object key )
   {
      return contextMap.remove( key );
   }

   public Chart getRunTimeModel( )
   {
      return gcs.getChartModel( );
   }

   public void paint( Graphics g )
   {
      super.paint( g );
      Graphics2D g2d = (Graphics2D) g;
      idr.setProperty( IDeviceRenderer.GRAPHICS_CONTEXT, g2d );
      idr.setProperty( IDeviceRenderer.UPDATE_NOTIFIER, this );
      Dimension d = getSize( );
      Bounds bo = BoundsImpl.create( 0, 0, d.width, d.height );
      bo.scale( 72d / idr.getDisplayServer( ).getDpiResolution());
      Generator gr = Generator.instance( );

      if ( bNeedsGeneration ) {
         bNeedsGeneration = false;
         try {
            gcs = gr.build( idr.getDisplayServer( ),
                  cm,
                  bo,
                  null,
                  null,
                  null );
         }
         catch ( ChartException ex ) {
            System.out.println( ex );
         }
      }
      try {
         gr.render( idr, gcs );
      }
      catch ( ChartException ex ) { System.out.println( ex ); }
   }

   public void componentHidden( ComponentEvent e ) { }
   public void componentMoved( ComponentEvent e ) { }
   public void componentResized( ComponentEvent e )
   {
      bNeedsGeneration = true;
   }
   public void componentShown( ComponentEvent e ) { }

}

Understanding the chart programming examples

The org.eclipse.birt.chart.examples plug-in is a collection of chart programming examples provided in the ChartSDK folder of the chart engine. To access the Java source code of the examples, extract the org.eclipse.birt .chart.examples.source plug-in’s JAR file to your workspace. Then, import those files as a project. Include the JAR files in the BIRT home folder and the Java EE JAR file, servlet.jar, in the build path. Add further JAR files from the chart engine’s ChartSDK and Eclipse home plugins folders as necessary to resolve build errors in individual examples. To run the examples, use the Eclipse Run dialog to set the VM arguments to include a line of the following form, where <Eclipse home> is the location of eclipse.exe:

-DBIRT_HOME="<Eclipse home>"

The examples are located in subdirectories of the plug-in’s src/org/eclipse/birt/chart/examples directory, called EXAMPLES_ROOT. Most of the examples consist of a Java application that displays a chart. The application classes, which have a main( ) method, are called viewer applications and their class names end in Viewer. Typically, these examples use one or more additional classes to build the chart. The following sections provide brief summaries of the examples in the chart examples plug-in.

api.data examples

The api.data package contains three examples, one that displays charts in a Java Swing environment and two that modify chart items in a report design.

DataCharts example

The DataCharts example consists of DataChartsViewer, a Java Swing application that uses the DataCharts class to build a chart. DataCharts displays hard-coded data values in the charts. Depending on user selection, the application builds one of the following kinds of charts:

• A bar chart that has multiple y-axes

• A bar chart that has multiple y-series

• A pie chart that has a minimum slice

GroupOnXSeries example

The GroupOnXSeries example is a Java application that reads a BIRT report design and modifies and saves it. The original report design, NonGroupOnXSeries.rptdesign, contains a chart report item that uses data from a scripted data source. The chart item has no grouping on the x-series. The GroupOnXSeries Java application modifies the design so that the chart report item does group on the x-series. The application saves the modified report design as GroupOnXSeries.rptdesign. Open these report designs and preview the reports to see the effect of this modification.

GroupOnYAxis example

The GroupOnYAxis example is a Java application that reads a BIRT report design and modifies and saves it. The original report design, NonGroupOnYAxis.rptdesign, contains a chart report item that uses data from a scripted data source. The chart item has no grouping on the y-axis. The GroupOnYAxis Java application modifies the design so that the chart report item does group on the y-axis. The application saves the modified BIRT report design as GroupOnYAxis.rptdesign. Open these report designs and preview the reports to see the effect of this modification.

api.data.autobinding example

This example is an Eclipse SWT application that consists of the AutoDataBindingViewer class. This class instantiates an SWT Display object and adds a chart to it. The application creates data row structures, which it binds to the chart. Then, the application renders the chart.

api.format example

This example is a Java Swing application that consists of the FormatCharts and FormatChartsViewer Java classes. The FormatChartsViewer class displays an interface that presents choices to the user. Based on the user choice, FormatChartsViewer calls static methods in the FormatCharts class to build a chart. FormatChartsViewer then renders the chart. The methods in FormatCharts modify the following chart properties:

• Axis format

• Colored by category

• Legend title

• Percentage value

• Plot format

• Series format

api.interactivity examples

This set of related example applications demonstrate chart interactivity features in the three Java frameworks: SVG, Swing, and SWT. The viewer applications are SvgInteractivityViewer, SwingInteractivityViewer, and SwtInteractivityViewer. The viewer classes display an interface that presents the same interactivity choices to the user. Based on the choice, the viewer class calls static methods in InteractivityCharts to build an interactive chart. Then, the viewer renders the chart. The interactivity types in these charts are:

• Displaying tooltips

• Executing call-back code

• Highlighting a series

• Linking to an external site by using a URL

• Toggling the visibility of a series

api.pdf example

This example is a Java application that builds a simple chart and renders it as a PDF file. The classes in the PDFChartGenerator example are ChartModels and PDFChartGenerator. ChartModels has a single method that builds a simple chart using hard-coded data values. PDFChartGenerator uses the BIRT charting API to render the chart into PDF format. The application saves the PDF file as test.pdf.

api.preference example

This example shows how a Java servlet can process URL parameters to set style preferences for a chart. The servlet class, PreferenceServlet, uses the ChartModels class to generate a chart. The servlet uses the style parameters in the LabelStyleProcessor class to affect the style of a label in the chart. The example also includes a help page, Help.htm, that explains how to:

• Develop chart pages using JSPs and servlets.

• Run the Preference example.

• Set up Eclipse to work with Tomcat.

api.processor example

This example builds a simple chart and applies styles to text in the chart. The example consists of StyleChartViewer, an SWT application, and StyleProcessor, which implements the IStyleProcessor interface to create a style object. StyleChartViewer creates a chart and applies the style to text in the chart. Finally, StyleChartViewer renders the chart.

api.script examples

This example consists of two SWT applications, JavaScriptViewer and JavaViewer. Both applications present the same set of choices to the user. The appearance of the chart that appears for a particular user choice is the same for both viewers. Each choice calls a static method in the ScriptCharts class to create a chart and displays the event handlers that the chart implements. JavaScriptViewer calls ScriptCharts methods to build charts that have JavaScript event handlers. JavaViewer calls ScriptCharts methods to build charts that have Java event handlers.

The ScriptCharts class illustrates techniques for creating charts having report element event handlers. Methods in this class create charts having report element event handlers written in JavaScript. Each JavaScript event handler is defined as a single string in ScriptCharts. A further set of methods creates charts having the same functionality using report element event handlers written in Java. The Java event handlers are Java classes that are located in EXAMPLES_ROOT/api/script/java. The ScriptCharts methods that define a Java event handler pass a string containing the path of the Java class.

api.viewer examples

The api.viewer package contains example applications that create a wide variety of charts. Each class creates and displays a set of charts based on user choices. Each viewer class, except SwingLiveChartViewer.java, calls static methods in the PrimitiveCharts class to create the chart to display. PrimitiveCharts uses hard-coded data values for each chart.

Chart3DViewer example

Chart3DViewer.java is an SWT application that displays the following chart types:

• 3D area chart

• 3D bar chart

• 3D line chart

CurveFittingViewer example

CurveFittingViewer.java is an SWT application that displays the following chart types:

• Curve fitting area chart

• Curve fitting bar chart

• Curve fitting line chart

• Curve fitting stock chart

DialChartViewer example

DialChartViewer.java is an SWT application that displays the following chart types:

• Multiple-dial, multiple-region chart

• Multiple-dial, single-region chart

• Single-dial, multiple-region chart

• Single-dial, single-region chart

SwingChartViewerSelector example

SwingChartViewerSelector.java is a Swing application that supports showing the same data values in different ways. For each chart type, the user can choose to show the chart as two-dimensional or two-dimensional with depth. The user can also choose to display the chart with axes transposed, with the values shown as percentages, or on a logarithmic scale. Some choices are available only for charts with axes. SwingChartViewerSelector displays the following chart types:

• Area chart

• Bar and line stacked chart

• Bar chart

• Bar chart that has two series

• Bubble chart

• Difference chart

• Line chart

• Pie chart

• Pie chart that has four series

• Scatter chart

• Stock chart

SwingLiveChartViewer example

SwingChartLiveChartViewer.java is a Swing application that displays a live, animated chart with scrolling data.

SWTChartViewerSelector example

SWTChartViewerSelector.java is an SWT application that displays the same user interface choices and chart types as SwingChartViewerSelector.java.

builder example

The builder example consists of two Java classes, ChartWizardLauncher and DefaultDataServiceProviderImpl. ChartWizardLauncher attempts to read a chart from testCharts.chart. If the file exists, ChartWizardLauncher modifies that file. If the file does not exist, the application creates a new file. ChartWizardLauncher uses the BIRT chart wizard to create the chart. DefaultDataServiceProviderImpl provides a basic implementation of a simulated data service.

radar.ui example

The radar.ui example consists of the classes that provide the user interface pages for the radar chart.

report.api examples

The three report.api examples are all Java applications that have no user interface. These examples use the BIRT design engine to build a new BIRT report design file in the chart example plug-in’s output folder. All the report examples add the following components to the report design file in the order shown:

• Master page

• Data source

• Data set

• A chart element in the body of the report

All the report examples use the BIRT charting API to add a chart to the body slot of the report design. After running these applications, open the new report design file and preview the report to see the chart.

MeterChartExample example

The MeterChartExample example adds a meter chart to the report design. The name of the report design is MeterChartExample.rptdesign.

SalesReport example

The SalesReport example creates styles and adds a pie chart to the report design. The name of the report design is SalesReport.rptdesign.

StockReport example

The StockReport example adds a stock chart to the report design. The name of the report design is StockAnalysis.rptdesign.

report.design examples

The report designs in this folder demonstrate ways to display chart elements in a report design. BarChartWithinTableGroup.rptdesign shows how to use a chart in a table element. BarChartWithJavascript.rptdesign shows how to use JavaScript to modify the rendered chart when a user views the report. DynamicSeriesPieChart.rptdesign shows how to customize a pie chart.

report.design.script examples

The report designs in this folder contain chart elements that use the same JavaScript event handlers that the api.script examples create dynamically. These report designs show how the scripts appear in BIRT Report Designer.

view example

The view folder and its subfolders include the content for the Eclipse view, Chart Examples. To open this view, from the Eclipse main menu, choose Window→Show View→Other. On Show View, expand Report and Chart Design, then select Chart Examples and choose OK. By default, the Chart Examples view appears below the main window, in the same position as the console window. To use the Chart Examples view, expand a node on the left of the view, then select an item. The selected chart appears on the right of the view, as shown in Figure 15-1.

Figure 15-1 Chart Examples view, showing the percentage value format example

image

To view the source code of the application that generates the selected chart, choose Open Java Source from the toolbar.

image

To save the XML of the chart item structure, choose Save XML Source from the toolbar.

image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset