You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
4.0 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="line-chart-page">
<div ref="chartRef" class="line-chart"></div>
<!-- 控制按钮 -->
<div class="controls">
<el-button @click="refreshData"></el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
const chartRef = ref<HTMLElement>();
let chartInstance: echarts.ECharts | null = null;
let isSmooth = false;
// 原始数据
const baseData = [160, 230, 224, 218, 135, 147, 260];
const categories = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
// 生成随机数据
const generateRandomData = () => {
return baseData.map((val) => Math.floor(val * (0.8 + Math.random() * 0.4)));
};
// 初始化图表
const initChart = () => {
if (!chartRef.value) return;
chartInstance = echarts.init(chartRef.value);
const option: EChartsOption = {
title: {
text: '周数据统计',
left: 'center',
top: 10
},
tooltip: {
trigger: 'axis',
formatter: '{b}: {c}'
},
xAxis: {
type: 'category',
data: categories,
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#ddd'
}
},
axisLabel: {
color: '#666'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: '#ddd'
}
},
axisLabel: {
color: '#666'
},
splitLine: {
lineStyle: {
color: '#f0f0f0'
}
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '60px',
containLabel: true
},
series: [
{
name: '数据',
type: 'line',
data: baseData,
smooth: true, //平滑曲线
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#409EFF',
borderColor: '#fff',
borderWidth: 2
},
lineStyle: {
width: 3,
color: '#409EFF'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(64, 158, 255, 0.3)'
},
{
offset: 1,
color: 'rgba(64, 158, 255, 0.05)'
}
])
},
emphasis: {
focus: 'series'
}
}
]
};
chartInstance.setOption(option);
// 初始调用一次 resize确保图表正确获取容器尺寸
setTimeout(() => {
chartInstance?.resize();
}, 10);
};
// 刷新数据
const refreshData = () => {
if (!chartInstance) return;
const newData = generateRandomData();
chartInstance.setOption({
series: [
{
data: newData,
type: 'line',
smooth: true
}
]
});
};
// 监听窗口大小变化 - 使用 ResizeObserver 更精确地监听容器变化
let resizeObserver: ResizeObserver | null = null;
const handleResize = () => {
chartInstance?.resize();
};
onMounted(() => {
initChart();
// 方案 1: 监听 window resize适用于视口大小变化
window.addEventListener('resize', handleResize);
// 方案 2: 使用 ResizeObserver 监听容器本身的大小变化(更精确)
if (chartRef.value && typeof ResizeObserver !== 'undefined') {
resizeObserver = new ResizeObserver(() => {
handleResize();
});
resizeObserver.observe(chartRef.value.parentElement!);
}
});
onUnmounted(() => {
resizeObserver?.disconnect();
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
});
</script>
<style scoped lang="scss">
.line-chart-page {
width: 100%;
height: 100%;
h2 {
text-align: center;
color: #333;
margin-bottom: 20px;
}
.line-chart {
width: 100%;
height: 100%;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.controls {
margin-top: 20px;
text-align: center;
.el-button {
margin-right: 10px;
}
}
}
</style>