作者:Dustin Marx 和 Michael G. Martin
使用 JFreeChart 可以轻松绘制 Oracle 数据库数据图表,并可以选择多种高质量的图表类型。
2007 年 9 月发布
借助图表、数字和图形可更快速地了解和分析大型数据集。俗话说“百闻不如一见”,因为图片可以传达有关难以从文本数据本身获得的数据的重要概述和比较信息。 JFreeChart 是一个基于 Java 的开源(免费)库,利用它可以轻松创建多种类型的以数据为中心的高质量图表。这个功能强大的库提供了一个非常方便的 API,使不熟悉 JFreeChart 的开发人员可以快速创建表示其数据的高质量图表。在本文中,我们将使用 Oracle 数据库 10g 快捷版 (XE) 中的 HR 模式数据提供一个该过程的示例。
JFreeChart 简介
JFreeChart 项目的启动可追溯到 2000 年。这个库的最新版本 1.0.6 版于 2007 年 6 月发布,本文使用的就是该版本。
JFreeChart 支持生成多种不同类型的图表,包括从饼形图、条形图、面积图、直线图、柱状图以及 Gantt 图表等常见类型到 Candlestick、Wind 以及 Wafer Map 图表等较专业、不太常用的类型。确定 JFreeChart 支持的现成图表类型的最快的一种方法是检查 JFreeChart 的 ChartFactory 类的 Javadoc API 文档。
在一些开发环境中,可以使用 JFreeChart 有效地生成面向数据的图表,这些环境包括:
- 生成的文件为可移植网络图形 (PNG) 或 JPEG 格式
- 基于 Java SE Swing 的应用程序,包括小程序
- Java EE servlet 和 JavaServer 页面 (JSP)
- 与 iText 集成创建 PDF
- 与 Batik 集成创建 SVG 格式
要绘制成图表的数据
本文的图表中要以图形方式表示的数据来自于 Oracle 数据库快捷版提供的 HR 模式。图 1 显示了 Oracle 数据库快捷版附带的 SQL*Plus 编辑器中显示的 HR 模式中的表。
图 1:SQL 命令行工具中显示的 HR 模式表
Oracle 数据库快捷版还提供了一个非常有用、易于使用的基于 Web 的管理工具,该工具是在 Oracle Application Express 上构建的。图 2 演示了该工具,并且再次显示了 HR 模式中的某些对象(在本示例中为表)。
图 2:Oracle Application Express 中的 HR 模式表
Oracle 数据库快捷版为开发人员提供了很多优势,而且自身与 JFreeChart 兼容。Oracle 免费提供 Oracle 数据库快捷版用于开发和生产。除了免费的优点之外,一个占用空间较小、易于安装和管理以及非常有用的集成 Web 管理工具,也是该数据库产品的其他优势之一。其缺点主要影响大型企业用户,因为缺陷涉及存储空间、内存大小以及比传统 Oracle 数据库产品小的特性集。对于开发和构建原型,甚至对于小型生产数据库,Oracle 数据库快捷版都非常适合。对于预算有限的企业或项目来说尤为如此。
图 3 中的快照再次显示了这个基于 Web 的管理工具,该工具显示了 Oracle 数据库快捷版的某些最重要的限制。Oracle 数据库快捷版中一个实例的存储空间被限制为 5 GB(包括系统表空间),因此目前为止使用的 710 MB 在该工具的屏幕截图中被描述为大约是该限制的 14%。内存使用被限制为 1 GB,因此该实例的 314 MB RAM 使用情况也是据此描述的。以 SYSTEM 身份登录到该管理工具可以在管理屏幕上显示更具体的存储和内存信息。图 3 中的屏幕截图还显示了该工具提供的用于管理数据库的所有子菜单选项。
图 3:Oracle 数据库快捷版工具和使用情况监视
介绍了 Oracle 数据库快捷版和作为本文图表生成的数据源的 HR 模式之后,我们现在回过头来继续介绍 JFreeChart 本身。
下载并“安装”JFreeChart
JFreeChart 可从 www.jfree.org/jfreechart/ 下载。单个下载文件包含几个用于 JFreeChart 的 JAR 文件。将下载的文件解压缩到所选目录下后,任何使用 JFreeChart 的应用程序的类路径至少需要指向 jfreechart-1.0.5.jar 和 jcommon-1.0.9.jar 文件。可以通过将这些 JAR 文件添加到您喜欢的 IDE 的项目中来处理此问题。为了在 IDE 的外部构建和运行,Java SE 6 允许在类路径中使用通配符指定 JAR,因此 JFreeChart 库目录中的 JAR 都可以包括在类路径中的一个 *.jar 表达式中。除了解压缩分发文件并将您的应用程序的类路径指向相应的 JFreeChart JAR 文件之外,不需要任何重要的安装工作。
为示例代码相关性配置 Oracle JDeveloper
图 4 显示了构建和运行本文中的大多数代码示例所需的相关 JAR 文件。列出了前面提到的两个 JFreeChart JAR,以及 iText(用于生成 PDF)、Batik(用于生成 SVG)和 Oracle JDBC(用于对 Oracle 数据库进行 Java 访问)的 JAR。即使您没使用 JDeveloper,图 4 还是会在一个单独的位置显示您将需要置于类路径中以构建和运行本文中讨论的大多数工具的相关性。
图 4:要添加到 JDeveloper 项目(或类路径中的其他位置)的 JAR
生成 JFreeChart Javadoc API 文档
JFreeChart 压缩的分发文件还包括一个 build.xml 文件,该文件对于生成基于 JFreeChart Javadoc 的文档尤为有用。要生成 JFreeChart 文档,请在提供的 Ant build.xml 文件上运行“javadoc”目标(在“ant”子目录中运行“ant javadoc”)。假定您已经安装了 Ant,该将在 JFreeChart 文件的解压缩目录中生成一个“javadoc”子目录,并将生成的 Javadoc 文件放在该目录中。JFreeChart Web 站点也在线提供 JFreeChart 的 Javadoc 文档。
简要介绍 JFreeChart 的主要类和接口
JFreeChart 附带了许多程序包、类和接口,但您只需了解其中很少一部分就可以开始使用 JFreeChart。本节简要介绍一些主要的类和接口,它们是使用 JFreeChart 的基础并将在本文的示例中使用。
JFreeChart 类
JFreeChart 库中最重要的类之一是它本身,名为 JFreeChart。该类提供一种 Java 二维图表的表示。利用该类上的方法,开发人员可以控制生成的图表的各个方面,并可以创建表示图表的抽象窗口工具包 (AWT) BufferedImage。您只需非常少的额外工作即可直接使用 JFreeChart 创建几种简单的图表类型,但 JFreeChart 却可以提供对代表(如允许对所生成的图表进行更多控制的 Plot)的访问。
ChartFactory 类
ChartFactory 类用于创建不同类型的图表。该类的每种静态方法都根据其生成的图表类型命名,无论调用何种类型的图表,每种方法都返回一个通用的 JFreeChart 类实例。扫描该类的 Javadoc 文档可以加深了解,也是确定 JFreeChart 提供的现成的基本图表类型的最简单方法之一。
ChartUtilities 类
与 ChartFactory 类相似,ChartUtilities 类也具有大量静态方法。该类提供的大多数方法都可以将图表转换为一种图像格式或基本的 HTML 图像映射。
数据集接口和实现类
检查 ChartFactory 图表创建方法表明这些方法中的每一种都接受某种类型的数据集扩展的接口(注意类名称中的数据集)作为参数。针对数据集接口生成的 Javadoc 文档显示了它是由几个子接口扩展的,由更多具体类实现的。
用于各种类型图表的数据集子接口通常是显而易见的,因为图表类型的名称通常出现在接口名称中。例如,PieDataset 用于饼形图,XYDataset 用于许多 x,y 类型图表。CategoryDataset 用于直线图和面积图,其他扩展数据集接口的子接口用于其他图表类型。
数据集子接口是为要在图表中表示的 ChartFactory 类提供数据的机制。创建适当数据集子接口的具体实现,对其进行填充并传递到 ChartFactory 的xiangy create***Chart 方法,其中 *** 是相关的图表类型。
不要将 JFreeChart 提供的数据集接口与 JDBC 4 提供的数据集接口混淆。JFreeChart 提供的数据集接口无需从数据库填充,也不必以任何方式与数据库相关。相反,JFreeChart 数据集接口及其子接口是为使用数据填充 JFreeChart 图表而设计的。
在运行中了解 JFreeChart:示例
本文的其余部分主要用于阐释某些 JFreeChart 特性以及 JFreeChart 是多么容易上手。本文通过一系列代码示例以及所生成图表的快照来阐释 JFreeChart 的可用性及特性。介绍每个示例时,还会介绍与每个具体示例有关的方面以及其他常用的 JFreeChart 概念。
示例 1:使用饼形图直接绘制 HR 模式数据图表
本文的大多数示例都涉及到使用 JFreeChart 根据 Oracle 数据库快捷版提供的 HR 模式中存储的数据创建图表。由于我们要绘制数据库中存储的数据的图表,因此面向 JDBC 的数据集类尤为便利。这第一个示例显示了如何使用饼形图绘制每个部门的员工数量的图表。
清单 1 演示了根据数据库中存储的数据创建图表是多么容易。databaseAccess.getOracleDbConnection() 方法(未在此处显示)是一个简单方法,它提供了一个 Oracle 数据库连接(返回一个 java.sql.Connection)。
清单 1: 使用 JFreeChart 的 JDBCPieDataset 创建一个饼形图
/** * Create pie chart representing percentage of employees in each department * that has at least one employee. * * @return Pie chart; null if no image created. */ public JFreeChart createNumberEmpsPerDeptPieChart() { JFreeChart pieChart = null; final String QUERY_NUMBER_EMPLOYEES_PER_DEPARTMENT = "SELECT departments.department_name, count(*) AS num_employees " + "FROM departments, employees " + "WHERE employees.department_id = departments.department_id " + "GROUP BY departments.department_name"; final String TITLE_EMPS_PER_DEPT = “Employees Per Department”; try { PieDataset pieDataset = new JDBCPieDataset( databaseAccess.getOracleDbConnection(), QUERY_NUMBER_EMPLOYEES_PER_DEPARTMENT ); pieChart = ChartFactory.createPieChart( TITLE_EMPS_PER_DEPT, // chart title pieDataset, true, // legend displayed true, // tooltips displayed false ); // no URLs } catch (SQLException sqlEx) // checked exception { System.err.println("Error trying to acquire JDBCPieDataset."); System.err.println("Error Code:" + sqlEx.getErrorCode()); System.err.println("SQLSTATE:" + sqlEx.getSQLState()); sqlEx.printStackTrace(); } return pieChart; }
如清单 1 所示,从数据库生成一个饼形图只需要两条重要的 Java 代码语句。创建相应的数据集,然后将其传递给 ChartFactory 的 createPieChart 方法,该方法返回包含所生成的饼形图的 JFreeChart。构造一个 JDBCPieDataset,并传递一个数据库连接和一个数据库 SQL 查询字符串。由于该具体类实现 PieDataset 接口,因此我们可以通过接口将其传递给 createPieChart 方法。该代码清单中 SQLException 的 catch 块是必需的,因为 JDBCPieDataset 构造器抛出检查到的 SQLException 异常。
以 JFreeChart 类的实例形式创建了一个图表之后,我们可以对该图表进行一些操作。对创建的图表可以做的最简单的操作之一是将其作为图像文件写入文件系统。清单 2 中的代码阐释了如何使用 ChartUtilities 将新创建的 JFreeChart 作为一个 PNG 格式的图像写入文件系统。
清单 2: 将图表写入 PNG 文件
/** * Write .png file based on provided JFreeChart. * * @param aChart JFreeChart. * @param aFileName Name of file to which JFreeChart will be written.. * @param aWidth Width of image. * @param aHeight Height of image. */ public void writePngBasedOnChart( JFreeChart aChart, String aFileName, int aWidth, int aHeight ) { try { ChartUtilities.writeChartAsPNG( new FileOutputStream(aFileName), aChart, aWidth, aHeight); } catch (IOException ioEx) { System.err.println("Error writing PNG file " + aFileName); } }
该代码清单只有一条重要的 Java 代码语句,用于将 JFreeChart 图表将作为 PNG 文件写出。这条语句调用 ChartUtilities.writeChartAsPNG 方法,向其传递清单 1 中新创建的 JFreeChart 图表,以及指明要将该图像写入到的文件的名称以及图像的长度和宽度的字符串。注意,这个通用方法可以接受任何 JFreeChart 图表,因此可用于所有图表类型。在本示例中,我们构造了一个饼形图(如图 5 所示)。从该图表可以很快看出绝大多数员工在 Shipping 或 Sales 部门工作。
图 5:根据 DB 查询创建的 PNG 格式饼形图
如果不算用于处理异常、获得一个数据库连接以及返回类的“基础架构”代码行,直接从数据库创建图 5 中的图表只需三条重要的 Java 代码语句。这三条语句对应于使用 JFreeChart 从数据库生成基本图表通常所需的三个步骤:
- 用一个有效的数据库连接和相应的数据库 SQL 查询字符串创建相应的面向 JDBC 的数据集的实例。
- 将上一步骤中的面向 JDBC 的数据集传递给所需图表类型对应的 ChartFactory.create***Chart 方法。
- 以适当的格式显示新创建的 JFreeChart(第一个示例中的 PNG 文件)。
本文的其余部分将介绍其他显示生成的图表的方法以及其他类型图表的示例。
示例 2:使用三维饼形图间接绘制 HR 模式数据图表
在第一个示例中,通过使用面向 JDBC 的数据集直接检索的数据集构造了一个饼形图。 特定的实现是使用提供的数据库连接和 SQL 查询语句构造的。然而,有时可能无法使用或者不希望使用面向 JDBC 的数据集。例如,JFreeChart 仅为 PieDataset、CategoryDataset 和 XYDataset 子接口提供面向 JDBC 的数据集实现。可能还存在这样的情况:很难以适合 JFreeChart 的格式从数据库中提取数据,必须先在 Java 代码中进行一些数据操作。最后,可能不希望图表生成与数据库查询紧密耦合。无论上述哪种情况,都可改用非面向 JDBC 的数据集。清单 3 演示了如何针对三维饼形图实现该操作。
清单 3: 手动构造数据集并生成 JPG 图表
JFreeChart pieChart3D = null; final DefaultPieDataset pieDataset = new DefaultPieDataset(); /* Query used by getNumberEmployeesByLocation() method: SELECT locations.city, count(*) AS num_employees FROM departments, employees, locations WHERE employees.department_id = departments.department_id AND departments.location_id = locations.location_id GROUP BY locations.city */ Map<String, Integer> empsAtEachLocation= databaseAccess.getNumberEmployeesByLocation(); for ( Map.Entry numEmpsAtLoc :empsAtEachLocation.entrySet() ) { pieDataset.setValue( numEmpsAtLoc.getKey().toString(), Integer.parseInt(numEmpsAtLoc.getValue().toString()) ); } pieChart3D = ChartFactory.createPieChart3D( TITLE_EMPS_PER_LOC, pieDataset, true, true, false ); final String fileName = "EmpsPerLocPieChart3D.jpg"; try { ChartUtilities.writeChartAsJPEG( new FileOutputStream(fileName), aChart, aWidth, aHeight); } catch (IOException ioEx) { System.err.println( "Error writing JPG file " + fileName); }
清单 3 中的代码比第一个实例中所需的代码略微冗长一些,因为它没有利用针对饼形图的 JDBC 数据集,而是将 Map 条目从其数据库存取器 (databaseAccess.getNumberEmployeesByLocation) 复制到一个被传递给 createPieChart3D 方法的 DefaultPieDataset 中。尽管这段代码比第一个实例所需的代码长,但它的优点是无需处理 SQLException,而且与数据库查询的的直接耦合程度也没那么高。
该示例还生成一个 JPEG (.jpg) 文件,而非第一个实例中生成的图像之类的 PNG (.png) 文件。这两个文件都是图像文件格式,这两个示例都显示了将一个图表写出到任何一种图像格式是多么容易。图 6 中显示了作为运行清单 3 中的代码的结果创建的实际 JPEG 图像。
图 6:从数据库创建的 JPEG 格式的三维饼形图
这种数据图形表示打动您的一点就在于大多数员工在南圣弗朗西斯科、牛津或西雅图工作。
由于使用面向 JDBC 的数据集无需从 Java 集合或结果集转换为 JFreeChart 所需的数据集格式,因此在可能的情况下,我们将在本文的其余部分都使用该方法以保持简单。然而如前所述,存在这样的情况:由于数据库访问与图表生成之间的强耦合,该方法无法实现或者不是所需要的。同样,尽管使用面向 JDBC 的数据集时需要捕获检查到的 SQLException 异常,但我们在本文后面的代码清单中将省略大多数异常处理代码。
示例 3:在 Swing 中生成条形图
该示例演示如何使用 JFreeChart 生成条形图,还将介绍在 Swing 中显示 JFreeChart 生成的图表的想法。清单 4 显示了用于生成该图表以及在 Swing 中显示生成的图表的最重要的代码。
清单 4: 从 Java Swing 生成条形图
/** * Create Bar Chart showing salary of each employee. * * @param aOrientation Horizontal or Vertical orientation of bar chart. * @return Bar Chart. */ public JFreeChart createSalaryPerFinanceEmployeeBarChart( PlotOrientation aOrientation) { JFreeChart barChart = null; try { final String QUERY_SALARY_PER_FINANCE_EMPLOYEE = "SELECT first_name || ' ' || last_name AS Name, salary " + "FROM employees " + "WHERE department_id = 100"; final CategoryDataset barDataset = new JDBCCategoryDataset( databaseAccess.getOracleDbConnection(), QUERY_SALARY_PER_FINANCE_EMPLOYEE ); barChart = ChartFactory.createBarChart( TITLE_SALARY_PER_FINANCE_EMP, // title LABEL_EMPLOYEES_FINANCE, // x-axis label LABEL_SALARIES, // y-axis label barDataset, aOrientation, true, // legend displayed true, // tooltips displayed false ); // no URLs } catch (SQLException sqlEx) { // . . . exception handling goes here . . . } return barChart; } . . . JFrame frame = new JFrame(aTitle); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JFreeChart barChart = createSalaryPerFinanceEmployeeBarChart( PlotOrientation.VERTICAL); BufferedImage image = barChart.createBufferedImage(750,450); JLabel label = new JLabel(); label.setIcon(new ImageIcon(image)); frame.getContentPane().add(label); frame.pack(); frame.setVisible(true);
该代码示例使用 String 常量取代硬编码的字符串,这些常量可以根据它们字母全部大写、单词之间用下划线分隔的命名规则得以轻松识别。
前两个饼形图生成示例使用了一个 PieDataset。这个条形图生成示例改用了一个 CategoryDataset。与饼形图不同,方向也是条形图的一个问题,可以指定垂直或水平两个方向。该示例指定了一个垂直绘制方向。
在代码清单的底部,示例代码演示了如何将图表作为一个可以作为图标轻松应用到 JLabel 的 BufferedImage 进行检索。图 7 显示了这个包含 JFreeChart 生成的条形图的简单的 Swing 图形用户界面 (GUI) 的快照图片。
图 7:在 Swing 应用程序中生成的条形图
示例 4:在 Java Servlet 中生成图表
该示例演示了如何在 servlet 容器中生成一个 JFreeChart。如前一个示例所示,JFreeChart 可以向 BufferedImage 显示任何图表。以下代码清单利用此功能并向 JFreeChart 生成的图像添加一个示例公司徽标。最终图像和 servlet 输出流被传递给 JFreeChart 的 ChartUtilities 类进行写操作。
清单 5:在 Java Servlet 中生成图表
/** * Processes requests for both HTTPGET
andPOST
methods. * @param request servlet request * @throws javax.servlet.ServletException * @throws java.io.IOException * @param response servlet response */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ImageType imageType = ImageType.valueOf(request.getParameter("type")); int imageWidth = Integer.valueOf(request.getParameter("width")); int imageHeight = Integer.valueOf(request.getParameter("height")); float imageQuality = Float.valueOf(request.getParameter("quality")); if (imageType.equals(ImageType.PNG)) { response.setContentType("image/png"); } else if (imageType.equals(ImageType.JPEG)) { response.setContentType("image/jpg"); } HrJobsData data = getHrJobData(); writeImage(imageType,data,response.getOutputStream(),imageWidth,imageHeight, quality); response.getOutputStream().close(); }
清单 5 中的代码显示了 getHrJobData() 方法提供的数据。此处并未显示该方法的实现,但该方法只不过是一个从持久性源检索数据的方法。由于该代码在一个 servlet 容器中执行,因此应使用一个数据源利用该 servlet 容器的事务支持和该数据源的连接缓冲池。使用数据源还将以与供应商无关的方式提供到我们代码的数据库连接。
从 servlet 的 doGet 和 doPost 方法调用 processRequest 方法。servlet 希望传入图像类型、宽度、高度和质量。目前,servlet 支持用简单枚举类型表示的 PNG 或 JPEG 类型的图像。数据对象是表示我们希望绘制成图表的数据的 XML 对象。servlet 根据传入的图像类型设置正确的内容类型,然后调用 writeImage 创建图像并通过 HTTP 响应输出流发送。
清单 6: 自定义图表生成器
private void writeImage(ImageType imageType,HrJobsData data, OutputStream outputStream, int width, int height, float quality) { try { double[][] minWages = new double[1][data.getHrJob().size()]; double[][] maxWages = new double[1][data.getHrJob().size()]; String[] categories = new String[data.getHrJob().size()]; int index = 0; for (HrJob hrJob :data.getHrJob()) { minWages[0][index] = hrJob.getMinimumSalary(); maxWages[0][index] = hrJob.getMaximumSalary(); categories[index] = hrJob.getJobTitle(); index++; } DefaultIntervalCategoryDataset dataset = new DefaultIntervalCategoryDataset(minWages,maxWages); dataset.setCategoryKeys(categories); JFreeChart chart = ChartFactory.createBarChart("Job Salary Ranges", "Job Title", "Salary Range", dataset, PlotOrientation.HORIZONTAL, false, false, false); IntervalBarRenderer renderer = new IntervalBarRenderer(); ((CategoryPlot)chart.getPlot()).setRenderer(renderer); BufferedImage img = chart.createBufferedImage(width, height); BufferedImage logo = getLogo(); Graphics2D graphics2D = (Graphics2D) img.getGraphics(); graphics2D.drawImage(logo, null,LOGO_OFFSET_X, LOGO_OFFSET_Y); graphics2D.dispose(); if (imageType.equals(ImageType.JPEG)) { ChartUtilities.writeBufferedImageAsJPEG(outputStream, quality, img); } else if (imageType.equals(imageType.PNG)) { // PNG scales the quality from 0-9 int pngQuality = (int) (quality * 9); ChartUtilities.writeBufferedImageAsPNG( outputStream, img, true, pngQuality); } } catch (IOException ex) { // . . . exception handling goes here . . . } }
我们要绘制成图表的数据表示各个职位的工资范围。具有 IntervalBarRenderer 的 JFreeChart 条形图可以很好地反映这组数据。对传入的 XML 数据进行迭代,用最低工资、最高工资和职位填写三个数组。在生成的图表上调用 createBufferedImage 可以提供一个 BufferedImage。getLogo 调用返回包含在另一个 BufferedImage 中的我们的公司徽标。使用 Java 的二维图形功能,可以将公司徽标绘制在图表图像上,与原来的图表图像有一些小的偏移。
quality 参数允许对压缩水平进行精细控制。对于 JPEG 图像,质量范围为 0.0 到 1.0。较低的值将产生较小的文件,但是会降低图像质量。对于 PNG 图像,质量范围为 0 到 9。PNG 是一个无损压缩格式,因此该质量适用于不会危及质量的数据的压缩水平。生成的 PNG 图像的质量与原来的图像质量相同。
最后调用 ChartUtilities.writeBufferedImageAsPNG 或 ChartUtilities.writeBufferedImageAsJPEG 使得 servlet 可以很容易地将最终图像发回到浏览器。
要调用 servlet,可以使用标准的 HTML img 标记。清单 7 显示了一个简单的 JSP 页面,该页面使用一个嵌入的 img 标记调用 servlet 并在 Web 页面中显示一个生成的图表。
清单 7: 调用 Servlet 以生成图表的 JSP
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Title Salary Ranges</title> </head> <body> <h1 style="text-align:center">Job Salary Ranges</h1> <img src="<%=request.getContextPath()%>/GetChart?type=PNG&width=800&height=400&quality=.9"></img> </body> </html>
图 8 显示了调用该 servlet 返回一个 JFreeChart 图像的最终结果。
图 8:PNG 格式的 Servlet 构建的时间间隔条形图
示例 5:使用 Cewolf 在 JSP 中生成图表
Cewolf(支持图表的 Web 对象框架)构建在 JFreeChart 上,使开发人员可以通过 JSP 自定义标记从 JavaServer 页面访问 JFreeChart 库。与 JFreeChart 一样,Cewolf 也提供了一个简单的 API。Cewolf 可免费获得。在本示例中,我们使用 Cewolf 0.9.3。
图 9 中的图像是使用 JFreeChart 和 Cewolf JSP 标记生成的垂直条形图的屏幕截图。它在 Firefox Web 浏览器中显示,在 Oracle Containers for J2EE 10g 上托管。该图像证明 HR 数据中表示的虚拟公司中的管理人员薪资很好。
图 9:使用 Cewolf JSP 自定义标记在 JSP 中生成的堆积条形图
使用 Cewolf 和 JSP 创建上图所示的图表很简单。下面是该 JSP 页面的代码:
清单 8: 使用 Cewolf 标记生成图表的 JSP 页面
<?xml version='1.0' encoding='windows-1252'?> <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0" xmlns:cewolf="etc/cewolf.tld"> <jsp:output omit-xml-declaration="true" doctype-root-element="HTML" doctype-system="http://www.w3.org/TR/html4/loose.dtd" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" <jsp:directive.page contentType="text/html;charset=windows-1252" <jsp:useBean id="chartData" class="org.marx.hr.charting.HrDeptSalariesCategoryDataset" <script type="JavaScript" src="overlib.js"><!-- overLIB (c) Erik Bosrup --></script> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252" <title>Render JFreeChart in JSP with Cewolf JSP Tag Library</title> </head> <body> <cewolf:chart id="theChart" type="stackedverticalbar" title="Salaries For Each Department" xaxislabel="Departments" yaxislabel="Salaries"> <cewolf:data> <cewolf:producer id="chartData" </cewolf:data> </cewolf:chart> <cewolf:img chartid="theChart" renderer="/cewolf" alt="Salaries per Employee Along Department Lines" width="1200" height="800" </body> </html> </jsp:root>
特定于 Cewolf 的部分代码包括 <cewolf:chart> 元素、<cewolf:img> 元素开始标记和结束标记之间的代码行,指向 Cewolf 命名空间以定义这些元素的 cewolf 前缀的代码行,以及用于包括实际生成图表的 Java 类的 jsp:useBean 代码行。
生成该示例所需的大多数工作都位于该 JSP 页面通过 jsp:useBean 代码行访问的 Java 类中。该 Java 类实现几个主要的 Cewolf 接口,从其 produceDataset(Map) 方法(实现 Cewolf 的 DatasetProducer 接口所需的方法)返回一个 JFreeChart 数据集子接口。
produceDataset(Map) 方法中的代码仅创建相应 JFreeChart 数据集接口的具体实现,与本文前述示例中完全相同。在本示例中,DefaultCategoryDataset 被实例化,用数据进行填充,并从 produceDataset(Map) 返回,这是因为 JSP 页面需要可以实现提供的 CategoryDataset 接口以生成堆积垂直条形图的内容。
Cewolf 主页包括一个教程,该教程演示如何对 web.xml 文件进行修改以便在适当时候可以调用 Cewolf servlet。该教程还解释如何实现 DatasetProducer 接口以便为 JSP 页面中的 Cewolf 自定义标记提供数据。
示例 6:使用 Apache Batik 在 SVG 中生成图表
无需任何专门的工作,JFreeChart 即可提供现成的 PNG 和 JPEG 图像生成。由于图表实际上是由直线以及诸如矩形、圆形以及其他矢量形状组成的,因此 SVG(可伸缩矢量图形)等基于矢量的格式似乎都非常适合图表。尽管 JFreeChart 并不直接提供 SVG 显示功能,但它可与 Apache 的 Batik SVG 工具包结合使用以形成其图表的 SVG 表示。
Batik SVG 工具包是一个基于 Java 的工具包,它用于操作 SVG,免费提供。本示例中使用 Batik 1.7。分发中包括几个可执行的 JAR 文件。其中一个文件 (batik.jar) 是一个可执行的 JAR,它运行一个名为 Squiggle 的 SVG 处理和查看工具 (java –jar batik.jar)。
在本示例中,我们首先将在自己的 Java 代码中将 Batik 直接用作一个库,然后将使用可执行的 JAR (batik.jar) 运行 Squiggle 以查看生成的 SVG 文件。为了构建和运行本示例中与 Batik 有关的代码,必须在类路径(或者 JDeveloper 或其他 IDE 的项目)中包括六个 JAR 文件。图 4 显示了这六个 JAR 文件(六个以“Batik”开头的 JAR 文件)。
在本示例中,生成的图表是一个显示发货员工资的三维条形图。这与前面的条形图示例(示例 3)不同,因为它具有三维而非二维的外观,并被指定为一个水平条形图而非垂直条形图。以下两个代码清单分别显示了如何生成该图表以及如何以 SVG 格式写出。
清单 9: 创建三维条形图
/** * Create 3D bar chart representing salaries of shipping clerks. * * @param aOrientation Horizontal or Vertical orientation. * @return 3D bar chart. */ public JFreeChart createSalaryPerShippingClerkBarChart3D( PlotOrientation aOrientation) { JFreeChart barChart = null; try { final String QUERY_SALARY_PER_SHIPPING_CLERK = "SELECT first_name || ' ' || last_name AS name, salary " + "FROM employees " + "WHERE job_id = 'SH_CLERK'"; final CategoryDataset barDataset = new JDBCCategoryDataset( databaseAccess.getOracleDbConnection(), QUERY_SALARY_PER_SHIPPING_CLERK ); barChart = ChartFactory.createBarChart3D( TITLE_COUNTRIES_PER_REGION, // title LABEL_SHIPPING_CLERKS, LABEL_SALARIES, barDataset, aOrientation, true, // legend displayed true, // tooltips displayed false ); // no URLs } catch (SQLException sqlEx) { // exception handling code . . . } return barChart; }
上一个代码清单演示了创建三维条形图与创建二维条形图基本相同,只是 ChartFactory 类上调用的方法名不同。以下代码清单显示了如何将这个或任何其他生成的 JFreeChart 写出为 SVG 格式。
清单 10: 以 SVG 格式显示 JFreeChart 生成的图表
/** * Write .svg file based on provided JFreeChart. * * @param aChart Chart to be written out as SVG. * @param aFileName Name of file (without extension) to hold SVG XML. * @param aWidth Width of image. * @param aHeight Height of image. */ public void writeSvgBasedOnChart( JFreeChart aChart, String aFileName, int aWidth, int aHeight ) { final String fileExtension = ".svg"; final String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI; final DOMImplementation dom = GenericDOMImplementation.getDOMImplementation(); org.w3c.dom.Document document = dom.createDocument(svgNS, "svg", null); SVGGraphics2D svgGraphic = new SVGGraphics2D(document); aChart.draw( svgGraphic, new java.awt.Rectangle(aWidth, aHeight) ); try { boolean useCSS = true; // we want to use CSS style attributes OutputStream outputStream = new FileOutputStream(aFileName + fileExtension); Writer output = new OutputStreamWriter(outputStream, "UTF-8"); svgGraphic.stream(output, useCSS); outputStream.flush(); outputStream.close(); } catch (IOException ioEx) { System.err.println("Problem encountered trying to write SVG file: "); ioEx.printStackTrace(); } }
将三维条形图传给上面的方法以便写出 SVG 时,会将该条形图写入到所提供的文件名。生成的 SVG 文件将只是一个扩展名为 .svg 的文本文件,包含符合 SVG 的 XML 内容。可以用任何文本编辑器查看该生成文件中的 XML,但使用 Batik、Inkscape 或几乎是任何现代图形文件编辑器等工具查看 SVG 显示的图像,则更为有趣。实际上,可以在任何最新版本的 Firefox Web 浏览器中直接打开某个 .svg 文件来查看 SVG,因为它附带了一个内置的 SVG 查看器。此处显示的图形是 Batik 的 Squiggle 显示生成的 SVG 文件的快照。
图 10:SVG 格式的三维水平条形图(由 Batik Squiggle 显示)
用 SVG 格式显示图表有几个好处,其中一个最明显的好处就是能够根据我们的需要放大图像且不会损失分辨率,这都多亏了 SVG 矢量图形的可伸缩性。其他好处包括使用 Inkscape 之类的工具或者甚至手动(如果需要的话)编辑生成的 SVG 来调整生成的图像也变得相对容易。
示例 7:使用 iText 在 PDF 中显示图表
图表经常用于为管理人员、客户、股东和其他利益相关者提供的演示中。然而,通过 Java 应用程序或作为纯文本文件显示图表通常不适合这些类型的观众。将生成的图表添加到 PDF 中对于向不同的观众演示很有帮助。有几种 Java 到 PDF 的转换器适用于该目的。下面我们演示一个使用其中的一个 Java 到 PDF 库 iText 的简单示例。
iText Java 到 PDF 库是免费提供的。我们的示例中使用的版本是 itext-2.0.2,是一个相对较小的文件,易于下载。这个下载的编译 JAR 是一个可执行文件,可通过 java –jar itext-2.0.2 命令或单击 Windows 中的 JAR 运行。运行该 JAR 会弹出“iText Toolbox”人机界面 (HMI),该界面可用于将文本或 TIFF 图像转换为 PDF 并提供其他实用工具功能。该示例没有使用这个 HMI,而是将 iText 用作一个库并使用该库将 JFreeChart 生成的图表转换为 PDF。
下载 iText JAR 后的第一个步骤是将它放在 build 和运行时类路径或 IDE 的项目中。使用 iText 将图表写入 PDF 并不比下载 JAR 文件并将其放在类路径中难很多。以下两个代码清单显示了创建圆环图(类似于饼形图,使用 PieDataset)的代码以及将该生成的图表写出到 PDF 中的代码。
清单 11: 创建圆环图
/** * Create ring chart indicating number of countries in each region. * * @return Ring (similar to Pie) Chart with number of countries per region. */ public JFreeChart createCountriesPerRegionRingChart() { JFreeChart ringChart = null; try { final String QUERY_NUMBER_COUNTRIES_PER_REGION = "SELECT regions.region_name, count(*) AS num_countries " + " FROM regions, countries " + "WHERE regions.region_id = countries.region_id " + "GROUP BY regions.region_name"; final PieDataset ringDataset = new JDBCPieDataset( databaseAccess.getOracleDbConnection(), QUERY_NUMBER_COUNTRIES_PER_REGION ); ringChart = ChartFactory.createRingChart( TITLE_COUNTRIES_PER_REGION, // title ringDataset, // pie (ring) dataset true, // legend displayed true, // tooltips displayed false ); // no URLs } catch ( SQLException sqlEx ) { // exception handling code here . . . } return ringChart; }
上述代码清单与本文中使用 JFreeChart 生成图表的其他代码清单十分相似。下一个代码清单显示如何将该图表或任何其他使用 JFreeChart 生成的图表写入 PDF。生成的 JFreeChart(在本例中为在上一个清单中创建的圆环图)可以与包含应写入的 PDF 文件的文件名的字符串一同被传递到下面的方法。
清单 12: 在 PDF 中显示 JFreeChart 生成的图表
/** * Write PDF based on the provided chart. * * @param aChart Chart to be written out as PDF. * @param aOutputPdfFileName File name (without extension) to write PDF file. * @param aWidth Width of chart to be rendered. * @param aHeight Height of chart to be rendered. */ public void writePdfBasedOnChart( JFreeChart aChart, String aOutputPdfFileName, int aWidth, int aHeight ) { final String fileExtension = ".pdf"; // com.lowagie.text.Document Document document = new Document(); try { PdfWriter.getInstance( document, new FileOutputStream( aOutputPdfFileName + fileExtension)); document.open(); Image png = Image.getInstance( ChartUtilities.encodeAsPNG( aChart.createBufferedImage(aWidth,aHeight))); document.add(png); document.close(); } catch (DocumentException docEx) // checked exception { docEx.printStackTrace(); } catch (IOException ioEx) // checked exception { ioEx.printStackTrace(); } }
如上述代码清单所示,只需六条与 iText 相关的 Java 代码语句即可将提供的图表写入 PDF。这些步骤如下所示:
- 创建 iText 文档(从 com.lowagie.text 程序包中)。
- 使用 open() 方法打开 iText 文档。
- 使用静态 Image.getInstance() 方法调用实例化一个 iText 图像,以 byte[] 形式接收图表。
- 将图像添加到 iText 文档中(使用它的 add() 方法)。
- 关闭 iText 文档(使用它的 close() 方法)。
图 11 是上述代码生成的 PDF 的屏幕截图。
图 11:显示包含生成的圆环图的 PDF 的 Adobe Reader
JFreeChart 支持将图表作为 BufferedImage 以 byte[] 格式写出,这使得将图表转换为可以通过 iText 直接转换为 PDF 的格式变得十分简单。
示例 8:自定义小图
虽然该 servlet 示例显示了某些图表创建的自定义,但是本文前面的大多数示例都直接使用了 JFreeChart 生成的图表,而没有进行任何自定义。利用 JFreeChart,开发人员可以自定义图表,但是这会增加复杂性。该示例显示的是一些相当简单的自定义,但是也可以进行功能强大得多也复杂得多的自定义。事实上,只要您愿意编写足够多的代码,自定义几乎是没有限制的。
在该示例中,生成的直线图将具有一个透明的背景(透明性支持是 PNG 格式的众多优势中的一个),并将其系列绘图颜色由默认的红色改为蓝色。直线图或许不是显示 HR 模式中每个 Oracle 数据库对象类型的数量的最佳图表类型,但是使用直线图为我们提供了一个演示 JFreeChart 的三维直线图功能的机会。
下面显示了三个图像。第一个(图 12)是使用 Oracle 数据库快捷版附带的基于 Web 的管理工具的屏幕截图,它按对象类型显示了 HR 模式中的模式对象的数量。下一个图像(图 13)显示 JFreeChart 使用默认的颜色(灰色背景和红色绘图色)未进行任何自定义现成生成的直线图,第三个图像(图 14)显示基于相同数据的自定义 JFreeChart 图表。这两个 JFreeChart 生成的图像都显示了各自在浏览器中显示的图表,背景颜色故意设置为较暗的阴影以使自定义图表的背景更明显。
图 14 中显示的图表具有一个透明的背景,这在该图与图 13 比较时最容易看到。但是,只有图表的外部是透明的。具有实际图形的绘图部分称为绘图区,在两种情况下都是白色的。可以使用与更改整体图表的背景相同的方式来更改绘图区的背景颜色。按照在与在图表自身上调用 setBackgroundPaint 方法相同的方式在绘图区上调用 setBackgroundPaint 方法,就生成了图 14。
图 12:Oracle 数据库快捷版 Web 工具对 HR 数据库对象的显示
图 13:显示 HR 模式中每个对象的数量的直线图
图 14:与图 13 中显示的是同一个图表,但是具有透明的背景颜色和蓝色轮廓颜色
下一个代码清单显示生成自定义的三维直线图的代码。
清单 13: 生成具有背景透明性的 PNG 文件
/** * Write .png file with transparent background based on provided JFreeChart. * * @param aChart JFreeChart. * @param aFileName Name of file to which JFreeChart will write chart. * @param aWidth Width of image. * @param aHeight Height of image. */ public void writePngTransparentBasedOnChart( JFreeChart aChart, String aFileName, int aWidth, int aHeight ) { final String fileExtension = ".png"; try { aChart.setBackgroundPaint( new Color(255,255,255,0) ); CategoryItemRenderer renderer = aChart.getCategoryPlot().getRenderer(); renderer.setSeriesPaint(0, Color.blue.brighter()); renderer.setSeriesVisible(0, true); // default renderer.setSeriesVisibleInLegend(0, true); // default ChartUtilities.writeChartAsPNG( new FileOutputStream(aFileName + fileExtension), aChart, aWidth, aHeight, null, true, // encodeAlpha 0 ); } catch (IOException ioEx) { System.err.println( "Error writing PNG file " + aFileName + fileExtension); } }
示例 9:使用 XML 为 JFreeChart 提供输入数据
最后一个示例演示如何基于 XML 数据创建 JFreeChart。在本示例中,我们将使用 Oracle 数据库支持以 XML 形式返回表中的数据。通常,当我们只使用 JDBC 数据集即可直接处理关系数据时,我们并不希望将关系数据转换为 XML 进行 JFreeChart 处理。但是,该关系到 XML 转换的特性在本示例中却很有用,因为利用该特性,我们可以使用 HR 模式模拟面向 XML 的数据源。许多源都可以 XML 格式提供数据,包括 XML 数据库(如存储 XML 文档而非传统的标准化关系数据的 Oracle 数据库)、XML Web 服务以及其他产品和库。
在本示例中,我们将收集 HR 模式中有关员工佣金率的信息。我们在此处假定表中佣金值为空的员工没有佣金补偿,因此只绘制了确实收到佣金的人员的佣金率图表。清单 14 显示了与此相关的一般关系数据查询。
清单 14:用于佣金查询的 SQL SELECT
SELECT commission_pct, count(commission_pct) FROM employees WHERE commission_pct IS NOT NULL GROUP BY commission_pct ORDER BY commission_pct;
清单 14 中的查询返回收到各个佣金级别(百分比)的员工的人数。总计中不包括未收到佣金的员工。
我们需要提供给 JFreeChart 以生成我们的图表的 XML 数据需要满足 JFreeChart 期望的 XML 语法。在清单 15 中,我们显示了一个在清单 14 中首次列出的查询的修改版本,它部分满足 JFreeChart 对 XML 语法的期望。
清单 15: 使用列别名将查询结果与 JFreeChart 期望的 XML 相匹配
SELECT commission_pct AS "Key" count(commission_pct) AS "Value" FROM employees WHERE commission_pct IS NOT NULL GROUP BY commission_pct ORDER BY commission_pct
这个新版本的查询重命名在 SELECT 语句中返回的列或使用该列的别名。我们现在不使用 commission_pct 和 count(commission_pct) 作为列标题,而改用这两个列标题的别名,分别称为 Key 和 Value。
虽然清单 15 对该查询进行了修改,但是我们仍然不能以 XML 格式检索数据。清单 16 提供了使用 OracleResultSet 以 XML 格式检索数据库中的数据的 Java 代码。
清单 16: 以 XML 格式获取 Oracle 数据库中的数据
/** * Get commission percentage breakdown from database. */ public String getCommissionPercentageBreakdownAsXml() { final String QUERY_NUMBER_EACH_COMMISSION_LEVEL = "SELECT commission_pct AS /"" + DatasetTags.KEY_TAG + "/", " + "count(commission_pct) AS /"" + DatasetTags.VALUE_TAG + "/" " + "FROM employees " + "WHERE commission_pct IS NOT NULL " + "GROUP BY commission_pct " + "ORDER BY commission_pct"; OracleXMLQuery qry = new OracleXMLQuery( getOracleDbConnection(), QUERY_NUMBER_EACH_COMMISSION_LEVEL); qry.setRowTag(DatasetTags.ITEM_TAG); qry.setRowsetTag(DatasetTags.PIEDATASET_TAG); return qry.getXMLString(); }
在清单 16 中,我们使用 JFreeChart 提供的静态常量(DatasetTags.KEY_TAG 和 DatasetTags.VALUE_TAG)而非两个列标题的硬编码值(Key 和 Value),因此,在 JFreeChart 的以后版本中,该查询仍将保持与这些常量的任何更改同步。
清单 16 显示了如何使用 OracleXMLQuery 以 XML 格式获得查询数据。setRowTag 和 setRowsetTag 调用很重要,因为利用通过它们,我们可以轻松更改行标记和行集标记以与满足 JFreeChart 期望。如前所述,我们使用 JFreeChart 提供的常量(DatasetTags.ITEM_TAG 和 DatasetTags.PIEDATASET_TAG)指定这些标记的名称。最后,在我们的 OracleXMLQuery 实例上调用 getXMLString 方法以完备的 XML 格式返回所有结果。清单 17 显示该生成的 XML 字符串的内容。
清单 17: 通过 Oracle 数据库查询生成的 JFreeChart 兼容 XML
<?xml version = '1.0'?> <PieDataset> <Item num="1"> <Key>0.1</Key> <Value>6</Value> </Item> <Item num="2"> <Key>0.15</Key> <Value>5</Value> </Item> <Item num="3"> <Key>0.2</Key> <Value>7</Value> </Item> <Item num="4"> <Key>0.25</Key> <Value>6</Value> </Item> <Item num="5"> <Key>0.3</Key> <Value>7</Value> </Item> <Item num="6"> <Key>0.35</Key> <Value>3</Value> </Item> <Item num="7"> <Key>0.4</Key> <Value>1</Value> </Item> </PieDataset>
如上面提到的,DatasetTags 常量用于提供 JFreeChart 期望的标记名称 PieDataset、Item、Key 和 Value。由于有了 OracleXMLQuery 类、使用返回列的别名的能力以及 JFreeChart 提供的常量,我们现在已经准备好 XML 文档可以将其填充到 JFreeChart 饼形图中了。
清单 18 显示如何使用 JFreeChart 的 DatasetReader 相应地将准备好的 XML 作为输入数据用于图表生成。
清单 18: 使用 DatasetReader 处理 XML 输入用于图表生成
/** * Create 3D pie chart displaying the number of employees at each * commission level.This method demonstrates use of DatasetReader to * translate data from XML format to JFreeChart data format. * * @return 3D Pie Chart showing number of employees at each commission * level. */ public JFreeChart createCommissionsPercentagePerLevelPieChart() { PieDataset pieData = null; final String xmlData = databaseAccess.getCommissionPercentageBreakdownAsXml(); final DatasetReader reader = new DatasetReader(); try { pieData = reader.readPieDatasetFromXML( new ByteArrayInputStream(xmlData.getBytes()) ); } catch (IOException ioEx) { ioEx.printStackTrace(); } JFreeChart chart = ChartFactory.createPieChart3D( "Commissioned Employees at Each Commission Level", pieData, false, true, false ); // Chart specifically provides getCategoryPlot() and getXYPlot() methods, // but not a getPiePlot() or getPiePlot3D() method. final PiePlot3D plot = (PiePlot3D) chart.getPlot(); plot.setDepthFactor(0.35); // pie depth 35% of plot height plot.setForegroundAlpha(0.5f); // Declare explicitly as float (50%) plot.setLabelGenerator(new HrCommissionsPieGenerator()); return chart; }
清单 18 中在 DatasetReader 上调用的方法是专为 PieDataset 实施设计的,方法名 (readPieDatasetFromXML) 证明了这一点。JFreeChart 的 DatasetReader 当前支持的另一个类型的数据集是 CategoryDataset(用于条形图、直线图等)。
清单 18 中的方法返回的 JFreeChart 实例的行为方式与在前面所有示例中显示的相同类的实例的行为方式相似。换言之,这个从 XML 输入数据生成 JFreeChart 可以保存为 PNG 或 JPEG 文件,可以在 Swing 应用程序中显示,可以在 servlet 或 JSP 页面中显示,甚至可以作为 SVG 图像或在 PDF 文件内显示。
图 15 显示了从清单 18 中生成的 JFreeChart 显示的 PNG。
图 15:用 XML 源数据生成的三维饼形图
当您用数据库数据构建图表时,直接从数据库结果构建通常要比先转换为 XML 然后再构建数据集简单。这是因为 XML 生成会给该过程增添额外的步骤,而且易于使用的 JDBC 数据集支持的图表类型要比 XML 的 DatasetReader 支持的更多。DatasetReader 支持 PieDataset 和 CategoryDataset,同时除了用于饼形图的 JDBC 数据集 (JDBCPieDataset) 和用于类别图的 JDBC 数据集 (JDBCCategoryDataset) 之外,还有一个用于基于 x,y 的图表的 JDBC 数据集 (JDBCXYDataset)。
当要绘制成图表的数据在 XML 中“本机”可用时,JFreeChart 对 XML 输入数据的支持很有用。但是,即使这个时候,数据的格式也可能不是 JFreeChart 所期望的。因此,源 XML 数据需要通过 XSLT、XQuery 或自定义处理转换为期望的 XML 格式。此外,XML 支持提供了一种简单的方法,将用于图表生成的静态数据编写为可以轻松手动编辑然后用于构建图表的纯文本文件。
除了演示如何使用 XML 为通过 JFreeChart 生成图表提供数据外,该示例还演示了使用 JFreeChart 的其他自定义可能。在本示例中,检索了绘图的特定类型 (PiePlot3D)。该绘图继承自 PiePlot 并增加了一些特定于其三维特性的方法(如本示例中应用的深度设置)。然后,可以使用该 PiePlot3D 向饼块中添加一些透明性,以使饼块更深,并自定义饼块的标签。将图 15 中的输出与本文前面的饼形图相比较演示了该自定义如何影响最终图表。
清单 18 包括对 HrCommissionsPieGenerator 类的引用。该类(其定义如清单 18 所示)覆盖了生成的饼形图中的饼块的标签。
清单 19: 自定义饼形图标签
public class HrCommissionsPieGenerator implements PieSectionLabelGenerator { /** * Generates a customized label for a pie section of pie chart depicting * commissions levels. * * @param aDataset Dataset destined for pie chart. * @param aKey The identifying key for each section of the pie chart. * * @return Customized label for section of pie chart identified by aKey. */ public String generateSectionLabel(final PieDataset aDataset, final Comparable aKey) { String labelResult = null; if (aDataset != null) { labelResult = (int)(Double.parseDouble(aKey.toString())*100) + "% sales (" + aDataset.getValue(aKey).intValue() + " employees)"; } return labelResult; } }
尽管我们提供了 9 个示例来演示 JFreeChart 的功能和灵活性,但还是有很多未尽之处。下一节概述本文没有重点描述的一些 JFreeChart 吸引人的特性。
其他 JFreeChart 特性
JFreeChart 提供很多本文未提及的特性和图表类型。其中包括:
- 本文生成和显示的图表类型只是 JFreeChart 使用默认设置生成的图表类型中的一部分。许多其他图表类型与财务报表图表类型有关,如 Box and Whisker、Bubble、Candlestick、Gantt、High Low、Polar、Scatter Plot、Wafer Map、Waterfall 和 Wind Plot。识别自动提供的图表类型的最简单的方式是在 ChartFactory 类上使用 JDeveloper 的代码完成 (CTRL+SPACE) 并从下拉列表中选择一种“create…”方法(参见图 16)。滚动条的长度表明还有多少可用图表。
图 16:使用 JDeveloper 自动完成识别 JFreeChart 图表类型
- 即使用 JFreeChart 提供的所有图表类型,还是会有一些情况需要提供额外的灵活性才能呈现完美的图表。虽然 JFreeChart 简化了许多图表类型的创建,但它也为开发人员提供了处理其他复杂性和显著自定义提供的图表类型的机会。本文只演示了该图表自定义功能的一小部分。JFreeChart 公开低级别的 API (AWT/Java2D) 以便在管理人员需要时为他们提供额外的灵活性。
- JFreeChart(和 Cewolf)提供为生成的图表生成工具提示的机制。
- JFreeChart 支持创建 HTML 图像映射(参见 ChartUtilities 类的文档)。
- JFreeChart 可以在基于标准 Widget 工具包 (SWT) 的应用程序中使用。本文提到的一个示例涉及 Swing,但 JFreeChart 还可以与 SWT 结合使用。有关 JFreeChart 与 SWT 结合使用的详细信息可以在 http://jfree.org/phpBB2/viewtopic.php?t=4693 找到。该链接还展现了 JFreeChart 论坛的有益之处。
总结 JFreeChart 的主要优势
使用 JFreeChart 生成以数据为中心的图表有几个令人信服的原因。下面是其中几个最重要的原因:
- 许可证/购买成本 — 免费。即使您将推荐的 JFreeChart 开发人员指南包含一点微薄的费用,该成本也是极低的,很难与之竞争。JFreeChart 在 GNU Lesser 一般公用许可下分发。
- 强大特性 — 如果一个库或框架缺少所需的特性,免费或低成本的许可并不足以让人选择它。JFreeChart 支持许多不同类型的图表,并支持在许多不同的环境中以许多不同的格式显示这些图表。
- 简单性 — 强大的、功能齐备的库通常极其复杂,学习时间较长。但是,JFreeChart 提供了一个 API,它学习和使用都极其容易,而且支持强大的特性。使用 JFreeChart 创建基本图表十分简单,创建更复杂的图表只需不断积累的使用 JFreeChart API 的经验。面向 JDBC 的数据集使得根据存储在关系数据库中的数据显示图表变得极为简单。
- 支持 Java 的若干版本 — 如同一下将 J2SE 5 和 Java SE 6 的批注、类和其他特性注入第三方框架、库和工具。虽然这些特性提供有吸引力的优点,但如果它们的基准 Java 版本的日期早于 J2SE 5,这些特性会妨碍开发人员对新的框架或库的利用。JFreeChart 1.0.6(编写本文时的最新版本)所需的最低 Java 版本为 JDK 1.3。这是很重要的,因为使用 Java 1.4.2 的开发人员可以使用 JFreeChart 的最新版本。反过来,JFreeChart 可以与 Java SE 6 结合使用,本文的所有示例都是针对 Java SE 6 编译和运行的。最后,如本文所演示的,JFreeChart 可以直接应用于 Java 标准版 (SE) 和 Java 企业版 (EE) 环境中的图表生成。
获得有关 JFreeChart 的其他信息
本文旨在介绍 JFreeChart 的众多特性。然而,JFreeChart 是一个强大、功能齐备的库,仅通过一篇文章无法全部涵盖。有些资源开发人员可以访问有关 JFreeChart 的更多信息,这些信息大多数可以通过 JFreeChart 的主页访问。
JFreeChart 类和接口的 Javadoc 文档是在这篇介绍性文章基础上进行提高的良好起点。当您在链接内下钻足够充分时,基于 Javadoc 的联机文档会链接到包含实际的 JFreeChart 代码的 HTML 页面(Javadoc“linksource”样式)。有时,该方法比通过打开源代码文件自身来检查代码更容易。
在我们的示例中,我们使用了 JFreeChart 提供的常量很多次。这些内容可以很方便地在 www.jfree.org/jfreechart/api/javadoc/constant-values.html 上找到。检查这些 JFreeChart 常量可以提供有关 JFreeChart 默认值和设置的洞察。
联机 JFreeChart 论坛还提供有关 JFreeChart 的以前的问题和解答的存档,并允许开发人员提问。只需一点微薄的费用,开发人员即可购买和下载《JFreeChart 开发人员指南》了解更全面的 JFreeChart 知识。
结论
JFreeChart 为生成以图形的形式表示数据库或其他数据的高质量图表提供了一种免费、开放源代码的方法。该库易于学习和使用,可以生成许多类型的图表,并支持在众多不同的环境中以标准或企业 Java 显示这些图表。