首页 前端知识 java后台生成echarts图表图片

java后台生成echarts图表图片

2024-02-27 11:02:31 前端知识 前端哥 145 495 我要收藏

Java后台生成echarts图表图片并发送html页面邮件


文章目录

  • Java后台生成echarts图表图片并发送html页面邮件
  • 前言
  • 一、如何后台生成图表图片
  • 二、使用步骤
    • 1.安装部署Phantomjs
    • 2.运行EChartsConvert
    • 3.调用接口生成图片
  • 三、官方使用nodejs转svg图片方案


前言

项目需求,生成报表并发送邮件给指定邮箱,报表中包含echarts图表,由于无法在邮件中渲染图表,所以需要后台生成图表图片再嵌入到邮件中。


一、如何后台生成图表图片

如何不依赖前端在JAVA后台生成echarts图表图片呢,这里需要借助Phantomjs和EChartsConvert工具,可以自行了解。

二、使用步骤

1.安装部署Phantomjs

在https://phantomjs.org/download.html下载对应环境的安装包,我这边用的是linux环境。

  1. 将phantomjs-2.1.1-linux-x86_64.tar包放到/usr/local下,解压
  2. 修改环境变量
    vi /etc/profile
    添加以下配置到最后一行
    export PATH=$PATH:/usr/local/phantomjs-2.1.1-linux-x86_64/bin
    保存环境变量
    source /etc/profile
    
  3. 安装依赖
    yum install -y fontconfig freetype2
    安装成功后判断是否成功
    phantomjs -v
    正常会输出版本号
    再安装好字体,不安装的话,图表中的中文会乱码
    可以先去windows下C:\Windows\Fonts复制字体文件,可以使用Microsoft YaHei UI这个字体,复制到linux下的/usr/share/fonts/chinese目录下。没有这个目录就自己创建一个,再执行以下命令
    mkfontscale
    mkfontdir
    fc-cache -fv
    ps:如果以上找不到命令,执行yum install -y fontconfig mkfontscale
    ps:字体更新后要重启phantomjs服务才会生效
    

2.运行EChartsConvert

将下载好的EChartsConvert放在任意位置,找到echarts-convert.js文件,在同级目录下执行

nohup phantomjs echarts-convert.js -s -p 50130 > echarts.log 2>&1 &

以上命令可以在后台执行echarts-convert.js脚本,指定端口50130

3.调用接口生成图片


三、官方使用nodejs转svg图片方案

1、以下是官方转svg图片方案,链接: 服务端渲染 ECharts 图表

var http = require("http");
var echarts = require("echarts");

function renderChart(data) {
  const chart = echarts.init(null, null, {
    renderer: "svg",
    ssr: true,
    width: data.width,
    height: data.height
  });
  if(data.type == "bar"){
    chart.setOption({
        xAxis: {
          type: "category",
          axisLine: {
            show: false
          },
          axisTick: {
            show: false
          },
          axisLabel: {
            interval: 0
          },
          data: data.xAxis
        },
        yAxis: {
          type: "value",
          boundaryGap: true,
          axisLine: {
            show: false,
            color: "#BDEDF8"
          },
          axisTick: {
            show: false
          },
          axisLabel: {
            rich: {
              valueStyle: {
                color: "#d9001b99"
              }
            }
          }
        },
        title: {
          show: false
        },
        tooltip: {
          axisPointer: {
            type: "shadow"
          },
          trigger: "axis",
          backgroundColor: "#fff",
          borderColor: "rgba(0,0,0,0.10)",
          borderWidth: 1,
          textStyle: {
            color: "#333"
          }
        },
        legend: {
          data: []
        },
        grid: {
          top: 30,
          left: 30,
          right: 50,
          bottom: 15,
          containLabel: true
        },
        color: [
          "#0066FF",
          "#8378EA",
          "#0092FF",
          "#00BDFF",
          "#FFA254",
          "#00BD7E",
          "#AD9DF3",
          "#FFCB00",
          "#4AD3A4",
          "#00FFCD"
        ],
        series: [
          {
            data: data.series,
            type: "bar",
            stack: "",
            name: "",
            barMaxWidth: 24,
            emphasis: {
              label: {
                fontWeight: "bold"
              },
              itemStyle: {
                opacity: 1
              }
            },
            itemStyle: {
              color: "#AD9DF3"
            },
            animationDelay: (idx) => {
              return idx * 100;
            },
          }
        ]
    });
  }else if(data.type == "line"){
    chart.setOption(
      {
        title: {
          show: false
        },
        tooltip: {
          trigger: "axis",
          backgroundColor: "#fff",
          borderColor: "rgba(0,0,0,0.10)",
          borderWidth: 1,
          textStyle: {
            color: "#333"
          }
        },
        color: [
          "#1890ff",
          "#19c2c6",
          "#dc122b",
          "#4E9AFE",
          "#4AD3A4 ",
          "#AD9DF3",
          "#F6C827",
          "#F9A46E",
          "#1890ff",
          "#b31212",
          "#faad14"
        ],
        legend: {
          type: "scroll",
          right: 50,
          top: 10,
          height: 20,
          data: data.legend,
          itemWidth: 12,
          itemHeight: 8,
          padding: 10
        },
        grid: {
          top: 50,
          left: 30,
          right: 50,
          bottom: 30,
          containLabel: true
        },
        xAxis: {
          type: "category",
          boundaryGap: false,
          axisLabel: {
            textStyle: {
              fontSize: "12",
              color: "#666"
            }
          },
          axisLine: {
            lineStyle: {
              color: "#ccc"
            }
          },
          axisTick: {
            inside: true,
            alignWithLabel: true
          },
          data: data.xAxis
        },
        yAxis: {
          type: "value",
          axisLine: {
            show: false
          },
          splitLine: {
            lineStyle: {
              color: "rgba(153,153,153,.2)"
            }
          },
          axisTick: {
            show: false
          },
          lineStyle: {
            width: 1
          },
          axisLabel: {
            rich: {
              valueStyle: {
                color: "#d9001b99"
              }
            }
          },
          nameLocation: "end",
          nameTextStyle: {
            verticalAlign: "middle"
          }
        },
        series: data.series
      }      
    );
  }else if(data.type == "pie"){
    chart.setOption(
      {
        title: {
          show: false
        },
        tooltip: {
          trigger: "item",
          borderWidth: 0,
          axisPointer: {
            type: "cross"
          }
        },
        legend: {
          type: "plain",
          orient: "vertical",
          left: "50%",
          top: "center",
          align: "left",
          itemGap: 6,
          itemWidth: 8,
          itemHeight: 8,
          icon: "circle",
          symbolKeepAspect: false,
          itemStyle: {
            opacity: 1
          },
          textStyle: {
            lineHeight: 18,
            fontSize: 12,
            color: "#333333",
            rich: {
              a: {
                width: 250
              },
              b: {
                width: 70
              },
              c: {
                color: "#666666"
              }
            }
          },
          tooltip: {
            show: true
          }
        },
        color: [
          "#4E9AFE",
          "#4AD3A4",
          "#AD9DF3",
          "#FBDB6A",
          "#F9A46E",
          "#9d96f5",
          "#8378EA",
          "#96BFFF",
          "#C5E545",
          "#E9967A",
          "#C8C8CB"
        ],
        series: [
          {
            name: "",
            type: "pie",
            right: "50%",
            radius: [
              "50%",
              "70%"
            ],
            center: [
              "50%",
              "50%"
            ],
            minAngle: 1,
            data: data.series,
            label: {
              show: false
            },
            itemStyle: {
              opacity: 0.8
            },
            emphasis: {
              itemStyle: {
                opacity: 1,
                shadowColor: "none"
              }
            }
          }
        ]
      }      
    );
  }
  return chart.renderToSVGString();
}

http
  .createServer(function (req, res) {
    res.writeHead(200, {
      "Content-Type": "application/xml"
    });
    var post = "";
    req.on("data",function(chunk){
        post+=chunk;
    })
    req.on("end",function(){
        post = JSON.parse(post)
        console.log(post);
        var chart = renderChart(post)
        console.log(chart)
        res.write(chart);
        res.end();
    })
  })
  .listen(8877);

接口传参

{
    "series": [
        1,
        2,
        3,
        4,
        5,
        6,
        7
    ],
    "xAxis": [
        "星期一",
        "星期二",
        "星期三",
        "星期四",
        "星期五",
        "星期六",
        "星期天"
    ],
    "type": "bar",
    "width": 450,
    "height": 200
}

样例图片
安装好node.js服务,将转换代码复制到app.js文件中,将文件复制到node.js可执行的任意目录下,执行node app.js,然后通过http调用即可

创建精简node.js容器

docker pull alpine:latest
docker run -dit -p 8877:8877 --name alpine alpine:latest
docker exec -it alpine /bin/sh
	sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
	apk update
	apk add npm
	cd /root
	npm install echarts
	apk del npm
	exit
docker cp app.js alpine:/root/app.js
docker exec -it alpine /bin/sh
nohup node app.js  > echarts.log 2>&1 &

使用docker镜像

docker pull node
docker run -dit -p 8877:8877 --name node node
docker cp app.js node:/root/app.js
docker exec -it node bash
cd /root
npm install echarts
apt -y install xfonts-utils fontconfig//安装字体

复制字体文件到/usr/share/fonts/和/usr/share/fonts/chinese

cd /usr/share/fonts/chinese
mkfontscale   # 生产字体索引 
mkfontdir    #
fc-cache -frv    # 更新字体缓存
nohup node app.js  > echarts.log 2>&1 &

打包镜像文件命令

docker commit ffaa3859d2b9(容器id)node_echarts:2.0.0
docker save -o node_echarts node_echarts:2.0.0//保存为node_echarts文件
加载镜像文件
docker load -i node_echarts
docker run -dit -p 8877:8877 --name node_echarts node_echarts:2.0.0 

svg字符串转base64图片字符串,利用batik包转png再转base64

implementation 'org.apache.xmlgraphics:batik-all:1.14'
package top.xxx.module.abac.util.echarts;

import cn.hutool.http.HttpUtil;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.Map;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import top.xxx.module.abac.util.JackJsonUtil;

public class EchartsUtil {
    private static String url = "http://abac.ensbrain.ztrust.top:8877";

	/**
	 * @description: 根据echarts配置项生成echarts图片并返回base64编码
	 * @param: opt
	 * @return: java.lang.String
	 **/
    public static String generateEchartsImg2Base64(Map opt) throws IOException {
		String jsonData = JackJsonUtil.obj2String(opt);
		String svg = HttpUtil.post(url, jsonData);
		try {
			ByteArrayInputStream bin=new ByteArrayInputStream(svg.getBytes());
			PNGTranscoder transcoder = new PNGTranscoder();
			TranscoderInput input = new TranscoderInput(bin);
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			TranscoderOutput output = new TranscoderOutput(outputStream);
			transcoder.transcode(input, output);
			byte[] pngData = outputStream.toByteArray();
			return Base64.getEncoder().encodeToString(pngData);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
    }
}

转载请注明出处或者链接地址:https://www.qianduange.cn//article/2825.html
标签
评论
发布的文章

前端大屏适配几种方案

2024-01-29 13:01:44

JQ效果—展开和收起

2024-03-13 00:03:45

JQuery事件的基本使用

2024-03-13 00:03:39

「jQuery系列」jQuery 事件

2024-03-13 00:03:36

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!