JFreeChart是一个开源的JAVA项目,它主要用来开发各种各样的图表,这些图表包括:饼图、柱状图(普通柱状图以及堆栈柱状图)、线图、区域图、分布图、混合图、甘特图以及一些仪表盘等等。在这些不同式样的图表上可以满足目前商业系统的要求。 JFreeChart是一种基于JAVA语言的图表开发技术。JFreeChart可用于Servlet、JSP、Applet、Java Appication环境中,通过JDBC可动态显示任何数据库数据,结合Itext可以输出至PDF文件。 JFreeChart主要是由三个类构成: A)org.jfree.chart.servlet.ChartDeleter继承自HttpSessionBindingListener,用于实现当Session 关闭时,删除临时目中的图象文件。 B)org.jfree.chart.servlet.DisplayChart继承自Httpservlet 用于处理显示图象。 C)org.jfree.chart.servlet.ServletUtilities有一系列方法,例如,saveChartAs*;saveChartAs*是把图表按照不同的形式存储为图象;sendTempFile方法被重载了很多次,用于把文件流发送response。 下面以柱状图和饼图为例,介绍图形创建方法。 1 柱状图 org.jfree.chart.ChartFactory这个工厂类有createBarChart、createStackedBarChart、createBarChart3D、createStackedBarChart3D,这几个工厂方法创建不同类型的柱状图,比较重要的是 PlotOrientation.VERTICAL 让平行柱垂直显示,而 PlotOrientation.HORIZONTAL 则让平行柱水平显示。对柱状图影响较大的几个类包括:org.jfree.chart.axis.CategoryAxis、org.jfree.chart.axis.ValueAxis、org.jfree.chart.renderer.BarRenderer、org.jfree.chart.renderer. BarRenderer3D。 具体实现步骤: 1)创建用于图形生成所要的数据集对象。 CategoryDataset dataset = DatasetUtilities.createCategoryDataset(rowKeys, columnKeys, data); 其中:rowKeys表示X轴数据,columnKeys表示Y轴数据,data表示填充柱状图所要的实际数据(来自于数据库)。 2)创建图形对象。 JFreeChart chart = ChartFactory.createBarChart3D("标题", null,null,dataset,PlotOrientation.VERTICAL,,true,false,false); createBarChart3D方法是ChartFactory工厂类里的一个方法,用于3D柱状图的生成,该类继承自JFreeChart。其中的八个参数分别代表:图形的标题、X轴标题、Y轴标题、dataset就是CategoryDataset类的实例对象、显示标题、启用热键、启用超键接。 3)设置图形显示的属性。 a ) ValueAxis类,设置柱到图上下边的距离。实现方法是: ValueAxis rangeAxis = plot.getRangeAxis(); 设置最高的一个柱与图片顶端的距离: rangeAxis.setUpperMargin(0.15) 设置最低的一个柱与图片底端的距离: rangeAxis.setLowerMargin(0.15) b)org.jfree.chart.renderer.BarRenderer3D类,设置图形上显示的数值。实现方法如下: BarRenderer3D renderer = new BarRenderer3D(); renderer.setBaseOutlinePaint(Color.BLACK); 设置 Wall 的颜色: renderer.setWallPaint(Color.gray); 设置每个柱的颜色: renderer.setSeriesPaint(0, new Color(0, 0, 255)); renderer.setSeriesPaint(1, new Color(0, 100, 255)); renderer.setSeriesPaint(2, Color.GREEN); 设置每个柱的 Outline 颜色 renderer.setSeriesOutlinePaint(0, Color.BLACK); renderer.setSeriesOutlinePaint(1, Color.BLACK); renderer.setSeriesOutlinePaint(2, Color.BLACK); 设置每个地区所包含的平行柱之间的距离 renderer.setItemMargin(0.1); 显示每个柱的数值,并修改该数值的字体属性 renderer.setItemLabelGenerator(new StandardCategoryItemLabelGenerator()); renderer.setItemLabelFont(new Font("黑体",Font.PLAIN,12)); renderer.setItemLabelsVisible(true); 为图形加入超连接 renderer.setItemURLGenerator(new StandardCategoryURLGenerator()); renderer.setToolTipGenerator(new StandardCategoryToolTipGenerator()); 2 饼图 org.jfree.chart.plot包,包含创建饼形图的所有方法和属性。 笔者根据业务需求创建了setURLGenerator(PieURLGenerator generator)方法,在图片上建立连接,就是图片不同部分连接不同的资源。 setSectionLabelType(int type)方法: 指定 section 标签的类型,共有 7 种类型。如果不指定,默认是 NAME_LABELS,其中类型分别是: PiePlot.NO_LABELS PiePlot.NAME_LABELS PiePlot.VALUE_LABELS PiePlot.PERCENT_LABELS 、PiePlot.NAME_AND_VALUE_LABELS、PiePlot. NAME_AND_PERCENT_LABELS、PiePlot.VALUE_AND_PERCENT_LABELS。 setDefaultOutlinePaint(java.awt.Paint paint)方法,指定 section 轮廓线的颜色,如果不指定,默认值为NULL。 setDefaultOutlineStroke(java.awt.Stroke stroke)方法,指定 section 轮廓线的厚度。 setRadius(double percent) 和 setExplodePercent(int section, double percent)方法,抽离 section,就是把某一section从饼形图剥离出来,需要两个方法一起使用。 setStartAngle(double angle)方法,设置第一个section开始位置,默认从12点钟方向开始。 setPaint(int section, java.awt.Paint paint)方法指定section的颜色。 setDirection(int direction)方法指定section顺序,默认是顺时针方向。顺时针:PiePlot.CLOCKWISE;逆时针:PiePlot.ANTICLOCKWISE。 具体实现步骤: 1)创建用于图形生成所要的数据集对象。 首先实例化类DefaultPieDataset dataset = new DefaultPieDataset()。然后利用DefaultPieDataset类提供的setValue(value1,value2)方法,把从数据库里提取的数据存入DefaultPieDataset对象。其中value1是数据名称、value2是数据值。 2)创建图形对象。 首先实例化JFreeChart chart = ChartFactory.createPieChart3D(title, dataset, true, true, false)createPieChart3D方法是用于饼图生成的主要方法。其中title代表图形的标题、dataset就是DefaultPieDataset对象的实例。 3)设置图形显示的属性。 String filename = ServletUtilities.saveChartAsPNG(jFreeChart, 700, 450, info, session); ChartUtilities.writeImageMap(pw, filename, info); pw.flush() saveChartAsPNG方法在ServletUtilities工厂类定义完成。主要用于把图形对象JFreeChart以图片的形式保存。其中的jFreeChart就是JFreeChart对象的实例。该方法返回一个文件名。 writeImageMap(pw, filename, info)方法用于把保存的图片文件以字节流的形式写入用户界面。 其中pw是java.io包的PrintWriter类的实例对象,该对象创建一个图形输出流。Filename是输出图片的文件名。该文件名来自ServletUtilities.saveChartAsPNG方法创建。 参数info用于图形信息的显示。 用ChartRenderingInfo info=new ChartRenderingInfo(new StandardEntityCollection())创建。 最后输出完成图形,调用pw.flush()方法关闭IO流。 --------------------------------------------------------------------- 高级主题 很多情况我们不仅仅要求可以在浏览器上显示一个图表,我们更需要客户可以直接在图表上做一下交互的操作,例如获取信息提示,点击图表某个部分进行更详细信息的展示等等。 例如前面生成的简单柱状图,用户需要在看到柱状图后点击某种水果例如是苹果即可看到各个地区苹果产量的情况。为此就要求该图形具有交互操作 的功能。在HTML中为了让一个图像具有可交互的功能就必须给该图像定义一个Map对象。下表节选一段具有该功能的HTML代码 由此就产生了一个问题:如果根据一个图像来生成对应的MAP对象。我们回头看看刚才的代码,在创建一个图表对象时候有两个参数,我们举柱状图的例子来讲这两个参数就是 ChartFactory. createBarChart3D方法中的最后两个参数,这两个参数的类型都是布尔值。这两个参数意思分别是:是否创建工具提示(tooltip)以及是 否生成URL。这两个参数分别对应着MAP中一个AREA的title属性以及href属性。 可是我想知道的是怎么来产生这个MAP啊! 哈哈,不要着急,JFreeChart已经帮我们做好生成MAP对象的功能。为了生成MAP对象就要引入另外一个对象:ChartRenderingInfo。因为JFreeChart没有直接的方法利用一个图表对象直接生成 MAP数据,它需要一个中间对象来过渡,这个对象就是ChartRenderingInfo。 ChartUtilities类是整个流程的核心,它周围的对象都是一些例如数据对象或者是文件等。 这个流程简单描述如下:首先创建一个 ChartRenderingInfo对象并在调用ChartUtilities的writeChartAsJPEG时作为最后一个参数传递进去。调用该 方法结束后将产生一个图像文件以及一个填充好MAP数据的ChartRenderingInfo对象,有了这个对象我们还是没有办法获取具体的MAP数 据,我们还必须借助于ChartUtilities的writeImageMap方法来将ChartRenderingInfo对象读取出来,获取MAP 数据的代码片断如下: PrintWriter w = null; FileOutputStream fos_jpg = null; FileOutputStream fos_cri = null; try{ //根据不同类型的图表使用不同类,以下是针对饼图的操作 PiePlot plot = (PiePlot) chart.getPlot(); plot.setURLGenerator(new StandardPieURLGenerator(url)); //设置工具提示 plot.setToolTipGenerator(new StandardPieToolTipGenerator()); fos_jpg = new FileOutputStream(“d:\\fruit.jpg”); ChartUtilities.writeChartAsJPEG(fos_jpg,100,chart, 400, 300, info); fos_cri = new FileOutputStream(__d:\\fruit.map__); w = new PrintWriter(fos_cri); ChartUtilities.writeImageMap(w, __mapname__, info); w.flush(); }finally{ try{ w.close(); }catch(Exception e){} try{ fos_cri.close(); }catch(Exception e){} try{ fos_jpg.close(); }catch(Exception e){} } 打开文件D:\ fruit.map,文件的内容就是要写到页面上的MAP数据。把生成的图像文件以及MAP数据文件写到页面上即可完成热点图表的功能。至于怎么结合两者 之间的关系例如图像的useMap属性值必须与MAP对象的名称结合起来,必须根据实际的应用情况进行相应的处理。笔者建议把二者通过标签库封装起来,图 像文件的名称以及MAP对象的名称由标签库统一进行控制,这样可以保证二者的一致性。