需求:
需要用柱状图展示每个部门的数据,以部门作为横轴,数据作为纵轴。如果部门超过一定数量,为了不让柱状图上每个部门被压缩得太小,柱状图使用滚动条更清楚地展示每个部门的数据。并且页面上有个导出按钮,能够下载柱状图为图片格式到本地。(vue框架内使用)
一般实现echarts截图办法:
常用的两种截取echarts图的方法
1、echarts图本身自带的截图,能够在柱状图上显示一个下载的图标,点击图标实现下载图片到本地。
用法:直接在echarts的options中配置
toolbox: { show: true, feature: { saveAsImage: {} } },
2、通过canvas的方式,创建canvas画布,将前端需要截取的dom绘制到canvas里,再使用canvas自带函数将其转换为base64格式,再调用函数将base64格式文件转换为file格式,最后调用接口将file格式文件传给后端,后端处理后,将图片下载到本地。(将base64转换为file格式这步,具体看后端需要什么格式)(代码在最后面)
两种方式比较
第一种,相对简单,且不需要调用接口。但是echarts自带的下载图标不好调整,要是有比较严格的样式要求就不行。
第二种,能自定义下载点击触发事件的样式,但是效率比较低,图片下载起来相对比较慢。
但是至此需求还没有实现
上面两种解决方式都可以实现截图,但是当echarts图带上滚动条后就会产生问题。
如果是在echarts的options配置里面通过dataZoom来设置滚动条,大概会达到下面的效果,滚动条在柱状图上。通过设置当数据大于某个数值时柱状图上的滚动条出现。
这样的图是非常动态的,滑动滚动条时纵坐标和横坐标都会变化。这就说明,滚动条以外,未展示的区域还没有生成,所以不论是使用第一种或者是第二种方式进行截图,只要滚动条在柱状图上,就只能截取当前展示的部分,无法实现完整截图。
改进思路:
1、生成echarts图时就全部生成,柱状图不再改变。
2、为了适应页面宽度,echarts图区域宽度为100%,外侧父容器宽度动态变化。再外层容器宽度固定。
具体代码
<div style='width:1613px'>
<div class="column-container" style="overflow-x: auto" id="export-region">
<div
ref="countRedBlack"
class="echarts-box"
style="height: 400px; background-color: #fff"
:style="{ width: echartsDomWidth }"
></div>
</div>
</div>
data() {
return {
echartsData: null,//柱状图的数据
barChart: null,
echartsDom: null,//获得生成柱状图的dom区域
echartsDomWidth: ""//柱状图dom区域的宽度 动态变化
};
},
watch: {
//监听 柱状图dom区域的宽度 的变化,宽度随着数据量的改变而变化,数据量改变-->重新绘图 and 宽度变化
echartsDomWidth() {
this.$nextTick(() => {
this.disposeCharts();//销毁原来柱状图的函数
this.initEcharts();//重新生成柱状图的函数
});
}
},
methods(){
//销毁柱状图
disposeCharts() {
echarts.dispose(this.barChart);
},
//销毁柱状图
initEcharts(){
//根据具体需求生成柱状图
//需要注意的是 不能设置dataZoom,在柱状图上展示滚动条
//关键代码
//获取柱状图数据
this.echartsData = await this.getEchartsData();
//柱状图区域宽度动态变化 此处我设置的是 当数据量大于8时柱状图区域宽度增加,因为内部宽度超过了外部容器宽度,区域内就会出现浏览器自带滚动条
if (
this.echartsData.length > 8 &&
parseInt(this.echartsDomWidth) < 1613
) {
this.echartsDomWidth =
this.echartsDom.offsetWidth +
(this.echartsData.length - 8) * 200 +
"px";
}
}
//截图
handleExport() {
//生成url
const canvas = document.createElement("canvas"); //生成canvas标签
const canvasBox = document.getElementById("export-region"); //得到柱状图的dom
const scrollWidth = canvasBox.scrollWidth; //柱状图区域包括滚动区域在内的宽度
const offsetHeight = canvasBox.offsetHeight;
canvasBox.setAttribute(
"style",
`width:${scrollWidth};height:${offsetHeight}`
); //把柱状图区域的宽高赋值给dom 因为canvas需要宽改一致才能实现截图
canvas.width = scrollWidth;
canvas.height = offsetHeight;
const options = {
backgroundColor: null,
canvas: canvas,
useCORS: true,
allowTaint: true,
tainTest: false
};
html2canvas(canvasBox, options).then(canvas => {
let imgUrl = canvas.toDataURL("image/png");
//将base64文件转换为file
let file = dataURLFile(imgUrl, "plusMinus.png");
//组织参数
let formData = new FormData();
formData.append("redblackGraphFile", file, "截图.png");
//调用接口导出图片
exportEcharts(formData).then(res => {
let resBlob = new Blob([res.data], { type: "application/x-xlsx" });
let fileUrl = window.URL.createObjectURL(resBlob);
let link = document.createElement("a");
link.href = fileUrl;
link.setAttribute(
"download",
"带滚动条柱状图导出_" + formatDate(+new Date(), "YYYY_MM_DD") + ".xlsx"
);
//防止导出一遍后柱状图上的滚动条消失
canvasBox.setAttribute("style", `overflow-x:auto`);
link.click();
});
});
},
}
此方法对柱状图自带的saveAsImage同样有用,能完整的截出柱状图。最重要的思路就是,让柱状图一开始就完全生成,滚动条使用浏览器自带的滚动条,而不是echarts的滚动条。