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

目录

问题

由于在开发功能需求中,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,也可以在指定位置进行合并
用户自定义函数(插件) 插件化设计,在文档任何位置执行函数

功能实现

引入依赖

xml 复制代码
		<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>

功能介绍

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

功能实例

饼图

模版
代码
java 复制代码
    @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();
        }
    }
效果图

雷达图(模版同饼图)

代码
java 复制代码
 @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();
        }
    }
效果图

柱状图(模版同饼图)

代码
java 复制代码
 @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 工具类

java 复制代码
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 数据对象

java 复制代码
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 插件类

java 复制代码
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;
    }
}
相关推荐
mghio1 小时前
Dubbo 中的集群容错
java·微服务·dubbo
咖啡教室6 小时前
java日常开发笔记和开发问题记录
java
咖啡教室6 小时前
java练习项目记录笔记
java
鱼樱前端6 小时前
maven的基础安装和使用--mac/window版本
java·后端
RainbowSea7 小时前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq
RainbowSea7 小时前
5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
java·消息队列·rabbitmq
李少兄9 小时前
Unirest:优雅的Java HTTP客户端库
java·开发语言·http
此木|西贝9 小时前
【设计模式】原型模式
java·设计模式·原型模式
可乐加.糖9 小时前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信