3 changed files with 29 additions and 370 deletions
@ -1,369 +0,0 @@ |
|||||||
<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> |
|
||||||
Loading…
Reference in new issue