使用Java的JFreeChart创建折线图

使用Java的JFreeChart创建折线图,并保存到word中

在一个项目中需要使用数据创建折线图,不过这个折线图比较丑。
先看效果

在这里插入图片描述

下面是代码。

     <!-- JFreeChart 依赖 -->
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jcommon</artifactId>
            <version>1.0.24</version>
        </dependency>
    	<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.4</version>
        </dependency>

这是装数据的实体

package com.example.dome.domain.dto;



public class GnssDataByYueBao {

    private String platformName;
    private String showName;
    //目标椭球平面坐标x
    private Double dPlaneX;
    //目标椭球平面坐标y
    private Double dPlaneY;
    //目标椭球平面坐标h
    private Double dPlaneH;
    //目标椭球平面坐标x方向差值
    private Double dVariationPlaneX;
    //目标椭球平面坐标y方向差值
    private Double dVariationPlaneY;
    //目标椭球平面坐标h方向差值
    private Double dVariationPlaneH;
    private String createTime;


    public String getPlatformName() {
        return platformName;
    }

    public void setPlatformName(String platformName) {
        this.platformName = platformName;
    }

    public String getShowName() {
        return showName;
    }

    public void setShowName(String showName) {
        this.showName = showName;
    }

    public Double getdPlaneX() {
        return dPlaneX;
    }

    public void setdPlaneX(Double dPlaneX) {
        this.dPlaneX = dPlaneX;
    }

    public Double getdPlaneY() {
        return dPlaneY;
    }

    public void setdPlaneY(Double dPlaneY) {
        this.dPlaneY = dPlaneY;
    }

    public Double getdPlaneH() {
        return dPlaneH;
    }

    public void setdPlaneH(Double dPlaneH) {
        this.dPlaneH = dPlaneH;
    }

    public Double getdVariationPlaneX() {
        return dVariationPlaneX;
    }

    public void setdVariationPlaneX(Double dVariationPlaneX) {
        this.dVariationPlaneX = dVariationPlaneX;
    }

    public Double getdVariationPlaneY() {
        return dVariationPlaneY;
    }

    public void setdVariationPlaneY(Double dVariationPlaneY) {
        this.dVariationPlaneY = dVariationPlaneY;
    }

    public Double getdVariationPlaneH() {
        return dVariationPlaneH;
    }

    public void setdVariationPlaneH(Double dVariationPlaneH) {
        this.dVariationPlaneH = dVariationPlaneH;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
}

业务逻辑代码

    public void MonthlyReportExport(MonthlyReportParam monthlyReportParam) {
        //先找下级单位
        List<SysDept> lstDept = sysDeptMapper.getChildDept(monthlyReportParam.getDepId());
        LinkedHashMap<String, Map<String, List<File>>> map = new LinkedHashMap<>();

        // 计算总的循环次数
        int totalLoops = 0;
        for (SysDept sysDept : lstDept) {
            List<PurviewPlatform> purviewPlatformList = purviewPlatformMapper.getPlatFormByDeptId(sysDept.getDeptId());
            totalLoops += purviewPlatformList.size();
        }

        int currentLoop = 0;

        // 创建以当前时间日期命名的文件夹
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String folderName = now.format(formatter);
        File dateFolder = new File(wordFileDownLoadPath, folderName);
        if (!dateFolder.exists()) {
            dateFolder.mkdirs();
        }
        for (SysDept sysDept : lstDept) {
            Map<String, List<File>> platformImages = new HashMap<>();
            //循环单位,找路段
            List<PurviewPlatform> purviewPlatformList = purviewPlatformMapper.getPlatFormByDeptId(sysDept.getDeptId());
            for (PurviewPlatform purviewPlatform : purviewPlatformList) {

                // 每个平台有独立的图片列表
                List<File> images = new ArrayList<>();

                //循环平台找数据
                monthlyReportParam.setDepId(sysDept.getDeptId());
                monthlyReportParam.setPlatformId(purviewPlatform.getPlatformId());
                //位移数据
                List<GnssDataByYueBao> gnssDataByYueBaoList = iGnssDataService.getGnssDataByDepIdAndPlatformId(monthlyReportParam);

                //倾角/加速度
                List<DipAngleByYueBao> dipAngleByYueBaoList = iDipAngleDataService.getDipAngleDataByDepId(monthlyReportParam);
  

                //深部位移
                List<ClinometerByYueBao> clinometerDataByDepId = iClinometerDataService.getClinometerDataByDepId(monthlyReportParam);

                //裂缝计
                List<FissureByYueBao> fissureDataByDepId = iFissureDataService.getFissureDataByDepId(monthlyReportParam);

                //浸润线
                List<OsmometerByYueBao> osmometerByYueBaoList = iOsmometerDataService.getOsmometerDataByDepId(monthlyReportParam);

                //雨量
                List<RainByYueBao> rainByYueBaoList = iRainDataService.getRainDataByDepId(monthlyReportParam);
                //应力计
                List<StressByYueBao> stressByYueBaoList = iStressDataService.getStressDataByDepId(monthlyReportParam);

                List<JFreeChart> jFreeChartList = createChartByData(
                        gnssDataByYueBaoList,
                        dipAngleByYueBaoList,
                        clinometerDataByDepId,
                        fissureDataByDepId,
                        osmometerByYueBaoList,
                        rainByYueBaoList,
                        stressByYueBaoList,
                        purviewPlatform.getPlatformName());

                if (!jFreeChartList.isEmpty()) {
                    for (JFreeChart jFreeChart : jFreeChartList) {
                        this.setPieChartFont(jFreeChart);
                        File file = saveChartAsImage(dateFolder.getPath(), jFreeChart);
                        images.add(file);
                    }
                }

                platformImages.put(purviewPlatform.getPlatformName(), images);
                //停50毫秒
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                currentLoop++;
                // 计算当前进度百分比
                double progress = ((double) currentLoop / totalLoops) * 100;
                // 确保进度不超过 100%
                progress = Math.min(progress, 100);
                smosTaskDevicedataReportMapper.updateProgress(monthlyReportParam.getId(),
                        new BigDecimal(progress).setScale(2, RoundingMode.HALF_UP).doubleValue());
                System.out.println("当前进度: " + progress + "%");
            }
            map.put(sysDept.getDeptName(), platformImages);
        }
        //在wordTemplateFilePath 里面多生成一个文件夹,将文件保存到这个文件夹中

        insertImagesIntoTemplate(map, wordFileDownLoadPath, monthlyReportParam.getFileName());
        //删除全部图片
        imagesDelete(dateFolder.getPath());

    }

删除生成的图片


    private void imagesDelete(String tempImgPath) {
        //删除temp文件夹里面的所有文件
        File tempFolder = new File(tempImgPath);
        File[] files = tempFolder.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    file.delete();
                }
            }
        }
        if (tempFolder.exists()) {
            tempFolder.delete();
        }
    }

设置字体

   private void setPieChartFont(JFreeChart freeChart) {
        XYPlot xyChart = (XYPlot) freeChart.getPlot();
        xyChart.setNoDataMessageFont(new Font("宋体", Font.BOLD, 20));
        TextTitle textTitle = freeChart.getTitle();
        textTitle.setFont(new Font("宋体", Font.ITALIC, 25));
        LegendTitle legendTitle = freeChart.getLegend();
        legendTitle.setItemFont(new Font("宋体", Font.BOLD + Font.ITALIC, 10));
    }

将生成的图片插入到word中

    private void insertImagesIntoTemplate(LinkedHashMap<String, Map<String, List<File>>> platformImages, String wordTemplateFilePath, String fileName) {
        try (XWPFDocument outputDoc = new XWPFDocument()) {

            XWPFStyles styles = outputDoc.createStyles();
            CTStyle ctStyle = CTStyle.Factory.newInstance();
            ctStyle.setStyleId("Heading1");
            CTString styleName = CTString.Factory.newInstance();
            styleName.setVal("Heading 1");
            ctStyle.setName(styleName);

            // 设置样式类型为段落样式
            ctStyle.setType(STStyleType.PARAGRAPH);

            // 设置字体和字号
            CTRPr rPr = ctStyle.addNewRPr();
            CTFonts fonts = rPr.addNewRFonts();
            fonts.setAscii("宋体");
            fonts.setEastAsia("宋体");
            fonts.setHAnsi("宋体");
            rPr.addNewSz().setVal(BigInteger.valueOf(28)); // 字号为 14pt,1pt = 2 个单位
            // 将样式添加到文档中
            XWPFStyle heading1Style = new XWPFStyle(ctStyle);
            styles.addStyle(heading1Style);

            int i = 1;
            for (Map.Entry<String, Map<String, List<File>>> stringMapEntry : platformImages.entrySet()) {
                String key = stringMapEntry.getKey();
                // 插入 key 到文档
                XWPFParagraph keyPara = outputDoc.createParagraph();
                keyPara.setStyle("Heading1");
                XWPFRun keyRun = keyPara.createRun();
                keyRun.setText(i + "、" + key);
                keyRun.setFontFamily("宋体");
                keyRun.setFontSize(14);
                keyRun.setBold(true);
                i++;
                for (Map.Entry<String, List<File>> entry : stringMapEntry.getValue().entrySet()) {
                    String platformName = entry.getKey();
                    List<File> images = entry.getValue();
                    XWPFParagraph para = outputDoc.createParagraph();
                    XWPFRun run = para.createRun();
                    run.setText(platformName);
                    run.setFontFamily("宋体");
                    run.setFontSize(12);
                    run.setBold(true);
                    // 插入图片
                    for (File image : images) {
                        XWPFParagraph imageParagraph = outputDoc.createParagraph();
                        XWPFRun imageRun = imageParagraph.createRun();
                        int format = XWPFDocument.PICTURE_TYPE_PNG;
                        imageRun.addPicture(Files.newInputStream(image.toPath()), format, image.getName(), Units.toEMU(400), Units.toEMU(300));
                        Thread.sleep(5);
                    }
                }
            }
            // 保存生成的文档
            try (FileOutputStream out = new FileOutputStream(wordTemplateFilePath + "/" + fileName + ".docx")) {
                outputDoc.write(out);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

创建数据集

    /*
     *根据数据不同创建不同数据集
     */

    private List<JFreeChart> createChartByData(List<GnssDataByYueBao> gnssDataList, String platformName) {
        List<JFreeChart> chartList = new ArrayList<>();

        //生成表面位移的折线图
        if (gnssDataList != null && !gnssDataList.isEmpty()) {
            Set<Map.Entry<String, List<GnssDataByYueBao>>> entrySet = gnssDataList.stream().collect(groupingBy(GnssDataByYueBao::getShowName)).entrySet();
            for (Map.Entry<String, List<GnssDataByYueBao>> stringListEntry : entrySet.stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList())) {
                TimeSeriesCollection gnssDataset = createGnssDataset(stringListEntry.getValue());
                JFreeChart jFreeChart = createChart(stringListEntry.getKey(), gnssDataset, platformName);
                chartList.add(jFreeChart);
            }
        }

        return chartList;

    }

创建折线图


    /**
     * 创建折线图
     *
     * @param chartTitle   图表标题
     * @param dataset      数据集
     * @param platformName
     * @return 折线图对象
     */
    private JFreeChart createChart(String chartTitle, TimeSeriesCollection dataset, String platformName) {
        JFreeChart lineChart = ChartFactory.createTimeSeriesChart(
                platformName + "_" + chartTitle,
                "",
                "",
                dataset,
                true,
                true,
                false
        );

        // 设置图例位置到图表上方
        org.jfree.chart.title.LegendTitle legend = lineChart.getLegend();
        if (legend != null) {
            legend.setPosition(org.jfree.chart.ui.RectangleEdge.TOP);
            legend.setHorizontalAlignment(org.jfree.chart.ui.HorizontalAlignment.CENTER);
        }

        // 设置 X 轴为日期轴
        XYPlot plot = lineChart.getXYPlot();
        DateAxis dateAxis = (DateAxis) plot.getDomainAxis();
        dateAxis.setDateFormatOverride(new SimpleDateFormat(ChartConfig.DATE_FORMAT));

        // 设置图表背景颜色为白色
        plot.setBackgroundPaint(Color.WHITE);

        // 设置纵轴
        NumberAxis valueAxis = (NumberAxis) plot.getRangeAxis();
        adjustValueAxisRange(valueAxis, dataset);


        // 设置线条粗细
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        BasicStroke stroke = new BasicStroke(ChartConfig.LINE_WIDTH, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        for (int i = 0; i < dataset.getSeriesCount(); i++) {
            renderer.setSeriesStroke(i, stroke);
        }


        //设置折线图颜色
        if (chartTitle.contains("表面位移")) {
            renderer.setSeriesPaint(0, Color.green);
            renderer.setSeriesPaint(1, Color.ORANGE);
            renderer.setSeriesPaint(2, Color.blue);
        }
        if (chartTitle.contains("倾角")) {
            renderer.setSeriesPaint(0, Color.green);
            renderer.setSeriesPaint(1, Color.ORANGE);
            renderer.setSeriesPaint(2, Color.blue);
            renderer.setSeriesPaint(3, Color.GRAY);
            renderer.setSeriesPaint(4, Color.CYAN);
            renderer.setSeriesPaint(5, Color.magenta);
        }
        if (chartTitle.contains("深部位移")) {
            renderer.setSeriesPaint(0, Color.green);
            renderer.setSeriesPaint(1, Color.ORANGE);
            renderer.setSeriesPaint(2, Color.blue);
            renderer.setSeriesPaint(3, Color.magenta);
        }
        if (chartTitle.contains("裂缝")) {
            renderer.setSeriesPaint(0, Color.green);
            renderer.setSeriesPaint(1, Color.ORANGE);
            renderer.setSeriesPaint(2, Color.blue);
            renderer.setSeriesPaint(3, Color.darkGray);
            renderer.setSeriesPaint(4, Color.cyan);
            renderer.setSeriesPaint(5, Color.magenta);
            renderer.setSeriesPaint(6, Color.green);
        }


        plot.setRenderer(renderer);


        return lineChart;
    }
    /**
     * 调整纵轴范围
     *
     * @param valueAxis 纵轴对象
     * @param dataset   数据集
     */
    private void adjustValueAxisRange(NumberAxis valueAxis, TimeSeriesCollection dataset) {
        // 检查 dataset 是否为 null
        if (dataset == null) {
            return;
        }

        double minValue = Double.MAX_VALUE;
        double maxValue = Double.MIN_VALUE;
        for (int i = 0; i < dataset.getSeriesCount(); i++) {
            TimeSeries series = dataset.getSeries(i);
            // 检查 series 是否为 null
            if (series == null) {
                continue;
            }
            for (int j = 0; j < series.getItemCount(); j++) {
                Number valueObj = series.getValue(j);
                // 检查 valueObj 是否为 null
                if (valueObj != null) {
                    double value = valueObj.doubleValue();
                    minValue = Math.min(minValue, value);
                    maxValue = Math.max(maxValue, value);
                }
            }
        }
        // 如果没有有效数据,不调整范围
        if (minValue == Double.MAX_VALUE && maxValue == Double.MIN_VALUE) {
            return;
        }
        minValue = minValue - 0.1;
        maxValue = maxValue + 0.1;
        valueAxis.setRange(minValue, maxValue);
    }

    /**
     * 将图表保存为图片
     *
     * @param chart 图表对象
     */
    private File saveChartAsImage(String folderPath, JFreeChart chart) {
        File file = new File(folderPath + "/" + "随机数" + ".jpg");
        try {
            ChartUtils.saveChartAsJPEG(file, chart, ChartConfig.IMAGE_WIDTH, ChartConfig.IMAGE_HEIGHT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return file;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值