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;

    }
}

文/程忠 浏览次数:0次   2023-03-27 17:09:36

相关阅读


评论:
点击刷新

↓ 广告开始-头部带绿为生活 ↓
↑ 广告结束-尾部支持多点击 ↑