将echarts导入到word中
echarts自带保存图表配置
在echarts中有导出echarts图表图片的工具配置项
// 保存图片配置
toolbox: {
feature: {
saveAsImage: {}
}
},
具体看下面代码的配置项
Documentation - Apache ECharts
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- vue在线引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 在线引入echarts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"></script>
</head>
<body>
<div id="app">
<div id="main" style="width: 500px; height: 400px;"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
myChart: null
},
methods: {
// 初始化echarts
initEcharts() {
var chartDom = document.getElementById('main');
// 将创建的echarts示例放到vue的data中,这样在这个界面就想到于全局配置了
this.myChart = echarts.init(chartDom);
},
// 配置echarts的option,展示数据图表
setEchartsOption() {
// 这里可以发送axios请求,然后通过响应的数据赋值给对应的x轴和y轴即可,由于这里没有于后端联调,所以简单请求判断一下,
// 请求后端大概也是这个过程
var option;
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
// 保存图片配置
toolbox: {
feature: {
saveAsImage: {}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
option && this.myChart.setOption(option);
},
},
mounted() {
// 注意调用顺序,先初始化echarts才给echarts赋值
this.initEcharts()
this.setEchartsOption()
}
})
</script>
</body>
</html>
echarts提供了获取图表的api
echarts官网:Documentation - Apache ECharts
代码如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- vue在线引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 在线引入echarts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"></script>
</head>
<body>
<div id="app">
<el-row>
<el-button type="primary" @click="daochupng">导出为png</el-button>
</el-row>
<div id="main" style="width: 500px; height: 400px;"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
myChart: null
},
methods: {
// 导出为png
daochupng() {
var image = this.myChart.getDataURL({
pixelRatio: 2,
backgroundColor: '#fff'
});
let blob = this.dataURLtoBlob(image);
let fileName = 'echarts导出结果.png';
let file = new File([blob], fileName, { type: 'image/png' })
const downloadElement = document.createElement('a');
const href = window.URL.createObjectURL(file);
downloadElement.href = href;
downloadElement.download = fileName;
document.body.appendChild(downloadElement);
downloadElement.click();
document.body.removeChild(downloadElement);
window.URL.revokeObjectURL(href);
},
// 将base64转化为blob数据
dataURLtoBlob(dataurl) {
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
// 初始化echarts
initEcharts() {
var chartDom = document.getElementById('main');
// 将创建的echarts示例放到vue的data中,这样在这个界面就想到于全局配置了
this.myChart = echarts.init(chartDom);
},
// 配置echarts的option,展示数据图表
setEchartsOption() {
// 这里可以发送axios请求,然后通过响应的数据赋值给对应的x轴和y轴即可,由于这里没有于后端联调,所以简单请求判断一下,
// 请求后端大概也是这个过程
var option;
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
// 保存图片配置
toolbox: {
feature: {
saveAsImage: {}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
option && this.myChart.setOption(option);
},
},
mounted() {
// 注意调用顺序,先初始化echarts才给echarts赋值
this.initEcharts()
this.setEchartsOption()
}
})
</script>
</body>
</html>
echarts通过服务器后端上传echarts图到服务器
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- vue在线引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 在线引入echarts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"></script>
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<el-row>
<el-button type="primary" @click="shangchuanfuwuqi">echarts上传到服务器</el-button>
</el-row>
<div id="main" style="width: 500px; height: 400px;"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
myChart: null
},
methods: {
// 导出为png
async shangchuanfuwuqi() {
var image = this.myChart.getDataURL({
pixelRatio: 2,
backgroundColor: '#fff'
});
let blob = this.dataURLtoBlob(image);
let fileName = 'echarts导出结果.png';
let file = new File([blob], fileName, { type: 'image/png' })
// 因为uploadecharts使用了async修饰,所以这里返回的是promise对象,这里使用await接受,也可以用then的形式
const result = await this.uploadecharts(file, fileName)
// debugger
console.log(result)
this.$message.success(result)
},
// 上传echarts图片给服务器接口
async uploadecharts(file, fileName) {
const form = new FormData();
form.append("file", file)
form.append("filename", fileName) // 这个写在这里只是想说明,出来传文件还可以填多个字段
const result = await axios.post('http://localhost:8080/upload/echarts', form)
// debugger
console.log(result)
return result.data
},
// 将base64转化为blob数据
dataURLtoBlob(dataurl) {
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
// 初始化echarts
initEcharts() {
var chartDom = document.getElementById('main');
// 将创建的echarts示例放到vue的data中,这样在这个界面就想到于全局配置了
this.myChart = echarts.init(chartDom);
},
// 配置echarts的option,展示数据图表
setEchartsOption() {
// 这里可以发送axios请求,然后通过响应的数据赋值给对应的x轴和y轴即可,由于这里没有于后端联调,所以简单请求判断一下,
// 请求后端大概也是这个过程
var option;
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
// 保存图片配置
toolbox: {
feature: {
saveAsImage: {}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
option && this.myChart.setOption(option);
},
},
mounted() {
// 注意调用顺序,先初始化echarts才给echarts赋值
this.initEcharts()
this.setEchartsOption()
}
})
</script>
</body>
</html>
后端代码
springboot2.5.0+jdk1.8
@RestController
@RequestMapping("/upload")
@CrossOrigin // 允许跨域,前后端分离
public class UploadEchartsController {
@RequestMapping("/echarts")
public String uploadEcharts(MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
// 文件保存路径
Path path = Paths.get("D:\\private\\javastudaykeshanchu\\img\\" + filename);
file.transferTo(path);
/* try {
file.transferTo(path);
} catch (IOException e) {
e.printStackTrace();
}*/
return "上传图片成功";
}
}
结果
到代码中对应的文件夹看,可以看到赌赢的echarts图片已经成功上传到服务器了
查看结果为
这时就可以将echarts图片写入到word中了
前端vue,后端springboot + easypoi
easypoi的maven坐标如下所示:
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
word模板如下所示
前端代码如下所示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- vue在线引入 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<!-- 在线引入echarts -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"></script>
<!-- axios -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<el-row>
<el-button type="primary" @click="shangchuanfuwuqi">echarts上传到服务器</el-button>
</el-row>
<div id="main" style="width: 500px; height: 400px;"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
myChart: null
},
methods: {
// 导出为png
async shangchuanfuwuqi() {
var image = this.myChart.getDataURL({
pixelRatio: 2,
backgroundColor: '#fff'
});
let blob = this.dataURLtoBlob(image);
let fileName = 'echarts导出结果.png';
let file = new File([blob], fileName, { type: 'image/png' })
// 因为uploadecharts使用了async修饰,所以这里返回的是promise对象,这里使用await接受,也可以用then的形式
const result = await this.uploadecharts(file, fileName)
// debugger
console.log(result)
this.$message.success(result)
// 这里将图片的名称传给后端,因为后端需要根据图片名加上路径找到上传图片所在的位置,
// 这里上传的图片放到了本地,而不是类似于上传到七牛云之类的。
// 这里的后端使用了map集合接收,具体看后端代码
const params = { echartsimgname: fileName, describe: '这个是一个星期对应的柱形图如下所示' }
// 虽然后端是void,但是后端是通过HttpServletResponse 以流的形式返回的,所以这里axios的data就是返回的流数据
const res = await axios.post('http://localhost:8080/upload/exportechartstoword', params, { responseType: "blob" })
const link = document.createElement("a");
let blob2 = new Blob([res.data], { type: "application/msword" });
link.style.display = "none";
link.href = URL.createObjectURL(blob2);
link.setAttribute("download", 'echarts将图片写入到word文档中.docx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
this.$message.success("将echarts导入到word成功")
},
// 上传echarts图片给服务器接口
async uploadecharts(file, fileName) {
const form = new FormData();
form.append("file", file)
form.append("filename", fileName) // 这个写在这里只是想说明,出来传文件还可以填多个字段
const result = await axios.post('http://localhost:8080/upload/echarts', form)
// debugger
console.log(result)
return result.data
},
// 将base64转化为blob数据
dataURLtoBlob(dataurl) {
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
},
// 初始化echarts
initEcharts() {
var chartDom = document.getElementById('main');
// 将创建的echarts示例放到vue的data中,这样在这个界面就想到于全局配置了
this.myChart = echarts.init(chartDom);
},
// 配置echarts的option,展示数据图表
setEchartsOption() {
// 这里可以发送axios请求,然后通过响应的数据赋值给对应的x轴和y轴即可,由于这里没有于后端联调,所以简单请求判断一下,
// 请求后端大概也是这个过程
var option;
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
// 保存图片配置
toolbox: {
feature: {
saveAsImage: {}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'bar',
barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220]
}
]
};
option && this.myChart.setOption(option);
},
},
mounted() {
// 注意调用顺序,先初始化echarts才给echarts赋值
this.initEcharts()
this.setEchartsOption()
}
})
</script>
</body>
</html>
java后端代码
@RestController
@RequestMapping("/upload")
@CrossOrigin // 允许跨域,前后端分离
public class UploadEchartsController {
/**
* 将echarts上传只服务器的接口
* @param file
* @return
* @throws IOException
*/
@RequestMapping("/echarts")
public String uploadEcharts(MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
// 文件保存路径,D:\private\javastudaykeshanchu\img\这里可以通过application.yml配置文件夹路径,然后在后面拼接文件名即可
Path path = Paths.get("D:\\private\\javastudaykeshanchu\\img\\" + filename);
file.transferTo(path);
/* try {
file.transferTo(path);
} catch (IOException e) {
e.printStackTrace();
}*/
return "上传图片成功";
}
/**
*
* @param response
* @param maps 这里使用map接收数据是因为这样更加方便,如果使用实体类接收,还要转化为Map<String,Object>这种类型,具体看另外一篇文章
* @throws Exception
*/
@PostMapping("/exportechartstoword")
public void exportword(HttpServletResponse response, @RequestBody Map<String,Object> maps) throws Exception {
// 读取模板文件所在的位置
// File filepath = new File("D:\\private\\javastudaykeshanchu\\javaweb\\echarts-demo\\src\\main\\resources\\templates\\wordtemplate.docx");
String name = "echarts图表保存到word中";
// filepath.getPath()是为了让路径变成string,否则下面的报错
// XWPFDocument word = WordExportUtil.exportWord07(filepath.getPath(), maps);
// 或者直接在这里填写路径也行,就不用创建File了,而且这个路径有条件的话也可以放在application.yml中配置,这样的通用性就会强一点,具体看静态资源配置那篇文章
// 创建图像对象
ImageEntity imageEntity = new ImageEntity();
// 如这里的文件路径就可以设置到applic.yml中,然后通过读取yml的配置项获得路径,放到这里,这里就暂时用这种形式来吧
imageEntity.setUrl("D:\\private\\javastudaykeshanchu\\img\\" + maps.get("echartsimgname").toString());
// 这里的宽高一定要设置,不然图片出不来,至于设置多少,可以自己到word中A4纸100%的缩放,然后通过Snipaste截图软件大概截图个宽高,然后照着输入就行了
imageEntity.setWidth(500);
imageEntity.setHeight(300);
maps.put("echartsimg", imageEntity);
XWPFDocument word = WordExportUtil.exportWord07("D:\\private\\javastudaykeshanchu\\javaweb\\echarts-demo\\src\\main\\resources\\templates\\wordtemplate.docx", maps);
String fileName = "echarts通过(" + name + ")详情.docx";
response.setHeader("content-disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
ServletOutputStream outputStream = response.getOutputStream();
word.write(outputStream);
outputStream.close();
word.close();
}
}
结果如下图所示
打开word文档得到的结果如下所示