java使用jfreechart生成图表

news2024/9/22 3:28:36

java使用jfreechart生成图表

  • java使用jfreechart生成图表
  • 创建java项目
  • 创建图表类
    • Serie
    • Charts
  • 测试
  • 效果
    • 柱状图
    • 折线图

java使用jfreechart生成图表

  1. 需求背景,公司有一个产品的外网体验地址,需要做一些数据监控,比如日活量、访问量等。因此需要生成一些运营的数据图表,小公司…所以就只能自己撸了。
  2. 为什么使用java呢?因为比较熟悉java,当然shell也是可以实现的。

创建java项目

在这里插入图片描述

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	
	<groupId>com.xqxyxchy.charts</groupId>
	<artifactId>java-charts</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>java-charts</name>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<clean.version>3.0.0</clean.version>
		<deploy.version>3.0.0</deploy.version>
		<compiler.version>3.8.0</compiler.version>
		<jdk.version>1.8</jdk.version><!-- 1.8/11/17 -->
		<maven.clean.source>${jdk.version}</maven.clean.source>
		<maven.clean.target>${jdk.version}</maven.clean.target>
		<maven.deploy.source>${jdk.version}</maven.deploy.source>
		<maven.deploy.target>${jdk.version}</maven.deploy.target>
		<maven.compiler.source>${jdk.version}</maven.compiler.source>
		<maven.compiler.target>${jdk.version}</maven.compiler.target>
		
		<slf4j.version>1.7.33</slf4j.version>
		<apache.log4j.version>2.17.2</apache.log4j.version>
		<jackson-core.version>2.14.3</jackson-core.version>
		<junit.version>5.8.0</junit.version>
		
		<hutool.version>5.8.0</hutool.version>
		<mail.version>5.2.0</mail.version>
		<jfreechart.version>1.5.5</jfreechart.version>
	</properties>

	<dependencies>
		<dependency>
		    <groupId>org.simplejavamail</groupId>
		    <artifactId>simple-java-mail</artifactId>
		    <version>${mail.version}</version>
		</dependency>
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-core</artifactId>
			<version>${hutool.version}</version>
		</dependency>
		
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>${jackson-core.version}</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>${jackson-core.version}</version>
		</dependency>
		
		<dependency>
		    <groupId>org.jfree</groupId>
		    <artifactId>jfreechart</artifactId>
		    <version>${jfreechart.version}</version>
		</dependency>
	
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${slf4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
			<version>${apache.log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-core</artifactId>
			<version>${apache.log4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-slf4j-impl</artifactId>
			<version>${apache.log4j.version}</version>
		</dependency>

		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-engine</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-clean-plugin</artifactId>
				<version>${clean.version}</version>
			</plugin>
			<plugin>
				<artifactId>maven-deploy-plugin</artifactId>
				<version>${deploy.version}</version>
			</plugin>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>${compiler.version}</version>
				<configuration>
					<fork>true</fork>
					<encoding>UTF-8</encoding>
					<!--<compilerArgs></compilerArgs>-->
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

主要依赖

  1. slf4j、log4j2,日志组件
  2. hutool,工具类组件
  3. junit,单元测试组件
  4. jfreechart,图表库组件

创建图表类

Serie

系列

package com.xqxyxchy.charts.entity;

import java.io.Serializable;
import java.util.Vector;

/**
 * 系列:名字和数据集合 构成一条曲线</br>
 * 可以将serie看作一根线或者一根柱子:
 *
 * <p>
 * 参照JS图表来描述数据:series: [{ name: 'Tokyo', data: [7.0, 6.9, 9.5, 14.5] }, { name: 'New York', data: [-0.2, 0.8, 5.7, 11.3}
 * ]
 *
 */
public class Serie implements Serializable {

    private static final long serialVersionUID = 1L;
    private String name;// 名字
    private Vector<Object> data;// 数据值ֵ

    public Serie() {
    }

    /**
    *
    * @param name 名称(线条名称)
    * @param data 数据(线条上的所有数据值)
    */
   public Serie(String name) {
       this.name = name;
       this.data = new Vector<>();
   }
    
    /**
     *
     * @param name 名称(线条名称)
     * @param data 数据(线条上的所有数据值)
     */
    public Serie(String name, Vector<Object> data) {
        this.name = name;
        this.data = data;
    }

    /**
     *
     * @param name 名称(线条名称)
     * @param array 数据(线条上的所有数据值)
     */
    public Serie(String name, Object[] array) {
        this.name = name;
        if (array != null) {
            data = new Vector<Object>(array.length);
            for (int i = 0; i < array.length; i++) {
                data.add(array[i]);
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Vector<Object> getData() {
        return data;
    }

    public void setData(Vector<Object> data) {
        this.data = data;
    }
    
    public void addData(Object data) {
        this.data.add(data);
    }

}

Charts

生成图表

package com.xqxyxchy.charts;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Vector;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.encoders.ImageFormat;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.DefaultDrawingSupplier;
import org.jfree.chart.plot.PieLabelLinkStyle;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StackedBarRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.chart.ui.TextAnchor;
import org.jfree.data.category.DefaultCategoryDataset;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xqxyxchy.charts.entity.Serie;

public class Charts {

    private static final Logger LOGGER = LoggerFactory.getLogger(Charts.class);

    /**
     * Jfreechart工具类
     * <p>
     * 解决中午乱码问题<br>
     * 用来创建类别图表数据集、创建饼图数据集、时间序列图数据集<br>
     * 用来对柱状图、折线图、饼图、堆积柱状图、时间序列图的样式进行渲染<br>
     * 设置X-Y坐标轴样式
     * <p>
     */
    private static final String NO_DATA_MSG = "数据加载失败";
    private static final Font FONT = new Font("宋体", Font.PLAIN, 22);

    private static final Color[] CHART_COLORS = {new Color(13, 131, 198), new Color(18, 76, 7),
        new Color(255, 117, 153), new Color(255, 204, 102), new Color(255, 188, 117), new Color(153, 158, 255),
        new Color(253, 236, 109), new Color(128, 133, 232), new Color(158, 90, 102), new Color(92, 92, 97)};// 颜色

    private static final List<String> CHART_TYPE = new ArrayList<String>();
    private String chartType;

    /**
     * 静态代码块
     */
    static {
        setChartTheme();
        CHART_TYPE.add("line");
        CHART_TYPE.add("bar");
        CHART_TYPE.add("stacked");
    }

    public Charts(String chartType) {
        this.chartType = chartType;
        if (!CHART_TYPE.contains(chartType)) {
            throw new RuntimeException("Type chart of " + chartType + " Not supported.");
        }
    }

    /**
     * 中文主题样式 解决乱码
     */
    private static void setChartTheme() {
        // 设置中文主题样式 解决乱码
        StandardChartTheme chartTheme = new StandardChartTheme("CN");
        // 设置标题字体
        chartTheme.setExtraLargeFont(FONT);
        // 设置图例的字体
        chartTheme.setRegularFont(FONT);
        // 设置轴向的字体
        chartTheme.setLargeFont(FONT);
        chartTheme.setSmallFont(FONT);
        chartTheme.setTitlePaint(new Color(51, 51, 51));
        chartTheme.setSubtitlePaint(new Color(85, 85, 85));

        chartTheme.setLegendBackgroundPaint(Color.WHITE);// 设置标注
        chartTheme.setLegendItemPaint(Color.BLACK);//
        chartTheme.setChartBackgroundPaint(Color.WHITE);

        Paint[] OUTLINE_PAINT_SEQUENCE = new Paint[] {Color.WHITE};
        // 绘制器颜色源
        DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(CHART_COLORS, CHART_COLORS,
            OUTLINE_PAINT_SEQUENCE, DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE,
            DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
        chartTheme.setDrawingSupplier(drawingSupplier);

        chartTheme.setPlotBackgroundPaint(Color.WHITE);// 绘制区域
        chartTheme.setPlotOutlinePaint(Color.WHITE);// 绘制区域外边框
        chartTheme.setLabelLinkPaint(new Color(8, 55, 114));// 链接标签颜色
        chartTheme.setLabelLinkStyle(PieLabelLinkStyle.CUBIC_CURVE);

        chartTheme.setAxisOffset(new RectangleInsets(5, 12, 5, 12));
        chartTheme.setDomainGridlinePaint(new Color(192, 208, 224));// X坐标轴垂直网格颜色
        chartTheme.setRangeGridlinePaint(new Color(192, 192, 192));// Y坐标轴水平网格颜色

        chartTheme.setBaselinePaint(Color.WHITE);
        chartTheme.setCrosshairPaint(Color.BLUE);// 不确定含义
        chartTheme.setAxisLabelPaint(new Color(51, 51, 51));// 坐标轴标题文字颜色
        chartTheme.setTickLabelPaint(new Color(67, 67, 72));// 刻度数字
        chartTheme.setBarPainter(new StandardBarPainter());// 设置柱状图渲染
        chartTheme.setXYBarPainter(new StandardXYBarPainter());// XYBar 渲染

        chartTheme.setItemLabelPaint(Color.BLACK);
        chartTheme.setThermometerPaint(Color.WHITE);// 温度计

        ChartFactory.setChartTheme(chartTheme);
    }

    /**
     * 可以通过调用这个方法, 提供对应格式的参数即可生成图片,并存在指定位置 生成一个这先出并保存为png格式,
     *
     * @param title 图片标题
     * @param xtitle x轴标题
     * @param ytitle y轴标题
     * @param filepath 文件路径+文件名
     * @param categorie 横坐标类型
     * @param series 数据内容
     * @param width 图片宽度
     * @param height 图片高度
     * @throws Exception
     */
    public void createToFile(String title, String xtitle, String ytitle, String filepath, List<String> categorie,
        List<Serie> series, int width, int height, String format, float quality, boolean encodeAlpha, int compression)
        throws Exception {
        ChartPanel chartPanel = createChart(title, xtitle, ytitle, categorie, series);
        // 将图片保存为png格式
        saveAsFile(format, chartPanel.getChart(), filepath, width, height, quality, encodeAlpha, compression);
    }

    /**
     * 可以通过调用这个方法, 提供对应格式的参数即可生成图片,并存在指定位置 生成一个这先出并保存为png格式,
     *
     * @param title 图片标题
     * @param xtitle x轴标题
     * @param ytitle y轴标题
     * @param categorie 横坐标类型
     * @param series 数据内容
     * @param width 图片宽度
     * @param height 图片高度
     * @throws Exception
     */
    public String createToBase64(String title, String xtitle, String ytitle, List<String> categorie, List<Serie> series,
        int width, int height, String format, float quality, boolean encodeAlpha, int compression) throws Exception {
        ChartPanel chartPanel = createChart(title, xtitle, ytitle, categorie, series);
        // 将图片保存为png格式
        return saveAsBase64(format, chartPanel.getChart(), width, height, quality, encodeAlpha, compression);
    }

    /**
     * 创建类别数据集合
     */
    private DefaultCategoryDataset createDataset(List<Serie> series, String[] categories) {
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        for (Serie serie : series) {
            String name = serie.getName();
            Vector<Object> data = serie.getData();
            if (data != null && categories != null && data.size() == categories.length) {
                for (int index = 0; index < data.size(); index++) {
                    String value = data.get(index) == null ? "" : data.get(index).toString();
                    if (isPercent(value)) {
                        value = value.substring(0, value.length() - 1);
                    }
                    if (isNumber(value)) {
                        dataset.setValue(Double.parseDouble(value), name, categories[index]);
                    }
                }
            }
        }
        return dataset;
    }

    /**
     * 是不是一个%形式的百分比
     *
     * @param str
     * @return
     */
    private boolean isPercent(String str) {
        return str != null ? str.endsWith("%") && isNumber(str.substring(0, str.length() - 1)) : false;
    }

    /**
     * 是不是一个数字
     *
     * @param str
     * @return
     */
    private boolean isNumber(String str) {
        return str != null ? str.matches("^[-+]?(([0-9]+)((([.]{0})([0-9]*))|(([.]{1})([0-9]+))))$") : false;
    }

    /**
     * 设置类别图表(CategoryPlot) X坐标轴线条颜色和样式
     *
     * @param axis
     */
    private void setXAixs(CategoryPlot plot) {
        Color lineColor = new Color(31, 121, 170);
        plot.getDomainAxis().setAxisLinePaint(lineColor);// X坐标轴颜色
        plot.getDomainAxis().setTickMarkPaint(lineColor);// X坐标轴标记|竖线颜色
        plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
    }

    /**
     * 设置类别图表(CategoryPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
     *
     * @param axis
     */
    private void setYAixs(CategoryPlot plot) {
        Color lineColor = new Color(192, 208, 224);
        ValueAxis axis = plot.getRangeAxis();
        axis.setAxisLinePaint(lineColor);// Y坐标轴颜色
        axis.setTickMarkPaint(lineColor);// Y坐标轴标记|竖线颜色
        // 隐藏Y刻度
        axis.setAxisLineVisible(false);
        axis.setTickMarksVisible(false);
        // Y轴网格线条
        plot.setRangeGridlinePaint(new Color(192, 192, 192));
        plot.setRangeGridlineStroke(new BasicStroke(1));

        plot.getRangeAxis().setUpperMargin(0.5);// 设置顶部Y坐标轴间距,防止数据无法显示
        plot.getRangeAxis().setLowerMargin(0.5);// 设置底部Y坐标轴间距
    }

    /**
     * 必须设置文本抗锯齿
     */
    private void setAntiAlias(JFreeChart chart) {
        chart.setTextAntiAlias(false);
    }

    // -----------------------------------------------------------------------------------------------------------------

    /**
     * 创建图形
     *
     * @param title 折线图标题
     * @param xtitle x轴标题
     * @param ytitle y轴标题
     * @param categorie 横坐标类别
     * @param series 数据集
     * @return
     * @throws Exception
     */
    private ChartPanel createChart(String title, String xtitle, String ytitle, List<String> categorie,
        List<Serie> series) throws Exception {
        DefaultCategoryDataset dataSet = createDataset(series, categorie.toArray(new String[categorie.size()]));
        // 2:创建Chart[创建不同图形]
        JFreeChart chart = null;
        if ("line".equals(chartType)) {
            chart = ChartFactory.createLineChart(title, xtitle, ytitle, dataSet);
            // 3:对柱子进行渲染[[采用不同渲染]]
            setLineRender(chart.getCategoryPlot(), true, true);//
        } else if ("stacked".equals(chartType)) {
            chart = ChartFactory.createStackedBarChart(title, xtitle, ytitle, dataSet);
            // 3:对柱子进行渲染[[采用不同渲染]]
            setStackedBarRender(chart.getCategoryPlot(), true);//
        } else {
            chart = ChartFactory.createBarChart(title, xtitle, ytitle, dataSet);
            // 3:对柱子进行渲染[[采用不同渲染]]
            setBarRender(chart.getCategoryPlot(), true);//
        }

        // 4:设置抗锯齿,防止字体显示不清楚
        setAntiAlias(chart);// 抗锯齿
        // 5:对其他部分进行渲染
        setXAixs(chart.getCategoryPlot());// X坐标轴渲染
        setYAixs(chart.getCategoryPlot());// Y坐标轴渲染
        // 设置标注无边框
        chart.getLegend().setFrame(new BlockBorder(Color.WHITE));
        // 6:使用chartPanel接收
        ChartPanel chartPanel = new ChartPanel(chart);
        return chartPanel;
    }

    /**
     * 设置折线图样式
     *
     * @param plot
     * @param isShowDataLabels 是否显示数据标签
     */
    private void setLineRender(CategoryPlot plot, boolean isShowDataLabels, boolean isShapesVisible) {
        plot.setNoDataMessage(NO_DATA_MSG);
        plot.setInsets(new RectangleInsets(10, 10, 0, 10), false);
        LineAndShapeRenderer renderer = (LineAndShapeRenderer)plot.getRenderer();

        renderer.setDefaultStroke(new BasicStroke(6F));
        if (isShowDataLabels) {
            renderer.setDefaultItemLabelsVisible(true);
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(
                StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, NumberFormat.getInstance()));
            renderer.setDefaultPositiveItemLabelPosition(
                new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BOTTOM_CENTER));// 位置
        }
        renderer.setDefaultShapesVisible(isShapesVisible);// 数据点绘制形状
        renderer.setDrawOutlines(true);
        renderer.setUseFillPaint(true);
        plot.setRenderer(renderer);// 将修改后的属性值保存到图中
        setXAixs(plot);
        setYAixs(plot);
    }

    /**
     * 设置堆叠图样式
     *
     * @param plot
     * @param isShowDataLabels 是否显示数据标签
     */
    private void setStackedBarRender(CategoryPlot plot, boolean isShowDataLabels) {
        plot.setNoDataMessage(NO_DATA_MSG);
        plot.setInsets(new RectangleInsets(10, 10, 0, 10), false);
        StackedBarRenderer renderer = (StackedBarRenderer)plot.getRenderer();

        renderer.setDefaultStroke(new BasicStroke(6F));
        if (isShowDataLabels) {
            renderer.setIncludeBaseInRange(true);// 显示每个柱的数值,并修改该数值的字体属性
            renderer.setDefaultItemLabelsVisible(true);
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(
                StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, NumberFormat.getInstance()));
            renderer.setDefaultPositiveItemLabelPosition(
                new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.CENTER));// 位置
        }
        renderer.setItemMargin(0.5D);// 设置每个柱之间距离
        renderer.setDrawBarOutline(true);
        plot.setRenderer(renderer);// 将修改后的属性值保存到图中
        setXAixs(plot);
        setYAixs(plot);
    }

    /**
     * 设置柱状图样式
     *
     * @param plot
     * @param isShowDataLabels 是否显示数据标签
     */
    private void setBarRender(CategoryPlot plot, boolean isShowDataLabels) {
        plot.setNoDataMessage(NO_DATA_MSG);
        plot.setInsets(new RectangleInsets(10, 10, 0, 10), false);
        BarRenderer renderer = (BarRenderer)plot.getRenderer();

        renderer.setDefaultStroke(new BasicStroke(6F));
        if (isShowDataLabels) {
            renderer.setDefaultItemLabelsVisible(true);
            renderer.setIncludeBaseInRange(true);// 显示每个柱的数值,并修改该数值的字体属性
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(
                StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, NumberFormat.getInstance()));
            renderer.setDefaultPositiveItemLabelPosition(
                new ItemLabelPosition(ItemLabelAnchor.INSIDE12, TextAnchor.TOP_CENTER));// 位置
        }
        renderer.setItemMargin(0.5D);// 设置每个柱之间距离
        renderer.setDrawBarOutline(true);
        plot.setRenderer(renderer);// 将修改后的属性值保存到图中
        setXAixs(plot);
        setYAixs(plot);
    }

    /**
     * 将图表保存图片
     *
     * @param chart 折线图对象
     * @param outputPath 文件保存路径, 包含文件名
     * @param weight 宽
     * @param height 高
     * @throws Exception
     */
    private void saveAsFile(String format, JFreeChart chart, String outputPath, int weight, int height, float quality,
        boolean encodeAlpha, int compression) throws Exception {
        FileOutputStream out = null;
        File outFile = new File(outputPath);
        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        out = new FileOutputStream(outputPath);

        if (ImageFormat.JPEG.equalsIgnoreCase(format)) {
            ChartUtils.writeChartAsJPEG(out, quality, chart, weight, height);
        } else {
            ChartUtils.writeChartAsPNG(out, chart, weight, height, encodeAlpha, compression);
        }

        out.flush();
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                LOGGER.error("{}", e.getMessage(), e);
            }
        }
    }

    /**
     * <pre>
     * 将图表保存为PNG图片并转成base64
     * <img src="data:image/png;base64,${img5}" width="1000px">
     * <img src="data:image/jpeg;base64,${img5}" width="1000px">
     * </pre>
     *
     * @param chart 折线图对象
     * @param weight 宽
     * @param height 高
     * @throws Exception
     */
    private String saveAsBase64(String format, JFreeChart chart, int weight, int height, float quality,
        boolean encodeAlpha, int compression) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        if (ImageFormat.JPEG.equalsIgnoreCase(format)) {
            ChartUtils.writeChartAsJPEG(out, quality, chart, weight, height);
        } else {
            ChartUtils.writeChartAsPNG(out, chart, weight, height, encodeAlpha, compression);
        }

        out.flush();
        String base64Image = Base64.getEncoder().encodeToString(out.toByteArray());
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                LOGGER.error("{}", e.getMessage(), e);
            }
        }
        return base64Image;
    }

}

测试

ChartsTest

package com.xqxyxchy.charts;

import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.Vector;

import org.jfree.chart.encoders.ImageFormat;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xqxyxchy.charts.entity.Serie;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;

public class ChartsTest {

    private static final Logger LOGGER = LoggerFactory.getLogger(ChartsTest.class);

    @Test
    public void bar() {
        try {
            String barOutputPath = cn.hutool.core.io.FileUtil.getAbsolutePath("bar.png");
            cn.hutool.core.io.FileUtil.del(barOutputPath);
            
            Date today = new Date();
            // 横坐标
            List<String> categories = new Vector<>();
            List<Serie> series = new Vector<>();
            Vector<Object> serieDatas = new Vector<>();
            // 柱子名称:柱子所有的值集合
            // 纵坐标
            series.add(new Serie("用户活跃", serieDatas));
            for (int day = 30; day > 0; day--) {
                DateTime datetime = DateUtil.date(today);
                datetime.offset(DateField.DAY_OF_YEAR, day);
                datetime.setTimeZone(TimeZone.getTimeZone("GMT+08"));
                categories.add(datetime.toString("yyyy年MM月dd日"));
                serieDatas.add(RandomUtil.randomInt(1000, 9999));
            }

            String chartType = "bar";
            charts(categories, series, chartType);
        } catch (Exception e1) {
            LOGGER.error("{}", e1.getMessage(), e1);
        }
    }

    @Test
    public void line() {
        try {
            String lineOutputPath = cn.hutool.core.io.FileUtil.getAbsolutePath("line.png");
            cn.hutool.core.io.FileUtil.del(lineOutputPath);
            
            Date today = new Date();
            // 横坐标
            List<String> categories = new Vector<>();
            List<Serie> series = new Vector<>();
            Vector<Object> serieDatas = new Vector<>();
            // 柱子名称:柱子所有的值集合
            // 纵坐标
            series.add(new Serie("用户活跃", serieDatas));
            for (int day = 30; day > 0; day--) {
                DateTime datetime = DateUtil.date(today);
                datetime.offset(DateField.DAY_OF_YEAR, day);
                datetime.setTimeZone(TimeZone.getTimeZone("GMT+08"));
                categories.add(datetime.toString("yyyy年MM月dd日"));
                serieDatas.add(RandomUtil.randomInt(1000, 9999));
            }

            String chartType = "line";
            charts(categories, series, chartType);
        } catch (Exception e1) {
            LOGGER.error("{}", e1.getMessage(), e1);
        }
    }

    private void charts(List<String> categories, List<Serie> series, String chartType) throws Exception {
        int width = 1600;
        int height = 800;

        Charts barCharts = new Charts(chartType);
        String base64 = barCharts.createToBase64("近30日用户活跃量", "", "用户活跃量", categories, series, width, height,
            ImageFormat.PNG, 1.0F, true, 0);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("{}, compression -> {}, length() -> '{}'", "近30日用户活跃量" + "." + ImageFormat.PNG, 0,
                base64.length());
        }

        String outputPath = cn.hutool.core.io.FileUtil.getAbsolutePath(chartType + ".png");
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("outputPath -> '{}'", outputPath);
        }
        barCharts.createToFile("近30日用户活跃量", "", "用户活跃量", outputPath, categories, series, width, height, ImageFormat.PNG,
            1.0F, true, 0);
    }

}

效果

柱状图

在这里插入图片描述

折线图

在这里插入图片描述

在线代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115519.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

爆改YOLOv8|利用特征融合网络FFA-Net改进YOLOv8-模糊图片检测

1&#xff0c;本文介绍 FFA-Net&#xff08;Feature Fusion Attention Network&#xff09;主要用于图像去雾任务&#xff0c;其核心思想是通过特征融合注意力网络直接恢复无雾图像。它的架构包括以下三个关键组件&#xff1a; 特征注意力&#xff08;Feature Attention, FA&a…

3280. 将日期转换为二进制表示

目录 一&#xff1a;题目&#xff1a; 二&#xff1a;代码&#xff1a; 三&#xff1a;结果 一&#xff1a;题目&#xff1a; 给你一个字符串 date&#xff0c;它的格式为 yyyy-mm-dd&#xff0c;表示一个公历日期。 date 可以重写为二进制表示&#xff0c;只需要将年、月…

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 &#xff1a;frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可&#xff0c;不过需要覆盖所有目录下的图片。 由于是静态修改&#xff0c;则需要make一下&#xff0c;重新编译。 2、方法二Overlay方式 由于上述方法有…

浅谈架构实战

目录 背景 1 架构演变 2 如何实现高层的复用 2 中台产生案例 3 技术架构的核心要点 4 技术架构的高可用案例 背景 业务架构、数据架构、应用架构和技术架构它们是相互关联和相互支持的&#xff0c;共同构成了企业的总体架构&#xff0c;业务架构是源头&#xff0c;然后才…

Java 中常用内置接口函数

在 Java 8 及以后的版本中&#xff0c;引入了许多函数式编程的特性&#xff0c;其中最重要的就是内置的函数式接口。这些接口使得编写更简洁、可读性更强的代码成为可能。今天我将介绍四个常用的内置接口&#xff1a;Predicate、Function、Consumer 和 Supplier&#xff0c;并提…

Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(4)

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​​ Unity数据持久化 之 一个通过2进制读取Excel并存储的轮子(3)-CSDN博客 这节就是真正的存储数据了 理清一下思路&am…

SprinBoot+Vue漫画天堂网的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…

0x06 记录一次挖src的经历(xss漏洞)

漏洞平台&#xff1a;补天 - 企业和白帽子共赢的漏洞响应平台&#xff0c;帮助企业建立SRC 个人总结的挖洞流程&#xff1a; 1&#xff09;先用工具信息收集一波 我这里先用灯塔收集一下目标资产 2&#xff09;然后用漏洞扫描工具扫描一波 我这里用Acunetix进行扫描 因为工具…

驱动(RK3588S)第九课时:多节点驱动与函数接口

目录 一、多节点概念1、所用到的结构体说明2、函数接口主要是read和write函数2.1、把应用层的数据拷贝给底层2.2、把应用层的数据拷贝给底层 3、应用层的read和write函数4、底层的read和write函数二、ioctl控制命令接口1、概念2、函数介绍应用层和驱动层 三、代码与现象1.编写L…

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师&#xff0c;爱吃土豆。如有需要技术交流或者需要方案帮助、需求&#xff1a;以下为联系方式—V 方案1&#xff1a;通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通…

使用 nuxi preview 命令预览 Nuxt 应用

title: 使用 nuxi preview 命令预览 Nuxt 应用 date: 2024/9/8 updated: 2024/9/8 author: cmdragon excerpt: 摘要:本文介绍了如何使用nuxi preview命令预览Nuxt.js应用,包括安装和准备环境、启动预览服务器的步骤,以及如何指定根目录和使用自定义.env文件等高级用法。通…

【H2O2|全栈】关于HTML(5)HTML基础(四)

HTML基础知识 目录 HTML基础知识 前言 准备工作 标签的具体分类&#xff08;四&#xff09; 本文中的标签在什么位置中使用&#xff1f; 表单&#xff08;一&#xff09; 表单标签 输入域标签 预告和回顾 后话 前言 本系列博客将分享HTML相关知识点。 这一期博客&…

使用 DBeaver 创建 MySQL 数据库

文章目录 创建数据库创建用户 创建数据库 1.在【数据库】上点右键&#xff0c;然后选择【新建 数据库】 2.输入 数据库名&#xff0c;点击确定 这样&#xff0c;数据库就创建好了 创建用户 1.在【用户】上点右键&#xff0c;然后选择【新建 用户】 在属性这里&#xff0c;输入…

基于yolov8的血细胞检测计数系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的血细胞检测与计数系统是一种利用深度学习技术&#xff0c;特别是YOLOv8目标检测算法&#xff0c;实现高效、准确血细胞识别的系统。该系统能够自动识别并计数图像或视频中的血细胞&#xff0c;包括红细胞、白细胞和血小板等&#xff0c;为医疗诊断提…

揭开面纱--机器学习

一、人工智能三大概念 1.1 AI、ML、DL 1.1.1 什么是人工智能? AI&#xff1a;Artificial Intelligence 人工智能 AI is the field that studies the synthesis and analysis of computational agents that act intelligently AI is to use computers to analog and instead…

v0.dev快速开发

探索v0.dev&#xff1a;次世代开发者之利器 今之技艺日新月异&#xff0c;开发者之工具亦随之进步不辍。v0.dev者&#xff0c;新兴之开发者利器也&#xff0c;迅速引起众多开发者之瞩目。本文将引汝探究v0.dev之基本功能与优势&#xff0c;助汝速速上手&#xff0c;提升开发之…

WSL 下的 CentOS 装 Docker

WSL 下的 CentOS 装 Docker 卸载旧版本安装前的准备工作1. 安装 yum-utils2. 添加阿里云的 yum 镜像仓库3. 快速生成 Yum 缓存 安装Docker启动docker运行 hello-world卸载 Docker 引擎参考资料 卸载旧版本 sudo yum remove docker \ docker-client \ docker-client-latest \ d…

论文阅读_检索增强生成 RAG 综述

英文名称: Retrieval-Augmented Generation for Large Language Models: A Survey 中文名称: 大型语言模型的检索增强生成&#xff1a;一项调查 链接: http://arxiv.org/abs/2312.10997v5 作者: Yunfan Gaoa, Yun Xiongb, Xinyu Gaob, Kangxiang Jiab, Jinliu Panb, Yuxi Bic, …

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【基础算法总结】滑动窗口

目录 一&#xff0c;滑动窗口介绍二&#xff0c;算法原理和代码实现209.长度最小的子数组3.无重复字符的最长子串1004.最大连续1的个数III1658.将x减到0的最小操作数904.水果成篮438.找到字符串中所有字母异位词30.串联所有单词的子串76.最小覆盖子串 三&#xff0c;算法总结 一…