word poi-tl 图表功能增强,插入图表折线图、柱状图、饼状图

news2025/1/18 6:10:21

目录

    • 问题
      • 解决问题
      • poi-tl介绍
    • 功能实现
      • 引入依赖
      • 功能介绍
    • 功能实例
      • 饼图
        • 模版
        • 代码
        • 效果图
      • 雷达图(模版同饼图)
        • 代码
        • 效果图
      • 柱状图(模版同饼图)
        • 代码
        • 效果图
    • 附加
      • CustomCharts 工具类
      • CustomChartSingleSeriesRenderData 数据对象
      • CustomChartRenderPolicy 插件类

问题

由于在开发功能需求中,word文档需要根据数据动态生成图表,不同的数据类型生成不同的图表信息,而word模版引擎原有功能只能做替换,不满足需求;

解决问题

  • 目前选择的poi-tl的模版引擎,在原有的基础上新增自定义插件来实现功能

poi-tl介绍

poi-tl 是一个基于Apache POI的Word模板引擎,也是一个免费开源的Java类库,你可以非常方便的加入到你的项目中;

Word模板引擎功能描述
文本将标签渲染为文本
图片将标签渲染为图片
表格将标签渲染为表格
图表条形图(3D条形图)、柱形图(3D柱形图)、面积图(3D面积图)、折线图(3D折线图)、雷达图、饼图(3D饼图)、散点图等图表渲染
If Condition判断根据条件隐藏或者显示某些文档内容(包括文本、段落、图片、表格、列表、图表等)
Foreach Loop循环根据集合循环某些文档内容(包括文本、段落、图片、表格、列表、图表等)
Loop表格行循环复制渲染表格的某一行
Loop表格列循环复制渲染表格的某一列
Loop有序列表支持有序列表的循环,同时支持多级列表
Highlight代码高亮word中代码块高亮展示,支持26种语言和上百种着色样式
Markdown将Markdown渲染为word文档
Word批注完整的批注功能,创建批注、修改批注等
Word附件Word中插入附件
SDT内容控件内容控件内标签支持
Textbox文本框文本框内标签支持
图片替换将原有图片替换成另一张图片
书签、锚点、超链接支持设置书签,文档内锚点和超链接功能
Expression Language完全支持SpringEL表达式,可以扩展更多的表达式:OGNL, MVEL
样式支持有序列表的循环,同时支持多级列表
模板嵌套模板包含子模板,子模板再包含子模板
模板嵌套模板包含子模板,子模板再包含子模板
合并Word合并Merge,也可以在指定位置进行合并
用户自定义函数(插件)插件化设计,在文档任何位置执行函数

功能实现

引入依赖

		<dependency>
            <groupId>com.deepoove</groupId>
            <artifactId>poi-tl</artifactId>
            <version>1.12.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-full</artifactId>
            <version>5.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>5.2.5</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
        </dependency>
        <!-- spring el表达式 -->
        <dependency>
	  		<groupId>org.springframework</groupId>
		  	<artifactId>spring-expression</artifactId>
		 	 <version>5.3.18</version>
		</dependency>

功能介绍

  • 目前支持的图表类型有饼图、柱形图、面积图、折线图、雷达图等
  • 同时支持添加到表格一起渲染

功能实例

饼图

模版

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/53b227ba4eca4923871b3f526f6784dd.png

代码
    @Test
    public void test() throws Exception {
        Configure config = Configure.builder()
                .addPlugin('&',new CustomChartRenderPolicy())
                .useSpringEL(false).build();
        Map<String,Object> dataMap = new HashMap<String, Object>();
        CustomChartSingleSeriesRenderData chartSingleSeriesRenderData = CustomCharts.ofPie("日期", new String[]{"2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06",
                        "2024-07", "2024-08", "2024-09", "2024-10", "2024-11", "2024-12"})
                .series("数值", new Integer[]{10, 35, 21, 46, 79, 55,
                        39, 32, 71, 28, 22, 11}).setWidthAndHeight(10,10).create();
        dataMap.put("testChars", chartSingleSeriesRenderData);


        ClassPathResource classPathResource = new ClassPathResource("static/word/template.docx");
        try (InputStream resourceInputStream = classPathResource.getInputStream();
             XWPFTemplate template = XWPFTemplate.compile(resourceInputStream,config);){

            template.render(dataMap);
            template.writeAndClose(new FileOutputStream("output.docx"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
效果图

在这里插入图片描述

雷达图(模版同饼图)

代码
 @Test
    public void test() throws Exception {
        Configure config = Configure.builder()
                .addPlugin('&',new CustomChartRenderPolicy())
                .useSpringEL(false).build();
        Map<String,Object> dataMap = new HashMap<String, Object>();
        CustomChartSingleSeriesRenderData chartSingleSeriesRenderData = CustomCharts.ofRadar("日期", new String[]{"2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06",
                        "2024-07", "2024-08", "2024-09", "2024-10", "2024-11", "2024-12"})
                .series("数值", new Integer[]{10, 35, 21, 46, 79, 55,
                        39, 32, 71, 28, 22, 11}).setWidthAndHeight(10,10).create();
        dataMap.put("testChars", chartSingleSeriesRenderData);


        ClassPathResource classPathResource = new ClassPathResource("static/word/template.docx");
        try (InputStream resourceInputStream = classPathResource.getInputStream();
             XWPFTemplate template = XWPFTemplate.compile(resourceInputStream,config);){

            template.render(dataMap);
            template.writeAndClose(new FileOutputStream("output.docx"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
效果图

在这里插入图片描述

柱状图(模版同饼图)

代码
 @Test
    public void test() throws Exception {
        Configure config = Configure.builder()
                .addPlugin('&',new CustomChartRenderPolicy())
                .useSpringEL(false).build();
        Map<String,Object> dataMap = new HashMap<String, Object>();
        CustomChartSingleSeriesRenderData chartSingleSeriesRenderData = CustomCharts.ofBar("日期", new String[]{"2024-01", "2024-02", "2024-03", "2024-04", "2024-05", "2024-06",
                        "2024-07", "2024-08", "2024-09", "2024-10", "2024-11", "2024-12"})
                .series("数值", new Integer[]{10, 35, 21, 46, 79, 55,
                        39, 32, 71, 28, 22, 11}).setWidthAndHeight(10,10).create();
        dataMap.put("testChars", chartSingleSeriesRenderData);


        ClassPathResource classPathResource = new ClassPathResource("static/word/template.docx");
        try (InputStream resourceInputStream = classPathResource.getInputStream();
             XWPFTemplate template = XWPFTemplate.compile(resourceInputStream,config);){

            template.render(dataMap);
            template.writeAndClose(new FileOutputStream("output.docx"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
效果图

在这里插入图片描述

附加

CustomCharts 工具类


import com.deepoove.poi.data.RenderData;
import com.deepoove.poi.data.RenderDataBuilder;
import com.deepoove.poi.data.SeriesRenderData;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;

public class CustomCharts {

    public static CustomCharts.ChartSingles ofArea(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.AREA);
    }

    public static CustomCharts.ChartSingles ofRadar(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.RADAR);
    }

    public static CustomCharts.ChartSingles ofLine(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.LINE);
    }

    public static CustomCharts.ChartSingles ofBar(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.BAR);
    }

    public static CustomCharts.ChartSingles ofPie(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.PIE);
    }

    public static CustomCharts.ChartSingles ofPie3D(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.PIE3D);
    }

    public static CustomCharts.ChartSingles ofDoughnut(String chartTitle, String[] categories) {
        return ofSingleSeries(chartTitle, categories, ChartTypes.DOUGHNUT);
    }

    public static CustomCharts.ChartSingles ofSingleSeries(String chartTitle, String[] categories, ChartTypes chartTypes) {
        return new CustomCharts.ChartSingles(chartTitle, categories, chartTypes);
    }

    public static interface ChartSetting<T extends RenderData> {
        CustomCharts.ChartBuilder<T> setxAsixTitle(String xAxisTitle);

        CustomCharts.ChartBuilder<T> setyAsixTitle(String yAxisTitle);
    }

    public static abstract class ChartBuilder<T extends RenderData> implements RenderDataBuilder<T>, CustomCharts.ChartSetting<T> {
        protected String chartTitle;
        protected String xAxisTitle;
        protected String yAxisTitle;
        protected String[] categories;
        protected ChartTypes chartTypes;

        protected ChartBuilder(String chartTitle, String[] categories, ChartTypes chartTypes) {
            this.chartTitle = chartTitle;
            this.categories = categories;
            this.chartTypes = chartTypes;
        }

        protected void checkLengh(int length) {
            if (categories.length != length) {
                throw new IllegalArgumentException(
                        "The length of categories and series values in chart must be the same!");
            }
        }

        public CustomCharts.ChartBuilder<T> setxAsixTitle(String xAxisTitle) {
            this.xAxisTitle = xAxisTitle;
            return this;
        }

        public CustomCharts.ChartBuilder<T> setyAsixTitle(String yAxisTitle) {
            this.yAxisTitle = yAxisTitle;
            return this;
        }
    }


    /**
     * builder to build single series chart
     */
    public static class ChartSingles extends CustomCharts.ChartBuilder<CustomChartSingleSeriesRenderData> {
        private SeriesRenderData series;
        /**
         * 宽度
         */
        private Integer width = 10;

        /**
         * 高度
         */
        private Integer height = 6;

        private ChartSingles(String chartTitle, String[] categories, ChartTypes chartTypes) {
            super(chartTitle, categories, chartTypes);
        }

        public CustomCharts.ChartSingles series(String name, Number[] value) {
            checkLengh(value.length);
            series = new SeriesRenderData(name, value);
            return this;
        }

        public CustomCharts.ChartSingles setWidthAndHeight(Integer width, Integer height) {
            this.width = width;
            this.height = height;
            return this;
        }

        @Override
        public CustomChartSingleSeriesRenderData create() {
            CustomChartSingleSeriesRenderData data = new CustomChartSingleSeriesRenderData();
            data.setChartTitle(chartTitle);
            data.setxAxisTitle(xAxisTitle);
            data.setyAxisTitle(yAxisTitle);
            data.setCategories(categories);
            data.setSeriesData(series);
            data.setChartTypes(chartTypes);
            data.setWidth(width);
            data.setHeight(height);
            return data;
        }
    }
}

CustomChartSingleSeriesRenderData 数据对象

import com.deepoove.poi.data.ChartSingleSeriesRenderData;
import lombok.Data;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;

@Data
public class CustomChartSingleSeriesRenderData extends ChartSingleSeriesRenderData {

    private ChartTypes chartTypes;

    /**
     * 宽度
     */
    private Integer width;

    /**
     * 高度
     */
    private Integer height;
}

CustomChartRenderPolicy 插件类



import cn.hutool.core.util.StrUtil;
import com.deepoove.poi.data.SeriesRenderData;
import com.deepoove.poi.policy.AbstractRenderPolicy;
import com.deepoove.poi.render.RenderContext;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.PresetColor;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.BarDirection;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.RadarStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFChartAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFRadarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xwpf.usermodel.XWPFChart;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class CustomChartRenderPolicy extends AbstractRenderPolicy<CustomChartSingleSeriesRenderData> {

    private Boolean titleOverlayCode;

    public CustomChartRenderPolicy() {
        this(false);
    }

    public CustomChartRenderPolicy(Boolean titleOverlayCode) {
        this.titleOverlayCode = titleOverlayCode;
    }

    @Override
    protected void afterRender(RenderContext<CustomChartSingleSeriesRenderData> context) {
        //清空标签 clearParagraph 为true 存在表外的图表渲染不了
        clearPlaceholder(context, false);
    }

    @Override
    public void doRender(RenderContext<CustomChartSingleSeriesRenderData> context) throws Exception {
        XWPFRun run = context.getRun();
        XWPFDocument xwpfDocument = (XWPFDocument)context.getXWPFDocument();
        CustomChartSingleSeriesRenderData singleSeriesRenderData = context.getData();
        if (Objects.isNull(singleSeriesRenderData)) {
            return;
        }

        Integer height = singleSeriesRenderData.getHeight();
        Integer width = singleSeriesRenderData.getWidth();
        //在标签位置创建chart图表对象
        XWPFChart chart = xwpfDocument.createChart(run, width * Units.EMU_PER_CENTIMETER, height * Units.EMU_PER_CENTIMETER);

        SeriesRenderData seriesData = singleSeriesRenderData.getSeriesData();

        //图例是否覆盖标题
        chart.setTitleOverlay(this.titleOverlayCode);
        String[] xAxisData = singleSeriesRenderData.getCategories();

        Number[] yAxisData = seriesData.getValues();
        ChartTypes chartTypes = singleSeriesRenderData.getChartTypes();
        //创建图表对象
        execChartData(chart, chartTypes, singleSeriesRenderData, xAxisData, yAxisData);

        //图表相关设置
        //图表标题
        if (StrUtil.isNotEmpty(singleSeriesRenderData.getChartTitle())) {
            chart.setTitleText(singleSeriesRenderData.getChartTitle());
        } else {
            chart.removeTitle();
            chart.deleteLegend();
        }
    }

    private static void solidFillSeries(XDDFChartData.Series series, PresetColor color) {
        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
        XDDFShapeProperties properties = series.getShapeProperties();
        if (properties == null) {
            properties = new XDDFShapeProperties();
        }
        properties.setFillProperties(fill);
        series.setShapeProperties(properties);
    }

    private void execChartData(XWPFChart chart, ChartTypes chartType, CustomChartSingleSeriesRenderData singleSeriesRenderData
            , String[] xAxisData, Number[] yAxisData) {
        XDDFChartData xddfChartData = null;
        switch (chartType) {
            case AREA:

                break;
            case AREA3D:

                break;
            case BAR:
                xddfChartData = performBarRendering(chart, chartType, singleSeriesRenderData, xAxisData, yAxisData);
                break;
            case BAR3D:

                break;
            case DOUGHNUT:
                break;
            case LINE:
                xddfChartData = performLineRendering(chart, chartType, singleSeriesRenderData, xAxisData, yAxisData);
                break;
            case LINE3D:
                break;
            case PIE:
                xddfChartData = performPieRendering(chart, chartType, singleSeriesRenderData, xAxisData, yAxisData);
                break;
            case PIE3D:
                break;
            case RADAR:
                performRadarRendering(chart, chartType, singleSeriesRenderData, xAxisData, yAxisData);
                break;
            case SCATTER:
                break;
            case SURFACE:
                break;
            case SURFACE3D:
                break;
            default:
                break;
        }

        //在标签位置绘制折线图
        if (Objects.nonNull(xddfChartData)) {
            chart.plot(xddfChartData);
        }
    }

    /**
     * PIE
     *
     * @param chart
     * @param chartType
     * @param xAxisData
     * @param yAxisData
     * @return
     */
    private XDDFChartData performPieRendering(XWPFChart chart, ChartTypes chartType, CustomChartSingleSeriesRenderData singleSeriesRenderData
            , String[] xAxisData, Number[] yAxisData) {
        // 图例位置
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.TOP_RIGHT);
        //设置X轴数据
        XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData);
        //设置Y轴数据
        XDDFNumericalDataSource<Number> yAxisSource = XDDFDataSourcesFactory.fromArray(yAxisData);
        //创建对象
        // 将数据源绑定到饼图上
        XDDFChartData xddfPieChartData = chart.createData(ChartTypes.PIE, null, null);
        XDDFPieChartData.Series series = (XDDFPieChartData.Series)xddfPieChartData.addSeries(xAxisSource, yAxisSource);
        series.setTitle(null,null);
        // 为了在饼图上显示百分比等信息,需要调用下面的方法
        series.setShowLeaderLines(true);
        if (StrUtil.isEmpty(singleSeriesRenderData.getChartTitle())) {
            // 隐藏图例标识、系列名称、分类名称和数值
            CTPieSer ctPieSer = series.getCTPieSer();
            showCateName(ctPieSer, false);
            showVal(ctPieSer, false);
            showLegendKey(ctPieSer, false);
            showSerName(ctPieSer, false);
        }
        return xddfPieChartData;
    }

    public void showCateName(CTPieSer series, boolean val) {
        if (series.getDLbls().isSetShowCatName()) {
            series.getDLbls().getShowCatName().setVal(val);
        } else {
            series.getDLbls().addNewShowCatName().setVal(val);
        }
    }

    public void showVal(CTPieSer series, boolean val) {
        if (series.getDLbls().isSetShowVal()) {
            series.getDLbls().getShowVal().setVal(val);
        } else {
            series.getDLbls().addNewShowVal().setVal(val);
        }
    }

    public void showSerName(CTPieSer series, boolean val) {
        if (series.getDLbls().isSetShowSerName()) {
            series.getDLbls().getShowSerName().setVal(val);
        } else {
            series.getDLbls().addNewShowSerName().setVal(val);
        }
    }

    public void showLegendKey(CTPieSer series, boolean val) {
        if (series.getDLbls().isSetShowLegendKey()) {
            series.getDLbls().getShowLegendKey().setVal(val);
        } else {
            series.getDLbls().addNewShowLegendKey().setVal(val);
        }
    }


    private XDDFChartData performBarRendering(XWPFChart chart, ChartTypes chartType, CustomChartSingleSeriesRenderData singleSeriesRenderData
            , String[] xAxisData, Number[] yAxisData) {

        // 定义类别轴和数值轴
        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);


        //设置X轴数据
        XDDFCategoryDataSource catSource = XDDFDataSourcesFactory.fromArray(xAxisData);
        //设置Y轴数据
        XDDFNumericalDataSource<Number> valSource = XDDFDataSourcesFactory.fromArray(yAxisData);

        // 创建柱状图数据系列
        XDDFBarChartData barChartData = (XDDFBarChartData) chart.createData(chartType, bottomAxis, leftAxis);
        XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) barChartData.addSeries(catSource, valSource);
        series1.setTitle("示例系列", null); // 设置系列标题

        // 设置柱状图样式
        barChartData.setBarDirection(BarDirection.COL);
        return barChartData;
    }

    private XDDFChartData performRadarRendering(XWPFChart chart, ChartTypes chartType, CustomChartSingleSeriesRenderData singleSeriesRenderData
            , String[] xAxisData, Number[] yAxisData) {
        List<Number[]> list = new ArrayList<>();
        list.add(yAxisData);
        setRadarData(chart, new String[]{"系列一"}, xAxisData, list);
        return null;
    }

    private void setRadarData(XWPFChart chart, String[] series, String[] categories,
                              List<Number[]> list) {
        XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
        leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
        XDDFRadarChartData radar = (XDDFRadarChartData) chart
                .createData(org.apache.poi.xddf.usermodel.chart.ChartTypes.RADAR, bottomAxis, leftAxis);
        final int numOfPoints = categories.length;
        final String categoryDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, 0, 0));
        final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, 0);

        for (int i = 0; i < list.size(); i++) {
            final String valuesDataRange = chart.formatRange(new CellRangeAddress(1, numOfPoints, i + 1, i + 1));
            final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(list.get(i),
                    valuesDataRange, i);
            XDDFChartData.Series s = radar.addSeries(categoriesData, valuesData);
            s.setTitle(series[i], chart.setSheetTitle(series[i], i));
        }
        radar.setStyle(RadarStyle.STANDARD);
        chart.plot(radar);
        if (list.size() > 1) {
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.BOTTOM);
            legend.setOverlay(false);
        }
    }


    /**
     * LINE 渲染
     */
    private XDDFChartData performLineRendering(XWPFChart chart, ChartTypes chartType, CustomChartSingleSeriesRenderData singleSeriesRenderData
            , String[] xAxisData, Number[] yAxisData) {

        //图例设置
        XDDFChartLegend legend = chart.getOrAddLegend();
        //图例位置:上下左右
        legend.setPosition(LegendPosition.TOP);

        //X轴(分类轴)相关设置
        //创建X轴,并且指定位置
        XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);

        String xAxisTitle = singleSeriesRenderData.getxAxisTitle();

        //x轴标题
        if (StrUtil.isNotEmpty(xAxisTitle)) {
            xAxis.setTitle(xAxisTitle);
        }
        //Y轴(值轴)相关设置
        XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置
        if (StrUtil.isNotEmpty(singleSeriesRenderData.getyAxisTitle())) {
            yAxis.setTitle(singleSeriesRenderData.getyAxisTitle()); // Y轴标题
        }

        //创建折线图对象
        XDDFLineChartData customChartData = (XDDFLineChartData) chart.createData(chartType, xAxis, yAxis);
        //设置X轴数据
        XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(xAxisData);
        //设置Y轴数据
        XDDFNumericalDataSource<Number> yAxisSource = XDDFDataSourcesFactory.fromArray(yAxisData);
        //加载折线图数据集
        XDDFLineChartData.Series lineSeries = (XDDFLineChartData.Series) customChartData.addSeries(xAxisSource, yAxisSource);
        //线条样式:true平滑曲线,false折线
        lineSeries.setSmooth(false);
        // 标记点样式
        lineSeries.setMarkerStyle(MarkerStyle.CIRCLE);
        //lineSeries.setMarkerSize((short) 5);

        return customChartData;
    }
}

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

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

相关文章

QT数据库SQLite:QsqlTableModel使用总结

数据库连接、数据模型与界面组件所涉及的类之间的关系如下所示&#xff1a; 数据库类 QSqlDatabase 类用于建立与数据库的连接&#xff0c;QSqlDatabase 对象就表示这种连接。QSqlDatabase 类的功能主要分为三大部分&#xff1a; 1、创建数据库连接&#xff0c;即创建 QSqlDat…

[MoeCTF 2022]what are y0u uploading?

[BJDCTF 2020]签个到? 解压后发现两个文件夹&#xff0c;进去发现有个压缩包 这里压缩包打不开&#xff0c;就直接给改成png后缀 发现变成了一个二维码 然后用QR工具扫一下 得到flag NSSCTF{i_am_a_tupian} [MoeCTF 2022]what are y0u uploading&#xff1f; 右击查看源码…

查询品牌涉及两张表(brand、brand_admin_mapping)

文章目录 1、BrandController2、AdminCommonService3、BrandApiService3、BrandCommonService4、BrandSqlService涉及的表SQL 查询逻辑参数处理执行查询完整 SQL 逻辑参数映射总结 SELECT * FROM brand_admin_mapping WHERE admin_id 252SELECT * FROM brand WHERE id 44SELE…

k8s 为什么需要Pod?

Pod&#xff0c;是 Kubernetes 项目中最小的 API 对象&#xff0c;更加专业的说&#xff0c;Pod&#xff0c;是 Kubernetes 项目的原子调度单位。 Pod 是 Kubernetes 里的原子调度单位。这就意味着&#xff0c;Kubernetes 项目的调度器&#xff0c;是统一按照 Pod 而非容器的资…

如何在Ubuntu中利用repo和git地址下载获取imx6ull的BSP

01-设置git的用户名和邮箱 git config --global user.name "suwenhao" git config --global user.email "2487872782qq.com"这里不设置的话后面在第5步的repo配置中还是会要求输入&#xff0c;而且以后进行相关操作都要输入&#xff0c;不妨现在就进行配置…

【机器学习】基于SVM、逻辑回归和CNN的手写数字识别:性能对比与应用分析

基于SVM、逻辑回归和CNN的手写数字识别&#xff1a;性能对比与应用分析 1 基于SVM对手写数字识别2 基于逻辑回归对手写数字进行识别3 基于CNN对手写数字进行识别总结对比分析 1 基于SVM对手写数字识别 在使用SVM方法对手写数字进行识别的时候&#xff0c;我采用了一对多&#…

Elasticsearch ILM 故障排除:常见问题及修复

作者&#xff1a;来自 Elastic Stef Nestor 大家好&#xff01;我们的 Elasticsearch 团队正在不断改进我们的索引生命周期管理 (index Lifecycle Management - ILM) 功能。当我第一次加入 Elastic Support 时&#xff0c;我通过我们的使用 ILM 实现自动滚动教程快速上手。在帮…

【html网页页面009】html+css制作学校官网主题网页制作含登录(5页面附效果及源码)

校园网站主题网页制作 &#x1f964;1、写在前面&#x1f367;2、涉及知识&#x1f333;3、网页效果&#x1f308;4、网页源码4.1 html4.2 CSS4.3 源码获取w034学校网页源码及介绍链接 &#x1f40b;5、作者寄语 &#x1f964;1、写在前面 学校网站主题的网页 一共5个页面 网…

JavaScript柯里化和组合函数以及严格模式介绍

柯里化介绍 柯里化的结构 简化版本 让函数的职责单一 柯里化的复用 对某些逻辑进行复用 打印日志的柯里化 自动化柯里化函数 实现柯理化函数 1.柯里化函数是对函数进行处理的方法&#xff0c;所以参数就为一个函数&#xff0c;这里取名w为fn 2.定义一个函数curried&#xff0…

查看 tomcat信息 jconsole.exe

Where is the jconsole.exe? location: JDK/bin/jconsole.exe

【SpringBoot】Day11-09 参数配置化

为什么需要参数配置化 对于这些配置信息是直接硬编码&#xff0c;写死在java程序中的&#xff0c;存在几个问题&#xff1a; 如果这些参数发生变化了&#xff0c;就必须在源程序代码中改动这些参数&#xff0c;然后需要重新进行代码的编译&#xff0c;将Java代码编译成class字节…

企业迎接现场网络安全检查准备

企业安全负责人一听到主管单位单位要来现场进行网络安全就紧张可是对于不少重点企业来说&#xff0c;现场检查又是不可避免的&#xff0c;今天就谈谈企业如何准备网络安全检查。 网络安全现场检查类型&#xff1a; 常规检查&#xff1a;年度例行重要信息系统网络安全检查&…

UE5.5 Geometry库平面切割原理分析

平面切割--FMeshPlaneCut 平面定义: 面上一个点 法线 算法流程如下 求几何体所有顶点和面的有向距离(Signs) Sign计算&#xff1a; float Sign (VertexPos - PlaneOrigin).Dot(PlaneNormal); 遍历所有几何体所有交叉边, 进行SplitEdge 对于位于切割面两侧的交叉边(Sign…

VideoConvertor.java ffmpeg.exe

VideoConvertor.java ffmpeg.exe 视频剪切原理 入点 和 出点 选中时间点&#xff0c;导出

react hooks讲解--通俗易懂版

面试必备&#xff01; useState:状态管理 useState有两个状态&#xff0c;一个是status&#xff0c;一个是setStatus setStatus修改数据后&#xff0c;会触发<App/>的re-render 什么是re-render? re-render:重新渲染&#xff0c;re-render并不意味着dom会更新&#x…

MongoDB集群的介绍与搭建

MongoDB集群的介绍与搭建 一.MongoDB集群的介绍 注意&#xff1a;Mongodb是一个比较流行的NoSQL数据库&#xff0c;它的存储方式是文档式存储&#xff0c;并不是Key-Value形式&#xff1b; 1.1集群的优势和特性 MongoDB集群的优势主要体现在以下几个方面&#xff1a; (1)高…

基于 Python、OpenCV 和 PyQt5 的人脸识别上课打卡系统

大家好&#xff0c;我是Java徐师兄&#xff0c;今天为大家带来的是基于 Python、OpenCV 和 PyQt5 的人脸识别上课签到系统。该系统采用 Python 语言开发&#xff0c;开发过程中采用了OpenCV框架&#xff0c;Sqlite db 作为数据库&#xff0c;系统功能完善 &#xff0c;实用性强…

element Plus中 el-table表头宽度自适应,不换行

在工作中&#xff0c;使用el-table表格进行开发后&#xff0c;遇到了小屏幕显示器上显示表头文字会出现换行展示&#xff0c;比较影响美观&#xff0c;因此需要让表头的宽度变为不换行&#xff0c;且由内容自动撑开。 以下是作为工作记录&#xff0c;用于demo演示教程 先贴个…

GitLab基础环境部署:Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册

文章目录 GitLab基础环境部署&#xff1a;Ubuntu 22.04.5系统在线安装GitLab 17.5.2实操手册一、环境准备1.1 机器规划1.2 环境配置1.2.1 设置主机名1.2.2 停止和禁用防火墙1.2.3 更新系统 二、GitLab安装配置2.1 安装GitLab所需的依赖包2.2 添加GitLab存储库2.2.1 将GitLab存储…

1.3.3 存储系统

目录 存储器分类存储器的层次结构主存储器高速缓存的特点及组成外存储器的种类和特点 存储器分类 存储器按照所处位置、制作材料、访问方式、寻址方式、工作方式可以分成多种类型。 位置&#xff1a;在主机或主板上的是内存&#xff0c;否则是外存。材料&#xff1a;磁存储器&…