| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <title>Using The BIRT Chart Engine in Your Plug-in</title> |
| <link rel="stylesheet" href="../article.css" type="text/css" /> |
| </head> |
| |
| <body> |
| <h1>Using the BIRT Chart Engine in Your Plug-in</h1> |
| |
| <div class="summary"> |
| <h2>Summary</h2> |
| <p>The BIRT Chart Engine is a powerful business chart generation |
| tool that can be used as a standalone charting component. This article |
| introduces the basic concepts of BIRT Chart Engine, explains what BIRT |
| Chart Engine is composed of, and illustrates how to create a chart and |
| use it as widget.</p> |
| |
| <div class="author">By Qi Liang, IBM</div> |
| <div class="copyright">Copyright © 2007 International |
| Business Machines Corp.</div> |
| <div class="date">May 14, 2007</div> |
| </div> |
| |
| <div class="content"> |
| <h2>Introduction</h2> |
| <p>Charts are a common and important way to display data in business |
| intelligence and other applications. Business Intelligence and Reporting |
| Tools (BIRT), an Eclipsed-based reporting tool, provides not only a nice |
| report designing tool, but a powerful charting engine. The BIRT Chart |
| Engine is a good choice for displaying charts in your Eclipse plug-ins, |
| Eclipse Rich Client Platform (RCP) applications, Java™ |
| applications, and more. It supports numerous chart types, and can be |
| rendered on SWT/Swing widgets and image files of many formats. In this |
| article, we show you some of the capabilities the BIRT Chart Engine |
| provides, and how to use it on an SWT widget in your plug-in.</p> |
| <h2>What the BIRT Chart Engine can provide</h2> |
| <p>The BIRT Chart Engine supports a variety of chart types. Here, we |
| take a look at some of the available chart choices. Note that only basic |
| and important charts are listed here; you can refer to BIRT |
| documentation for more details.</p> |
| <table class="no-border" width="60%" align="center" cellpadding="2"> |
| <tr> |
| <td width="33%"> |
| <div align="center"><a href="images/bar.png"><img |
| src="images/bar_s.png" width="128" height="96" border="0"></a></div> |
| </td> |
| <td width="33%"> |
| <div align="center"><a href="images/multibar.png"><img |
| src="images/multibar_s.png" width="128" height="96" border="0"></a></div> |
| </td> |
| <td width="33%"> |
| <div align="center"><a href="images/line.png"><img |
| src="images/line_s.png" border="0"></a></div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center">Bar Chart</div> |
| </td> |
| <td> |
| <div align="center">Multi-Bar Chart</div> |
| </td> |
| <td> |
| <div align="center">Line Chart</div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center"></div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center"><a href="images/pie.png"><img |
| src="images/pie_s.png" width="128" height="96" border="0"></a></div> |
| </td> |
| <td> |
| <div align="center"><a href="images/stacked.png"><img |
| src="images/stacked_s.png" border="0"></a></div> |
| </td> |
| <td> |
| <div align="center"><a href="images/scatter.png"><img |
| src="images/scatter_s.png" border="0"></a></div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center">Pie Chart</div> |
| </td> |
| <td> |
| <div align="center">Stacked Chart</div> |
| </td> |
| <td> |
| <div align="center">Scatter Chart</div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center"></div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center"><a href="images/stock.png"><img |
| src="images/stock_s.png" border="0"></a></div> |
| </td> |
| <td> |
| <div align="center"><a href="images/area.png"><img |
| src="images/area_s.png" border="0"></a></div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| </tr> |
| <tr> |
| <td> |
| <div align="center">Stock Chart</div> |
| </td> |
| <td> |
| <div align="center">Area Chart</div> |
| </td> |
| <td> |
| <div align="center"></div> |
| </td> |
| </tr> |
| </table> |
| <p align="center"><strong>Figure 1. Chart Samples</strong></p> |
| <h2>Preparation</h2> |
| <p>This article uses Eclipse SDK 3.2.2 and BIRT 2.1.1. The Eclipse <a |
| href="http://www.eclipse.org/callisto/discovery.php">Callisto |
| Discovery Site</a> can be used to install BIRT and its prerequisite plug-ins |
| by selecting "Help > Software Updates > Find and |
| Install..." and choosing "Search for new features to |
| install" in the update dialog. After selecting a mirror update |
| site, you can see all features under Callisto Discovery Site as follows.</p> |
| <p align="center"><img src="images/selectbirt.png"></p> |
| <p align="center"><strong>Figure 2. The Callisto Update |
| Site</strong></p> |
| <p>In this dialog box, select "Eclipse BIRT Report Designer |
| Framework 2.1.2" and click "Select Required". Now BIRT |
| and all its dependency features are selected to install. Then click |
| "Next", and install all these features. |
| <p>BIRT contains about fifty plug-ins, but if you use BIRT Chart |
| Engine in your application, you only need four of them (along with |
| several EMF prerequisite plug-ins). They are listed in the following |
| table. So you just need include these four when distributing your |
| application.</p> |
| <table width="80%" border="1" align="center"> |
| <tr> |
| <td> |
| <div align="center"><strong>Plug-in Name</strong></div> |
| </td> |
| <td> |
| <div align="center"><strong>Description</strong></div> |
| </td> |
| </tr> |
| <tr> |
| <td width="37%">org.eclipse.birt.chart.device.extension</td> |
| <td width="59%">Allows third parties to extend the chart render |
| device</td> |
| </tr> |
| <tr> |
| <td> |
| <p>org.eclipse.birt.chart.engine.extension</p> |
| </td> |
| <td>Allows third parties to extend the chart engine.</td> |
| </tr> |
| <tr> |
| <td>org.eclipse.birt.chart.engine</td> |
| <td>Renders charts.</td> |
| </tr> |
| <tr> |
| <td>org.eclipse.birt.core</td> |
| <td>Provides basic functionalities for all BIRT plug-ins.</td> |
| </tr> |
| </table> |
| <p align="center"><strong>Table 1. BIRT Chart Engine |
| Plug-ins</strong></p> |
| <p>You will find all the code snippets shown in this article in the |
| sample code that you can download at <a |
| href="com.ibm.examples.chart.zip">com.ibm.examples.chart.zip</a>.</p> |
| <h2>Concepts</h2> |
| <p>Before we start to use the chart engine, let's go through the |
| basic concepts, which can help to understand the chart engine API |
| better. The following is a simple bar chart, which contains the basic |
| elements, like the title, axes, and so on.</p> |
| <p align="center"><img src="images/concepts.png" width="700" |
| height="500"></p> |
| <p align="center"><strong>Figure 3. Concepts in a Bar Chart</strong></p> |
| <table width="60%" border="1" align="center"> |
| <tr> |
| <th>Concept</th> |
| <th>Description</th> |
| </tr> |
| <tr> |
| <td>Title Area</td> |
| <td>The area containing the chart's title.</td> |
| </tr> |
| <tr> |
| <td>Plot Area</td> |
| <td>The area with red border, containing X and Y axes, the axes |
| titles, and bars.</td> |
| </tr> |
| <tr> |
| <td>Legend Area</td> |
| <td>The area that is reserved to host the legend.</td> |
| </tr> |
| <tr> |
| <td>Legend Client Area</td> |
| <td>The area containing the legend to explain the meaning of each |
| bar with different series.</td> |
| </tr> |
| <tr> |
| <td>Title</td> |
| <td>Describes the data that the chart displays.</td> |
| </tr> |
| <tr> |
| <td>Major Grid</td> |
| <td>Indicates the major scale (minor Grid is supported, but not |
| displayed here).</td> |
| </tr> |
| <tr> |
| <td>X/Y Title</td> |
| <td>Describes the meaning of X/Y axis</td> |
| </tr> |
| <tr> |
| <td>X/Y Axis</td> |
| <td>Provides the label or scale value of X/Y axis</td> |
| </tr> |
| <tr> |
| <td>Series</td> |
| <td>Defines how to display data, bar, line, or pie, for example</td> |
| </tr> |
| </table> |
| <p align="center"><strong>Table 2. Some Concepts in Chart.</strong></p> |
| <p>Most charts have two or more axes, but some have none. One |
| example of a chart with no axis is pie chart. The horizontal axis is |
| called base axis. The base axis can be category axis or value axis. The |
| category axis just contains a sequence of labels, while the value axis |
| contains numeric or datetime values. The vertical axis is an orthogonal |
| axis, and it is always a value axis. The BIRT Chart Engine supports one |
| base axis, and one or more orthogonal axes, but only one orthogonal axis |
| is primary. The series determines how to show data. For example, a bar |
| series will show data with a bar graph, and a pie series shows data with |
| a pie chart. The series definition defines the color palette, label |
| displaying format, and the associated series. Each axis can have more |
| than one series definition, but typically only one series definition is |
| used. A series definition can itself have more than one series.</p> |
| <h2>Create Your First Chart</h2> |
| <p>Let's see how to create a simple bar chart to understand the |
| above concepts. This bar chart has one category base axis, and one |
| orthogonal value axis. It also contains a title and legend as follows:</p> |
| <p align="center"><img src="images/firstchart.png"></p> |
| <p align="center"><strong>Figure 4. A Sample Bar Chart.</strong></p> |
| <p>The complete source can be found in <code>com.ibm.examples.chart.widget.chart.TestChartBuilder</code>.</p> |
| <ol> |
| <li>Create chart instance <pre> |
| chart = ChartWithAxesImpl.create(); |
| chart.setDimension(ChartDimension.TWO_DIMENSIONAL_WITH_DEPTH_LITERAL);</pre> |
| <p>A bar chart has two axes, so we call <code>ChartWithAxesImpl.create()</code> |
| to create it. The second statement sets dimension with <code>ChartDimension.TWO_DIMENSIONAL_WITH_DEPTH_LITERAL</code>, |
| so that the bar is shaded, which looks prettier.</p> |
| </li> |
| <li>Set background color of plot <pre> chart.getPlot().setBackground(ColorDefinitionImpl.ORANGE()); |
| chart.getPlot().getClientArea().setBackground(ColorDefinitionImpl.YELLOW()); |
| </pre> |
| <p>The background color of a plot or a plot's client area can be |
| changed. The above code sets the plot's background to orange, and sets |
| the client area's background to yellow. |
| </li> |
| <li>Enable legend <pre> chart.getLegend().setItemType(LegendItemType.CATEGORIES_LITERAL); |
| chart.getLegend().setVisible(true); |
| </pre> |
| <p>By default, the legend is disabled, so you need use <code>Legend.setVisible(true)</code> |
| to enable it. There are two legend types, <code>LegendItemType.CATEGORIES_LITERAL</code> |
| and <code>LegendItemType.SERIES_LITERAL</code>. The former shows a |
| different legend icon for each category, and the later shows different |
| icon for each series.</p> |
| </li> |
| <li>Set the chart title <pre> chart.getTitle().getLabel().getCaption().setValue(title); |
| chart.getTitle().getLabel().getCaption().getFont().setSize(14); |
| chart.getTitle().getLabel().getCaption().getFont().setName(FONT_NAME); |
| </pre> |
| <p>Setting the chart title is very simple, as the first line shows. |
| You can also set other attributes, like the font size, font name, font |
| style, and more.</p> |
| </li> |
| <li>Create axes <pre><img src="images/tag_1.gif" height=13 |
| width=24 align=bottom> xAxis = ((ChartWithAxes) chart).getPrimaryBaseAxes()[0]; |
| xAxis.getTitle().setVisible(true); |
| |
| xAxis.getTitle().getCaption().setValue(xTitle); |
| |
| |
| <img src="images/tag_2.gif" height=13 width=24> yAxis = ((ChartWithAxes) chart).getPrimaryOrthogonalAxis(xAxis); |
| yAxis.getTitle().setVisible(true); |
| yAxis.getTitle().getCaption().setValue(yTitle); |
| yAxis.getScale().setStep(1.0); |
| </pre> |
| <p>We get <img src="images/tag_1.gif" height=13 width=24 |
| align=bottom> the first primary base axis as the X axis, while <img |
| src="images/tag_2.gif" height=13 width=24> the Y axis is |
| orthogonal to the X axis. By default, the title of the axis is not |
| visible, so we enable that for both axes and set their titles. Finally, |
| we specify the scale step on Y axis as 1.</p> |
| </li> |
| <li>Create the X series <pre><img src="images/tag_1.gif" |
| height=13 width=24 align=bottom> TextDataSet categoryValues = TextDataSetImpl.create(dataSet.getCities()); |
| |
| |
| <img src="images/tag_2.gif" height=13 width=24> Series seCategory = SeriesImpl.create(); |
| seCategory.setDataSet(categoryValues); |
| |
| |
| <img src="images/tag_3.gif" height=13 width=24> SeriesDefinition sdX = SeriesDefinitionImpl.create(); |
| sdX.getSeriesPalette().update(1); |
| |
| |
| <img src="images/tag_4.gif" height=13 width=24> xAxisPrimary.getSeriesDefinitions().add(sdX); |
| sdX.getSeries().add(seCategory); |
| |
| |
| </pre> |
| <p>The first thing to create the X series is <img |
| src="images/tag_1.gif" height=13 width=24 align=bottom> to |
| create the data set to bind. There are four types of data set: they are |
| <code>DataTimeDataSet</code>, <code>NumberDataSet</code>, <code>StockDataSet</code>, |
| and <code>TextDataSet</code>. In this example, the X axis is a category |
| axis, so we use <code>TextDataSet</code>. Then, <img |
| src="images/tag_2.gif" height=13 width=24> we create a series, |
| and bind the data set to it. In order to define what the series looks |
| like, we need to <img src="images/tag_3.gif" height=13 width=24> |
| create a series definition. The BIRT Chart Engine predefines two color |
| palettes. Here we choose the first series palette. Finally, we <img |
| src="images/tag_4.gif" height=13 width=24> add the series |
| definition to X axis, and add the series to the series definition.</p> |
| </li> |
| <li>Create the Y series <pre><img src="images/tag_1.gif" |
| height=13 width=24 align=bottom> NumberDataSet orthoValuesDataSet1 = NumberDataSetImpl.create(dataSet.getTechnitians()); |
| |
| |
| BarSeries bs1 = (BarSeries) BarSeriesImpl.create(); |
| bs1.setDataSet(orthoValuesDataSet1); |
| |
| |
| SeriesDefinition sdY = SeriesDefinitionImpl.create(); |
| yAxisPrimary.getSeriesDefinitions().add(sdY); |
| sdY.getSeries().add(bs1); |
| </pre> |
| <p>Creation of the Y series is similar to that of the X series. |
| Here, the Y axis must be a value axis, so we use a <img |
| src="images/tag_1.gif" height=13 width=24 align=bottom> <code>NumberDataSet</code>.</p> |
| </li> |
| </ol> |
| <p>In the next section, we will see how to make this chart display |
| on an SWT canvas.</p> |
| <h2>Create the Chart Canvas</h2> |
| <p>The BIRT Chart Engine doesn't provide a SWT chart widget that can |
| be used directly, so we need create it by ourselves if we want to |
| display a chart in an editor or view. In the following example, we |
| create the <code>ChartCanvas</code> class, which extends from <code>Canvas</code>.</p> |
| <pre> public class ChartCanvas extends Canvas { |
| |
| ... |
| <br> public ChartCanvas(Composite parent, int style) { |
| super(parent, style); |
| |
| // initialize the SWT rendering device |
| try { |
| <img src="images/tag_1.gif" height=13 width=24 align=bottom> PluginSettings ps = PluginSettings.instance(); |
| render = ps.getDevice("dv.SWT"); |
| } catch (ChartException pex) { |
| DefaultLoggerImpl.instance().log(pex); |
| } |
| ...</pre> |
| <p>In the constructor, <img src="images/tag_1.gif" height=13 |
| width=24 align=CENTER> we need to get the device renderer for |
| SWT. The device renderer is responsible for rendering a chart onto a |
| target device. The target device can be an image file or widget toolkit |
| like SWT or Swing. The BIRT Chart Engine defines nine device renderers |
| in <code>org.eclipse.birt.chart.util.PluginSettings</code>; they are |
| shown below:</p> |
| <table width="55%" border="1" align="center"> |
| <tr> |
| <th>Device Name</th> |
| <th>Description</th> |
| </tr> |
| <tr> |
| <td>dv.SWING</td> |
| <td>Renders a charts using Swing's <code>java.awt.Graphics2D</code>.</td> |
| </tr> |
| <tr> |
| <td>dv.SWT</td> |
| <td>Renders a chart using SWT's <code>org.eclipse.swt.graphics.GC</code>.</td> |
| </tr> |
| <tr> |
| <td>dv.PNG24</td> |
| <td>Renders a chart to a 24-bit PNG file (deprecated).</td> |
| </tr> |
| <tr> |
| <td>dv.GIF8</td> |
| <td>Renders a chart to an 8-bit GIF file (deprecated).</td> |
| </tr> |
| <tr> |
| <td>dv.PNG</td> |
| <td>Renders a chart to a PNG file.</td> |
| </tr> |
| <tr> |
| <td>dv.GIF</td> |
| <td>Renders a chart to GIF file.</td> |
| </tr> |
| <tr> |
| <td>dv.JPEG/dv.JPG</td> |
| <td>Renders a chart to a JPEG file.</td> |
| </tr> |
| <tr> |
| <td>dv.BMP</td> |
| <td>Renders a chart to a BMP file</td> |
| </tr> |
| <tr> |
| <td>dv.SVG</td> |
| <td>Renders a chart to an SVG file (requires the <code>org.eclipse.birt.chart.device.svg</code> |
| plug-in).</td> |
| </tr> |
| </table> |
| <p align="center"><strong>Table 3. Available Device |
| Renderers.</strong></p> |
| <p>We selected <code>dv.SWT</code> as our device renderer, since we |
| will render chart on an SWT widget. In the constructor, we add one paint |
| listener to do the actual painting work.</p> |
| <pre><img src="images/tag_1.gif" height=13 width=24> addPaintListener(new PaintListener() { |
| |
| public void paintControl(PaintEvent e) { |
| |
| Composite co = (Composite) e.getSource(); |
| final Rectangle rect = co.getClientArea(); |
| |
| if (cachedImage == null) { |
| <br><img src="images/tag_2.gif" height=13 width=24> buildChart(); |
| <img src="images/tag_3.gif" height=13 width=24> drawToCachedImage(rect); |
| } |
| <br><img src="images/tag_4.gif" height=13 width=24> e.gc.drawImage(cachedImage, |
| 0, 0, |
| cachedImage.getBounds().width, |
| cachedImage.getBounds().height, |
| 0, 0, |
| rect.width, |
| rect.height); |
| } |
| }); |
| </pre> |
| <p>We use double-buffering to draw the chart on the canvas to avoid |
| flickering while the chart is being drawn. In the paint listener <img |
| src="images/tag_1.gif" height=13 width=24 align=bottom>, if this |
| is the first time to get paint event, we <img src="images/tag_2.gif" |
| height=13 width=24 align=bottom> build the chart via the <code>buildChart()</code> |
| method, and then <img src="images/tag_3.gif" height=13 width=24 |
| align=bottom> draw the chart on an <code>org.eclipse.swt.graphics.Image</code> |
| named <code>cachedImage</code> through the <code>drawToCachedImage(...) |
| method.</code>. Thereafter, the cached image is used to draw the chart with a |
| call to <code>GC.drawImage(...)</code> <img src="images/tag_4.gif" |
| height=13 width=24 align=bottom> to draw the cached image on the |
| widget. The <code>buildChart()</code>, and <code>drawToCachedImage(...)</code> |
| follow:</p> |
| <pre> private void buildChart() {<br> Point size = getSize();<br> Bounds bo = BoundsImpl.create(0, 0, size.x, size.y);<br> int resolution = render.getDisplayServer().getDpiResolution();<br><img |
| src="images/tag_1.gif" height=13 width=24 align=CENTER> bo.scale(72d / resolution);<br> try {<br><img |
| src="images/tag_2.gif" height=13 width=24 align=CENTER> Generator gr = Generator.instance();<br><img |
| src="images/tag_3.gif" height=13 width=24 align=CENTER> state = gr.build(render.getDisplayServer(),<br> chart,<br> bo,<br> null,<br> null,<br> null);<br> } catch (ChartException ex) {<br> DefaultLoggerImpl.instance().log(ex);<br> }<br> }<br></pre> |
| <p>The <code>buildChart()</code> method is responsible for building |
| the runtime chart state with the render display server. One important |
| thing to do is to scale the bounds of chart from pixel to point. SWT and |
| other screen based renders always use pixels as the logical unit. |
| However, the BIRT Chart Engine uses points, which is an absolute unit (1 |
| point = 1/72 inch). We need to <img src="images/tag_1.gif" height=13 |
| width=24 align=CENTER> scale the bounds of chart from pixels to |
| points. Another important step is to <img src="images/tag_2.gif" |
| height=13 width=24> get a <code>Generator</code> instance and <img |
| src="images/tag_3.gif" height=13 width=24 align=CENTER> build the |
| runtime chart state with the given chart model and display server. So |
| the generated runtime chart state takes all necessary information to |
| render, which includes the <code>DisplayServer</code>, chart model, and |
| the bounds. The <code>DisplayServer</code> provides rendering-related |
| information, like DPI (Dots Per Inch) resolution. The bounds define the |
| area that the generated chart will be drawn on.</p> |
| <pre> public void drawToCachedImage(Rectangle size) {<br> GC gc = null;<br> try {<br> if (cachedImage != null)<br> cachedImage.dispose();<br> cachedImage = new Image(Display.getCurrent(), imageData);<br> |
| <img src="images/tag_1.gif" height=13 width=24 align=CENTER> gc = new GC(cachedImage);<br><img |
| src="images/tag_2.gif" height=13 width=24 align=CENTER> render.setProperty(IDeviceRenderer.GRAPHICS_CONTEXT, gc); |
| <br> Generator gr = Generator.instance();<br><img |
| src="images/tag_3.gif" height=13 width=24> gr.render(render, state);<br> } catch (ChartException ex) {<br> DefaultLoggerImpl.instance().log(ex);<br> } finally {<br> if (gc != null)<br> gc.dispose();<br> }<br></pre> |
| <p>In the <code>drawToCachedImage(...)</code> method we draw the |
| generated runtime chart state on the cached image. First, we <img |
| src="images/tag_1.gif" height=13 width=24 align=CENTER> create a |
| <code>GC</code> for the cached image, and <img src="images/tag_2.gif" |
| height=13 width=24 align=CENTER> set it into the renderer with |
| the property name <code>IDeviceRenderer.GRAPHICS_CONTEXT</code>. Then, |
| generator <img src="images/tag_3.gif" height=13 width=24> asks the |
| renderer to perform actual rendering with the generated runtime chart |
| state. Finally, we dispose the <code>GC</code> to ensure that underlying |
| system resources are released.</p> |
| <p>Next, we get a SWT canvas widget to display chart and also go |
| through the process to render the chart to a specific device. Now you |
| can create an instance of <code>ChartCanvas</code>, assign a chart |
| instance to it, and insert this canvas into the view.</p> |
| <h2>Others</h2> |
| <p><strong>Render Chart to File</strong></p> |
| <p>The BIRT Chart Engine also supports the rendering of a charts |
| directly to a file. The process is similar to the above. The difference |
| is the render device and you needn't use a cached image. First, get the |
| render device for PNG files. Then, set the render property, <code>IDeviceRender.FILE_IDENTIFIER</code>, |
| with file name. The other steps are as same as rendering chart on |
| screen.</p> |
| <pre> try { |
| PluginSettings ps = PluginSettings.instance(); |
| render = ps.getDevice("dv.PNG"); |
| render.setProperty(IDeviceRenderer.FILE_IDENTIFIER, "chart.png"); |
| } catch (ChartException ex) { |
| DefaultLoggerImpl.instance().log(ex); |
| } |
| </pre> |
| <h2><strong>Conclusion</strong></h2> |
| <p>This article introduces the whole process of using the BIRT Chart |
| Engine in plug-in development. BIRT Chart Engine supports almost all |
| types of chart, including bar charts, pie charts, and more. It also has |
| good abstraction for device renderers, and supports many rendering |
| devices, including SWT widgets, SWING components, numerous file formats |
| (JPEG, GIF, and PNG), and more. Although this article focuses on |
| rendering chart on SWT canvas, the concepts and process to render on |
| other devices are similar.</p> |
| </div> |
| <div class="notices"> |
| <h2>Notices</h2> |
| Java and all Java-based trademarks and logos are trademarks or |
| registered trademarks of Sun Microsystems, Inc. in the United States, |
| other countries, or both.</div> |
| </body> |
| </html> |