最近项目生成报表中,用户要求生成的饼图和柱图都不用颜色区分,用纹理填充来区分。饼图要求随机一块 隔离 出来,特别显示,柱图要求用柱图和折线图联合比较。
后台生成图表选择的工具是jfreechart,个人感觉功能相当齐全,网上相关资料也很多。但填充图片网上是真的找不到类似案例。没办法,研究了一下jfreechart API ,终于还是给发现了解决方法。
正文 柱图填充
先了解一下主要类及作用。JFreeChart类是通过ChartFactory(理解为生成chart的工厂)创建的类,代表图表。抽象类plot代表图表本身,包括背景,柱图,坐标轴,标题等等属性。基本上各个图有对应的PLOT类,饼图(pieplot)柱图(CategoryPlot)等。Render类,图表的渲染工具,类似画笔,用什么线条画,什么图片填充,同样的每个类有对应的render。(饼图没有)。柱图的render是BarRenderer,她有一个属性,BarPainter,即设置画笔画的内容
重写BarPainter。
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.RectangularShape;
import org.jfree.chart.renderer.category.BarPainter;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.ui.RectangleEdge;
public class CustomeBarPainter implements BarPainter{
@Override
public void paintBar(Graphics2D paramGraphics2D, BarRenderer paramBarRenderer, int paramInt1, int paramInt2,
RectangularShape paramRectangularShape, RectangleEdge paramRectangleEdge) {
// TODO Auto-generated method stub
Paint itemPaint = paramBarRenderer.getItemPaint(paramInt1, paramInt2);
paramGraphics2D.setPaint(itemPaint);
paramGraphics2D.fill(paramRectangularShape);
if (!(paramBarRenderer.isDrawBarOutline()))//柱状图加边框 从StandardBarPainter实现类copy
return;
Stroke stroke = paramBarRenderer.getItemOutlineStroke(paramInt1, paramInt2);
Paint paint = paramBarRenderer.getItemOutlinePaint(paramInt1, paramInt2);
if ((stroke != null) && (paint != null)) {
paramGraphics2D.setStroke(stroke);
paramGraphics2D.setPaint(paint);
paramGraphics2D.draw(paramRectangularShape);
}
}
@Override
public void paintBarShadow(Graphics2D paramGraphics2D, BarRenderer paramBarRenderer, int paramInt1, int paramInt2,
RectangularShape paramRectangularShape, RectangleEdge paramRectangleEdge, boolean paramBoolean) {
// TODO Auto-generated method stub
Paint itemPaint = paramBarRenderer.getItemPaint(paramInt1, paramInt2);
paramGraphics2D.setPaint(itemPaint);
paramGraphics2D.fill(paramRectangularShape);
}
}
设置柱图的barrender对象
if (dataset != null) {
plot.setDataset(1, dataset);//设置折线数据源
LineAndShapeRenderer lineandshaperenderer = new LineAndShapeRenderer(); //shape理解为数据点和线的渲染器
lineandshaperenderer.setSeriesPaint(0, new java.awt.Color(0, 0, 0));//设置线为黑色
plot.setRenderer(1, lineandshaperenderer);//渲染折线
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);//折线在柱状图前面显示
}
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());//柱子上顯示相關信息
renderer.setMaximumBarWidth(0.075);// 设置柱子最大宽度
renderer.setBaseOutlinePaint(Color.BLACK);//设置柱子边框
renderer.setDrawBarOutline(true);
renderer.setBarPainter(new CustomeBarPainter());//自定义barPainter实现方法
renderer.setItemMargin(0);//設置不同種類柱子之間的距離
ValueAxis valueAxis = plot.getRangeAxis();
Axis axis = plot.getDomainAxis();
valueAxis.setLowerMargin(0);
valueAxis.setAxisLinePaint(Color.BLACK);//纵轴设置为黑
axis.setAxisLinePaint(Color.BLACK);//横轴设置为黑
String[] imageArray = new String[]{"16.png","17.png","4.png","15.png","3.png"};//填充纹理图片库
for (int i = 0,count = plot.getDataset().getRowCount(); i < count; i++) {
renderer.setSeriesPaint(i, getTexturePaint(imageArray[i%(imageArray.length)]));
}//多柱子不同图片渲染
获取纹理填充图片
/**
* 获取填充图片
* */
private static TexturePaint getTexturePaint(String fileName){
BufferedImage bi=null;
Rectangle r = null;
TexturePaint tp = null;
try {
InputStream in = ChartUtils.class.getClassLoader().getResourceAsStream("config/texture/"+fileName);
bi = ImageIO.read(in);
} catch (IOException e) {
e.printStackTrace();
}
r = new Rectangle(0,0,bi.getWidth(),bi.getHeight());
tp = new TexturePaint(bi,r);
return tp;
}
运行即可生成纹理填充的柱状图。
饼图的填充和柱图不一样,因为饼图没有对应的render方法。但是查看了pieplot的方法之后,发现setSectionPaint()方法。同样,把纹理图片获取成Paint对象即可。
String[] imageArray = new String[]{"16.png","17.png","4.png","15.png","3.png"};
for (int i = 0,pieCount = piePlot.getDataset().getItemCount(); i < pieCount; i++) {
int j = i%imageArray.length;
piePlot.setSectionPaint(i,getTexturePaint(imageArray[j]));
}
结果如下: