<template>
<div class="chart-container">
<div class="upload-section">
<input
type="file"
accept=".xlsx, .xls"
@change="handleFileChange"
class="file-input"
/>
<button @click="generateChart" class="generate-btn">生成图表</button>
</div>
<div ref="chart" class="chart" style="width: 100%; height: 500px;"></div>
</div>
</template>
<script>
import * as echarts from 'echarts';
import * as XLSX from 'xlsx';
export default {
name: 'ExcelZoomChart',
data() {
return {
chartInstance: null,
excelData: null
};
},
methods: {
handleFileChange(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = (e) => {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
this.excelData = XLSX.utils.sheet_to_json(worksheet);
};
reader.readAsArrayBuffer(file);
},
generateChart() {
if (!this.excelData || this.excelData.length === 0) {
alert('请先上传有效的Excel文件');
return;
}
if (this.chartInstance) {
this.chartInstance.dispose();
}
this.chartInstance = echarts.init(this.$refs.chart);
// 获取Excel表头作为系列名称
const headers = Object.keys(this.excelData[0]);
const xAxisKey = headers[0]; // 使用第一列作为x轴数据
const seriesNames = headers.slice(1); // 其余列作为数据系列
// 处理x轴数据为数值类型
const processedData = this.excelData.map(row => {
const xValue = Number(row[xAxisKey]);
return {
...row,
[xAxisKey]: xValue
};
});
const option = {
title: {
text: 'Excel数据可视化',
left: 'center'
},
tooltip: {
trigger: 'axis',
formatter: params => `X: ${params[0].value[0]}<br/>Y: ${params[0].value[1].toFixed(2)}`
},
grid: {
top: '15%',
bottom: '25%'
},
xAxis: {
type: 'value',
name: 'X 轴'
},
yAxis: {
type: 'value',
name: 'Y 轴'
},
series: seriesNames.map(name => ({
name,
type: 'line',
showSymbol: false,
data: processedData.map(item => [item[xAxisKey], item[name]]),
smooth: true,
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(64, 158, 255, 0.6)' },
{ offset: 1, color: 'rgba(64, 158, 255, 0.1)' }
])
},
lineStyle: {
width: 2,
color: '#409EFF'
}
})),
dataZoom: [
{
type: 'inside',
xAxisIndex: 0,
start: 0,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true
},
{
type: 'slider',
xAxisIndex: 0,
start: 0,
end: 100,
bottom: 20,
height: 20,
fillerColor: 'rgba(64, 158, 255, 0.6)',
borderColor: '#409EFF'
},
{
type: 'inside',
yAxisIndex: 0,
zoomOnMouseWheel: 'shift',
moveOnMouseMove: false
}
],
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {}
},
right: 20
}
};
this.chartInstance.setOption(option);
// 响应式调整
window.addEventListener('resize', this.resizeChart);
},
resizeChart() {
if (this.chartInstance) {
this.chartInstance.resize();
}
}
},
beforeDestroy() {
window.removeEventListener('resize', this.resizeChart);
if (this.chartInstance) {
this.chartInstance.dispose();
}
}
};
</script>
<style scoped>
.chart-container {
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
}
.upload-section {
display: flex;
gap: 10px;
align-items: center;
}
.file-input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.generate-btn {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.generate-btn:hover {
background-color: #0d1b52;
}
.chart {
border: 1px solid #eee;
border-radius: 4px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
</style>
解释以上代码
最新发布