Files
profitManage1.2/src/components/echartsList/line.vue
T

311 lines
12 KiB
Vue
Raw Normal View History

2025-11-11 14:06:13 +08:00
<template>
<div>
<DateTimeSelect ref="changeDateTime" v-if="!(lineData && lineData.hiddenTime)" :sideIcon="sideIcon" :dateDataTrans="dateDataTrans" :dateShowType="dateShowType" @dataChange="dataChangeValue"></DateTimeSelect>
<!-- <div :id="`lineChart` + num" style="width:100%;height: 100%;" />-->
<!-- 新增包裹图表和自定义下拉框的容器设置为相对定位 -->
<div class="chart-wrapper">
<!-- 自定义的下拉选择框 -->
<template v-if="this.lineData && this.lineData.unitSelList && this.lineData.unitSelList.length > 0">
<select :class="'yaxis-selector yaxis-selector' + num" v-model="selectedYAxisName">
<option v-for="item of this.lineData.unitSelList" :value="item.value">{{item.label}}</option>
</select>
</template>
<!-- 图表容器id 用于初始化 ECharts -->
<div :id="`lineChart` + num" class="chart-container"></div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
import DateTimeSelect from './dateTimeSelect.vue'
export default {
name: 'echartsLine',
components: {DateTimeSelect},
props: {
lineData: {
type: Object,
default: () => {}
},
title: {
type: String,
default: null
},
dateShowType: {
type: String,
default: null
},
dateDataTrans: {
type: Object,
default: () => ({})
},
chartData: {
type: Function,
default: () => {
}
},
sideIcon: {
type: Object,
default: () => {}
}
},
watch: {
lineData: {
handler(val) {
this.$nextTick(() => {
this.selectedYAxisName = this.lineData && this.lineData.unitModel || '';
this.getList(this.title, this.lineData);
});
},
deep: true,
immediate: true
},
// 新增:监听下拉框选择的变化
selectedYAxisName(newVal) {
if (newVal != (this.lineData && this.lineData.unitModel)) {
let times = this.lineData && this.lineData.hiddenTime ? [] : this.$refs.changeDateTime.dateRange;
this.chartData({timeArr: times}, newVal);
}
}
},
data() {
return {
lineDataList: '',
num: '',
selectedYAxisName: '' // 新增:用于绑定下拉框选中的值
}
},
created() {
this.num = Math.floor(Math.random() * 9000);
},
mounted() {
if (this.lineData && this.lineData.hiddenTime) {
this.$nextTick(() => {
this.getList(this.title, this.lineData);
});
}
},
methods: {
getList(title, dataXY) {
const lineDataListIntance = echarts.init(document.getElementById('lineChart' + this.num));
let titleList = [{text: title, x: '50%', y: '3%', textAlign: 'center',textStyle: {fontSize: 16}}];
if (dataXY && dataXY.titleSubtext) {
titleList.push(dataXY.titleSubtext);
} else if (dataXY && dataXY.titleVal) {
titleList[0] = Object.assign({},titleList[0], dataXY.titleVal);
}
let legendData = dataXY && dataXY.legend ? dataXY.legend : {};
if (dataXY && dataXY.legend && dataXY.legend.formatter) {
let formatData = {
formatter: function(params) {
const customSuffix = dataXY && dataXY.content && dataXY.content[params] || ' ';
return `${params} ${customSuffix}`;
},
};
legendData = Object.assign({}, legendData, formatData);
}
let series = [];
if (dataXY && dataXY.dataList && dataXY.dataList.length > 0) {
dataXY.dataList.forEach(item => {
let str = {
name: item && item.name || '',
type: 'line',
// showSymbol: false,
symbol: item && item.symbol || 'circle',
data: item && item.data || []
};
if (!(item && item.areaStyleNone)) {
str['areaStyle'] = {
opacity: 0.6
};
}
series.push(str);
});
} else {
series = [{
data: dataXY && dataXY.data || [],
type: 'line',
smooth: true,
// areaStyle: { // 阴影
// color: 'rgba(140, 158, 217, 1)'
// }
}];
}
let option = {
title: titleList,
legend: legendData,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
grid: {
top: dataXY && dataXY.gridTop || '80px',
left: dataXY && dataXY.gridLeft || '2%',
right: '4%',
bottom: dataXY && dataXY.gridBotm || '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
formatter: function(value) {
if (value) {
// 每4个字符换一行(根据实际文本长度调整)
const maxLength = 11;
let result = '';
let count = 0;
for (let i = 0; i < value.length; i++) {
count++;
result += value[i];
if (count % maxLength === 0 && i !== value.length - 1) {
result += '\n'; // 换行
}
}
return result;
}
},
// lineHeight: 10, // 行高(确保换行后不重叠)
},
data: dataXY && dataXY.lineXData || []
},
yAxis: {
type: 'value',
name: dataXY?.yAxisName || ' ',
nameTextStyle: dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0 ? {color: 'transparent'} : {}, // 将名称文本颜色设为透明,使其不可见
min: 0, // 自定义最小刻度(根据业务需求调整,如 0)
max: dataXY && dataXY.data && dataXY.data.length > 0 ? null : dataXY && dataXY.dataList && dataXY.dataList[0] && dataXY.dataList[0].data.length > 0 ? null : 100,
splitLine: {
show: true,
},
},
series: series
};
lineDataListIntance.setOption(option);
if (dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0) {
// 初始化图表后,调用方法定位下拉框
this.positionYAxisSelector(lineDataListIntance);
}
window.addEventListener("resize", () => {
lineDataListIntance.resize();
if (dataXY && dataXY.unitSelList && dataXY.unitSelList.length > 0) {
this.positionYAxisSelector(lineDataListIntance);
}
});
},
positionYAxisSelector(chartInstance) {
const selector = document.querySelector('.yaxis-selector' + this.num);
if (!selector || !chartInstance) return;
const chartDom = chartInstance.getDom();
const chartRect = chartDom.getBoundingClientRect();
// 获取图表配置项中的网格设置
const option = chartInstance.getOption();
const grid = option.grid && option.grid[0] ? option.grid[0] : {};
// 使用网格的 left 和 top 作为基准点
const gridLeft = this.parseGridValue(grid.left || '2%', chartRect.width);
const gridTop = this.parseGridValue(grid.top || '80px', chartRect.height);
// const labelAreaLeft = gridLeft - 100; // 向左偏移
// const labelAreaTop = gridTop + (chartRect.height / 2) - 10; // 垂直居中
// selector.style.left = `${chartRect.left + window.pageXOffset + labelAreaLeft}px`;
// selector.style.top = `${chartRect.top + window.pageYOffset + labelAreaTop}px`;
const labelAreaLeft = gridLeft - 5; // 向左偏移
const labelAreaTop = gridTop - 35; // 垂直居中
selector.style.left = `${labelAreaLeft}px`;
selector.style.top = `${labelAreaTop}px`;
},
// 辅助方法:解析网格值(百分比、像素等)
parseGridValue(value, containerSize) {
if (typeof value === 'number') return value;
if (typeof value === 'string') {
if (value.includes('%')) {
return (parseFloat(value) / 100) * containerSize;
} else if (value.includes('px')) {
return parseFloat(value);
}
}
return 0;
},
// updateChartOnYAxisChange(selectedValue) {
// // 根据选择的值,动态更新图表配置
// // 例如,可以更新 Y 轴的单位名称、最大值、最小值,甚至切换整个 series 的数据[2](@ref)
// const chartDom = document.getElementById('lineChart' + this.num);
// const chartInstance = echarts.getInstanceByDom(chartDom);
//
// if (chartInstance) {
// // 示例:更新 Y 轴的名称显示(虽然它是隐藏的,但可能用于 tooltip 等)
// const option = chartInstance.getOption();
// option.yAxis[0].name = this.getYAxisNameByValue(selectedValue); // 假设的方法,根据值返回要显示的名称文本
//
// // 示例:可以在这里根据 selectedValue 重新设置 series 的 data[5](@ref)
// // option.series[0].data = ... 从某个数据源获取新数据
//
// chartInstance.setOption(option);
// }
// },
// getYAxisNameByValue(value) {
// // 一个简单映射,将下拉框的值转换为实际要显示的轴名称
// const map = {
// 'value1': '温度 (°C)',
// 'value2': '湿度 (%)',
// 'value3': '压力 (Pa)'
// };
// return map[value] || '';
// },
dataChangeValue(val, timeArr, iconVal) {
// 调用父级页面传过来的事件,在父级中处理该方法的逻辑--
if (timeArr) {
this.chartData(timeArr);
}
if (iconVal) {
this.chartData({iconVal: iconVal})
}
// let lineDataList = days && days.length > 0 ? days: this.lineData.lineXData;
// this.getList(this.title, {data: this.lineData.data, lineXData: lineDataList});
}
}
}
</script>
<style scoped>
/* 新增样式 */
.chart-wrapper {
position: relative; /* 为绝对定位的下拉框提供参考 */
width: 100%;
height: 100%;
}
.chart-container {
width: 100%;
height: 100%;
}
.yaxis-selector {
position: absolute; /* 绝对定位,相对于 .chart-wrapper */
z-index: 10; /* 确保下拉框显示在图表上方 */
/* 初始位置,后续由 js 方法精细调整 */
top: 0;
left: 0;
background: white;
border: 1px solid #ccc;
border-radius: 3px;
padding: 2px 5px;
font-size: 12px;
}
</style>