echarts支持多种canvas和svg的两种方式渲染图表,常用的几乎都是canvas,但是canvas渲染有个问题,在放大的情况下会失真模糊,而svg因为矢量的,无法如何放大都不会模糊。所以追求高质量的效果,都会选用svg的格式。
但svg模式下导出图片也只支持svg格式,但是用户使用的时候肯定是需要png或者jpeg。下面提供一种方案解决这个问题。
解决的原理是:自定义导出按钮,单独加个不可见的div,在导出时按照option重新渲染一个canvas的图表。有一个注意的点是如果用户在svg的图表中添加了操作,比如隐藏了图例,那么需要记下用户的操作,并且同步到canvas的模式下,可以通过echarts提供的action和event处理。
<div class="chart-content">
<div
:ref="id"
class="jy-chart"
:style="{ height: height }"
>
<a-tooltip placement="bottom" v-if="showExportBtn">
<template slot="title">
保存图片
</template>
<a-icon type="download" class="chart_export" @click="echartExport()"/>
</a-tooltip>
</div>
<!-- chart副本,用于导出图片 -->
<div v-if="isShowExport" ref="sub_Chart" :style="{ height: curHeight,width:curWidth,display:'none' }"></div>
</div>
/**
* 导出图片
*/
echartExport(){
//获取svg模式下的图标宽高
this.curHeight=this.$refs[this.id].offsetHeight+'px';
let chartWidth=this.$refs[this.id].offsetWidth;
this.curWidth=chartWidth+'px';
this.isShowExport=true;
this.$nextTick(()=> {
//加载canvas模式的图表
let barChart = this.$echarts.getInstanceByDom(this.$refs['sub_Chart']);
if (barChart == undefined) {
barChart = this.$echarts.init(this.$refs['sub_Chart']);
}
//调用导出方法
exportImg(barChart, this.chartOption,'line',this.legendSelected,chartWidth)
});
//销毁图表
this.$nextTick(()=>{
this.isShowExport=false;
})
}
export function exportImg(barChart,oriChartOption,chartType,legendSelected,chartWidth){
//深拷贝option 防止特殊操作影响原图表
let chartOption=cloneDeep(oriChartOption)
//图例是翻页的情况,需要特殊处理转成正常模式,并调整距离。
if(chartOption.legend && chartOption.legend.type==='scroll'){
if(['line','bar'].includes(chartType)){
chartOption.legend.type='plain'
chartOption.legend.top='10'
}
if(chartType=='pie' && chartOption.series.length && chartOption.series[0].data.length>14){
chartOption.legend.type='plain'
chartOption.legend.left='50%'
}
}
barChart.setOption(chartOption);
barChart.resize();
//同步原图表的操作 此处只有图例的隐藏 通过action绑定
let timeout=200;
legendSelected && Object.keys(legendSelected).forEach(key=>{
if(!legendSelected[key]){
if(chartType=='pie'){
timeout=500
}
//执行事件
barChart.dispatchAction({
type: 'legendUnSelect',
// 图例名称
name: key
})
}
})
// action事件有延时,图标的隐藏也有延时特效,所以导出操作需要延时处理
setTimeout(()=>{
let fileName = chartOption.toolbox.feature.saveAsImage.name;
var imageType = 'image/png';
var dataURI = barChart.getDataURL({
type:'png',
backgroundColor: '#fff'
});
var ua = window.navigator.userAgent;
if (ua.indexOf('MSIE ') > 0 || ua.indexOf('Trident/') > 0 || ua.indexOf('Edge') > 0) {
var dataURItoBlob = function (dataURI) {
var binary = atob(dataURI.split(',')[1]);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], { type: imageType });
}
var blob = dataURItoBlob(dataURI);
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else {
var link = document.createElement("a");
link.setAttribute("href", dataURI);
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
}
},timeout)
}