-
在iReport中通过JFreeChart生成雷达图(蜘蛛图)
日期:2010-07-13 | 分类:技术
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://gang613.blogbus.com/logs/69142477.html
在iReport中提供了丰富的chart组件,包括:Pie、Pie 3D、Bar、YX Bar、Stacked Bar、Stacked Bar 3D、Line、XY Line、Area、YX Area、Stacked Area、Scatter、Bubble、Time Series、High Low、Candlestick、Gantt、Meter、Thermometer、Multi Axis 等。iReport为以上组件提供了相应的wizard,可以快速地在报表中输出chart。

在我们的项目中用户需要在报表中生成雷达图(Spider Chart)——又名蜘蛛图,而这种chart在iReport中并没有相应的组件。我们发现通过jFreeChart能够生成Spider Chart,然后通过iReport对jFreeChart的调用完成在报表中输出Spider Chart 。
1)在报表中创建一个Image对象,如下图所示:
该Image的类型为:“java.awt.Image”,表达式为“$F{spiderimage}”其xml属性如下图:

字段spiderimage的类型为“java.awt.image.BufferedImage”

2)jFreeChart创建Spider Chart的代码如下:
/**
* 扩展了SpiderWebPlot,用于在显示刻度和说明。
* 来源于:http://javacrazyer.javaeye.com/blog/623741
*/
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.AffineTransform;
import java.awt.geom.Arc2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import org.jfree.chart.plot.SpiderWebPlot;
import org.jfree.data.category.CategoryDataset;
public class MySpiderWebPlot extends SpiderWebPlot {
private static final long serialVersionUID = 4005814203754627127L;
private int ticks = DEFAULT_TICKS;
private static final int DEFAULT_TICKS = 5;
private NumberFormat format = NumberFormat.getInstance();
private static final double PERPENDICULAR = 90;
private static final double TICK_SCALE = 0.015;
private int valueLabelGap = DEFAULT_GAP;
private static final int DEFAULT_GAP = 10;
private static final double THRESHOLD = 15;
MySpiderWebPlot(CategoryDataset createCategoryDataset) {
super(createCategoryDataset);
}
protected void drawLabel(final Graphics2D g2, final Rectangle2D plotArea,
final double value, final int cat, final double startAngle,
final double extent) {
super.drawLabel(g2, plotArea, value, cat, startAngle, extent);
final FontRenderContext frc = g2.getFontRenderContext();
final double[] transformed = new double[2];
final double[] transformer = new double[2];
final Arc2D arc1 = new Arc2D.Double(plotArea, startAngle, 0, Arc2D.OPEN);
for (int i = 1; i <= ticks; i++) {
final Point2D point1 = arc1.getEndPoint();
final double deltaX = plotArea.getCenterX();
final double deltaY = plotArea.getCenterY();
double labelX = point1.getX() - deltaX;
double labelY = point1.getY() - deltaY;
final double scale = ((double) i / (double) ticks);
final AffineTransform tx = AffineTransform.getScaleInstance(scale,
scale);
final AffineTransform pointTrans = AffineTransform
.getScaleInstance(scale + TICK_SCALE, scale + TICK_SCALE);
transformer[0] = labelX;
transformer[1] = labelY;
pointTrans.transform(transformer, 0, transformed, 0, 1);
final double pointX = transformed[0] + deltaX;
final double pointY = transformed[1] + deltaY;
tx.transform(transformer, 0, transformed, 0, 1);
labelX = transformed[0] + deltaX;
labelY = transformed[1] + deltaY;
double rotated = (PERPENDICULAR);
AffineTransform rotateTrans = AffineTransform.getRotateInstance(
Math.toRadians(rotated), labelX, labelY);
transformer[0] = pointX;
transformer[1] = pointY;
rotateTrans.transform(transformer, 0, transformed, 0, 1);
final double x1 = transformed[0];
final double y1 = transformed[1];
rotated = (-PERPENDICULAR);
rotateTrans = AffineTransform.getRotateInstance(Math
.toRadians(rotated), labelX, labelY);
rotateTrans.transform(transformer, 0, transformed, 0, 1);
final Composite saveComposite = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
1.0f));
g2.draw(new Line2D.Double(transformed[0], transformed[1], x1, y1));
if (startAngle == this.getStartAngle()) {
final String label = format
.format(((double) i / (double) ticks)
* this.getMaxValue());
final LineMetrics lm = getLabelFont()
.getLineMetrics(label, frc);
final double ascent = lm.getAscent();
if (Math.abs(labelX - plotArea.getCenterX()) < THRESHOLD) {
labelX += valueLabelGap;
labelY += ascent / (float) 2;
} else if (Math.abs(labelY - plotArea.getCenterY()) < THRESHOLD) {
labelY += valueLabelGap;
} else if (labelX >= plotArea.getCenterX()) {
if (labelY < plotArea.getCenterY()) {
labelX += valueLabelGap;
labelY += valueLabelGap;
} else {
labelX -= valueLabelGap;
labelY += valueLabelGap;
}
} else {
if (labelY > plotArea.getCenterY()) {
labelX -= valueLabelGap;
labelY -= valueLabelGap;
} else {
labelX += valueLabelGap;
labelY -= valueLabelGap;
}
}
g2.setPaint(getLabelPaint());
g2.setFont(getLabelFont());
g2.drawString(label, (float) labelX, (float) labelY);
}
g2.setComposite(saveComposite);
}
}
}
/**
* 通过构造DefaultCategoryDataset创建Spider Chart。
*
*/
public class MySpriderWebPlotFactory {
public static JFreeChart createChart() {
MySpiderWebPlot spiderwebplot = new MySpiderWebPlot(createDataset());
JFreeChart jfreechart = new JFreeChart("前三个季度水果销售报告",
TextTitle.DEFAULT_FONT, spiderwebplot, false);
LegendTitle legendtitle = new LegendTitle(spiderwebplot);
legendtitle.setPosition(RectangleEdge.RIGHT);
jfreechart.addSubtitle(legendtitle);
return jfreechart;
}
public static DefaultCategoryDataset createDataset() {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
String group1 = "苹果";
dataset.addValue(50, group1, "一月份");
dataset.addValue(60, group1, "二月份");
dataset.addValue(40, group1, "三月份");
dataset.addValue(20, group1, "四月份");
// dataset.addValue(50, group1, "五月份");
dataset.addValue(53, group1, "六月份");
dataset.addValue(52, group1, "七月份");
// dataset.addValue(80, group1, "八月份");
String group2 = "橙子";
dataset.addValue(31, group2, "一月份");
dataset.addValue(34, group2, "二月份");
dataset.addValue(45, group2, "三月份");
dataset.addValue(74, group2, "四月份");
// dataset.addValue(46, group2, "五月份");
dataset.addValue(59, group2, "六月份");
dataset.addValue(33, group2, "七月份");
// dataset.addValue(31, group2, "八月份");
String group3 = "香蕉";
dataset.addValue(47, group3, "一月份");
dataset.addValue(58, group3, "二月份");
dataset.addValue(20, group3, "三月份");
dataset.addValue(50, group3, "四月份");
// dataset.addValue(65, group3, "五月份");
dataset.addValue(67, group3, "六月份");
dataset.addValue(44, group3, "七月份");
// dataset.addValue(49, group3, "八月份");
return dataset;
}
}
3)将jFreeChart转换为BufferedImage
public BufferedImage extractImage(JFreeChart chart, int width, int height) {
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = img.createGraphics();
chart.draw(g2, new Rectangle2D.Double(0, 0, width, height));
g2.dispose();
return img;
}4)定义ChartBean,用于封装数据。
public class ChartBean {
java.awt.image.BufferedImage spiderimage;
public ChartBean() {
}
public BufferedImage getSpiderimage(){
return this.spiderimage;
}
public void setSpiderimage(BufferedImage spiderimage) {
this.spiderimage = spiderimage;
}
}5)完成调用过程如下:
…
List charts = new ArrayList();
JFreeChart jfreechart = MySpiderWebPlotFactory.createChart();
BufferedImage bi = extractImage(jfreechart, 800, 600);
ChartBean chartBean = new ChartBean();
chartBean.setSpiderimage(bi);
charts.add(chartBean);
JRBeanCollectionDataSource ds = new JRBeanCollectionDataSource(charts);
…
try {
JasperPrint jasperPrint = JasperFillManager.fillReport(rep,
new HashMap(), ds);
} catch (JRException jre) {
pw.println("生成JasperPrint错误!");
jre.printStackTrace();
}
…最终生成效果图如下:

参考资料:
1)Using Dynamically Generated JFreeChart charts and JasperReports
收藏到:Del.icio.us







