jfreechart
在网页显示图表,echart就很强大了,一般应用都可以了。但如果是生成图片文件,如果还是用echart,还要引入js引擎,太麻烦了。
可以用jfreechart,但要制定一些显示,会麻烦点,需要重载 jfreechart 的方法。但这也能感觉到编程的乐趣,我在扩展开源框架,哈哈。
比如在柱状图纵坐标和每个柱子的值后面加个"%"。可以这么用。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.highersoft</groupId> <artifactId>jfreechart</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.5.3</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.5</version> </dependency> </dependencies> </project>
主类:
package com.xx.mp.report.service.impl; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.geom.Rectangle2D; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartFrame; import org.jfree.chart.ChartUtils; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.NumberTick; import org.jfree.chart.axis.Tick; import org.jfree.chart.axis.TickType; import org.jfree.chart.axis.TickUnit; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.labels.CategoryItemLabelGenerator; import org.jfree.chart.labels.StandardCategoryItemLabelGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.renderer.category.StandardBarPainter; import org.jfree.chart.ui.RectangleEdge; import org.jfree.chart.ui.RectangleInsets; import org.jfree.chart.ui.TextAnchor; import org.jfree.data.DataUtils; import org.jfree.data.category.CategoryDataset; import org.jfree.data.category.DefaultCategoryDataset; import org.springframework.stereotype.Service; /** * https://tool.4xseo.com/a/3161.html * @author chengzhong * */ @Service public class JFreeChartService { public static void main(String[] args) { String outPath="/template/dev/a.png"; LinkedHashMap<String,Double> dataMap=new LinkedHashMap<>(); dataMap.put("政府",10d); dataMap.put("新闻媒体",20d); dataMap.put("Ⅲ",5.0d); dataMap.put("Ⅳ",45.0d); dataMap.put("Ⅰ",15.0d); JFreeChartService js=new JFreeChartService(); js.exportImg(dataMap,outPath,400, 300); } public void exportImg(LinkedHashMap<String,Double> dataMap,String outPath,int width,int height){ // 创建数据 DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for(Map.Entry<String,Double> entry:dataMap.entrySet()){ dataset.addValue(entry.getValue(), "A", entry.getKey()); } //创建JFreeChart对象 JFreeChart chart = ChartFactory.createBarChart("", // 图标题 "", "", dataset, PlotOrientation.VERTICAL, false, true, false); CategoryPlot plot = chart.getCategoryPlot(); //设置内边距 chart.setPadding(new RectangleInsets(5,3,3,3)); //CategoryItemRenderer renderer = plot.getRenderer(); //设置柱子 CustomRender renderer=new CustomRender(); //BarRenderer renderer = (BarRenderer) plot.getRenderer(); DecimalFormat df = new DecimalFormat("##.#"); //CategoryItemLabelGenerator generator = new StandardCategoryItemLabelGenerator("{2}", df); CategoryItemLabelGenerator generator = new MyStandardCategoryItemLabelGenerator("{2}",df); renderer.setDefaultItemLabelGenerator(generator); renderer.setDefaultItemLabelsVisible(true); plot.setBackgroundPaint(Color.white); //设置边距 //plot.setInsets(new RectangleInsets(5, 3, 3, 3)); renderer.setDefaultFillPaint(new Color(0x61, 0x7d, 0xca)); StandardBarPainter sbp=new StandardBarPainter(); renderer.setBarPainter(sbp); //renderer.setDefaultItemLabelPaint(new Color(0x61, 0x7d, 0xca)); renderer.setDefaultPaint(new Color(0x61, 0x7d, 0xca)); renderer.setShadowVisible(false); renderer.setMaximumBarWidth(0.05); plot.setRenderer(renderer); ValueAxis va=plot.getRangeAxis(); MyNumberAxis ns[]=new MyNumberAxis[1]; ns[0]=new MyNumberAxis(); //设置纵坐标最大为110% ns[0].setUpperBound(110); plot.setRangeAxes(ns); // plot.setWallPaint(Color.gray); saveAsFile(chart, outPath, width, height); } public static void show(JFreeChart chart) { // 利用awt进行显示 ChartFrame chartFrame = new ChartFrame("Test", chart); chartFrame.pack(); chartFrame.setVisible(true); } // 保存为文件 public static void saveAsFile(JFreeChart chart, String outputPath, int weight, int height) { FileOutputStream out = null; try { File outFile = new File(outputPath); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } out = new FileOutputStream(outputPath); // 保存为PNG文件 ChartUtils.writeChartAsPNG(out, chart, weight, height); // 保存为JPEG文件 // ChartUtilities.writeChartAsJPEG(out, chart, 500, 400); out.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.close(); } catch (IOException e) { // do nothing } } } } } class CustomRender extends org.jfree.chart.renderer.category.IntervalBarRenderer { private Paint[] colors; // 初始化柱子颜色 private String[] colorValues = { "#FF0000", "#0070C0", "#00AF4E", "#7030A0" }; public CustomRender() { colors = new Paint[colorValues.length]; for (int i = 0; i < colorValues.length; i++) { colors[i] = Color.decode(colorValues[i]); } } // 每根柱子以初始化的颜色不断轮循 public Paint getItemPaint(int i, int j) { //return colors[j % colors.length]; return new Color(0x61, 0x7d, 0xca); } } /** * 改一处result[2]=value+"%"; * @author chengzhong * */ class MyStandardCategoryItemLabelGenerator extends StandardCategoryItemLabelGenerator{ DecimalFormat df = new DecimalFormat("##.#"); NumberFormat percentFormat=NumberFormat.getPercentInstance(); public MyStandardCategoryItemLabelGenerator(String string, DecimalFormat df) { super(string, df); } protected Object[] createItemArray(CategoryDataset dataset, int row, int column) { Object[] result = new Object[4]; result[0] = dataset.getRowKey(row).toString(); result[1] = dataset.getColumnKey(column).toString(); Number value = dataset.getValue(row, column); if (value != null) { /* if (super.getNumberFormat() != null) { result[2] = super.getNumberFormat().format(value); } else if (super.getDateFormat() != null) { result[2] = super.getDateFormat().format(value); } */ result[2]= df.format(value)+"%"; } else { result[2] = "-"; } if (value != null) { double total = DataUtils.calculateColumnTotal(dataset, column); double percent = value.doubleValue() / total; result[3] = percentFormat.format(percent); } return result; } } /** * 只改一处tickLabel=tickLabel+"%"; * @author chengzhong * */ class MyNumberAxis extends NumberAxis{ protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) { List result = new java.util.ArrayList(); result.clear(); Font tickLabelFont = getTickLabelFont(); g2.setFont(tickLabelFont); if (isAutoTickUnitSelection()) { selectAutoTickUnit(g2, dataArea, edge); } TickUnit tu = getTickUnit(); double size = tu.getSize(); int count = calculateVisibleTickCount(); double lowestTickValue = calculateLowestVisibleTickValue(); if (count <= ValueAxis.MAXIMUM_TICK_COUNT) { int minorTickSpaces = getMinorTickCount(); if (minorTickSpaces <= 0) { minorTickSpaces = tu.getMinorTickCount(); } for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { double minorTickValue = lowestTickValue - size * minorTick / minorTickSpaces; if (getRange().contains(minorTickValue)) { result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); } } for (int i = 0; i < count; i++) { double currentTickValue = lowestTickValue + (i * size); String tickLabel; NumberFormat formatter = getNumberFormatOverride(); if (formatter != null) { tickLabel = formatter.format(currentTickValue); } else { tickLabel = getTickUnit().valueToString(currentTickValue); } tickLabel=tickLabel+"%"; TextAnchor anchor; TextAnchor rotationAnchor; double angle = 0.0; if (isVerticalTickLabels()) { if (edge == RectangleEdge.LEFT) { anchor = TextAnchor.BOTTOM_CENTER; rotationAnchor = TextAnchor.BOTTOM_CENTER; angle = -Math.PI / 2.0; } else { anchor = TextAnchor.BOTTOM_CENTER; rotationAnchor = TextAnchor.BOTTOM_CENTER; angle = Math.PI / 2.0; } } else { if (edge == RectangleEdge.LEFT) { anchor = TextAnchor.CENTER_RIGHT; rotationAnchor = TextAnchor.CENTER_RIGHT; } else { anchor = TextAnchor.CENTER_LEFT; rotationAnchor = TextAnchor.CENTER_LEFT; } } Tick tick = new NumberTick(currentTickValue, tickLabel, anchor, rotationAnchor, angle); result.add(tick); double nextTickValue = lowestTickValue + ((i + 1) * size); for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { double minorTickValue = currentTickValue + (nextTickValue - currentTickValue) * minorTick / minorTickSpaces; if (getRange().contains(minorTickValue)) { result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); } } } } return result; } }
配置柱子类:
class CustomRender extends org.jfree.chart.renderer.category.IntervalBarRenderer { private Paint[] colors; // 初始化柱子颜色 private String[] colorValues = { "#FF0000", "#0070C0", "#00AF4E", "#7030A0" }; public CustomRender() { colors = new Paint[colorValues.length]; for (int i = 0; i < colorValues.length; i++) { colors[i] = Color.decode(colorValues[i]); } } // 每根柱子以初始化的颜色不断轮循 public Paint getItemPaint(int i, int j) { //return colors[j % colors.length]; return new Color(0x61, 0x7d, 0xca); } }
配置柱子上面的值,类:
/** * 改一处result[2]=value+"%"; * @author chengzhong * */ class MyStandardCategoryItemLabelGenerator extends StandardCategoryItemLabelGenerator{ NumberFormat percentFormat=NumberFormat.getPercentInstance(); public MyStandardCategoryItemLabelGenerator(String string, DecimalFormat df) { super(string, df); } protected Object[] createItemArray(CategoryDataset dataset, int row, int column) { Object[] result = new Object[4]; result[0] = dataset.getRowKey(row).toString(); result[1] = dataset.getColumnKey(column).toString(); Number value = dataset.getValue(row, column); if (value != null) { /* if (super.getNumberFormat() != null) { result[2] = super.getNumberFormat().format(value); } else if (super.getDateFormat() != null) { result[2] = super.getDateFormat().format(value); } */ result[2]=value+"%"; } else { result[2] = "-"; } if (value != null) { double total = DataUtils.calculateColumnTotal(dataset, column); double percent = value.doubleValue() / total; result[3] = percentFormat.format(percent); } return result; } }
配置纵坐标,类:
/** * 只改一处tickLabel=tickLabel+"%"; * @author chengzhong * */ class MyNumberAxis extends NumberAxis{ protected List refreshTicksVertical(Graphics2D g2, Rectangle2D dataArea, RectangleEdge edge) { List result = new java.util.ArrayList(); result.clear(); Font tickLabelFont = getTickLabelFont(); g2.setFont(tickLabelFont); if (isAutoTickUnitSelection()) { selectAutoTickUnit(g2, dataArea, edge); } TickUnit tu = getTickUnit(); double size = tu.getSize(); int count = calculateVisibleTickCount(); double lowestTickValue = calculateLowestVisibleTickValue(); if (count <= ValueAxis.MAXIMUM_TICK_COUNT) { int minorTickSpaces = getMinorTickCount(); if (minorTickSpaces <= 0) { minorTickSpaces = tu.getMinorTickCount(); } for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { double minorTickValue = lowestTickValue - size * minorTick / minorTickSpaces; if (getRange().contains(minorTickValue)) { result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); } } for (int i = 0; i < count; i++) { double currentTickValue = lowestTickValue + (i * size); String tickLabel; NumberFormat formatter = getNumberFormatOverride(); if (formatter != null) { tickLabel = formatter.format(currentTickValue); } else { tickLabel = getTickUnit().valueToString(currentTickValue); } tickLabel=tickLabel+"%"; TextAnchor anchor; TextAnchor rotationAnchor; double angle = 0.0; if (isVerticalTickLabels()) { if (edge == RectangleEdge.LEFT) { anchor = TextAnchor.BOTTOM_CENTER; rotationAnchor = TextAnchor.BOTTOM_CENTER; angle = -Math.PI / 2.0; } else { anchor = TextAnchor.BOTTOM_CENTER; rotationAnchor = TextAnchor.BOTTOM_CENTER; angle = Math.PI / 2.0; } } else { if (edge == RectangleEdge.LEFT) { anchor = TextAnchor.CENTER_RIGHT; rotationAnchor = TextAnchor.CENTER_RIGHT; } else { anchor = TextAnchor.CENTER_LEFT; rotationAnchor = TextAnchor.CENTER_LEFT; } } Tick tick = new NumberTick(currentTickValue, tickLabel, anchor, rotationAnchor, angle); result.add(tick); double nextTickValue = lowestTickValue + ((i + 1) * size); for (int minorTick = 1; minorTick < minorTickSpaces; minorTick++) { double minorTickValue = currentTickValue + (nextTickValue - currentTickValue) * minorTick / minorTickSpaces; if (getRange().contains(minorTickValue)) { result.add(new NumberTick(TickType.MINOR, minorTickValue, "", TextAnchor.TOP_CENTER, TextAnchor.CENTER, 0.0)); } } } } return result; } }
相关阅读
评论:
↓ 广告开始-头部带绿为生活 ↓
↑ 广告结束-尾部支持多点击 ↑