最近项目生成报表中,用户要求生成的饼图和柱图都不用颜色区分,用纹理填充来区分。饼图要求随机一块 隔离 出来,特别显示,柱图要求用柱图和折线图联合比较。
后台生成图表选择的工具是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])); }
结果如下: