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

310 lines
9.7 KiB

<template>
<!-- <div > -->
<div ref="ChartsTimeBarRef" style="height:100%;width: 100%;" class="chart-container"></div>
<!-- </div> -->
</template>
<script setup>
import * as echarts from "echarts";
import dayjs from 'dayjs'
import { onMounted, nextTick, ref, onUnmounted } from "vue";
const props = defineProps({
legendData: {
type: Array,
default: () => []
},
xAxisData: {
type: Array,
default: () => []
},
seriesData: {
type: Array,
default: () => []
},
textTitle: {
type: String,
default: ''
},
unit: {
type: String,
default: 'mm'
},
echartType: {
type: String,
default: 'bar'
},
grid: {
type: Object,
default: () => {
return {
left: "5%",
right: "5%",
bottom: "16%",
top: "16%",
containLabel: true,
}
}
}
})
const ChartsTimeBarRef = ref(null);
let echartsBar = null;
let resizeObserver = null;
// 监听props变化,确保数据更新后重新初始化图表
watch([() => props.legendData, () => props.xAxisData, () => props.seriesData], () => {
if (echartsBar) {
updateChart();
}
}, { deep: true });
onMounted(() => {
initEcharts();
window.addEventListener('resize', handleResize);
// 监听容器本身尺寸变化
if (ChartsTimeBarRef.value) {
resizeObserver = new ResizeObserver(handleResize);
resizeObserver.observe(ChartsTimeBarRef.value);
}
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
if (resizeObserver && ChartsTimeBarRef.value) {
resizeObserver.unobserve(ChartsTimeBarRef.value);
}
if (echartsBar) {
echartsBar.dispose();
}
});
const echartsLoading = ref(true);
const initEcharts = () => {
nextTick(() => {
if (ChartsTimeBarRef.value) {
echartsBar = echarts.init(ChartsTimeBarRef.value, "macarons");
let option = getChartOption();
echartsBar.setOption(option);
// 确保图表尺寸适应容器
const resizeChart = () => {
if (echartsBar && ChartsTimeBarRef.value) {
echartsBar.resize({
width: ChartsTimeBarRef.value.clientWidth,
height: ChartsTimeBarRef.value.clientHeight
});
}
};
// 初始化时调整一次大小
resizeChart();
}
});
};
const updateChart = () => {
nextTick(() => {
if (echartsBar) {
let option = getChartOption();
echartsBar.setOption(option, true); // 使用notMerge:true来完全替换旧选项
resizeChart();
}
});
};
const resizeChart = () => {
if (echartsBar && ChartsTimeBarRef.value) {
echartsBar.resize({
width: ChartsTimeBarRef.value.clientWidth,
height: ChartsTimeBarRef.value.clientHeight
});
}
};
const handleResize = () => {
if (echartsBar && ChartsTimeBarRef.value) {
// 添加防抖机制,避免频繁触发
clearTimeout(window.resizeTimer);
window.resizeTimer = setTimeout(() => {
echartsBar.resize({
width: ChartsTimeBarRef.value.clientWidth,
height: ChartsTimeBarRef.value.clientHeight,
animation: {
duration: 300
}
});
}, 100);
}
};
const getChartOption = () => {
console.log(props.legendData, props.xAxisData, props.seriesData)
const series = props.seriesData.map((item, index) => {
const colors = [
["#248ff7", "#6f5be8"],
["#248ff7", "#6f5be8"],
];
const color = colors[index % colors.length];
return {
name: props.legendData[index],
type: item.type,
barWidth: item.data.length > 100 ? '15%' : "20",
yAxisIndex: index,
showSymbol: false,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: color[0] },
{ offset: 1, color: color[1] }
]),
barBorderRadius: 12,
},
},
data: item.data?.map(val => val[1]),
};
});
let option = {
// backgroundColor: "#323a5e",
title: {
text: props.textTitle,
textStyle: {
align: "center",
color: "#000",
fontSize: 20,
},
top: "3%",
left: "50%",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
grid: props.grid,
legend: {
data: props.legendData,
right: 10,
top: 12,
textStyle: {
color: "#000",
},
itemWidth: 12,
itemHeight: 10,
// itemGap: 35
},
xAxis: {
type: "category",
data: props.xAxisData,
axisLine: {
lineStyle: {
color: "#ccc",
},
},
axisLabel: {
textStyle: {
fontFamily: "Microsoft YaHei",
},
showMinLabel: true, // 强制显示最小值标签
showMaxLabel: true, // 强制显示最大值标签
formatter: function (value) {
let date = dayjs(value)
let yearMonthDay = date.format('YYYY-MM-DD')
let hourMinute = date.format('HH:mm')
let result = `{a|${hourMinute}}\n{b|${yearMonthDay}}`;
if (props.timeType == 'day') {
result = `{b|${yearMonthDay}}`;
}
return result
},
rich: {
a: {
fontSize: 12,
color: '#000',
padding: [0, 0, 5, 0] // 上右下左的内边距,这里给上方小时分钟添加一点底部间距
},
b: {
fontSize: 12,
color: '#000'
}
}
},
},
yAxis: [
{ // 水位 - 右侧
type: 'value',
name: '水位 (m)',
axisLabel: { color: '#EE6666' },
nameTextStyle: { color: '#EE6666', fontWeight: 'bold' },
splitLine: {
show: true,
lineStyle: {
color: "#ccc",
},
},
},
{ // 雨量 - 左侧
type: 'value',
name: '雨量 (mm)',
inverse: true,
nameLocation: 'start',
position: 'right',
axisLabel: { color: '#1075FD' },
nameTextStyle: { color: '#1075FD', fontWeight: 'bold' },
splitLine: {
show: true,
lineStyle: {
color: "#ccc",
},
},
}
],
series: series,
};
return option
// var app = {
// currentIndex: -1,
// };
// setInterval(function () {
// var dataLen = option.series[0].data.length;
// // 取消之前高亮的图形
// myChart.dispatchAction({
// type: "downplay",
// seriesIndex: 0,
// dataIndex: app.currentIndex,
// });
// app.currentIndex = (app.currentIndex + 1) % dataLen;
// //console.log(app.currentIndex);
// // 高亮当前图形
// myChart.dispatchAction({
// type: "highlight",
// seriesIndex: 0,
// dataIndex: app.currentIndex,
// });
// // 显示 tooltip
// myChart.dispatchAction({
// type: "showTip",
// seriesIndex: 0,
// dataIndex: app.currentIndex,
// });
// }, 1000);
}
</script>
<style scoped>
.chart-container {
width: 100%;
height: 100%;
min-height: 300px;
position: relative;
}
</style>