用JFreeChart建设基于Web的图表
副标题#e#
WWW的成长使得基于因特网的应用措施不再范围于静态可能简朴的动态内容提供。传统的一些以软件包形式宣布应用措施譬喻报表系统等都在逐渐搬到因特网上。可是这两者之间有着天壤之别,固然对付数据获取、业务处理惩罚等方面根基雷同,可是最大的不同在于用户界面。为了能在web欣赏器上显示要求用户界面利用HTML以及图片的方法来揭示数据,而传统的一些操作操纵系统自己的控件来开拓的用户界面无法适应琳琅满目标客户端,因此在这里也变得无能为力。
回到本文的题目上来,为了建设一个可以在web欣赏器上查察到图表一般有两种做法:第一种就是利用applet操作java自己对图形的支持来显示一个图表;第二种就是直接在web处事器端生成好图表图片文件后发送给欣赏器。第一种方法显然对付客户端要求太高,跟着此刻主流欣赏器放弃对JAVA的支持后,这种方法只适合一些局域网的应用,而对付因特网的情况就显得不太适合。因此我们下面将先容一个JAVA的图表引擎JFreeChart用来发生基于WEB的图表。
一、JFreeChart项目简介
JFreeChart是开放源代码站点SourceForge.net上的一个JAVA项目,它主要用来各类百般的图表,这些图表包罗:饼图、柱状图(普通柱状图以及仓库柱状图)、线图、区域图、漫衍图、殽杂图、甘特图以及一些仪表盘等等。这些差异式样的图表根基上可以满意今朝的要求。为了淘汰篇幅本文主要先容前面三种范例的图表,读者可以闻一知十去开拓其他样式的图表。下面几个是JFreeChart发生的这三种范例图表的功效:
图1
图2
图3
上面的三个图都是暗示四个季度的某个产物的销量信息。在继承下面小节之前必需先筹备好开拓情况,因为是基于WEB欣赏器的图表揭示,因此需要一个Servlet引擎可能是J2EE应用处事器(譬喻WebSphere,Tomcat等)。WEB情况的搭建就不累赘了,读者按照爱好自行安装。JFreeChart引擎自己需要到SourceForge.net上下载,地点如下:
JFreeChart主页:http://www.jfree.org/jfreechart/index.html
JFreeChart下载页面:http://sourceforge.net/projects/jfreechart/
下载的时候需要留意的是必需下载两个文件:JFreeChart以及Jcommon。今朝最新配套版本是:JFreeChart 0.9.11 Jcommon 0.8.6
这里有点笔者在开拓中碰见的问题需要留意的是:在利用Eclipse开拓的时候会报一个莫名其妙的错误,错误大概指向某个类文件的第一行。碰着这样的问题一般是因为没有把Jcommon的jar包配置到项目标类路径中的缘故。详细的原因不祥。 (尚有log4j等也咬一起导入)。
#p#副标题#e#
二、解读JFreeChart的源码布局
在开始利用JFreeChart之前我们有须要先或许相识一下JFreeChart自己的布局以及它所带一些例子措施,这样有助于我们下一步自行开拓。下载JFreeChart包后已经带有很是富厚的例子,因为JFreeChart这个项目自己的利用文档很是少,因此进修它最好的步伐就是进修它所带的例子源码。在包org.jfree.chart.demo中有几十个文件用于展示JFreeChart所能支持的所有图表的功效。假如你的JDK是较量新的环境下大概在运行这些例子时会有问题,现象如下:
java.lang.UnsatisfiedLinkError: initDDraw
at sun.awt.windows.Win32OffScreenSurfaceData.initDDraw(Native Method)
at sun.awt.windows.Win32OffScreenSurfaceData.<clinit>(Win32OffScreenSurfaceData.java:141)
at sun.awt.Win32GraphicsDevice.<clinit>(Win32GraphicsDevice.java:58)
at sun.awt.Win32GraphicsEnvironment.makeScreenDevice(Win32GraphicsEnvironment.java:168)
at sun.java2d.SunGraphicsEnvironment.getScreenDevices(SunGraphicsEnvironment.java:240)
at sun.awt.Win32GraphicsEnvironment.getDefaultScreenDevice(Win32GraphicsEnvironment.java:61)
at java.awt.Window.init(Window.java:224)
at java.awt.Window.<init>(Window.java:268)
at java.awt.Frame.<init>(Frame.java:398)
at javax.swing.JFrame.<init>(JFrame.java:198)
at org.jfree.chart.demo.JFreeChartDemo.<init>(JFreeChartDemo.java:148)
at org.jfree.chart.demo.JFreeChartDemo.main(JFreeChartDemo.java:285)
Exception in thread "main"
这个错误是由于新版的Swing大量的利用了微软的DirectDraw的技能来提高绘图的机能,而大概你的显卡在这时候会跟你闹点情绪可能显卡自己并不支持这样的一个技能。莫非就没有步伐了嘛?要办理这个问题也很是简朴,我们可以屏蔽掉DirectDraw,不让Swing利用该技能就可以了。在运行这些代码时给虚拟机指定参数-Dsun.java2d.noddraw即可。
#p#分页标题#e#
这时大概你又该烦闷了,不说是基于Web的图表嘛,怎么又扯到Swing上了?这是因为为了使开拓者容易上手,无需设置任何运行情况,所以这些例子都是基于GUI方法的用于揭示给开拓者假如生成一个图表,我们要进修的也就是如何操作这个引擎生成图表而不是怎么来显示一个图表。当我们把生成的图表工具Export到一个图像文件即可在Web上宣布。
下面我们来先容JFreeChart中几个焦点的工具类:
<table boder=0>
<tr><td>类名</td><td>类的浸染以及简朴描写</td></tr>
<tr><td>JFreeChart</td><td>图表工具,任何范例的图表的最终表示形式都是在该工具举办一些属性的定制。JFreeChart引擎自己提供了一个工场类用于建设差异范例的图表工具</td></tr>
<tr><td>XXXXXDataset</td><td>数据集工具,用于提供显示图表所用的数据。按照差异范例的图表对应着许多范例的数据集工具类</td></tr>
<tr><td>XXXXXPlot</td><td> 图表区域工具,根基上这个工具抉择着什么样式的图表,建设该工具的时候需要Axis、Renderer以及数据集工具的支持</td></tr>
<tr><td>XXXXXAxis</td><td> 用于处理惩罚图表的两个轴:纵轴和横轴</td></tr>
<tr><td>XXXXXRenderer</td><td>认真如何显示一个图表工具</td></tr>
<tr><td>XXXXXURLGenerator</td><td> 用于生成Web图表中每个项目标鼠标点击链接</td></tr>
<tr><td>XXXXXToolTipGenerator</td><td> 用于生成图象的辅佐提示,差异范例图表对应差异范例的东西提示类</td></tr>
</table>
根基上我认为JFreeChart项目自己的类布局的设计并不是很好,首先在建设图表的时候用到了大量的工场要领,这样做固然可以简化建设图表工具的代码,可是对项目自己可能开拓人员来讲自行扩展一种新的图表都仍然是一件很贫苦的工作;其次除图表工具自己外其余的类过于巨大,利用者必需去相识每个范例的图表工具应该对应哪些Axis、Plot、Renderer类,而且必需很是熟悉这些类的结构函数中每个参数的详细寄义。这些问题都大大困扰许多初学者。不外,固然存在许多问题,可是JFreeChart自己仍不失为一个很是优秀的图表引擎,何况项目自己也在逐渐的成长中。
在很是大略的先容了JFreeChart自己的代码布局后,下面我们开始动手试验几个常用的图表并把他们放到web上。
三、利用JFreeChart生成各类样式的图表
限于篇幅的问题我们在这里只实现两种常用的图表,其他范例图表读者可以闻一知十。我们先给出柱状图的实现,饼图的实现再来跟柱状图举办较量。
1 柱状图
[code]package lius.chart.demo;
import java.io.*;
import org.jfree.data.*;
import org.jfree.chart.*;
import org.jfree.chart.plot.*;
/**
* 该类用于演示最简朴的柱状图生成
* @author Winter Lau
*/
public class BarChartDemo {
public static void main(String[] args) throws IOException{
CategoryDataset dataset = getDataSet2();
JFreeChart chart = ChartFactory.createBarChart3D(
"水果产量图", // 图表标题
"水果", // 目次轴的显示标签
"产量", // 数值轴的显示标签
dataset, // 数据集
PlotOrientation.VERTICAL, // 图表偏向:程度、垂直
true, // 是否显示图例(对付简朴的柱状图必需是false)
false, // 是否生成东西
false // 是否生成URL链接
);
FileOutputStream fos_jpg = null;
try {
fos_jpg = new FileOutputStream("D:\\fruit.jpg");
ChartUtilities.writeChartAsJPEG(fos_jpg,100,chart,400,300,null);
} finally {
try {
fos_jpg.close();
} catch (Exception e) {}
}
}
/**
* 获取一个演示用的简朴数据集工具
* @return
*/
private static CategoryDataset getDataSet() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addvalue(100, null, "苹果");
dataset.addvalue(200, null, "梨子");
dataset.addvalue(300, null, "葡萄");
dataset.addvalue(400, null, "香蕉");
dataset.addvalue(500, null, "荔枝");
return dataset;
}
/**
* 获取一个演示用的组合数据集工具
* @return
*/
private static CategoryDataset getDataSet2() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addvalue(100, "北京", "苹果");
dataset.addvalue(100, "上海", "苹果");
dataset.addvalue(100, "广州", "苹果");
dataset.addvalue(200, "北京", "梨子");
dataset.addvalue(200, "上海", "梨子");
dataset.addvalue(200, "广州", "梨子");
dataset.addvalue(300, "北京", "葡萄");
dataset.addvalue(300, "上海", "葡萄");
dataset.addvalue(300, "广州", "葡萄");
dataset.addvalue(400, "北京", "香蕉");
dataset.addvalue(400, "上海", "香蕉");
dataset.addvalue(400, "广州", "香蕉");
dataset.addvalue(500, "北京", "荔枝");
dataset.addvalue(500, "上海", "荔枝");
dataset.addvalue(500, "广州", "荔枝");
return dataset;
}
}
[/code]
措施运行竣事后生成的图片文件结果如下图所示:
图4
假如是利用简朴的数据纵然用getDataSet要领获取数据集时发生的图片文件如下:
图5
2 饼图
#p#分页标题#e#
对付饼图而言,数据集的获取用的不是同一个数据集类,别的饼图不支持同一个类此外项目中尚有子项目这样的数据。我们只给出建设饼图的代码,至于写图表到一个文件则与柱状图一致,无需反复。
[code]
package lius.chart.demo;
import java.io.*;
import org.jfree.data.*;
import org.jfree.chart.*;
/**
* 用于演示饼图的生成
* @author Winter Lau
*/
public class PieChartDemo {
public static void main(String[] args) throws IOException{
DefaultPieDataset data = getDataSet();
JFreeChart chart = ChartFactory.createPie3DChart("水果产量图", // 图表标题
data,
true, // 是否显示图例
false,
false
);
//写图表工具到文件,参照柱状图生成源码
}
/**
* 获取一个演示用的简朴数据集工具
* @return
*/
private static DefaultPieDataset getDataSet() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setvalue("苹果",100);
dataset.setvalue("梨子",200);
dataset.setvalue("葡萄",300);
dataset.setvalue("香蕉",400);
dataset.setvalue("荔枝",500);
return dataset;
}
}
[/code]
生成的饼图文件结果如下:
图6
四、将生成的图表移到欣赏器上
为了将生成的图表直接传给客户端欣赏器,只需要将前面两个例子中的文件流换成是通过HttpServletResponse工具获取到的输出流,具体代码清单如下:
package lius.chart.demo;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import org.jfree.data.*;
import org.jfree.chart.*;
/**
* 演示通过servlet直接输出图表
* @author Winter Lau
*/
public class ChartDemoServlet extends HttpServlet {
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException
{
res.setContentType("image/jpeg");
DefaultPieDataset data = getDataSet();
JFreeChart chart = ChartFactory.createPie3DChart("水果产量图",
data,
true,
false,
false
);
ChartUtilities.writeChartAsJPEG(res.getOutputStream(),100,chart,400,300,null);
}
/**
* 获取一个演示用的简朴数据集工具
* @return
*/
private static DefaultPieDataset getDataSet() {
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setvalue("苹果",100);
dataset.setvalue("梨子",200);
dataset.setvalue("葡萄",300);
dataset.setvalue("香蕉",400);
dataset.setvalue("荔枝",500);
return dataset;
}
}
高级主题
#p#分页标题#e#
许多环境我们不只仅要求可以在欣赏器上显示一个图表,我们更需要客户可以直接在图表上做一下交互的操纵,譬喻获取信息提示,点击图表某个部门举办更具体信息的展示等等。譬喻前面生成的简朴柱状图,用户需要在看到柱状图后点击某种水果譬喻是苹果即可看到各个地域苹果产量的环境。为此就要求该图形具有交互操纵的成果。在HTML中为了让一个图像具有可交互的成果就必需给该图像界说一个Map工具。下表节选一段具有该成果的HTML代码
<MAP NAME="chartMap">
<AREA SHAPE="RECT" COORDS="81,15,126,254" href="?series=0&category=100" title="100 = 7,048"
onclick="javascript:clickChart('100');return false;">
<AREA SHAPE="RECT" COORDS="143,27,188,255" href="?series=0&category=200" title="200 = 6,721"
onclick="javascript: clickChart ('200');return false;">
<AREA SHAPE="RECT" COORDS="205,54,250,255" href="?series=0&category=300" title="300 = 5,929"
onclick="javascript: clickChart ('300');return false;">
<AREA SHAPE="RECT" COORDS="267,85,312,255" href="?series=0&category=400" title="400 = 5,005"
onclick="javascript: clickChart ('400');return false;">
<AREA SHAPE="RECT" COORDS="329,17,374,255" href="?series=0&category=Diet" title="Diet = 7,017" onclick="javascript:
clickChart ('Diet');return false;">
</MAP>
由此就发生了一个问题:假如按照一个图像来生成对应的MAP工具。我们转头看看适才的代码,在建设一个图表工具时候有两个参数,我们举柱状图的例子来讲这两个参数就是ChartFactory. createBarChart3D要领中的最后两个参数,这两个参数的范例都是布尔值。这两个参数意思别离是:是否建设东西提示(tooltip)以及是否生成URL。这两个参数别离对应着MAP中一个AREA的title属性以及href属性。
但是我想知道的是怎么来发生这个MAP啊!哈哈,不要着急,JFreeChart已经帮我们做好生成MAP工具的成果。为了生成MAP工具就要引入别的一个工具:ChartRenderingInfo。因为JFreeChart没有直接的要领操作一个图表工具直接生成MAP数据,它需要一其中间工具来过渡,这个工具就是ChartRenderingInfo。下图是生成MAP数据的流程图:
图7
如上图所示,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工具的名称由标签库统一举办节制,这样可以担保二者的一致性。