Files
profitManage1.2/src/components/echartsList/line.vue
T
2025-11-11 14:06:13 +08:00

311 lines
12 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>