Saturday, March 28, 2009

在 Web 上套用統計圖表 Jfreechart + cewolf

在開發 Web Page 時若要將統計圖表放到 Web 上,可以使用 JFreeChart 將數據轉換成圖形後,再以檔案的方式存起來,當 WebPage 顯示時再利用 URL 的方式將 image 從檔案中讀取出來並顯示在 Web Page 上

這個方式雖然可以解決統計圖顯示在 Web Page 上問題,但彈性太小,無法透過參數的方式指定圖形型態,大小,資料等,而 cewolf 這個 open source 便提供了此彈性的解決方案

Cewolf 在實作上是一個 JFreeChart 的 Wrapper 並提供 Tag Library 讓 Developer 可以方便的在 JSP 上套用統計圖表。要在 JSP 下顯示圖表可以參考以下步驟

1. Setup Libarary of JFreeChart and Cewolf
從 JFreeChart 與 Cewolf 下載 library 後,必須在 web.xml 中設定 servlet 與 servlet mapping 讓圖形可以透過此 mappng 讓 Browser 下載圖表









2. Add Chart into JSP
在 JSP 中若要加 JFreeChart 的圖表,需要加上 tag 如下 ([] 取代 <>)
[%@ taglib uri="/WEB-INF/cewolf.tld" prefix="cewolf" %]
[cewolf:chart id="line" title="EPS" type="verticalbar" xaxislabel="category" axislabel="value"]
[cewolf:data]
[cewolf:producer id="datasetProducer" /]
[/cewolf:data]
[cewolf:chartpostprocessor id="dataColor"/]
[/cewolf:chart]
[cewolf:img chartid="line" renderer="/cewolf" width="600" height="300" /]

3. Assign data to id associated to chart
這邊是用 struts 2 的方式,所以在 action 中加上 API 就可以當 id 用

public DatasetProducer getDatasetProducer() {
DatasetProducer producer = new DatasetProducer() {
/**
* Produces some random data.
*/
public Object produceDataset(Map params) throws DatasetProduceException {
log.info("producing data.");

// create the dataset...
DefaultCategoryDataset dataset = new DefaultCategoryDataset();

dataset.addValue(100, "serial1", "category1");
dataset.addValue(120, "serial2", "category1");
dataset.addValue(120, "serial3", "category1");

dataset.addValue(130, "serial1", "category2");
dataset.addValue(140, "serial2", "category2");
dataset.addValue(140, "serial3", "category2");

return dataset;
}

/**
* This producer's data is invalidated after 5 seconds. By this method the
* producer can influence Cewolf's caching behaviour the way it wants to.
*/
public boolean hasExpired(Map params, Date since) {
log.debug(getClass().getName() + "hasExpired()");
//return (System.currentTimeMillis() - since.getTime()) > 5000;
return true;
}

/**
* Returns a unique ID for this DatasetProducer
*/
public String getProducerId() {
return "PageViewCountData DatasetProducer";
}


/**
* @see java.lang.Object#finalize()
*/
protected void finalize() throws Throwable {
super.finalize();
log.debug(this + " finalized.");
}
};
return producer;
}

public ChartPostProcessor getDataColor() {
ChartPostProcessor dataColor = new ChartPostProcessor() {
public void processChart(Object chart, Map params) {
CategoryPlot categoryplot = (CategoryPlot) ((JFreeChart) chart) .getPlot();
categoryplot.setDomainGridlinesVisible(true);
categoryplot.setRangeCrosshairVisible(true);
categoryplot.setRangeCrosshairPaint(Color.blue);
NumberAxis numberaxis = (NumberAxis)categoryplot.getRangeAxis();
numberaxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
BarRenderer barrenderer = (BarRenderer)categoryplot.getRenderer();
barrenderer.setDrawBarOutline(false);
GradientPaint gradientpaint = new GradientPaint(0.0F, 0.0F, Color.blue, 0.0F, 0.0F, new Color(0, 0, 64));
GradientPaint gradientpaint1 = new GradientPaint(0.0F, 0.0F, Color.green, 0.0F, 0.0F, new Color(0, 64, 0));
GradientPaint gradientpaint2 = new GradientPaint(0.0F, 0.0F, Color.red, 0.0F, 0.0F, new Color(64, 0, 0));
barrenderer.setSeriesPaint(0, gradientpaint);
barrenderer.setSeriesPaint(1, gradientpaint1);
barrenderer.setSeriesPaint(2, gradientpaint2);
barrenderer.setLegendItemToolTipGenerator(new StandardCategorySeriesLabelGenerator("Tooltip: {0}"));
CategoryAxis categoryaxis = categoryplot.getDomainAxis();
categoryaxis.setCategoryLabelPositions(CategoryLabelPositions.createUpRotationLabelPositions(0.52359877559829882D));

}
};
return dataColor;
}

如此就可以在畫面上顯示














PS:
1. 在 cewolf:img chartid="line" renderer="/cewolf" width="600" height="300"中的 renderer 需要加上 "/" 因為 servlet 的 mapping 設定是以 "/" 為主
2. 這個 cewolf package 在 resin 下若顯示兩個圖表以上會有 bug

這邊提供一個範例 webchart ,提供給需要實作的人可以快速上手

No comments: