图表导出与打印
数据可视化中的图表导出与打印
ECharts提供了多种方式将图表导出为图片或PDF格式,并支持直接打印。这些功能对于数据分享、报告生成和离线分析非常实用。开发者可以通过简单的配置实现复杂的导出需求。
导出为图片
ECharts内置了图片导出功能,可以通过getDataURL()
方法获取图表base64格式的URL:
// 获取图表实例
const chartInstance = echarts.init(document.getElementById('chart-container'));
// 导出为PNG
const pngDataUrl = chartInstance.getDataURL({
type: 'png',
pixelRatio: 2, // 提高导出图片质量
backgroundColor: '#fff'
});
// 创建下载链接
const link = document.createElement('a');
link.href = pngDataUrl;
link.download = 'chart-export.png';
link.click();
支持导出的图片格式包括:
png
(默认)jpeg
svg
(需要浏览器支持)
批量导出多个图表
实际项目中经常需要同时导出多个关联图表:
// 假设页面上有多个图表容器
const chartContainers = [
'#chart1',
'#chart2',
'#chart3'
];
// 使用Promise.all处理多个图表导出
Promise.all(chartContainers.map(container => {
const chart = echarts.init(document.querySelector(container));
return chart.getDataURL({ type: 'png' });
})).then(urls => {
urls.forEach((url, index) => {
const a = document.createElement('a');
a.href = url;
a.download = `chart-${index+1}.png`;
a.click();
});
});
导出为PDF
虽然ECharts本身不直接支持PDF导出,但可以结合jsPDF等库实现:
import jsPDF from 'jspdf';
// 先获取图表图片数据
const chart = echarts.init(document.getElementById('chart'));
const imgData = chart.getDataURL({
type: 'jpeg',
quality: 0.95
});
// 创建PDF文档
const doc = new jsPDF();
doc.addImage(imgData, 'JPEG', 10, 10, 180, 100);
doc.save('chart-export.pdf');
打印图表
直接调用浏览器打印API可以打印图表:
function printChart() {
const printWindow = window.open('', '_blank');
const chartHtml = `
<!DOCTYPE html>
<html>
<head>
<title>Chart Print</title>
<style>
body { margin: 0; padding: 20px; }
#print-chart {
width: 100%;
height: 600px;
}
</style>
</head>
<body>
<div id="print-chart"></div>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script>
const chart = echarts.init(document.getElementById('print-chart'));
chart.setOption(${JSON.stringify(chart.getOption())});
setTimeout(() => window.print(), 500);
</script>
</body>
</html>
`;
printWindow.document.write(chartHtml);
printWindow.document.close();
}
高级导出配置
ECharts允许对导出过程进行精细控制:
// 自定义导出内容
chartInstance.getDataURL({
type: 'png',
excludeComponents: ['toolbox', 'dataZoom'], // 排除特定组件
pixelRatio: 3, // 高清导出
backgroundColor: '#f5f5f5',
connectedBackgroundColor: '#333' // 连接背景色
});
服务端导出
对于需要大量计算或保密的场景,可以在服务端完成导出:
// 前端发送配置到后端
const exportOnServer = async () => {
const option = chart.getOption();
const response = await fetch('/api/export-chart', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ option })
});
const blob = await response.blob();
saveAs(blob, 'server-export.png'); // 使用FileSaver.js
};
导出事件处理
可以监听导出相关事件实现自定义逻辑:
chart.on('finished', () => {
console.log('图表渲染完成,可以安全导出');
});
// 自定义工具栏按钮触发导出
chart.setOption({
toolbox: {
feature: {
myExport: {
show: true,
title: '自定义导出',
icon: 'path://M...',
onclick: () => {
// 自定义导出逻辑
}
}
}
}
});
导出性能优化
处理大型数据集导出时的性能问题:
// 临时简化数据提高导出速度
function exportOptimized() {
const originalOption = chart.getOption();
// 简化数据系列
const simplifiedOption = JSON.parse(JSON.stringify(originalOption));
simplifiedOption.series.forEach(series => {
if (series.data && series.data.length > 1000) {
series.data = downsampleData(series.data, 500);
}
});
// 使用简化配置导出
chart.setOption(simplifiedOption, { silent: true });
const imgUrl = chart.getDataURL();
// 恢复原始配置
chart.setOption(originalOption, { silent: true });
return imgUrl;
}
// 降采样函数示例
function downsampleData(data, maxPoints) {
if (data.length <= maxPoints) return data;
const step = Math.floor(data.length / maxPoints);
return data.filter((_, index) => index % step === 0);
}
导出样式定制
确保导出结果与屏幕显示一致:
// 强制使用打印样式
function getPrintStyleUrl() {
const style = document.createElement('style');
style.innerHTML = `
@media print {
body { background: white !important; }
.chart-container {
width: 100% !important;
height: auto !important;
}
}
`;
const blob = new Blob([style.innerHTML], { type: 'text/css' });
return URL.createObjectURL(blob);
}
// 应用打印样式
const printWindow = window.open('', '_blank');
printWindow.document.write(`
<link rel="stylesheet" href="${getPrintStyleUrl()}" />
<div class="chart-container">${document.getElementById('chart').outerHTML}</div>
`);
动态水印添加
导出时自动添加水印信息:
function exportWithWatermark() {
const canvas = chart.getDom().querySelector('canvas');
const ctx = canvas.getContext('2d');
// 添加水印
ctx.font = '20px Arial';
ctx.fillStyle = 'rgba(0,0,0,0.1)';
ctx.rotate(-20 * Math.PI / 180);
for (let i = -5; i < 15; i++) {
for (let j = -5; j < 15; j++) {
ctx.fillText('CONFIDENTIAL', i * 200, j * 100);
}
}
// 重置变换
ctx.setTransform(1, 0, 0, 1, 0, 0);
// 导出带水印的图片
return canvas.toDataURL('image/png');
}
导出前的数据处理
在导出前对图表数据进行最后处理:
function preprocessBeforeExport() {
const option = chart.getOption();
// 1. 确保所有数据标签可见
option.series.forEach(series => {
if (series.label) {
series.label.show = true;
series.label.position = 'top';
}
});
// 2. 调整图例位置
if (option.legend) {
option.legend.top = 'bottom';
}
// 3. 禁用动画确保导出时状态稳定
option.animation = false;
// 应用预处理配置
chart.setOption(option);
// 返回Promise确保渲染完成
return new Promise(resolve => {
setTimeout(() => {
resolve(chart.getDataURL());
}, 500);
});
}
多主题导出
支持根据不同场景导出不同主题的图表:
const themes = {
light: {
backgroundColor: '#ffffff',
textStyle: { color: '#333' }
},
dark: {
backgroundColor: '#1a1a1a',
textStyle: { color: '#eee' }
},
print: {
backgroundColor: '#fff',
textStyle: { color: '#000' },
grid: { borderWidth: 1 }
}
};
function exportWithTheme(themeName) {
const originalOption = chart.getOption();
const theme = themes[themeName] || {};
// 应用主题
chart.setOption(theme, true);
// 导出
const url = chart.getDataURL();
// 恢复原始主题
chart.setOption(originalOption, true);
return url;
}
导出分辨率控制
针对不同用途设置不同导出质量:
function exportWithQuality(quality) {
let pixelRatio, type;
switch(quality) {
case 'low':
pixelRatio = 1;
type = 'jpeg';
break;
case 'medium':
pixelRatio = 2;
type = 'png';
break;
case 'high':
pixelRatio = 3;
type = 'png';
break;
case 'print':
pixelRatio = 4;
type = 'png';
break;
default:
pixelRatio = 2;
type = 'png';
}
return chart.getDataURL({
type,
pixelRatio,
backgroundColor: '#fff'
});
}
导出状态保存与恢复
在导出过程中保持图表状态稳定:
class ChartExporter {
constructor(chartInstance) {
this.chart = chartInstance;
this.originalStates = [];
}
saveState() {
this.originalStates.push({
option: this.chart.getOption(),
width: this.chart.getDom().style.width,
height: this.chart.getDom().style.height
});
}
restoreState() {
const state = this.originalStates.pop();
if (state) {
this.chart.getDom().style.width = state.width;
this.chart.getDom().style.height = state.height;
this.chart.setOption(state.option);
}
}
export(config) {
this.saveState();
// 临时调整尺寸
if (config.width && config.height) {
this.chart.getDom().style.width = config.width;
this.chart.getDom().style.height = config.height;
this.chart.resize();
}
return new Promise(resolve => {
setTimeout(() => {
const url = this.chart.getDataURL(config);
this.restoreState();
resolve(url);
}, 300);
});
}
}
// 使用示例
const exporter = new ChartExporter(chart);
exporter.export({
type: 'png',
width: '1200px',
height: '800px'
}).then(url => {
console.log('Exported with custom size:', url);
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn