1、前端部署node.js服务代码如下:
const express = require('express');
const { createCanvas } = require('canvas');
const echarts = require('echarts');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
app.use(bodyParser.json({ limit: '10mb' }));
app.post('/render', (req, res) => {
try {
const { width = 800, height = 600, option } = req.body;
// 创建一个空的 codes 对象
const codes = {};
// 使用 Function 构造器执行传入的 JS 配置代码
const func = new Function('codes', option);
func(codes);
// 获取配置对象
const config = codes.value;
if (!config) {
throw new Error('配置对象 codes.value 未定义');
}
// 创建画布并渲染
const canvas = createCanvas(width, height);
const chart = echarts.init(canvas);
chart.setOption(config);
// 返回 PNG 图像
res.set('Content-Type', 'image/png');
res.send(canvas.toBuffer());
} catch (error) {
console.error('渲染错误:', error.message);
res.status(500).send(error.message);
}
});
app.listen(port, () => {
console.log(`图表渲染服务运行在 http://localhost:${port}`);
});
2、后端访问请求数据,直接下载生成图片
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class EChartsRenderer {
private static final String RENDER_SERVICE_URL = "http://localhost:3000/render";
/**
* 渲染ECharts图表为PNG字节数组(使用Hutool优化)
*/
public static byte[] renderChart(
String config,
int width,
int height,
boolean transparent) {
// 使用Hutool构建JSON请求体
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("width", width);
paramMap.put("height", height);
paramMap.put("transparent", transparent);
paramMap.put("option", config); // 自动转换JSON
// 发送HTTP POST请求
HttpResponse response = HttpRequest.post(RENDER_SERVICE_URL)
.header("Content-Type", "application/json")
.body(JSONUtil.toJsonStr(paramMap)) // 自动序列化为JSON字符串
.timeout(30 * 1000) // 30秒超时
.execute();
// 处理响应
if (response.isOk()) {
return response.bodyBytes();
} else {
String errorMsg = "图表渲染失败: HTTP " + response.getStatus() + " - " + response.body();
throw new RuntimeException(errorMsg);
}
}
/**
* 渲染ECharts图表为PNG字节数组(默认大小)
*/
public static byte[] renderChart(String config) {
return renderChart(config, 800, 600, false);
}
public static void main(String[] args) {
// 准备ECharts配置(与之前相同)
String echartsConfig = "codes.value = {\n" +
" xAxis: {\n" +
" type: 'category',\n" +
" data: ['2021', '2022', '2023', '2024', '2025']\n" +
" },\n" +
" yAxis: {\n" +
" type: 'value',\n" +
" max: 40,\n" +
" axisLabel: {\n" +
" formatter: '{value}亿美元'\n" +
" }\n" +
" },\n" +
" series: [\n" +
" {\n" +
" data: [5, 12, 24, 34, 50],\n" +
" type: 'line',\n" +
" itemStyle: {\n" +
" color: '#4CAF50'\n" +
" },\n" +
" label: {\n" +
" show: true,\n" +
" position: 'top', // 标签显示在曲线顶部\n" +
" formatter: '{c}亿美元' // 显示数值和单位\n" +
" }\n" +
" }\n" +
" ]\n" +
"};";
// 渲染图表
byte[] chartImage = EChartsRenderer.renderChart(echartsConfig);
// 保存图片(示例)
FileUtil.writeBytes(chartImage, new File("D:\\app\\echarts-chart.png"));
System.out.println("图表已保存到D:\\app\\echarts-chart.png");
}
}