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.

369 lines
12 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'
},
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(() => {
console.log(props.xAxisData, '======xAxisData')
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 = () => {
let allData = [];
props.seriesData.forEach(series => {
if (series.data) {
series.data.forEach(item => {
// 根据数据结构获取数值,可能是 [time, value] 或 {tm: time, value: value} 格式
const value = Array.isArray(item) ? item[1] : (item.value !== undefined ? item.value : item);
if (value !== undefined && value !== null && !isNaN(value)) {
allData.push(Number(value));
}
});
}
});
// 计算y轴范围
let yAxisMin = 0;
let yAxisMax = 100;
if (allData.length > 0) {
const minVal = Math.min(...allData);
const maxVal = Math.max(...allData);
// 添加一些边距,使图表更美观
const range = maxVal - minVal;
const margin = range > 0 ? range * 0.1 : 1;
yAxisMin = Math.floor((minVal - margin) * 100) / 100; // 保留两位小数
yAxisMax = Math.ceil((maxVal + margin) * 100) / 100; // 保留两位小数
// 如果数据值都很小,确保最小值不为负数(可根据实际需求调整)
if (minVal >= 0 && yAxisMin < 0) {
yAxisMin = 0;
}
}
const series = props.seriesData.map((item, index) => {
const colors = [
["#fccb05", "#f5804d"],
["#8bd46e", "#09bcb7"],
["#248ff7", "#6851f1"]
];
const color = colors[index % colors.length];
return {
name: props.legendData[index],
type: "line",
barWidth: item.data.length > 100 ? '15%' : "20",
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",
min: yAxisMin,
max: yAxisMax,
name: 'mm',
nameLocation: 'middle',
nameTextStyle: {//y轴上方单位的颜色
color: '#464b50'
},
nameGap: 50,
axisLine: {
show: true,
lineStyle: {
color: "#ccc",
},
},
splitLine: {
show: true,
lineStyle: {
color: "#ccc",
},
},
axisLabel: {
textStyle: {
color: "#000000",
},
// 添加formatter属性,保留两位小数
formatter: function (value) {
return value.toFixed(2);
}
},
},
dataZoom: [
{
show: true,
// height: 15,
xAxisIndex: [0],
bottom: "8%",
start: 0,
end: 100,
handleIcon:
"path://M306.1,413c0,2.2-1.8,4-4,4h-59.8c-2.2,0-4-1.8-4-4V200.8c0-2.2,1.8-4,4-4h59.8c2.2,0,4,1.8,4,4V413z",
handleSize: "110%",
handleStyle: {
color: "#d3dee5",
},
textStyle: {
color: "#000",
},
borderColor: "#90979c",
},
{
type: "inside",
show: true,
// height: 15,
start: 1,
end: 35,
},
// {
// type: 'inside'
// },
// {
// type: 'slider'
// }
],
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>