先展现一个echarts,并配置dataZoom,每页最多10条数据,超出滚动
<div class="echartsBox" id="echartsBox"></div>
onMounted(() => {
nextTick(() => {
var chartDom = document.getElementById('echartsBox');
myChart = echarts.init(chartDom);
option = {
grid: {
left: '0px', // 图表左边距
right: '50px', // 图表右边距
top: '50px', // 图表上边距
bottom: '0px', // 图表下边距
containLabel: true // 包含坐标轴标签在内
},
graphic: [{
type: 'text',
left: '15', // 根据需要调整位置
top: '20', // 根据需要调整位置
z: 100, // 设置 z 轴数值较高,确保文本显示在最前面
style: {
text: '课程内容', // 指定要显示的文本
fill: '#666666', // 文本颜色
fontSize: '14px',
}
}],
yAxis: {
// name: '课程内容',
type: 'category',
data: ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19', 'A20', 'A21', 'A22', 'A23', 'A24', 'A25'],
inverse: true,
},
xAxis: {
name: '得分',
type: 'value',
min: 5,
max: 0,
axisLabel: {
formatter: function (value: any) {
return Math.floor(value); // 取整数部分
}
},
},
dataZoom: [
{
type: "slider",
realtime: true, // 拖动时,是否实时更新系列的视图
// show:false, // 是否展示滚动条根据数据判断
startValue: 0,
endValue: 9, // 最多10条 超出滚动
width: 5,
height: "75%",
top: "12.5%",
right: 0,
brushSelect: false,
yAxisIndex: [0, 1], // 控制y轴滚动
fillerColor: "#0093ff", // 滚动条颜色
borderColor: "rgba(17, 100, 210, 0.12)",
backgroundColor: "#cfcfcf", //两边未选中的滑动条区域的颜色
handleSize: 0, // 两边手柄尺寸
showDataShadow: false, //是否显示数据阴影 默认auto
showDetail: false, // 拖拽时是否展示滚动条两侧的文字
zoomLock: true,
moveHandleStyle: {
opacity: 0,
},
},
{
type: "inside",
startValue: 0,
endValue: 10,
minValueSpan: 10,
yAxisIndex: [0],
zoomOnMouseWheel: false, // 关闭滚轮缩放
moveOnMouseWheel: true, // 开启滚轮平移
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
},
],
series: [
{
data: [5, 0, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1],
type: 'bar',
label: {
show: true,
position: 'right',
formatter: '{c}分', // 显示数值
textStyle: {
color: '#333',
fontSize: 14
}
},
itemStyle: {
color: function (params: any) {
// 根据数据值取整后选择颜色
var value = Math.round(params.data);
var colors = ['#A6A6A6', '#FF7F2D', '#FCC946', '#A2C081', '#619C8A', '#016B25'];
return colors[value];
}
},
}
]
};
option && myChart.setOption(option);
})
})
效果:
调用echarts中getDataURL获取图表的数据 URL
// 下载echarts
const downloadBtn = (() => {
nextTick(() => {
const loading = ElLoading.service({
lock: true,
text: '图表生成中',
background: 'rgba(0, 0, 0, 0.7)',
})
// 需要3s左右生成
setTimeout(() => {
loading.close()
// 获取图表的数据 URL
var dataURL = myChart.getDataURL({
type: 'png', // 可以根据需要修改为其他格式,如 'jpeg'
pixelRatio: 2, // 图片分辨率,根据需要进行调整
backgroundColor: '#fff' // 图片背景色,根据需要进行调整
});
// 创建一个虚拟的下载链接并模拟点击下载
var link = document.createElement('a');
link.href = dataURL;
link.download = 'echarts_image.png'; // 下载的文件名,可以根据需要修改
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, 3000)
})
})
问题来了:如数据不分页则可以下载全数据,如数据分页了则只能下载出可视区内容,如何解决?
解决思路:echarts最终生成了canvas,canvas的宽高就是当前可视区的宽高,那么是否可以动态计算高度???
解决:
新增一个容器,这个容器为动态计算高度后导出使用
<!-- 导出echarts使用 -->
<div id="newEchartsBox" style="display:none;"></div>
// 下载echarts
const downloadBtn = (() => {
// 获取完整的数据
const fullData = myChart.getOption();
let newOption = fullData
newOption.dataZoom = []
//
var chartDom: any = document.getElementById('newEchartsBox');
chartDom.style.width = '600px'
chartDom.style.height = 50 * fullData.series[0].data.length + 'px'
//
newMyChart = echarts.init(chartDom);
//
newOption && newMyChart.setOption(newOption);
//
nextTick(() => {
const loading = ElLoading.service({
lock: true,
text: '图表生成中',
background: 'rgba(0, 0, 0, 0.7)',
})
// 需要3s左右生成
setTimeout(() => {
loading.close()
// 获取图表的数据 URL
var dataURL = newMyChart.getDataURL({
type: 'png', // 可以根据需要修改为其他格式,如 'jpeg'
pixelRatio: 2, // 图片分辨率,根据需要进行调整
backgroundColor: '#fff' // 图片背景色,根据需要进行调整
});
// 创建一个虚拟的下载链接并模拟点击下载
var link = document.createElement('a');
link.href = dataURL;
link.download = 'echarts_image.png'; // 下载的文件名,可以根据需要修改
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, 3000)
})
});
通过getOption获取echarts数据,根据数据长度动态设置新容器的高度,并赋值,赋值时把dataZoom清空,这里就不需要分页了,因为不做回显。
然后通过新容器调用echarts导出图片,问题完美解决。
源码如下:
<template>
<div class="kcnrzt">
<div class="left">
<div class="l">
已选<br />课程内容
</div>
<div class="r">
<el-scrollbar>
<div class="list">
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
<div class="item">11111111111111111111111111111111111111111111111111111111111111111</div>
</div>
</el-scrollbar>
</div>
</div>
<div class="right">
<div class="exportBtn" @click="downloadBtn">导出报告</div>
<div class="echartsBox" id="echartsBox"></div>
</div>
</div>
<!-- 导出echarts使用 -->
<div id="newEchartsBox" style="display:none;"></div>
</template>
<script setup lang="ts">
import { ElLoading } from 'element-plus'
import { watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
import { dataStore } from '@/store'
let store = dataStore()
import * as echarts from 'echarts';
//
var myChart: any = null
var option: any = null
// 导出专用
var newMyChart: any = null
onMounted(() => {
nextTick(() => {
var chartDom = document.getElementById('echartsBox');
myChart = echarts.init(chartDom);
option = {
grid: {
left: '0px', // 图表左边距
right: '50px', // 图表右边距
top: '50px', // 图表上边距
bottom: '0px', // 图表下边距
containLabel: true // 包含坐标轴标签在内
},
graphic: [{
type: 'text',
left: '15', // 根据需要调整位置
top: '20', // 根据需要调整位置
z: 100, // 设置 z 轴数值较高,确保文本显示在最前面
style: {
text: '课程内容', // 指定要显示的文本
fill: '#666666', // 文本颜色
fontSize: '14px',
}
}],
yAxis: {
// name: '课程内容',
type: 'category',
data: ['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', 'A11', 'A12', 'A13', 'A14', 'A15', 'A16', 'A17', 'A18', 'A19', 'A20', 'A21', 'A22', 'A23', 'A24', 'A25'],
inverse: true,
},
xAxis: {
name: '得分',
type: 'value',
min: 5,
max: 0,
axisLabel: {
formatter: function (value: any) {
return Math.floor(value); // 取整数部分
}
},
},
dataZoom: [
{
type: "slider",
realtime: true, // 拖动时,是否实时更新系列的视图
// show:false, // 是否展示滚动条根据数据判断
startValue: 0,
endValue: 9, // 最多10条 超出滚动
width: 5,
height: "75%",
top: "12.5%",
right: 0,
brushSelect: false,
yAxisIndex: [0, 1], // 控制y轴滚动
fillerColor: "#0093ff", // 滚动条颜色
borderColor: "rgba(17, 100, 210, 0.12)",
backgroundColor: "#cfcfcf", //两边未选中的滑动条区域的颜色
handleSize: 0, // 两边手柄尺寸
showDataShadow: false, //是否显示数据阴影 默认auto
showDetail: false, // 拖拽时是否展示滚动条两侧的文字
zoomLock: true,
moveHandleStyle: {
opacity: 0,
},
},
{
type: "inside",
startValue: 0,
endValue: 10,
minValueSpan: 10,
yAxisIndex: [0],
zoomOnMouseWheel: false, // 关闭滚轮缩放
moveOnMouseWheel: true, // 开启滚轮平移
moveOnMouseMove: true, // 鼠标移动能触发数据窗口平移
},
],
series: [
{
data: [5, 0, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1],
type: 'bar',
label: {
show: true,
position: 'right',
formatter: '{c}分', // 显示数值
textStyle: {
color: '#333',
fontSize: 14
}
},
itemStyle: {
color: function (params: any) {
// 根据数据值取整后选择颜色
var value = Math.round(params.data);
var colors = ['#A6A6A6', '#FF7F2D', '#FCC946', '#A2C081', '#619C8A', '#016B25'];
return colors[value];
}
},
}
]
};
option && myChart.setOption(option);
})
//
window.addEventListener('resize', updateEcharts);
})
//
onBeforeUnmount(() => {
myChart.dispose();
//
window.removeEventListener('resize', updateEcharts);
})
//
const updateEcharts = (() => {
nextTick(() => {
myChart.resize();
})
})
//
watch(
() => store.isCollapse,
() => {
setTimeout(() => { updateEcharts() }, 300);
},
{
immediate: false, // 是否初始化立即执行一次, 默认是false
deep: true // 是否是深度监视, 默认是false
}
)
// 下载echarts
const downloadBtn = (() => {
// 获取完整的数据
const fullData = myChart.getOption();
let newOption = fullData
newOption.dataZoom = []
//
var chartDom: any = document.getElementById('newEchartsBox');
chartDom.style.width = '600px'
chartDom.style.height = 50 * fullData.series[0].data.length + 'px'
//
newMyChart = echarts.init(chartDom);
//
newOption && newMyChart.setOption(newOption);
//
nextTick(() => {
const loading = ElLoading.service({
lock: true,
text: '图表生成中',
background: 'rgba(0, 0, 0, 0.7)',
})
// 需要3s左右生成
setTimeout(() => {
loading.close()
// 获取图表的数据 URL
var dataURL = newMyChart.getDataURL({
type: 'png', // 可以根据需要修改为其他格式,如 'jpeg'
pixelRatio: 2, // 图片分辨率,根据需要进行调整
backgroundColor: '#fff' // 图片背景色,根据需要进行调整
});
// 创建一个虚拟的下载链接并模拟点击下载
var link = document.createElement('a');
link.href = dataURL;
link.download = 'echarts_image.png'; // 下载的文件名,可以根据需要修改
link.style.display = 'none';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, 3000)
})
});
</script>
<style scoped lang="scss">
.kcnrzt {
flex: 1;
display: flex;
justify-content: space-between;
overflow: hidden;
margin: 20px 15px;
.left {
width: 50%;
height: 100%;
border: 1px solid #DEDEDE;
display: flex;
overflow: hidden;
margin-right: 20px;
.l {
width: 87px;
border-right: 1px solid #DEDEDE;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
overflow: hidden;
}
.r {
flex: 1;
overflow: hidden;
.list {
.item {
padding: 10px;
font-size: 14px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #333333;
line-height: 22px;
border-bottom: 1px solid #DEDEDE;
}
}
}
}
.right {
width: 50%;
height: 100%;
position: relative;
margin-left: 20px;
.exportBtn {
width: 81px;
height: 30px;
background: #FFB100;
border-radius: 6px;
font-size: 14px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #FFFFFF;
line-height: 30px;
text-align: center;
cursor: pointer;
position: absolute;
top: 0;
right: 0;
z-index: 999;
}
.echartsBox {
width: 100%;
height: 100%;
}
}
}
</style>