打赏
Fork me on GitHub

java Jfree 生成 环形图、柱状图、环形图

 <!-- jfreechart begin -->
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jcommon</artifactId>
            <version>1.0.24</version>
        </dependency>
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.0</version>
        </dependency>
        <!-- jfreechart end -->
pom.xml
package org.lcoil.drools.demo.vo;

import lombok.Builder;
import lombok.Data;

/**
 * @Classname BarChartVO
 * @Description TODO
 * @Date 2022/2/18 8:49 PM
 * @Created by l-coil
 */
@Data
@Builder
public class BarChartVO {
    private String series;
    private double value;
    private String keyRow;
}
BarChartVO
package org.lcoil.drools.demo.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.awt.*;

/**
 * @Classname ColumnarVO
 * @Description TODO
 * @Date 2022/2/18 8:48 PM
 * @Created by l-coil
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ColumnarVO {

    /**
     * y轴坐标
     */
    private Number value;
    /**
     * y轴名称
     */
    private String key;
    /**
     * x轴坐标
     */
    private String keyName;
    /**
     * 柱子颜色
     */
    private Color color;
}
ColumnarVO
package org.lcoil.drools.demo.jfree;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.lcoil.drools.demo.vo.BarChartVO;
import org.lcoil.drools.demo.vo.ColumnarVO;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
 * @Classname BarSpChart
 * @Description TODO
 * @Date 2022/2/18 8:48 PM
 * @Created by l-coil
 */
public class BarSpChart {

    /**
     * @param columnarVos 数据
     * @param imgWidth    图片宽度
     * @param imageHeight 图片高度
     * @param path        生成图片位置
     * @return
     */
    public static String createColumnar(List<ColumnarVO> columnarVos, int imgWidth, int imageHeight, String path) {//柱形间的间距
        int marginLeft = 10;
        //最上边刻度距离图片的最顶端的距离
        int top = 20;
        BufferedImage image = new BufferedImage(imgWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = (Graphics2D) image.getGraphics();
        graphics.setStroke(new BasicStroke(1f));
        graphics.setFont(new Font("微软雅黑", Font.PLAIN, 16));
        graphics.setColor(new Color(229, 239, 245));
        //设置字体划线平滑
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
        //计算y轴最大值以及x轴刻度的最大长度
        Number max = 0;
        int maxWidth = 0;
        for (ColumnarVO c : columnarVos) {
            if (max.intValue() < c.getValue().intValue()) {
                max = c.getValue().intValue();
            }
            if (maxWidth < graphics.getFontMetrics().stringWidth(c.getValue().toString())) {
                maxWidth = graphics.getFontMetrics().stringWidth(c.getValue().toString());
            }
        }
        //每个刻度的最小像素数
        float singleMinHeight = 50;
        //图片宽度减去x轴距离底部的距离
        int realHeight = imageHeight - 30;
        //y轴距离左侧的距离(除去y轴刻度的宽度)
        int left = 20;
        //平分x轴,y轴的值
        double singleWidth = (imageHeight - maxWidth - left - marginLeft - columnarVos.size() * marginLeft) / (double) columnarVos.size();
        float singleHeight = (float) Math.floor((realHeight - top) / (max.doubleValue() + 1));
        //刻度值默认是数组value最大值
        int markNumber = max.intValue();
        //刻度值默认是1
        int markValue = 1;
        //如果y轴1个刻度的距离小于最小刻度值重新计算刻度以及刻度的最新值
        if (singleMinHeight > singleHeight) {
            singleHeight = singleMinHeight;
            markNumber = (int) Math.floor((realHeight - top) / singleHeight);
            markValue = (int) Math.ceil(max.intValue() / ((double) markNumber - 1));
        } else {
            markNumber = markNumber + 1;
        }
        graphics.fillRect(0, 0, imgWidth, imageHeight);
        graphics.setColor(Color.black);
        int x = 0;
        //x轴数据以及填充的柱状
        for (ColumnarVO c : columnarVos) {
            graphics.setColor(c.getColor());
            float y = singleHeight * (c.getValue().floatValue() / markValue);
            Rectangle2D rectangle2D = new Rectangle2D.Float(60, maxWidth + left + (float) singleWidth * x + (x + 1) * marginLeft, y, (float) 20.0);
            graphics.fill(rectangle2D);
            graphics.setColor(Color.black);
            int index = strWidthIndex(c.getKeyName(), (int) singleWidth, 0, graphics.getFontMetrics());
            graphics.drawString(index < c.getKeyName().length() ? c.getKeyName().substring(0, index) + "..." : c.getKeyName(), 10, maxWidth + left + (int) singleWidth * x + (x + 1) * marginLeft + 16);
            graphics.drawString(c.getValue() + "", imageHeight - 10, maxWidth + left + (int) singleWidth * x + (x + 1) * marginLeft + 14);
            x++;
        }
        try {
            File outFile = new File(path);
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            ImageIO.write(image, "jpg", new File(path));
            String result = JfreeUtil.getImageBase(path);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 指定字体宽度的计算
     *
     * @param cont
     * @param width
     * @param i
     * @param metrics
     * @return
     */
    private static int strWidthIndex(String cont, int width, int i, FontMetrics metrics) {
        if (width > metrics.stringWidth(cont.substring(0, cont.length() - i))) {
            return cont.length() - i;
        } else {
            return strWidthIndex(cont, width, i + 1, metrics);
        }
    }


    /**
     * 生成水平柱状图柱状图
     *
     * @param barChartVOList
     * @param tempFilePath
     * @param width
     * @param height
     * @return
     */
    public static String spBarChart(List<BarChartVO> barChartVOList, String tempFilePath, Integer width, Integer height) {
        JFreeChart chart = ChartFactory.createBarChart("",
                "", "", createDataset2(barChartVOList), PlotOrientation.HORIZONTAL, //显示方向
                false, //是否显示图例如图一的均值、差值
                false, // 是否生成工具
                false); // 是否生成URL链接
        iSetBarSpChart(chart);
        try {
            File outFile = new File(tempFilePath);
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            ChartUtils.saveChartAsJPEG(new File(tempFilePath), chart, width, height);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String result = JfreeUtil.getImageBase(tempFilePath);
        return result;
    }

    /**
     * 数据集合
     *
     * @return
     */
    public static CategoryDataset createDataset2(List<BarChartVO> barChartVOList) {
        DefaultCategoryDataset result = new DefaultCategoryDataset();
        for (BarChartVO bc : barChartVOList) {
            result.addValue(bc.getValue(), bc.getKeyRow(), bc.getSeries());
        }
        return result;
    }

    /**
     * 水平柱状图的样式
     *
     * @param chart
     */
    public static void iSetBarSpChart(JFreeChart chart) {
        CategoryPlot categoryplot = chart.getCategoryPlot();// 图本身
        ValueAxis rangeAxis = categoryplot.getRangeAxis();
        CategoryAxis domainAxis = categoryplot.getDomainAxis();
        // 设置Y轴的提示文字样式
        rangeAxis.setLabelFont(new Font("微软雅黑", Font.PLAIN, 8));
        // 设置Y轴刻度线的长度
        rangeAxis.setTickMarkInsideLength(10f);
        // 设置X轴下的标签文字
        domainAxis.setLabelFont(new Font("微软雅黑", Font.PLAIN, 10));
        // 设置X轴上提示文字样式
        domainAxis.setTickLabelFont(new Font("微软雅黑", Font.PLAIN, 10));
        domainAxis.setAxisLineVisible(false);
        domainAxis.setTickMarksVisible(false);

        NumberAxis numAxis = (NumberAxis) categoryplot.getRangeAxis();
        numAxis.setVisible(false);
        // 自定义柱状图中柱子的样式
        BarRenderer brender = (BarRenderer) categoryplot.getRenderer();
        Paint[] paints = {
                new Color(237, 125, 49),//超危颜色
                new Color(255, 192, 0),//高危
                new Color(112, 173, 71),//中危
                new Color(158, 72, 14),//低危
                new Color(153, 115, 0)//未知
        };
        brender.setSeriesPaint(0, paints[0]);
        brender.setSeriesPaint(1, paints[1]);
        brender.setSeriesPaint(2, paints[2]);
        brender.setSeriesPaint(3, paints[3]);
        brender.setSeriesPaint(4, paints[4]);
        // 设置柱状图的顶端显示数字
        brender.setIncludeBaseInRange(true);
        brender.setDefaultItemLabelsVisible(true, true);
        brender.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator());
        // 设置柱子为平面图不是立体的
        brender.setBarPainter(new StandardBarPainter());
        brender.setMaximumBarWidth(0.05);
        brender.setMinimumBarLength(0.05);
        // 设置柱状图之间的距离0.1代表10%;
        brender.setItemMargin(0.02);
        // 设置柱子的阴影,false代表没有阴影
        brender.setShadowVisible(false);

        categoryplot.setRenderer(brender);
        // 设置图的背景为白色
        categoryplot.setBackgroundPaint(Color.WHITE);
        // 去掉柱状图的背景边框,使边框不可见
        categoryplot.setOutlineVisible(false);
        // 设置标题的字体样式
        chart.getTitle().setFont(new Font("微软雅黑", Font.PLAIN, 10));
    }
}
BarSpChart
package org.lcoil.drools.demo.jfree;

import lombok.extern.slf4j.Slf4j;
import org.drools.core.io.impl.ClassPathResource;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.general.DefaultPieDataset;
import org.kie.api.io.Resource;
import sun.misc.BASE64Encoder;

import java.awt.*;
import java.io.*;
import java.util.Map;
/**
 * @Classname JfreeUtil
 * @Description TODO
 * @Date 2022/2/18 8:48 PM
 * @Created by l-coil
 */
@Slf4j
public class JfreeUtil {

    /**
     * 将图片转化为字节数组
     *
     * @return 字节数组
     */
    private static byte[] imgToByte(String tempImgPath) {
        File file = new File(tempImgPath);
        byte[] buffer = null;
        try {
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = fis.read(b)) != -1) {
                bos.write(b, 0, n);
            }
            fis.close();
            bos.close();
            buffer = bos.toByteArray();
        } catch (IOException e) {
            log.error(e.getMessage());
        }
        //删除临时文件
        file.delete();
        return buffer;
    }

    public static String pieChart2(String title, Map<String, Integer> datas, int width, int height, String tempImgPath) {

        //创建主题样式
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
        //设置标题字体
        standardChartTheme.setExtraLargeFont(new Font("宋体", Font.BOLD, 20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 15));
        //设置主题样式
        ChartFactory.setChartTheme(standardChartTheme);

        //根据jfree生成一个本地饼状图
        DefaultPieDataset pds = new DefaultPieDataset();
        datas.forEach(pds::setValue);
        //图标标题、数据集合、是否显示图例标识、是否显示tooltips、是否支持超链接
        JFreeChart chart = ChartFactory.createPieChart(title, pds, true, false, false);
        //设置抗锯齿
        chart.setTextAntiAlias(false);
        PiePlot plot = (PiePlot) chart.getPlot();
        plot.setNoDataMessage("暂无数据");
        //忽略无值的分类
        plot.setIgnoreNullValues(true);
        plot.setBackgroundAlpha(0f);
        //设置标签阴影颜色
        plot.setShadowPaint(new Color(255, 255, 255));
        //设置标签生成器(默认{0})
        plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}({1})/{2}"));
        try {
            File outFile = new File(tempImgPath);
            if (!outFile.getParentFile().exists()) {
                outFile.getParentFile().mkdirs();
            }
            ChartUtils.saveChartAsJPEG(new File(tempImgPath), chart, width, height);
        } catch (IOException e1) {
            log.error("生成饼状图失败!");
        }
        String result = getImageBase(tempImgPath);
        return result;
    }

    //获得图片的base64码
    public static String getImageBase(String src) {
        File file = new File(src);
        if (!file.exists()) {
            return "";
        }
        InputStream in = null;
        byte[] data = null;
        try {
            in = new FileInputStream(file);
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }
        try {
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BASE64Encoder encoder = new BASE64Encoder();
        //删除临时文件
        file.delete();
        return encoder.encode(data);
    }

    public static String getLogoBase64() {
        Resource resource = new ClassPathResource("template/logo.png");
        InputStream in = null;
        byte[] data = null;
        try {
            in = resource.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            data = new byte[in.available()];
            in.read(data);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);
    }
}
JfreeUtil
package org.lcoil.drools.demo.jfree;

import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.RingPlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.chart.ui.RectangleEdge;
import org.jfree.data.general.DefaultPieDataset;
import org.lcoil.drools.demo.vo.BarChartVO;

import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
/**
 * @Classname RingChart
 * @Description TODO
 * @Date 2022/2/18 8:48 PM
 * @Created by l-coil
 */
@Slf4j
public class RingChart {
    /**
     * 生成环状图
     *
     * @param barChartVOList
     * @param tempImgPath
     * @param width
     * @param height
     * @return
     */
    public static String generateRingChart(List<BarChartVO> barChartVOList, String tempImgPath, Integer width, Integer height) {
        DefaultPieDataset dataset = getDataSet2(barChartVOList);
        setTheme();
        JFreeChart chart = ChartFactory.createRingChart(
                "",
                dataset,
                true,
                false,
                false
        );
        RingPlot plot = (RingPlot) chart.getPlot();//获得图形面板
        plot.setIgnoreNullValues(true);  //忽略null值
        plot.setIgnoreZeroValues(false); //不忽略0值
        plot.setBackgroundPaint(Color.WHITE);//设置画布背景颜色
        plot.setOutlineVisible(false);//设置绘图区边框是否可见
        plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0}      {1} 个", NumberFormat.getNumberInstance(),
                new DecimalFormat("0.00%"))); //设置图例数据格式
        plot.setBackgroundPaint(new Color(253, 253, 253));
        //设置标签样式
        plot.setLabelFont(new Font("宋体", Font.BOLD, 15));
        plot.setSimpleLabels(false);
        plot.setLabelLinkPaint(Color.WHITE);
        plot.setLabelOutlinePaint(Color.WHITE);
        plot.setLabelLinksVisible(false);
        plot.setLabelShadowPaint(null);
        plot.setLabelOutlinePaint(new Color(0, true));
        plot.setLabelBackgroundPaint(new Color(0, true));
        plot.setLabelPaint(Color.WHITE);
        plot.setSeparatorPaint(Color.WHITE);
        plot.setShadowPaint(new Color(253, 253, 253));
        plot.setSectionDepth(0.35);
        plot.setStartAngle(90);
        plot.setDrawingSupplier(new DefaultDrawingSupplier(
                new Paint[]{
                        new Color(237, 125, 49),//超危颜色
                        new Color(255, 192, 0),//高危
                        new Color(112, 173, 71),//中危
                        new Color(158, 72, 14),//低危
                        new Color(153, 115, 0),//未知
                        new Color(67, 104, 43)//
                },
                DefaultDrawingSupplier.DEFAULT_OUTLINE_PAINT_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE));
        plot.setSectionDepth(0.35);
        //图例样式的设定,图例含有M 和P 方法
        LegendTitle legendTitle = chart.getLegend();//获得图例标题
        legendTitle.setPosition(RectangleEdge.LEFT);//图例右边显示
        legendTitle.setBorder(0, 0, 0, 0);//设置图例上下左右线
        legendTitle.setPadding(0, 0, 0, 50);
        //标题的距离的设定
        TextTitle title = chart.getTitle();    //设置标题居左的距离
        title.setMargin(0, -20, 0, 0);//标题距离上下左右的距离

        FileOutputStream fos_jpg = null;
        try {
            try {
                File outFile = new File(tempImgPath);
                if (!outFile.getParentFile().exists()) {
                    outFile.getParentFile().mkdirs();
                }
                fos_jpg = new FileOutputStream(tempImgPath);
                ChartUtils.writeChartAsJPEG(fos_jpg, 1.0f, chart, width, height, null);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } finally {
            try {
                fos_jpg.close();
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        String result = JfreeUtil.getImageBase(tempImgPath);
        return result;
    }

    /**
     * <p>样式设定</p>
     */
    private static void setTheme() {
        //创建主题样式
        StandardChartTheme standardChartTheme = new StandardChartTheme("CN");
        //设置标题
        standardChartTheme.setExtraLargeFont(new Font("隶书", Font.BOLD, 20));
        //设置图例的字体
        standardChartTheme.setRegularFont(new Font("宋书", Font.PLAIN, 15));
        //设置轴向的字体
        standardChartTheme.setLargeFont(new Font("宋书", Font.PLAIN, 15));
        ChartFactory.setChartTheme(standardChartTheme);
    }

    /*
     * 基本数据集
     */
    private static DefaultPieDataset getDataSet2(List<BarChartVO> barChartVOList) {
        DefaultPieDataset dataset = new DefaultPieDataset();
        for (BarChartVO bc : barChartVOList) {
            dataset.setValue(bc.getSeries(), bc.getValue());
        }
        return dataset;
    }
}
RingChart

 

posted @ 2022-02-18 22:57  l-coil  阅读(524)  评论(0编辑  收藏  举报