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

397 lines
15 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="draggable-chart" :style="{ top: `${position.top}px`, left: `${position.left}px` }"
@mousedown="startDrag">
<el-card class="box-card">
<div id="chart" :style="{ width: `${dimensions.width}px`, height: `${dimensions.height}px` }"></div>
<div class="resize-handle" @mousedown.stop="startResize"></div> <!-- 添加调整大小控制柄 -->
</el-card>
</div>
</template>
<script>
import * as echarts from 'echarts';
import { CanvasRenderer } from 'echarts/renderers';
echarts.use([CanvasRenderer]);
export default {
props: {
data: Array,
title: String,
titleSize: Number,
titlePosition: String,
showAxis: Boolean,
showYAxis: Boolean,
barWidth: Number,
yXAxisMaxValue: Number,
chartType: String,
chartNum: Number,
wellParamData: {
type: Object // 提供一个默认值为一个空对象
},
reverseScatter: Boolean
},
data() {
// 初始化拖动和调整大小状态和偏移量
return {
position: { top: 150, left: 400 },
dragging: false,
offset: { x: 0, y: 0 },
dimensions: { width: 1000, height: 600 }, // 初始宽度和高度
resizing: false,
resizeStart: { x: 0, y: 0 }
};
},
mounted() {
this.initChart();
},
watch: {
data: {
handler: 'initChart',
deep: true,
},
title: 'initChart',
titleSize: 'initChart',
titlePosition: 'initChart',
showAxis: 'initChart',
showYAxis: 'initChart',
barWidth: 'initChart',
yXAxisMaxValue: 'initChart',
chartType: 'initChart',
wellParamData: {
handler: 'initChart',
deep: true
},
reverseScatter: {
handler: 'initChart',
deep: true // 启用深度监听
}
},
methods: {
initChart() {
const chartDom = document.getElementById('chart');
this.chart = echarts.init(chartDom);
if (this.chartNum === 5) {
// 动态确定横坐标和纵坐标参数名称
const allParams = Object.values(this.wellParamData).flat(); // 展平所有数据
const paramNames = [...new Set(allParams.map(item => item.ParamName))]; // 获取唯一参数名称
if (paramNames.length !== 2) {
console.error("数据中的参数名称数量不是2个无法绘制散点图");
return;
}
const shapes = ['circle', 'rect', 'triangle', 'diamond', 'pin', 'arrow'];
let shapeIndex = 0;
const [xParamName, yParamName] = this.reverseScatter ? paramNames : paramNames.reverse(); // 动态获取两个参数名称
let minXValue = 0;
let minYValue = 0;
const series = Object.entries(this.wellParamData).map(([key, paramList]) => {
const xValues = paramList
.filter(item => item.ParamName === xParamName)
.map(item => item.Point.Z); // 横坐标值 (垂直地应力)
if (xValues.length > 0) {
let thisMinXValue = Math.min(...xValues);
if (minXValue == 0 || minXValue > thisMinXValue) {
minXValue = thisMinXValue;
}
}
const yValues = paramList
.filter(item => item.ParamName === yParamName)
.map(item => item.Point.Z); // 纵坐标值 (加砂强度)
if (yValues.length > 0) {
let thisMinYValue = Math.min(...yValues);
if (minYValue == 0 || minYValue > thisMinYValue) {
minYValue = thisMinYValue;
}
}
// 匹配阶段号
const stageNos = paramList
.filter(item => item.ParamName === xParamName)
.map(item => item.StageNo);
// 将每个阶段的横纵坐标配对
const scatterData = stageNos.map((stage, index) => [
xValues[index], // X 值
yValues[index], // Y 值
stage, // 阶段号,用于提示
]);
const symbol = shapes[shapeIndex % shapes.length];
shapeIndex++;
return {
name: key, // 当前 series 的名称 (井号)
type: "scatter",
data: scatterData,
itemStyle: {
color: this.getRandomColor(), // 设置每个 series 的随机颜色
},
symbol,
// 设置不同的形状
symbolSize: 10, // 控制形状大小
};
});
const scatterOption = {
title: {
text: this.title,
left: this.titlePosition,
textStyle: {
fontSize: this.titleSize,
},
top: 'bottom',
},
tooltip: {
trigger: "item",
formatter: params => {
const stage = params.value[2];
return `${params.seriesName}<br>阶段号: ${stage}<br>${xParamName}: ${params.value[0]}<br>${yParamName}: ${params.value[1]}`;
},
},
legend: {
show: true,
type: "scroll",
orient: "horizontal",
top: 10,
},
xAxis: {
name: xParamName,
type: "value",
min: Math.floor(minXValue * 10) / 10
},
yAxis: {
name: yParamName,
type: "value",
min: Math.floor(minYValue * 10) / 10
},
series, // 将生成的 series 数据放入配置
};
this.chart.clear();
this.chart.setOption(scatterOption);
}
else if (this.chartNum == 4) {
let xValueName = '';
let minXValue = 0;
let minYValue = 0
let yValueName = '';
const series = Object.entries(this.wellParamData).map(([JH, params]) => {
let xValue = 0;
let yValue = 0
if (this.reverseScatter) {
xValue = params[0]?.Point.Z;
xValueName = params[0]?.ParamName;
yValue = params[1]?.Point.Z;
yValueName = params[1]?.ParamName;
} else {
xValue = params[1]?.Point.Z;
xValueName = params[1]?.ParamName;
yValue = params[0]?.Point.Z;
yValueName = params[0]?.ParamName;
}
if (minXValue == 0 || minXValue > xValue) {
minXValue = Math.floor(xValue * 10) / 10;
}
if (minYValue == 0 || minYValue > yValue) {
minYValue = Math.floor(yValue * 10) / 10;
}
return {
name: JH,
type: "scatter",
data: [[xValue, yValue]],
itemStyle: {
color: this.getRandomColor()
}
};
});
const scatterOption = {
title: {
text: this.title,
left: this.titlePosition,
textStyle: {
fontSize: this.titleSize,
},
top: 'bottom',
},
tooltip: {
trigger: "item",
formatter: params => {
return `${params.seriesName}<br>${xValueName}: ${params.value[0]}<br>${yValueName}: ${params.value[1]}`;
}
},
legend: {
show: true,
type: "scroll",
orient: "horizontal",
top: 10
},
xAxis: {
name: xValueName,
type: "value",
min: minXValue
},
yAxis: {
name: yValueName,
type: "value",
min: minYValue
},
series
}
this.chart.clear();
if (scatterOption.series.length > 0) {
this.chart.setOption(scatterOption);
}
}
else {
const wells = Object.keys(this.wellParamData);
const maxLength = Math.max(...Object.values(this.wellParamData).map(arr => arr.length));
const xAxisData = Array.from({ length: maxLength }, (_, i) => `${i + 1}`);
const seriesData = wells.map(well => {
const wellData = this.wellParamData[well]; // 获取某个井的数据
const colorItem = this.data.find(item => item.ParamName == wellData[0].ParamName); // 查找对应的 color 项
const color = colorItem ? colorItem.Color : 'gray';
const zValues = wellData.map(item => item.Point.Z);
return { color, zValues }; // 返回包含颜色和 z 值的对象
});
const firstSeriesData = seriesData.map(item => [item.color, item.zValues[0]]);
const option = {
title: {
text: this.title,
left: this.titlePosition,
textStyle: {
fontSize: this.titleSize,
},
top: 'bottom',
},
tooltip: {},
legend: {
data: wells
},
xAxis: this.chartType === 'pie' ? { show: false } : {
data: (this.chartNum == 0 || this.chartNum == 1 || this.chartNum == 4) ? xAxisData : wells,
show: this.showAxis,
axisLabel: {
rotate: 45 // 将标签旋转45度
}
},
yAxis: this.chartType === 'pie' ? { show: false } : {
axisLine: {
show: true,
},
max: this.yXAxisMaxValue,
show: this.showYAxis,
},
series: (this.chartNum == 0 || this.chartNum == 1) ? wells.map((well, index) => ({
name: well,
type: this.chartType,
data: seriesData[index].zValues,
color: this.chartNum == 0 ? this.getRandomColor() : seriesData[index].color,
barWidth: this.barWidth // 动态设置柱宽
})) : [
{
type: this.chartType,
data: firstSeriesData.map(item => ({
value: item[1],
itemStyle: {
color: item[0],
}
})),
barWidth: this.barWidth
}
],
};
this.chart.clear();
if (option.series.length > 0) {
this.chart.setOption(option);
}
}
},
getRandomColor() {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
},
startResize(event) {
this.resizing = true;
this.resizeStart = { x: event.clientX, y: event.clientY };
document.addEventListener('mousemove', this.onResize);
document.addEventListener('mouseup', this.stopResize);
},
onResize(event) {
if (this.resizing) {
const deltaX = event.clientX - this.resizeStart.x;
const deltaY = event.clientY - this.resizeStart.y;
this.dimensions.width += deltaX;
this.dimensions.height += deltaY;
this.resizeStart = { x: event.clientX, y: event.clientY };
this.chart.resize(); // 更新图表大小
}
},
stopResize() {
this.resizing = false;
document.removeEventListener('mousemove', this.onResize);
document.removeEventListener('mouseup', this.stopResize);
},
startDrag(event) {
this.dragging = true;
this.offset.x = event.clientX - this.position.left;
this.offset.y = event.clientY - this.position.top;
document.addEventListener('mousemove', this.onDrag);
document.addEventListener('mouseup', this.stopDrag);
},
onDrag(event) {
if (this.dragging) {
this.position.left = event.clientX - this.offset.x;
this.position.top = event.clientY - this.offset.y;
}
},
stopDrag() {
this.dragging = false;
document.removeEventListener('mousemove', this.onDrag);
document.removeEventListener('mouseup', this.stopDrag);
},
},
};
</script>
<style scoped>
.box-card {
position: relative;
}
.draggable-chart {
position: absolute;
cursor: move;
z-index: 1000;
}
.resize-handle {
position: absolute;
width: 0;
height: 0;
right: 0;
bottom: 0;
border-left: 10px solid transparent;
border-top: 10px solid transparent;
border-right: 10px solid #37e40b;
/* 控制柄颜色 */
cursor: se-resize;
z-index: 10;
}
</style>