在開始使用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.(Win32OffScreenSurfaceData.java:141) at sun.awt.Win32GraphicsDevice.(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.(Window.java:268) at java.awt.Frame.(Frame.java:398) at javax.swing.JFrame.(JFrame.java:198) at org.jfree.chart.demo.JFreeChartDemo.(JFreeChartDemo.java:148) at org.jfree.chart.demo.JFreeChartDemo.main(JFreeChartDemo.java:285)Exception in thread "main"
|
這個錯誤是由于新版的Swing大量的使用了微軟的DirectDraw的技術來提高畫圖的性能,而可能你的顯卡在這時候會跟你鬧點情緒或者顯卡本身并不支持這樣的一個技術。難道就沒有辦法了嘛?要解決這個問題也非常簡單,我們可以屏蔽掉DirectDraw,不讓Swing使用該技術就可以了。在運行這些代碼時給虛擬機指定參數-Dsun.java2d.noddraw即可。
這時可能你又該納悶了,不說是基于Web的圖表嘛,怎么又扯到Swing上了?這是因為為了使開發者容易上手,無需配置任何運行環境,所以這些例子都是基于GUI方式的用于展現給開發者如果生成一個圖表,我們要學習的也就是如何利用這個引擎生成圖表而不是怎么來顯示一個圖表。當我們把生成的圖表對象Export到一個圖像文件即可在Web上發布。
類名
|
類的作用以及簡單描述
|
JFreeChart
|
圖表對象,任何類型的圖表的最終表現形式都是在該對象進行一些屬性的定制。JFreeChart引擎本身提供了一個工廠類用于創建不同類型的圖表對象
|
XXXXXDataset
|
數據集對象,用于提供顯示圖表所用的數據。根據不同類型的圖表對應著很多類型的數據集對象類。常用的數據集對象有:柱狀圖數據集對象DefaultCategoryDataset、餅圖數據集對象DefauldPieDataset和曲線圖數據集對象DefaultTableXYDataset
|
XXXXXPlot
|
圖表區域對象,基本上這個對象決定著什么樣式的圖表,創建該對象的時候需要Axis、Renderer以及數據集對象的支持。常用的Plot對象有:柱狀圖CategoryPlot、餅圖PiePlot和曲線圖XYPlot。
|
XXXXXAxis
|
用于處理圖表的兩個軸:縱軸和橫軸。常用的有NumberAxis數據軸,DateAxis日期軸。
|
XXXXXRenderer
|
負責如何顯示一個圖表對象。常用的Renderer有DefaultCategoryItemRenderer 柱狀圖顯示器StandardXYItemRenderer曲線圖顯示器。餅圖的Renderer
|
XXXXXURLGenerator
|
用于生成Web圖表中每個項目的鼠標點擊鏈接。常用的URLCenerator有StandardCategoryURLGenerator StandardPieURLGenerator StandardXYURLGenerator
|
XXXXXToolTipGenerator
|
用于生成圖象的幫助提示,不同類型圖表對應不同類型的工具提示類。常用的有:StandardXYToolTipGenerator StandardCategoryToolTipGenerator StandardPieItemLabelGenerator
|
一般的創建圖表的過程為:
1. 從數據庫里讀取數據
2. 將數據保存到圖表對應的數據集對象中
3. 創建坐標軸對象
4. 創建Renderer對象
5. 創建Plot對象
6. 創建JfreeChart對象
7. 生成圖片文件(或者二進制流)
以JfreeChart提供的Web應用的例子來說明一下以上幾個步驟:
一.柱圖。
public static String generateBarChart(Date hitDate, HttpSession session, PrintWriter pw) {
String filename = null;
try {
// Retrieve list of WebHits
WebHitDataSet whDataSet = new WebHitDataSet();
ArrayList list = whDataSet.getDataBySection(hitDate);//獲得數據集
// Throw a custom NoDataException if there is no data
if (list.size() == 0) {
System.out.println("No data has been found");
throw new NoDataException();
}
// Create and populate a CategoryDataset
Iterator iter = list.listIterator();
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
while (iter.hasNext()) {
WebHit wh = (WebHit)iter.next();
dataset.addValue(new Long(wh.getHitCount()), "Hits", wh.getSection());
}//將數據集保存到
Dataset對象
// Create the chart object
CategoryAxis categoryAxis = new CategoryAxis("");
ValueAxis valueAxis = new NumberAxis("");//創建坐標軸
BarRenderer renderer = new BarRenderer();//創建Renderer
renderer.setItemURLGenerator(new StandardCategoryURLGenerator("xy_chart.jsp","series","section"));//創建URLGenerator.再不需要連接的情況下將第一個參數設置成"###"就可以了
renderer.setToolTipGenerator(new StandardCategoryToolTipGenerator());//創建提示標簽
Plot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer);//創建圖表區域對象
JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
chart.setBackgroundPaint(java.awt.Color.white);//創建圖表
// Write the chart image to the temporary directory
ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());//該工具類上面沒有介紹,在鼠標移動到圖片時顯示提示信息是用
Map實現的,這些
Map是用該類生成的。
filename = ServletUtilities.saveChartAsPNG(chart, 500, 300, info, session);//保存圖表為文件
// Write the image map to the PrintWriter
ChartUtilities.writeImageMap(pw, filename, info);//生成
Map信息。這些信息寫在
pw的輸出流中,這里的輸出流就是
Response.out。也就是直接輸出到頁面了
pw.flush();
} catch (NoDataException e) {
System.out.println(e.toString());
filename = "public_nodata_500x300.png";
} catch (Exception e) {
System.out.println("Exception - " + e.toString());
e.printStackTrace(System.out);
filename = "public_error_500x300.png";
}
return filename;
}
二.圖表顯示:
<%
......
String filename = WebHitChart.generateBarChart(dDate, session, new PrintWriter(out));//獲得圖片的文件名。注意該語句寫在jsp文件(bar_chart.jsp)的開頭,而用out的封裝類作為參數,訪問該頁面后可以看到生成Map熱點的內容輸出再該頁面的開頭部分。也就是說最好是把這幾句話寫在頁面有輸出之前。
String graphURL = request.getContextPath() + "/servlet/DisplayChart?filename=" + filename;//顯示圖片的Servlet全路徑名,另外文件名作為該Servlet的參數
......
%>
......
<img src="<%= graphURL %>" width=500 height=300 border=0 usemap="#<%= filename %>">
src指定了servlet的全路徑名,usermap指定了使用的熱點。
該Servlet必須在WEB-INF/web.xml文件中配置:
<servlet>
<servlet-name>DisplayChart</servlet-name>
<servlet-class>org.jfree.chart.servlet.DisplayChart</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DisplayChart</servlet-name>
<url-pattern>/servlet/DisplayChart</url-pattern>
</servlet-mapping>
該Servlet的作用就是將圖片文件的二進制流數據寫道response的輸出流中,在客戶端也就顯示成了圖片。
博客中國分類:java技術,
jfreechart是一個優秀的開源JAVA 2D項目,缺點是缺乏文檔,中英文都是如此。本文是經驗總結的第二部分
二、jfreechart作圖類對象的協調關系
jfreechart 的繪圖對象由一個org.jfree.chart.JFreeChart組成,但作為繪圖關鍵的Graphich2d通過 org.jfree.chart.render.*中的對應render類包裝后設入,換言之,開發者可以通過對基礎圖板Graphic的設置,完成必要的繪圖預定效果設計;而大多數的修改,實際上可以通過包裝的各個類操作而不用直接修改Graphic對象屬性(誰記得呢?)。jfreechart的數據接口由org.jfree.chart.plot.*中的不同的plot包裝,與之相對應的是不同的dataset,位于 org.jfree.chart.data.*中不同的dataset接口包裝。使用jfreechart作圖的關鍵在于生一個個相應的數據集對象,,然后包裝成對應的一個個繪圖集plot對象,最后再包裝成不同的JFreeChart對象交付輸出。通過new方法可以一步步完成上面的步驟。換言之, plot類是圖形的設計,render 是繪制的工具,而dataset則是填充的數據;這樣就把作圖的三個關鍵因素分別抽象成統一的接口,互想搭配出各種圖形。對于可能有多套數據集的圖表,如時間序列的多條曲線走勢圖(象幾只股票),傳入plot的不是數據集,而是數據集的集合,一般命名為某某collection。
通過 ChartFactory的不同方法生成不同的Chart類型,可以相應地縮小了由dataset對不同的chart對象的操作過程代碼量,直接獲得 chart對象。實際上是由工廠類代替用戶生成必要的render和plot類,如果用戶不想使用默認的設置,就需要再通過get方法得出相應的plot 對象進行修改。jfreechart的最后圖像輸出一般由org.jfree.chart.ChartUtilites完成,這個類可以向接定的 PrintWriter對象輸出完成的Chart對象。在服務器程序中,另一個ServerUtilites方法調用了這個方法,生成一個圖像臨時文件,并向JSP或servlet返回這個文件對象,通過把這個圖像的生命周期與session綁定,希望可以實現緩沖功能,降低服務器動態生成圖像的損耗。但是也有很大的問題其一就是如果session很長,就等于不能生成實時圖像,其二就是訪問的人多了,服務器的負擔似乎反而加大了。這個算法顯然有問題,倒不如修改成按時間更新一個圖像更為合適。
觀察代碼,兩者效果是一樣的:
A、工廠方法:
JFreeChart chart = ChartFactory.createPieChart3D( "2000 GDP分布比例圖", data, true, false, false );//指定獲得不同的實現chart對象,含有不同的plot繪圖對象
PiePlot plot = (PiePlot) chart.getPlot();//獲取plot對象用于修訂屬性,強制造型,以便調用各自的方法
plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設定注釋方式
plot.setForegroundAlpha(0.5f);//設定透明度
plot.setNoDataMessage("無記錄內容");//無記錄異常顯示
B、手工生成對象
PiePlot plot = new PiePlot(dataset);
plot.setLabelGenerator(new StandardPieItemLabelGenerator( "{0} = {2}", NumberFormat.getNumberInstance(), NumberFormat.getPercentInstance() ));//設定注釋方式
plot.setForegroundAlpha(0.5f);//設定透明度
plot.setNoDataMessage("無記錄內容");//無記錄異常顯示
JFreeChart chart = new JFreeChart("", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
一:jfreechart介紹
jfreechart是一個免費創建圖片的java工具.可以創建如下圖形:
餅圖(pie charts;)
曲線圖(line charts )
柱狀圖(horizontal/vertical bar charts)
甘特圖(Gantt charts; )
XY plots and scatter plots;
time series, high/low/open/close charts and candle stick charts;
combination charts;
Pareto charts;
bubble charts;
wind plots, meter charts and symbol charts;
從以下地址可以看到jfreechart可以創建的圖形類型
http://www.jfree.org/jfreechart/samples.html
sourceforge有一個基于jfreechart的項目Cewolf可以很方便的在jsp/servlet中創建圖片
jfreechart目前(2003-05-08)版本為0.98
希望得到詳細的信息或下載jfreechart請訪問如下站點:
http://www.jfree.org/jfreechart/
二:特別說明:
jfreechart是一個開源項目,但是文檔是需要40美金去購買的。
還有一個很重要的問題,jfreechart如果使用中文,他使用的默認字體
顯示出來的中文會很模糊,你可能需要修改源代碼。
下面我就舉幾個簡單的例子說明一下如何使用jfreechart創建圖片
在開發中有可能會導入以下的類
import com.jrefinery.chart.ChartFactory;
import com.jrefinery.chart.ChartUtilities;
import com.jrefinery.chart.JFreeChart;
import com.jrefinery.chart.TextTitle;
import com.jrefinery.chart.axis.NumberAxis;
import com.jrefinery.chart.plot.CategoryPlot;
import com.jrefinery.chart.plot.PiePlot;
import com.jrefinery.data.Day;
import com.jrefinery.data.DefaultCategoryDataset;
import com.jrefinery.data.DefaultPieDataset;
import com.jrefinery.data.TimeSeries;
import com.jrefinery.data.TimeSeriesCollection;
import com.jrefinery.data.TimeSeriesDataPair;
在0.98以后包由com.jrefinery.*改變為:org.jfree
三:創建餅圖
//圖片標題
String title = "空調2002年市場占有率";
//設定數據源
DefaultPieDataset piedata = new DefaultPieDataset();
//第一個參數為名稱,第二個參數是double數
piedata.setValue("聯想", 27.3);
piedata.setValue("長城", 12.2);
piedata.setValue("海爾", 5.5);
piedata.setValue("美的", 17.1);
piedata.setValue("松下", 9.0);
piedata.setValue("科龍", 19.0);
//創建JFreeChart,都使用ChartFactory來創建JFreeChart,很標準的工廠設計模式
JFreeChart chart =
ChartFactory.createPieChart(title, piedata, true, true, true);
//設定圖片標題
chart.setTitle(new TextTitle(title, new Font("隸書", Font.ITALIC, 15)));
//chart.addSubtitle(new TextTitle("2002財年分析", new Font("隸書", Font.ITALIC, 12)));
//設定背景
chart.setBackgroundPaint(Color.white);
//chart.s
//餅圖使用一個PiePlot
PiePlot pie = (PiePlot)chart.getPlot();
//pie.setSectionLabelType(PiePlot.NAME_AND_PERCENT_LABELS);
pie.setSectionLabelType(PiePlot.NAME_AND_VALUE_LABELS);
//設定顯示格式(名稱加百分比或數值)
pie.setPercentFormatString("#,###0.0#%");
//設定百分比顯示格式
pie.setBackgroundPaint(Color.white);
pie.setSectionLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//設定背景透明度(0-1.0之間)
pie.setBackgroundAlpha(0.6f);
//設定前景透明度(0-1.0之間)
pie.setForegroundAlpha(0.90f);
//輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(12) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//可以保存文件為jpg或png格式。
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
//第一個參數為文件名
//第二個參數質量
//第三個參數為哪個chart創建圖片
//第四個寬度
//第五個高度
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
其實使用JFreeChart創建圖片很簡單,不同的的圖片類型區別在于設置數據集
四:創建曲線圖
// create a default chart based on some sample data...
//曲線圖標題
String title = "趨勢分析";
//曲線圖X軸提示
String domain = "月份走勢";
//曲線圖Y軸提示
String range = "應收余額";
//曲線圖自標題
String subtitleStr = "2003財年分析";
//創建時間數據源
//每一個TimeSeries在圖上是一條曲線
TimeSeries ca = new TimeSeries("用友");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ca.add(new Month(mon + 1, i), new Double(500 + Math.random() * 100));
//TimeSeriesDataPair是一個時間點的數值體現
ca.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(500 + Math.random() * 100)));
}
}
TimeSeries ibm = new TimeSeries("金碟");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
ibm.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(400 - Math.random() * 100)));
}
}
TimeSeries king = new TimeSeries("東軟");
for (int i = 1999; i < 2005; i++) {
for (int mon = 0; mon < 12; mon++) {
//ibm.add(new Month(mon+1,i),new Double(400-Math.random()*100));
king.add(
new TimeSeriesDataPair(
new Day(1, mon + 1, i),
new Double(300 - Math.random() * 100)));
}
}
//時間曲線數據集合
TimeSeriesCollection dataset = new TimeSeriesCollection();
dataset.addSeries(ca);
dataset.addSeries(ibm);
dataset.addSeries(king);
//dataset.addSeries(jpy);
//dataset.addSeries(mav);
//時間曲線元素
JFreeChart chart =
ChartFactory.createTimeSeriesChart(
title,
domain,
range,
dataset,
true,
true,
false);
// then customise it a little...
TextTitle subtitle =
new TextTitle(subtitleStr, new Font("黑體", Font.BOLD, 12));
chart.addSubtitle(subtitle);
chart.setTitle(new TextTitle(title, new Font("隸書", Font.ITALIC, 15)));
//pie.setSeriesLabelFont(new Font("黑體", Font.BOLD, 15));
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 0, 1000, Color.blue));
//sysout
//輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(22) + ".jpeg";
String fileName = "d:/test/" + rfname;
try {
//for
//System.out.println();
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
五:創建柱狀圖
String title = "柱狀圖測試";
String domain = "單位比較";
String range = "數值";
//CategoryDataset data = DemoDatasetFactory.createCategoryDataset();
DefaultCategoryDataset data = new DefaultCategoryDataset();
for (int r = 0; r < 5; r++) {
String rowKey = "單位 [" + (r + 1)+"]" ;
//第一層循環:分析對象
for (int c = 0; c < 6; c++) {
//第二層循環:分析對象在時間點上的數據
String columnKey = "2001年" + (c + 1) + "月";
data.addValue(new Double(r * c + 5), rowKey, columnKey);
}
}
JFreeChart chart =
ChartFactory.createVerticalBarChart(
title,
domain,
range,
data,
true,
true,
false);
// then customise it a little...
chart.setBackgroundPaint(
new GradientPaint(0, 0, Color.white, 1000, 0, Color.red));
chart.setTitle(new TextTitle(title, new Font("隸書", Font.ITALIC, 15)));
CategoryPlot plot = (CategoryPlot)chart.getPlot();
plot.setForegroundAlpha(0.9f);
plot.setValueLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//plot.setSectionLabelFont(new Font("黑體", Font.TRUETYPE_FONT, 12));
//注意以下代碼
NumberAxis verticalAxis = (NumberAxis)plot.getRangeAxis();
verticalAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
// 輸出文件到指定目錄
String rfname = MathUtil.getRoundCode(22) + "b.jpeg";
String fileName = "d:/test/" + rfname;
try {
ChartUtilities.saveChartAsJPEG(new File(fileName), 100, chart, 600, 600);
// log.info("....Create image File:" + fileName);
} catch (IOException exz) {
System.out.print("....Cant't Create image File");
}
六:結束語
個人感覺JFreeChart可以滿足大部分圖片創建的需要,美中不足的是:對字體的設置做的
不夠好,特別是使用中文的時候字體很不清晰。因為這個原因建議你自己去修改他的源代碼,最好使用properties文件去設置字體.還有就是文檔要錢所以要多花點時間去看源代碼。或多上社區.因為時間等原因我只介紹了三種圖片的創建,其他類型的圖片可以參考jfreechart提供的例子。
凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
、轉載請注明來處和原文作者。非常感謝。