Commit 344e397f by zhaopanyu

zpy

parent 8b364239
<template>
<div class="app-container" v-loading="loading" element-loading-text="正在加载钻头设计数据...">
<div>
<div style="position: relative">
<canvas ref="plot" style="height: 700px; width: 100%; position: relative" />
<!-- 合并表头 -->
<div style="position: absolute; top: 5px; left: 770px; display: flex; margin-top: -4px; z-index: 1;">
<div
style="width: 85px; border-bottom: 1px solid #000000; border-right: 1px solid #000000; border-left: 0; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
布齿密度</div>
<div style="display: flex; flex-direction: column;">
<div
style="width: 270px;border-right: 1px solid #000000; border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
刀翼设计
</div>
<div style="display: flex;">
<div
style="width: 150px; border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
刀翼数</div>
<div
style="width: 119px;border-right: 1px solid #000000; border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
冠部轮廓</div>
</div>
</div>
<div style="display: flex; flex-direction: column;">
<div
style="width: 300px;border-right: 1px solid #000000; border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
切削齿
</div>
<div style="display: flex;">
<div
style="width: 120px; border-right: 1px solid #000000;border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
尺寸(mm)</div>
<div
style="width: 180px;border-right: 1px solid #000000; border-bottom: 1px solid #000000; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
后倾角(°)</div>
</div>
</div>
</div>
<!-- 添加伽马和纵波时差表头 -->
<div style="position: absolute; top: 5px; left: 50px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 100px;">
<div
style="width: 98px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
伽马/纵波时差
</div>
</div>
</div>
<!-- 添加层位表头 -->
<div style="position: absolute; top: 20px; left: 345px; display: flex;margin-top: -4px;">
<div style="display: flex; width: 100px;">
<div
style="width: 70px; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; ">
层位</div>
</div>
</div>
<!-- 添加单轴线压强度表头 -->
<div style="position: absolute; top: 5px; left: 385px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 100px;">
<div
style="width: 98px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
单轴线压强度
</div>
</div>
</div>
<!-- 添加岩石可钻性级值表头 -->
<div style="position: absolute; top: 5px; left: 485px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 100px;">
<div
style="width: 98px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
岩石可钻性级值
</div>
</div>
</div>
<!-- 添加研磨性系数表头 -->
<div style="position: absolute; top: 5px; left: 585px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 100px;">
<div
style="width: 98px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
研磨性系数
</div>
</div>
</div>
<!-- 添加均质性系数表头 -->
<div style="position: absolute; top: 5px; left: 685px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 80px;">
<div
style="width: 78px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
均质性系数
</div>
</div>
</div>
<!-- 添加钻头尺寸表头 -->
<!-- <div style="position: absolute; top: 10px; left: 150px; display: flex; margin-top: -4px; z-index: 2;">
<div style="display: flex; width: 173px;">
<div
style="width: 180px; height: 73px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 10px; font-weight: bold; background-color: #f3f8ff;">
<div>钻头尺寸(mm)</div>
<div style="width: 100%; height: 1px; background-color: #000; margin-top: 5px;"></div>
<div
style="display: flex; justify-content: space-between; width: 100%; padding: 0 10px; margin-top: 5px;">
<span>{{ this.curveData['ztccmax'] !== undefined ? this.curveData['ztccmax'] : '-'
}}</span>
<span>{{ this.curveData['ztccmin'] !== undefined ? this.curveData['ztccmin'] : '-'
}}</span>
</div>
</div>
</div>
</div> -->
<!-- 原有的列结构 -->
<div
style="position: absolute; top: 50px; left: 775px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
</div>
<div
style="position: absolute; top: 50px; left: 805px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
</div>
<div
style="position: absolute; top: 50px; left: 835px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
</div>
<div
style="position: absolute; top: 50px; left:865px; font-size: 10px; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: center;">
4</div>
<div
style="position: absolute; top: 50px; left:895px; font-size: 10px; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: center;">
5</div>
<div
style="position: absolute; top: 50px; left: 925px; font-size: 10px; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: center;">
6</div>
<div
style="position: absolute; top: 50px; left: 955px; font-size: 10px; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: center;">
7</div>
<div
style="position: absolute; top: 50px; left: 985px; font-size: 10px; font-weight: bold; display: flex; flex-direction: column; align-items: center; justify-content: center;">
8</div>
<div
style="position: absolute; top: 40px; left: 1015px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
长抛物线</div>
<div
style="position: absolute; top: 30px; left: 1045px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
中等抛物线</div>
<div
style="position: absolute; top: 40px; left: 1075px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
短抛物线</div>
<div
style="position: absolute; top: 50px; left: 1100px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
鱼尾型</div>
<div
style="position: absolute; top: 50px; left: 1135px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
13</div>
<div
style="position: absolute; top: 50px; left: 1165px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
16</div>
<div
style="position: absolute; top: 50px; left: 1195px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
19</div>
<div
style="position: absolute; top: 50px; left: 1225px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
24</div>
<div
style="position: absolute; top: 50px; left: 1255px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
15</div>
<div
style="position: absolute; top: 50px; left: 1285px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
18</div>
<div
style="position: absolute; top: 50px; left:1315px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
20</div>
<div
style="position: absolute; top: 50px; left: 1345px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
25</div>
<div
style="position: absolute; top: 50px; left: 1375px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
30</div>
<div
style="position: absolute; top: 50px; left: 1405px; font-size: 10px; writing-mode: vertical-rl; font-weight: bold;">
35</div>
<div class="well1Title" v-if="jjgTrue" style="position: absolute;top: 30px;left: 112px;font-size: 14px">
井身结构
</div>
<!-- 开次表头 -->
<div style="position: absolute; top: 3px; left: 1425px; width: 80px; height: 100px; z-index: 11;">
<div
style="width: 80px; height: 80px; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: bold; background-color: #f3f8ff; border: 1px solid #000000;">
开次
</div>
</div>
<!-- 开次信息显示区域 -->
<div ref="kcListContainer"
style="position: absolute; top: 90px; left: 1425px; width: 80px; height: 560px; overflow: visible; z-index: 10; border: 1px solid #000000; border-top: 0;">
</div>
</div>
<div id="tooltip-container" style="display: none;position: absolute"></div>
</div>
</div>
</template>
<script>
import { ComponentNodeFactoryRegistry } from '@int/geotoolkit/schematics/factory/ComponentNodeFactoryRegistry';
import { v3 as WellLogWidget } from '@int/impl/geotoolkit.welllog.widgets.js';
import { WellBoreData } from '@int/geotoolkit/schematics/data/WellBoreData';
import { LogAbstractVisual } from '@int/geotoolkit/welllog/LogAbstractVisual';
import { WellBoreNode, ViewMode } from '@int/geotoolkit/schematics/scene/WellBoreNode';
import { TrackType } from '@int/geotoolkit/welllog/TrackType';
import { HeaderType } from '@int/geotoolkit/welllog/header/LogAxisVisualHeader';
import { Rect } from '@int/geotoolkit/util/Rect';
import { LogData } from '@int/geotoolkit/welllog/data/LogData';
import { LogCurve } from '@int/geotoolkit/welllog/LogCurve';
import { Group } from '@int/geotoolkit/scene/Group';
import { CssLayout } from '@int/geotoolkit/layout/CssLayout';
import { Plot } from '@int/geotoolkit/plot/Plot';
import { MathUtil } from '@int/geotoolkit/util/MathUtil';
import { NodeTubingBW } from '@/views/wellTest/wellComData/NodeTubingBW';
import { NodeCementBW } from '@/views/wellTest/wellComData/NodeCementBW';
import { NodeCasingBW } from '@/views/wellTest/wellComData/NodeCasingBW';
//曲线数据
import curveData from '@/views/wellTest/wellComData/MutiWells.json';
//井结构数据
import mixin from "@/views/wellTest/wellComData/mixin.json"
import cjsj from "@/views/wellTest/wellComData/cjsj.json"
import wellLogCurve from "@/views/wellTest/wellComData/wellLogCurve.json"
import { TooltipTool } from '@/views/wellTest/wellCurveData/tooltipTool';
import { CssStyle } from '@int/geotoolkit/css/CssStyle';
import { getCjqxDataztyx, ztTj } from "@/api/system/cjsjLas";
//地层
import { LogMudLogSection } from '@int/geotoolkit/welllog/LogMudLogSection';
import { Text } from '@int/geotoolkit/scene/shapes/Text';
import { AnchorType } from '@int/geotoolkit/util/AnchorType';
export default {
name: "cjqx",
data() {
return {
// 加载状态
loading: false,
//井号
jhSelection: [],
qkSelection: [],
jh: '',
qk: '',
formInline: {
dcljList: [],
jhList: [],
qk: ''
},
options: [{
value: '录井曲线',
label: '录井曲线'
}],
curveData: {},
curve: {},
jjg: [],
//井最大深度
scale: '',
//井最小深度
scale1: '',
jjgTrue: false,
//对数曲线集合
logCurveList: [],
// 添加层位相关数据
layerColors: {}, // 存储层位和颜色的映射
uniqueLayers: [], // 存储唯一的层位列表
// 预定义的颜色数组
predefinedColors: [
'#fbd860', '#f3a43a', '#5fc0de', '#d74f4a', '#c6e679',
'#fce913',
],
// 开次数据
kcList: [],
// 图表实例
widgetInstance: null
}
},
mounted() {
this.onSearch()
},
methods: {
getQk() {
const jsjg = {
jh: ''
}
getQkNumber(jsjg).then(res => {
this.qkSelection = res.map(item => {
return {
value: item.qk,
label: item.qk
}
})
})
},
//查询按钮
onSearch() {
console.log('this.formInline', this.formInline)
const canvas = this.$refs.plot;
const parent = canvas.parentElement; // 获取父元素
if (canvas && parent) {
parent.removeChild(canvas); // 从父元素中移除 canvas 元素
// 创建一个新的 canvas 元素
this.newCanvas = document.createElement('canvas');
this.newCanvas.style.height = '650px';
this.newCanvas.style.width = '100%';
this.newCanvas.style.position = 'relative';
this.newCanvas.setAttribute('ref', 'plot'); // 添加 ref 属性
parent.appendChild(this.newCanvas); // 将新的 canvas 元素添加到父元素中
}
this.$refs.plot = this.newCanvas;
this.getWelllogData()
},
//重置按钮
resetForm() {
this.qk = '孤东'
this.jh = ''
this.formInline.dcljList = []
this.onSearch()
},
// 添加 processData 方法
processData(data, key) {
if (!data) {
console.warn(`${key} 数据为空`);
return [];
}
if (Array.isArray(data)) {
console.log(`${key} 数据长度:`, data.length);
return data;
}
console.warn(`${key} 数据格式不正确:`, data);
return [];
},
//获取数据
getWelllogData() {
this.loading = true; // 开始加载
this.formInline.jhList = []
this.formInline.jhList.push(this.jh)
this.formInline.qk = this.qk
console.log('this.formInline', this.formInline)
getCjqxDataztyx({ jh: this.$route.query.jh }).then(res => {
console.log('获取到的原始数据:', res)
this.scale = res.scale
this.scale1 = res.scale1
console.log('深度显示范围 - 起始(scale1):', this.scale1, '结束(scale):', this.scale);
// 初始化 curveData 对象
this.curveData = {}
// 处理钻头尺寸和层位数据
console.log('开始处理关键数据...');
// 特殊处理钻头尺寸数据
console.log('处理钻头尺寸数据');
// 检查是否有 ztccLeftList2 和 ztccRigntList2 数据
if (res.ztccLeftList2 && res.ztccRigntList2 && Array.isArray(res.ztccLeftList2) && res.ztccLeftList2.length > 0) {
console.log('使用 ztccLeftList2 和 ztccRigntList2 数据');
// 检查数据格式:如果是对象数组格式 [{ztcc: 33.76, dept: 3660.15}, ...]
if (typeof res.ztccLeftList2[0] === 'object' && res.ztccLeftList2[0].hasOwnProperty('dept') && res.ztccLeftList2[0].hasOwnProperty('ztcc')) {
console.log('数据是对象数组格式,直接使用');
this.curveData['钻头尺寸左'] = res.ztccLeftList2;
this.curveData['钻头尺寸右'] = res.ztccRigntList2;
} else {
console.log('数据是普通数组格式,进行处理');
this.curveData['钻头尺寸左'] = this.filterValidData(this.processData(res.ztccLeftList2, '钻头尺寸左'), '钻头尺寸左');
this.curveData['钻头尺寸右'] = this.filterValidData(this.processData(res.ztccRigntList2, '钻头尺寸右'), '钻头尺寸右');
}
// 显示前两个值用于头部展示
if (res.ztccmax !== undefined) {
this.curveData['ztccmax'] = res.ztccmax;
}
if (res.ztccmin !== undefined) {
this.curveData['ztccmin'] = res.ztccmin;
}
// 检查数据点的深度范围(仅对对象数组格式)
if (this.curveData['钻头尺寸左'].length > 0 && typeof this.curveData['钻头尺寸左'][0] === 'object' && this.curveData['钻头尺寸左'][0].hasOwnProperty('dept')) {
const deptValues = this.curveData['钻头尺寸左'].map(item => item.dept);
const minDept = Math.min(...deptValues);
const maxDept = Math.max(...deptValues);
console.log('钻头尺寸数据深度范围:', minDept, '-', maxDept);
// 如果数据深度范围与widget显示范围不匹配,更新scale1和scale
if (minDept < this.scale1 || maxDept > this.scale) {
console.log('数据深度范围超出显示范围,调整显示范围');
this.scale1 = Math.min(this.scale1, minDept);
this.scale = Math.max(this.scale, maxDept);
console.log('调整后的深度显示范围:', this.scale1, '-', this.scale);
}
}
console.log('钻头尺寸左数据(ztccLeftList2):', this.curveData['钻头尺寸左']);
console.log('钻头尺寸右数据(ztccRigntList2):', this.curveData['钻头尺寸右']);
} else {
console.warn('钻头尺寸数据无效或为空');
this.curveData['钻头尺寸左'] = [];
this.curveData['钻头尺寸右'] = [];
}
// 处理层位数据
this.curveData['层位'] = this.filterValidData(this.processData(res.cwList, '层位'), '层位');
// 处理层位颜色映射
this.processLayerData(this.curveData['层位']);
// 处理开次数据
this.kcList = res.kcList || [];
console.log('开次数据:', this.kcList);
// 处理其他数据...
this.curveData['伽马'] = this.filterValidData(this.processData(res.grList, '伽马'), '伽马');
this.curveData['纵波时差'] = this.filterValidData(this.processData(res.zbList, '纵波时差'), '纵波时差');
this.curveData['单轴线压强度'] = this.filterValidData(this.processData(res.dzkyList, '单轴线压强度'), '单轴线压强度');
this.curveData['岩石可钻性级值'] = this.filterValidData(this.processData(res.yskzxjzList, '岩石可钻性级值'), '岩石可钻性级值');
this.curveData['研磨性系数'] = this.filterValidData(this.processData(res.ymzsList, '研磨性系数'), '研磨性系数');
this.curveData['均质性系数'] = this.filterValidData(this.processData(res.cjzsList, '均质性系数'), '均质性系数');
this.curveData['布齿密度(低)'] = this.filterValidData(this.processData(res.bcmdXList, '布齿密度(低)'), '布齿密度(低)');
this.curveData['布齿密度(中)'] = this.filterValidData(this.processData(res.bcmdZList, '布齿密度(中)'), '布齿密度(中)');
this.curveData['布齿密度(高)'] = this.filterValidData(this.processData(res.bcmdMList, '布齿密度(高)'), '布齿密度(高)');
console.log('布齿密度(高)原始数据:', res.bcmdMList);
console.log('布齿密度(高)处理后数据:', this.curveData['布齿密度(高)']);
this.curveData['刀翼数4'] = this.filterValidData(this.processData(res.dysList4, '刀翼数4'), '刀翼数4');
this.curveData['刀翼数5'] = this.filterValidData(this.processData(res.dysList5, '刀翼数5'), '刀翼数5');
this.curveData['刀翼数6'] = this.filterValidData(this.processData(res.dysList6, '刀翼数6'), '刀翼数6');
this.curveData['刀翼数7'] = this.filterValidData(this.processData(res.dysList7, '刀翼数7'), '刀翼数7');
this.curveData['刀翼数8'] = this.filterValidData(this.processData(res.dysList8, '刀翼数8'), '刀翼数8');
this.curveData['冠部轮廓(长抛物线)'] = this.filterValidData(this.processData(res.gblkYwList, '冠部轮廓(长抛物线)'), '冠部轮廓(长抛物线)');
this.curveData['冠部轮廓(中等抛物线)'] = this.filterValidData(this.processData(res.gblkDList, '冠部轮廓(中等抛物线)'), '冠部轮廓(中等抛物线)');
this.curveData['冠部轮廓(短抛物线)'] = this.filterValidData(this.processData(res.gblkZList, '冠部轮廓(短抛物线)'), '冠部轮廓(短抛物线)');
this.curveData['冠部轮廓(圆形)'] = this.filterValidData(this.processData(res.gblkCList, '冠部轮廓(圆形)'), '冠部轮廓(圆形)');
this.curveData['尺寸(13)'] = this.filterValidData(this.processData(res.qxcccList13, '尺寸(13)'), '尺寸(13)');
this.curveData['尺寸(16)'] = this.filterValidData(this.processData(res.qxcccList16, '尺寸(16)'), '尺寸(16)');
this.curveData['尺寸(19)'] = this.filterValidData(this.processData(res.qxcccList19, '尺寸(19)'), '尺寸(19)');
this.curveData['尺寸(24)'] = this.filterValidData(this.processData(res.qxcccList22, '尺寸(24)'), '尺寸(24)');
this.curveData['后倾角(°)(15)'] = this.filterValidData(this.processData(res.qxcfqj15List, '后倾角(15)'), '后倾角(15)');
this.curveData['后倾角(°)(18)'] = this.filterValidData(this.processData(res.qxcfqj18List, '后倾角(18)'), '后倾角(18)');
this.curveData['后倾角(°)(20)'] = this.filterValidData(this.processData(res.qxcfqj20List, '后倾角(20)'), '后倾角(20)');
this.curveData['后倾角(°)(25)'] = this.filterValidData(this.processData(res.qxcfqj25List, '后倾角(25)'), '后倾角(25)');
this.curveData['后倾角(°)(30)'] = this.filterValidData(this.processData(res.qxcfqj30List, '后倾角(30)'), '后倾角(30)');
this.curveData['后倾角(°)(35)'] = this.filterValidData(this.processData(res.qxcfqj35List, '后倾角(35)'), '后倾角(35)');
this.curveData['mc'] = Array(200).fill(' ');
console.log('数据处理完成');
console.log('处理后的曲线数据:', this.curveData);
// 创建图表
this.createScene(this.$refs.plot);
}).catch(error => {
console.error('获取数据失败:', error);
this.$message.error('获取钻头设计数据失败,请重试');
}).finally(() => {
this.loading = false; // 结束加载
})
},
createScene(canvas) {
//网格结构
const widget = new WellLogWidget({
'header': { 'visible': true },
'footer': { 'visible': false },
'border': { 'visible': true },
'horizontalscrollable': false,
'verticalscrollable': false,
'nodefilter': (node) => node instanceof LogAbstractVisual || node instanceof WellBoreNode
})
.setAxisHeaderType(HeaderType.Simple)
.setHeaderHeight(90)
.setIndexUnit('m');
// 保存图表实例,用于后续交互
this.widgetInstance = widget;
// 设置深度范围
console.log('设置widget深度范围:', this.scale1, '-', this.scale);
// 检查钻头尺寸数据深度范围
let dataMinDepth = this.scale1;
let dataMaxDepth = this.scale;
if (this.curveData['钻头尺寸左'] && this.curveData['钻头尺寸左'].length > 0 &&
typeof this.curveData['钻头尺寸左'][0] === 'object' &&
this.curveData['钻头尺寸左'][0].hasOwnProperty('dept')) {
const deptValues = this.curveData['钻头尺寸左'].map(item => item.dept);
const minDept = Math.min(...deptValues);
const maxDept = Math.max(...deptValues);
console.log('钻头尺寸数据深度范围:', minDept, '-', maxDept);
// 调整深度范围以适应数据
dataMinDepth = Math.min(dataMinDepth, minDept);
dataMaxDepth = Math.max(dataMaxDepth, maxDept);
}
console.log('最终使用的深度范围:', dataMinDepth, '-', dataMaxDepth);
widget.setDepthLimits(dataMinDepth, dataMaxDepth);
//样式
this.applyModernThemeCSS(widget);
//曲线提示框
widget.connectTool(new TooltipTool(widget));
//添加坐标
widget.addTrack(TrackType.IndexTrack);
//曲线
widget.addTrack(TrackType.LinearTrack)
.setWidth(100)
.addChild([
this.createCurve(0, 30, '伽马', 'orange'),
this.createCurve(0, 30, '纵波时差', '#b3428a'),
].filter(curve => curve !== null));
// 添加钻头尺寸左右线
console.log('钻头尺寸左数据:', this.curveData['钻头尺寸左']);
console.log('钻头尺寸右数据:', this.curveData['钻头尺寸右']);
const ztccTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(175)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px', // 将表头放在 track 上方
'height': '45px'
})
);
// 只有当钻头尺寸数据有效时才添加曲线
if (this.curveData['钻头尺寸左'] && this.curveData['钻头尺寸左'].length > 0) {
console.log('添加钻头尺寸左曲线');
console.log('原始数据点数量:', this.curveData['钻头尺寸左'].length);
// 创建深度数组和值数组
let depths = [];
let values = [];
// 检查是否为对象数组格式
if (typeof this.curveData['钻头尺寸左'][0] === 'object' && this.curveData['钻头尺寸左'][0].hasOwnProperty('dept') && this.curveData['钻头尺寸左'][0].hasOwnProperty('ztcc')) {
console.log('钻头尺寸左数据是对象数组格式,提取dept和ztcc值');
let dataToProcess = this.curveData['钻头尺寸左'];
// 对于大数据集进行采样
if (dataToProcess.length > 1000) {
console.log('数据量过大,进行采样处理');
const sampleRate = Math.max(1, Math.floor(dataToProcess.length / 500)); // 确保不超过500个点
const sampledData = [];
// 确保包含第一个点
sampledData.push(dataToProcess[0]);
// 采样中间点
for (let i = sampleRate; i < dataToProcess.length - sampleRate; i += sampleRate) {
sampledData.push(dataToProcess[i]);
}
// 确保包含最后一个点
if (dataToProcess.length > 1) {
sampledData.push(dataToProcess[dataToProcess.length - 1]);
}
dataToProcess = sampledData;
console.log('采样后数据点数量:', dataToProcess.length);
}
// 从对象中提取dept和ztcc值
depths = dataToProcess.map(item => item.dept);
values = dataToProcess.map(item => item.ztcc);
console.log('钻头尺寸左 - 深度数组长度:', depths.length);
console.log('钻头尺寸左 - 值数组长度:', values.length);
console.log('钻头尺寸左 - 深度范围:', Math.min(...depths), '-', Math.max(...depths));
console.log('钻头尺寸左 - 值范围:', Math.min(...values), '-', Math.max(...values));
console.log('钻头尺寸左 - 前5个深度值:', depths.slice(0, 5));
console.log('钻头尺寸左 - 前5个ztcc值:', values.slice(0, 5));
} else {
// 使用常规方法创建深度数组
depths = Array.from({ length: this.curveData['钻头尺寸左'].length }, (_, i) => this.scale1 + i * 0.5);
values = this.curveData['钻头尺寸左'];
console.log('钻头尺寸左 - 使用常规方法,深度数组长度:', depths.length);
console.log('钻头尺寸左 - 使用常规方法,值数组长度:', values.length);
}
// 创建LogData
console.log('创建钻头尺寸左LogData,参数:', { depths: depths.slice(0, 3), values: values.slice(0, 3), indexunit: 'm' });
const logData = new LogData({ depths: depths, values: values, indexunit: 'm' });
console.log('LogData创建成功,最小值:', logData.getMinValue(), '最大值:', logData.getMaxValue());
// 创建曲线
const leftCurve = new LogCurve(logData)
.setLineStyle({
'color': '#00dae4', // 蓝色
'width': 2,
'pattern': [1]
})
.setName('钻头尺寸左');
console.log('钻头尺寸左曲线创建成功');
// 设置归一化范围
if (this.curveData['ztccmin'] !== undefined && this.curveData['ztccmax'] !== undefined) {
console.log('使用ztccmin和ztccmax设置归一化范围:', this.curveData['ztccmin'], '-', this.curveData['ztccmax']);
leftCurve.setNormalizationLimits(this.curveData['ztccmin'], this.curveData['ztccmax']);
} else {
// 检查是否为固定值数据
const isConstantValue = values.every(v => v === values[0]);
if (isConstantValue) {
console.log('钻头尺寸左为固定值:', values[0]);
// 对于固定值,手动设置归一化范围以确保曲线显示
const range = Math.abs(values[0]) * 0.1 || 10; // 使用10%的范围或默认10
leftCurve.setNormalizationLimits([values[0] - range, values[0] + range]);
console.log('设置固定值归一化范围:', values[0] - range, '-', values[0] + range);
}
}
ztccTrack.addChild(leftCurve);
console.log('钻头尺寸左曲线已添加到轨道');
}
if (this.curveData['钻头尺寸右'] && this.curveData['钻头尺寸右'].length > 0) {
console.log('添加钻头尺寸右曲线');
console.log('原始数据点数量:', this.curveData['钻头尺寸右'].length);
// 创建深度数组和值数组
let depths = [];
let values = [];
// 检查是否为对象数组格式
if (typeof this.curveData['钻头尺寸右'][0] === 'object' && this.curveData['钻头尺寸右'][0].hasOwnProperty('dept') && this.curveData['钻头尺寸右'][0].hasOwnProperty('ztcc')) {
console.log('钻头尺寸右数据是对象数组格式,提取dept和ztcc值');
let dataToProcess = this.curveData['钻头尺寸右'];
// 对于大数据集进行采样
if (dataToProcess.length > 1000) {
console.log('数据量过大,进行采样处理');
const sampleRate = Math.max(1, Math.floor(dataToProcess.length / 500)); // 确保不超过500个点
const sampledData = [];
// 确保包含第一个点
sampledData.push(dataToProcess[0]);
// 采样中间点
for (let i = sampleRate; i < dataToProcess.length - sampleRate; i += sampleRate) {
sampledData.push(dataToProcess[i]);
}
// 确保包含最后一个点
if (dataToProcess.length > 1) {
sampledData.push(dataToProcess[dataToProcess.length - 1]);
}
dataToProcess = sampledData;
console.log('采样后数据点数量:', dataToProcess.length);
}
// 从对象中提取dept和ztcc值
depths = dataToProcess.map(item => item.dept);
values = dataToProcess.map(item => item.ztcc);
console.log('钻头尺寸右 - 深度数组长度:', depths.length);
console.log('钻头尺寸右 - 值数组长度:', values.length);
console.log('钻头尺寸右 - 深度范围:', Math.min(...depths), '-', Math.max(...depths));
console.log('钻头尺寸右 - 值范围:', Math.min(...values), '-', Math.max(...values));
console.log('钻头尺寸右 - 前5个深度值:', depths.slice(0, 5));
console.log('钻头尺寸右 - 前5个ztcc值:', values.slice(0, 5));
} else {
// 使用常规方法创建深度数组
depths = Array.from({ length: this.curveData['钻头尺寸右'].length }, (_, i) => this.scale1 + i * 0.5);
values = this.curveData['钻头尺寸右'];
console.log('钻头尺寸右 - 使用常规方法,深度数组长度:', depths.length);
console.log('钻头尺寸右 - 使用常规方法,值数组长度:', values.length);
}
// 创建LogData
console.log('创建钻头尺寸右LogData,参数:', { depths: depths.slice(0, 3), values: values.slice(0, 3), indexunit: 'm' });
const logDataRight = new LogData({ depths: depths, values: values, indexunit: 'm' });
console.log('LogData创建成功,最小值:', logDataRight.getMinValue(), '最大值:', logDataRight.getMaxValue());
// 创建曲线
const rightCurve = new LogCurve(logDataRight)
.setLineStyle({
'color': '#0000FF', // 蓝色
'width': 2,
'pattern': [1]
})
.setName('钻头尺寸右');
console.log('钻头尺寸右曲线创建成功');
// 设置归一化范围
if (this.curveData['ztccmin'] !== undefined && this.curveData['ztccmax'] !== undefined) {
console.log('使用ztccmin和ztccmax设置归一化范围:', this.curveData['ztccmin'], '-', this.curveData['ztccmax']);
rightCurve.setNormalizationLimits(this.curveData['ztccmin'], this.curveData['ztccmax']);
} else {
// 检查是否为固定值数据
const isConstantValue = values.every(v => v === values[0]);
if (isConstantValue) {
console.log('钻头尺寸右为固定值:', values[0]);
// 对于固定值,手动设置归一化范围以确保曲线显示
const range = Math.abs(values[0]) * 0.1 || 10; // 使用10%的范围或默认10
rightCurve.setNormalizationLimits([values[0] - range, values[0] + range]);
console.log('设置固定值归一化范围:', values[0] - range, '-', values[0] + range);
}
}
ztccTrack.addChild(rightCurve);
console.log('钻头尺寸右曲线已添加到轨道');
}
// 层位轨道 - 无论是否有数据都创建轨道和表头
const layerTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(60)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px',
'height': '45px'
})
);
// 添加层位数据(如果有数据)
if (this.curveData['层位'] && Array.isArray(this.curveData['层位']) && this.curveData['层位'].length > 0) {
// 过滤出在当前显示范围内的层位
const visibleLayers = this.curveData['层位'].filter(layer => {
// 检查层位是否与显示范围有交集
return !(layer.endDepth < dataMinDepth || layer.startDepth > dataMaxDepth);
});
console.log('层位数据总数:', this.curveData['层位'].length);
console.log('可见层位数量:', visibleLayers.length);
console.log('可见层位详情:', visibleLayers.map(l => ({ layer: l.layer, start: l.startDepth, end: l.endDepth })));
console.log('显示深度范围:', dataMinDepth, '-', dataMaxDepth);
if (visibleLayers.length > 0) {
// 构建深度数组和值数组
// LogMudLogSection 的 setDepthsAndValues 方法工作原理:
// 深度数组和值数组长度必须相同,每个深度点对应一个值
// 对于层位显示,我们需要为每个层位区间创建深度边界点
const allDepths = [];
const allValues = [];
visibleLayers.forEach((layer, index) => {
// 确保深度在显示范围内
const startDepth = Math.max(layer.startDepth, dataMinDepth);
const endDepth = Math.min(layer.endDepth, dataMaxDepth);
// 如果是第一个层位,添加起始深度
if (index === 0) {
allDepths.push(startDepth);
allValues.push(layer.layer);
} else {
// 检查是否与前一个层位连续
const prevLayer = visibleLayers[index - 1];
const prevEndDepth = Math.min(prevLayer.endDepth, dataMaxDepth);
if (startDepth !== prevEndDepth) {
// 不连续,添加前一个层位的结束深度和当前层位的起始深度
allDepths.push(prevEndDepth);
allValues.push(prevLayer.layer);
allDepths.push(startDepth);
allValues.push(layer.layer);
} else {
// 连续,只添加当前层位的起始深度(边界点)
allDepths.push(startDepth);
allValues.push(layer.layer);
}
}
// 添加当前层位的结束深度(最后一个层位必须添加)
if (index === visibleLayers.length - 1 || endDepth !== visibleLayers[index + 1].startDepth) {
allDepths.push(endDepth);
allValues.push(layer.layer);
}
});
console.log('构建的深度数组长度:', allDepths.length);
console.log('构建的值数组长度:', allValues.length);
console.log('深度数组前10个:', allDepths.slice(0, 10));
console.log('值数组前10个:', allValues.slice(0, 10));
console.log('层位范围详情:', visibleLayers.map(l => ({
layer: l.layer,
start: l.startDepth,
end: l.endDepth,
inRange: l.startDepth >= dataMinDepth && l.endDepth <= dataMaxDepth
})));
layerTrack.addChild(
new Group()
.setLayout(new CssLayout())
.addChild(
new LogMudLogSection({
'fillstyles': (depth, text, i) => {
const layerInfo = visibleLayers.find(
range => depth >= range.startDepth && depth < range.endDepth
);
const color = layerInfo ? this.layerColors[layerInfo.layer] : '#FFFFFF';
return color;
},
'textstyles': {
'color': '#FFFFFF !important',
'font': 'bold 14px Arial',
'alignment': 'center',
'baseline': 'middle',
'angle': 0,
'fillstyle': {
'color': '#FFFFFF !important'
},
'css': {
'writing-mode': 'vertical-rl',
'text-orientation': 'upright',
'white-space': 'nowrap',
'text-shadow': '1px 1px 2px rgba(0,0,0,0.8)',
'color': '#FFFFFF !important'
}
},
'displaytext': (depth, text) => {
const layerInfo = visibleLayers.find(
range => depth >= range.startDepth && depth < range.endDepth
);
if (!layerInfo) return '';
return `<div style="color: white !important; font-weight: bold; font-size: 14px; writing-mode: vertical-rl; text-orientation: upright; text-shadow: 1px 1px 3px black; width: 100%; text-align: center;">${layerInfo.layer}</div>`;
},
'textposition': 'center',
'textoptions': {
'horizontaloffset': 0,
'sectionheight': 20,
'verticaloffset': 0,
'wordwrap': false,
'useHTML': true
}
})
.setDepthsAndValues(allDepths, allValues)
.setEllipsisString('')
)
);
} else {
console.warn('没有可见的层位数据');
}
}
// 单轴线压强度轨道 - 无论是否有数据都创建轨道和表头
const dzkTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(100)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px',
'height': '45px'
})
);
// 添加单轴线压强度曲线(如果有数据)
const dzkCurve = this.createCurve(0, 20, '单轴线压强度', 'orange');
if (dzkCurve !== null) {
dzkTrack.addChild(dzkCurve);
}
// 岩石可钻性级值轨道 - 无论是否有数据都创建轨道和表头
const yskzTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(100)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px',
'height': '45px'
})
);
// 添加岩石可钻性级值曲线(如果有数据)
const yskzCurve = this.createCurve(0, 20, '岩石可钻性级值', 'orange');
if (yskzCurve !== null) {
yskzTrack.addChild(yskzCurve);
}
// 研磨性系数轨道 - 无论是否有数据都创建轨道和表头
const ymzsTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(100)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px',
'height': '45px'
})
);
// 添加研磨性系数曲线(如果有数据)
const ymzsCurve = this.createCurve(0, 20, '研磨性系数', '#7cb342');
if (ymzsCurve !== null) {
ymzsTrack.addChild(ymzsCurve);
}
// 均质性系数轨道 - 无论是否有数据都创建轨道和表头
const cjzsTrack = widget.addTrack(TrackType.LinearTrack)
.setWidth(80)
.addChild(
new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'left': '0%',
'right': '0%',
'top': '-45px',
'height': '45px'
})
);
// 添加均质性系数曲线(如果有数据)
const cjzsCurve = this.createCurve(0, 20, '均质性系数', 'orange');
if (cjzsCurve !== null) {
cjzsTrack.addChild(cjzsCurve);
}
// 添加钻头体和布齿密度相关列
const styles = ['#A1FE44', '#fafafa'];
const styles2 = ['#FDFC3E', '#fafafa'];
const styles3 = ['#FFA616', '#fafafa'];
const styles5 = ['#48FEFE', '#fafafa'];
const styles6 = ['#1212FE', '#fafafa'];
// 通用函数来添加带检查的track
const addTrackWithCheck = (widget, dataKey, stylePair, width = 30) => {
if (!this.curveData[dataKey] || !Array.isArray(this.curveData[dataKey])) {
console.warn(`${dataKey} 数据无效,跳过创建`);
widget.addTrack(TrackType.LinearTrack).setWidth(width);
return;
}
// 检查mc数据
if (!this.curveData['mc'] || !Array.isArray(this.curveData['mc'])) {
console.warn(`mc 数据无效,使用空数组`);
this.curveData['mc'] = Array(this.curveData[dataKey].length).fill(' ');
}
// 确保mc数据长度足够
while (this.curveData['mc'].length < this.curveData[dataKey].length) {
this.curveData['mc'].push(' ');
}
console.log(`添加 ${dataKey} 轨道:`, {
dataLength: this.curveData[dataKey].length,
mcLength: this.curveData['mc'].length,
sampleData: this.curveData[dataKey].slice(0, 5),
sampleMc: this.curveData['mc'].slice(0, 5)
});
widget.addTrack(TrackType.LinearTrack)
.setName(" ")
.setWidth(width)
.addChild(
new LogMudLogSection({
'fillstyles': (depth, text, i) => {
const style = i === 2 ? '#fdd835' : stylePair[i % 2];
return style;
}
})
.setDepthsAndValues(this.curveData[dataKey], this.curveData['mc'])
.setEllipsisString(' ')
);
};
// 布齿密度
if (this.curveData['布齿密度(低)']) {
addTrackWithCheck(widget, '布齿密度(低)', styles);
}
if (this.curveData['布齿密度(中)']) {
addTrackWithCheck(widget, '布齿密度(中)', styles2);
}
console.log('准备添加布齿密度(高):', this.curveData['布齿密度(高)']);
if (this.curveData['布齿密度(高)'] && Array.isArray(this.curveData['布齿密度(高)']) && this.curveData['布齿密度(高)'].length > 0) {
console.log('添加布齿密度(高)轨道');
addTrackWithCheck(widget, '布齿密度(高)', styles3);
} else {
console.warn('布齿密度(高)数据无效,跳过创建轨道');
widget.addTrack(TrackType.LinearTrack).setWidth(30);
}
// 刀翼数4-8
['4', '5', '6', '7', '8'].forEach((num, index) => {
const key = `刀翼数${num}`;
if (this.curveData[key]) {
addTrackWithCheck(widget, key, [styles, styles2, styles5, styles3, styles][index]);
}
});
// 冠部轮廓
['长抛物线', '中等抛物线', '短抛物线', '圆形'].forEach((type, index) => {
const key = `冠部轮廓(${type})`;
if (this.curveData[key]) {
addTrackWithCheck(widget, key, [styles, styles2, styles3, styles][index]);
}
});
// 尺寸
['13', '16', '19', '24'].forEach((size, index) => {
const key = `尺寸(${size})`;
if (this.curveData[key]) {
addTrackWithCheck(widget, key, [styles, styles5, styles6, styles3][index]);
}
});
// 后倾角
['15', '18', '20', '25', '30', '35'].forEach((angle, index) => {
console.log(`正在添加后倾角(${angle})轨道`);
console.log(`数据:`, this.curveData[`后倾角(°)(${angle})`]);
const styleArray = [styles, styles3, styles2, styles5, styles6, styles3];
addTrackWithCheck(widget, `后倾角(°)(${angle})`, styleArray[index], 30);
});
// 添加层位图例
const legendGroup = new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'position': 'absolute',
'top': '10px',
'right': '100px', // 调整图例位置,避免与开次信息重叠
'background': 'rgba(255, 255, 255, 0.9)',
'padding': '10px',
'border': '1px solid #ccc',
'borderRadius': '4px',
'width': '120px'
});
// 添加图例标题
const legendTitle = new Text({
text: '层位图例',
textbaseline: 'top',
textalign: 'left'
})
.setTextStyle({
'color': '#000000',
'font': 'bold 12px Roboto'
})
.setLayoutStyle({
'position': 'absolute',
'left': '5px',
'top': '5px'
});
legendGroup.addChild(legendTitle);
// 添加图例项
this.uniqueLayers.forEach((layer, index) => {
const legendItemGroup = new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'position': 'absolute',
'left': '5px',
'top': `${index * 25 + 30}px`,
'width': '110px',
'height': '20px'
});
// 创建颜色块
const colorBox = new Group()
.setLayout(new CssLayout())
.setLayoutStyle({
'position': 'absolute',
'left': '0px',
'top': '2px',
'width': '15px',
'height': '15px',
'background': this.layerColors[layer],
'border': '1px solid #ccc'
});
// 创建文本标签
const legendText = new Text({
text: layer,
textbaseline: 'top',
textalign: 'left'
})
.setTextStyle({
'color': '#000000',
'font': '10px Roboto'
})
.setLayoutStyle({
'position': 'absolute',
'left': '25px',
'top': '2px'
});
legendItemGroup.addChild(colorBox);
legendItemGroup.addChild(legendText);
legendGroup.addChild(legendItemGroup);
});
widget.addChild(legendGroup);
widget.setLayoutStyle({
'top': 0,
'left': 0,
'bottom': 0,
'width': 1280
});
const plot = new Plot({
'canvasElement': canvas,
'autosize': false,
'root': widget
});
//适应大小
widget.fitToHeight();
// 完全禁用 widget 的工具,防止拖动
try {
const widgetTool = widget.getTool();
if (widgetTool) {
// 禁用所有工具
if (widgetTool.setEnabled) {
widgetTool.setEnabled(false);
}
}
} catch (e) {
console.warn('无法禁用 widget 工具:', e);
}
// 不添加 widget 的工具到 plot,避免拖动功能
// plot.getTool().add(widget.getTool());
// 通过事件监听完全阻止 header 区域的所有鼠标交互(防止拖动)
const canvasElement = canvas;
const headerHeight = 120; // header 高度,稍微大一点确保覆盖
// 完全阻止 header 区域的所有鼠标事件
const blockAllHeaderEvents = (e) => {
const rect = canvasElement.getBoundingClientRect();
const y = e.clientY - rect.top;
// 如果在 header 区域,完全阻止所有事件
if (y < headerHeight) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
return false;
}
};
// 使用捕获阶段,设置为非 passive,确保可以阻止默认行为
const eventOptions = { capture: true, passive: false };
// 阻止 header 区域的所有鼠标事件
canvasElement.addEventListener('mousedown', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('mousemove', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('mouseup', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('click', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('dblclick', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('contextmenu', blockAllHeaderEvents, eventOptions);
// 阻止所有拖动事件
canvasElement.addEventListener('dragstart', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('drag', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('dragend', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('dragover', blockAllHeaderEvents, eventOptions);
canvasElement.addEventListener('drop', blockAllHeaderEvents, eventOptions);
// 通过 CSS 禁用用户选择
canvasElement.style.userSelect = 'none';
canvasElement.style.webkitUserSelect = 'none';
canvasElement.style.mozUserSelect = 'none';
canvasElement.style.msUserSelect = 'none';
canvasElement.style.pointerEvents = 'auto'; // 确保事件可以捕获
// 图表初始化完成后渲染开次信息
this.renderGroupedKcList();
return plot;
},
//自定义css样式
applyModernThemeCSS(widget) {
widget.setCss(new CssStyle(
{
'css': [
'* {',
//字体颜色
' textstyle-font : 10px Roboto;',
' textstyle-color : #000;',
'}',
'.geotoolkit.welllog.header.AdaptiveLogCurveVisualHeader {',
' element-tracking-textstyle-font : bold 10px Roboto;',
//头部数字颜色
' element-tracking-textstyle-color : #000;',
'}',
//头部样式
'.geotoolkit.welllog.header.LogTrackHeader {',
//线性渐变
' borderfillstyle-style: lineargradient;',
//绝对坐标
' borderfillstyle-unittype: absoluteCoordinates;',
' borderfillstyle-startpoint-x: 0;',
' borderfillstyle-startpoint-y: 0;',
//头部背景色
' borderfillstyle-startcolor: rgba(255, 255, 255, 0);',
' borderfillstyle-endpoint-x: 0;',
' borderfillstyle-endpoint-y: 500;',
//头部背景色-渐变色
' borderfillstyle-endcolor: rgba(255, 255, 255, 0);',
//头部边框色
' borderlinestyle: null;', // if it is null then we use track border line style
' isbordervisible: true;',
' borders-left: true;',
' borders-top: true;',
' borders-right: true;',
' borders-bottom: true;',
'}',
//网格样式
'.geotoolkit.welllog.LogTrack {',
//线性渐变
' backgroundcolor-style: lineargradient;',
//绝对坐标
' backgroundcolor-unittype: absoluteCoordinates;',
' backgroundcolor-startpoint-x: 0;',
' backgroundcolor-startpoint-y: 0;',
//网格背景色
' backgroundcolor-startcolor: rgba(255, 255, 255, 0);',
' backgroundcolor-endpoint-x: 0;',
' backgroundcolor-endpoint-y: 500;',
' backgroundcolor-endcolor: rgba(255, 255, 255, 0);',
' clipping : true;',
' borderstrategy: top;',
' border-visible : true;',
' border-borderstyle: visible-bounds;',
' border-linestyle-color: #000;',
' border-linestyle-weight: blod;',
' border-linestyle-pixelsnapmode-x: true;',
' border-linestyle-pixelsnapmode-y: true;',
' border-borders-left : true;',
' border-borders-right : true;',
' border-borders-top : true;',
' border-borders-bottom : true;',
'}',
'.geotoolkit.welllog.LogAxis {',
//坐标字体颜色
' tickgenerator-major-labelstyle-color: red;',
' tickgenerator-major-labelstyle-font: 10px Roboto;',
//坐标字体颜色
' tickgenerator-major-tickstyle-color: #C8C8C8;',
//坐标横线粗细
' tickgenerator-major-tickstyle-width: 1;',
' tickgenerator-major-tickstyle-pixelsnapmode-x: true;',
' tickgenerator-major-tickstyle-pixelsnapmode-y: true;',
' tickgenerator-minor-tickstyle-color: #646464;',
' tickgenerator-edge-labelstyle-color: red;',
' tickgenerator-edge-tickstyle-color: #EFFFFF;',
' tickgenerator-edge-labelstyle-font: 10px Roboto;',
'}',
'.geotoolkit.welllog.LogCurve:highlight {',
' linestyle-width: 2;',
' linestyle-shadow-enable: true;',
' linestyle-shadow-blur: 2;',
' linestyle-shadow-offsetx: 0;',
' linestyle-shadow-offsety: 0;',
'}',
'.geotoolkit.welllog.LogTrack:highlight {',
' borderstrategy: top;',
// 高亮的边框颜色
' linestyle-color: grey;',
' linestyle-width: 2;',
' linestyle-shadow-enable: true;',
' linestyle-shadow-blur: 2;',
' linestyle-shadow-offsetx: 0;',
' linestyle-shadow-offsety: 0;',
'}'
].join('')
}))
},
//井结构数据
registerSchematicComponents(arr, data) {
const components = arr.map((component) => {
const { name, from, to, outer, inner } = component;
data.addComponent(name, {
geometry: {
depth: { from, to },
diameter: { outer, inner }
}
});
return JSON.parse(JSON.stringify(data.getComponents().slice(-1)[0]));
});
return components;
},
//井结构
createSchematicRegistry() {
const factoryRegistry = new ComponentNodeFactoryRegistry(false);
factoryRegistry.setFactory('tubing', (data) => new NodeTubingBW(data));
factoryRegistry.setFactory('cement', (data) => new NodeCementBW(data));
factoryRegistry.setFactory('casing', (data) => new NodeCasingBW(data));
return factoryRegistry;
},
//曲线
createCurve(from, step, curveMnemonic, color) {
try {
// 数据验证
if (!this.curveData) {
console.warn('curveData 对象不存在');
return null;
}
const values = this.curveData[curveMnemonic];
if (!values || !Array.isArray(values) || values.length === 0) {
console.warn(`${curveMnemonic} 的数据无效:`, values);
return null;
}
// 创建深度数组
const depths = Array.from({ length: values.length }, (_, i) => from + i * step);
// 创建数据对象
const data = new LogData(depths, values);
// 计算限制
let limits;
try {
limits = MathUtil.calculateNeatLimits(data.getMinValue(), data.getMaxValue(), false, false);
} catch (e) {
console.warn(`计算 ${curveMnemonic} 的限制时出错:`, e);
limits = [0, 1]; // 默认限制
}
// 创建曲线
return new LogCurve(data)
.setName(curveMnemonic)
.setNormalizationLimits(limits)
.setLineStyle({
'color': color,
'width': 1
});
} catch (e) {
console.error(`创建曲线 ${curveMnemonic} 时出错:`, e);
return null;
}
},
//对数曲线
createLogCurve(name, depths, values, color) {
const data = new LogData({
'name': name,
'depths': depths,
'values': values,
'indexunit': 'ft'
});
return new LogCurve(data)
.setLineStyle({
'color': color,
'width': 2
});
},
// 添加数据过滤函数
filterValidData(data, name) {
if (!data || !Array.isArray(data)) {
console.warn(`${name} 数据无效或为空`);
return []; // 始终返回空数组而不是 null
}
// 对于所有数据类型,确保返回的是数组
if (data.length === 0) {
console.warn(`${name} 数据长度为0`);
return [];
}
// 如果是mc数据,确保它有足够的长度
if (name === 'mc' && (!Array.isArray(data) || data.length === 0)) {
// 返回一个足够长的空字符串数组
return Array(200).fill(' ');
}
// 对于尺寸相关的数据特殊处理
if (name.startsWith('尺寸(')) {
console.log(`处理${name}数据开始`);
console.log(`原始数据长度: ${data.length}`);
// 确保数据是数值类型且有效
const validData = data.filter(value =>
value !== null &&
value !== undefined &&
!isNaN(value) &&
value !== 0
);
if (validData.length === 0) {
console.warn(`${name} 没有有效数据点`);
return [];
}
console.log(`${name} 有效数据点数量: ${validData.length}`);
return validData;
}
// 特殊处理层位数据
if (name === '层位') {
if (!data || !Array.isArray(data)) {
console.warn('层位数据无效或为空');
return []; // 返回空数组而不是null
}
const layerRanges = [];
let currentLayer = null;
let startDepth = null;
data.forEach((value, index) => {
const depth = this.scale1 + index * 0.5;
if (value && value !== currentLayer) {
if (currentLayer) {
layerRanges.push({
layer: currentLayer,
startDepth: startDepth,
endDepth: depth
});
}
currentLayer = value;
startDepth = depth;
}
});
if (currentLayer) {
layerRanges.push({
layer: currentLayer,
startDepth: startDepth,
endDepth: this.scale
});
}
return layerRanges.length > 0 ? layerRanges : [];
}
// 特殊处理钻头尺寸数据
if (name.includes('钻头尺寸')) {
console.log(`处理${name}数据,数据长度: ${data.length}`);
// 如果是对象数组格式,直接返回,不进行过滤
if (data.length > 0 && typeof data[0] === 'object' && data[0].hasOwnProperty('dept') && data[0].hasOwnProperty('ztcc')) {
console.log(`${name}是对象数组格式,直接返回`);
return data;
}
// 对于普通数组格式的处理
// 检查是否所有值都相同
const isAllSameValue = data.every(val => val === data[0]);
console.log(`${name}数据是否全部相同: ${isAllSameValue}, 第一个值: ${data[0]}`);
// 如果数据量太大,进行采样
if (data.length > 1000) {
const sampledData = [];
// 每100个点取一个,确保至少有20个点
const sampleRate = Math.max(1, Math.floor(data.length / 20));
// 确保至少包含第一个和最后一个点
sampledData.push(data[0]);
for (let i = sampleRate; i < data.length - sampleRate; i += sampleRate) {
sampledData.push(data[i]);
}
// 添加最后一个点
if (data.length > 1) {
sampledData.push(data[data.length - 1]);
}
console.log(`${name}数据采样后长度: ${sampledData.length}`);
return sampledData;
}
// 数据量不大,直接返回
return data;
}
// 其他数据的处理保持不变
const validData = [];
let totalPoints = 0;
let validPoints = 0;
data.forEach((value, index) => {
totalPoints++;
if (value !== 0) {
validPoints++;
validData.push({
depth: this.scale1 + index * 0.5,
value: value
});
}
});
if (validData.length > 0) {
console.log(`[${name}] 数据统计:`);
console.log(`- 总数据点: ${totalPoints}`);
console.log(`- 有效数据点: ${validPoints}`);
console.log(`- 有效率: ${((validPoints / totalPoints) * 100).toFixed(2)}%`);
console.log(`- 数据范围: ${Math.min(...validData.map(d => d.value))} ~ ${Math.max(...validData.map(d => d.value))}`);
} else {
console.warn(`[${name}] 未找到有效数据点`);
}
return validData.map(item => item.value);
},
// 生成随机颜色
generateRandomColor(index) {
// 使用预定义的颜色
if (index < this.predefinedColors.length) {
console.log(`为层位分配预定义颜色: ${this.predefinedColors[index]}`);
return this.predefinedColors[index];
}
// 如果预定义颜色用完,生成随机颜色
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
console.log(`生成随机颜色: ${color}`);
return color;
},
// 处理层位数据
processLayerData(layerRanges) {
if (!layerRanges || !Array.isArray(layerRanges) || layerRanges.length === 0) {
console.warn('层位数据无效,使用默认值');
this.uniqueLayers = [];
this.layerColors = {};
return { uniqueLayers: [], layerColors: {}, layerRanges: [] };
}
// 获取唯一的层位值
const uniqueLayers = [...new Set(layerRanges.map(item => item.layer))];
console.log('唯一层位列表:', uniqueLayers);
// 为每个层位生成颜色
const layerColors = {};
uniqueLayers.forEach((layer, index) => {
const color = this.generateRandomColor(index);
console.log(`为层位 ${layer} 分配颜色: ${color}`);
this.$set(layerColors, layer, color);
});
this.uniqueLayers = uniqueLayers;
this.layerColors = layerColors;
return { uniqueLayers, layerColors, layerRanges };
},
// 解析开次数据,提取每个开次的完整深度区间(处理连续深度点)
parseKcDepthRanges() {
if (!this.kcList.length || !this.kcList[0].hasOwnProperty('kc') || !this.kcList[0].hasOwnProperty('dept')) {
console.warn('开次数据格式错误,需包含 kc(开次名称)和 dept(深度)');
return [];
}
// 1. 先按深度排序(确保深度从浅到深)
const sortedKcList = [...this.kcList].sort((a, b) => a.dept - b.dept);
const kcRanges = [];
let currentKc = null;
let currentRange = null;
// 2. 遍历排序后的深度点,提取连续的开次区间
sortedKcList.forEach((item) => {
const { kc, dept } = item;
// 如果是新的开次,或当前开次的深度不连续(间隔超过0.5m,可根据你的数据精度调整)
if (kc !== currentKc || (currentRange && dept - currentRange.endDepth > 0.5)) {
// 保存上一个开次的区间
if (currentRange) {
kcRanges.push(currentRange);
}
// 初始化新的开次区间
currentKc = kc;
currentRange = {
kc: kc,
startDepth: dept, // 区间起始深度
endDepth: dept, // 区间结束深度(初始等于起始深度)
depthPoints: [dept] // 存储该区间的所有深度点(用于校验)
};
} else {
// 同一开次且深度连续,更新区间结束深度
currentRange.endDepth = dept;
currentRange.depthPoints.push(dept);
}
});
// 3. 保存最后一个开次的区间
if (currentRange) {
kcRanges.push(currentRange);
}
console.log('解析后的开次深度区间:', kcRanges);
return kcRanges;
},
// 渲染开次信息
renderGroupedKcList() {
console.log('开始渲染开次信息...');
const container = this.$refs.kcListContainer;
if (!container) {
console.error('开次容器未找到');
return;
}
// 检查开次数据
if (!this.kcList || this.kcList.length === 0) {
console.warn('没有开次数据');
container.innerHTML = '<div style="text-align:center; padding:10px; color:#999; font-size:12px;">无开次数据</div>';
return;
}
console.log('开次数据:', this.kcList);
// 按开次分组
const kcGroups = {};
this.kcList.forEach(item => {
if (!kcGroups[item.kc]) {
kcGroups[item.kc] = [];
}
kcGroups[item.kc].push(item.dept);
});
console.log('开次分组:', kcGroups);
// 计算每个开次的深度范围
const kcRanges = [];
Object.keys(kcGroups).forEach(kcName => {
const depths = kcGroups[kcName].sort((a, b) => a - b);
kcRanges.push({
kc: kcName,
startDepth: Math.min(...depths),
endDepth: Math.max(...depths),
pointCount: depths.length
});
});
// 按起始深度排序
kcRanges.sort((a, b) => a.startDepth - b.startDepth);
console.log('开次范围:', kcRanges);
// 获取图表参数
const chartStartDepth = this.scale1;
const chartEndDepth = this.scale;
const chartTotalDepth = chartEndDepth - chartStartDepth;
// 获取widget的实际绘制区域高度
let actualChartHeight = 600;
if (this.widgetInstance) {
try {
const bounds = this.widgetInstance.getBounds();
actualChartHeight = bounds.getHeight() - 90; // 减去头部高度
console.log('Widget实际高度:', actualChartHeight);
} catch (e) {
console.warn('无法获取widget高度,使用默认值');
}
}
console.log('图表深度范围:', chartStartDepth, '-', chartEndDepth, '总深度:', chartTotalDepth, '图表高度:', actualChartHeight);
// 清空容器
container.innerHTML = "";
// 颜色配置
const colors = [
{ bg: 'rgba(76, 175, 80, 0.3)', border: '#4caf50', text: '#2e7d32' },
{ bg: 'rgba(33, 150, 243, 0.3)', border: '#2196f3', text: '#1565c0' },
{ bg: 'rgba(255, 152, 0, 0.3)', border: '#ff9800', text: '#e65100' },
{ bg: 'rgba(156, 39, 176, 0.3)', border: '#9c27b0', text: '#4a148c' },
{ bg: 'rgba(244, 67, 54, 0.3)', border: '#f44336', text: '#b71c1c' },
{ bg: 'rgba(0, 150, 136, 0.3)', border: '#009688', text: '#004d40' }
];
// 渲染每个开次
kcRanges.forEach((range, index) => {
const { kc, startDepth, endDepth, pointCount } = range;
console.log(`处理开次 ${kc}: ${startDepth}-${endDepth}m, 图表范围: ${chartStartDepth}-${chartEndDepth}m`);
const color = colors[index % colors.length];
// 严格按照深度比例计算位置,使用实际图表高度
const topPos = ((startDepth - chartStartDepth) / chartTotalDepth) * actualChartHeight;
const bottomPos = ((endDepth - chartStartDepth) / chartTotalDepth) * actualChartHeight;
const height = Math.max(bottomPos - topPos, 25); // 最小高度25px
console.log(`开次 ${kc}: 起始深度${startDepth}m -> ${topPos.toFixed(1)}px, 结束深度${endDepth}m -> ${bottomPos.toFixed(1)}px, 高度 ${height.toFixed(1)}px`);
// 检查开次是否与当前图表显示范围有交集
const hasOverlap = !(endDepth < chartStartDepth || startDepth > chartEndDepth);
if (!hasOverlap) {
console.log(`开次 ${kc} 与当前显示范围无交集,但仍然显示`);
}
// 创建背景条
const bgDiv = document.createElement('div');
bgDiv.style.cssText = `
position: absolute;
top: ${topPos}px;
left: 0;
width: 100%;
height: ${height}px;
background-color: ${color.bg};
border-left: 3px solid ${color.border};
border-radius: 0 4px 4px 0;
`;
container.appendChild(bgDiv);
// 创建标签
const labelDiv = document.createElement('div');
labelDiv.style.cssText = `
position: absolute;
top: ${topPos + height / 2}px;
left: 2px;
width: 76px;
transform: translateY(-50%);
text-align: center;
font-size: 10px;
font-weight: bold;
color: ${color.text};
background-color: rgba(255,255,255,0.9);
border: 1px solid ${color.border};
border-radius: 3px;
padding: 2px;
cursor: pointer;
`;
labelDiv.innerHTML = `
<div style="font-size: 12px; font-weight: bold; color: ${color.text};">${kc}</div>
`;
// 点击事件
labelDiv.addEventListener('click', () => {
console.log(`点击开次 ${kc},跳转到推荐方案页面`);
// 收集该开次的ztcc数据
const kcZtccData = this.kcList.filter(item => item.kc === kc);
const ztccValues = kcZtccData.map(item => item.ztcc);
const uniqueZtccValues = [...new Set(ztccValues)]; // 去重
console.log(`开次 ${kc} 的ztcc数据:`, kcZtccData);
console.log(`开次 ${kc} 的ztcc值:`, uniqueZtccValues);
// 查找该开次的ksjs和jsjs值
const kcData = this.kcList.find(item => item.kc === kc);
const startDepth = kcData ? kcData.ksjs : 0;
const endDepth = kcData ? kcData.jsjs : 0;
console.log(startDepth, 'startDepth');
console.log(endDepth, 'endDepth');
// 跳转到钻头设计参数推荐页面,传递开次信息
this.$router.push({
name: 'BitDesignRecommendation',
query: {
from: 'main',
jh: this.jh || this.$route.query.jh,
qk: this.qk,
openingTimes: kc,
startDepth: startDepth.toString(), // 确保转换为字符串
endDepth: endDepth.toString(), // 确保转换为字符串
pointCount: pointCount,
ztccValues: JSON.stringify(uniqueZtccValues), // 将ztcc值数组转为JSON字符串传递
ztccData: JSON.stringify(kcZtccData) // 传递完整的ztcc数据
}
});
});
container.appendChild(labelDiv);
});
console.log('开次信息渲染完成');
},
// 跳转到钻头设计参数推荐页面
goToRecommendation() {
console.log('跳转到钻头设计参数推荐页面')
// 使用路由跳转到推荐方案页面
this.$router.push({
name: 'BitDesignRecommendation',
query: {
from: 'main',
jh: this.jh,
qk: this.qk
}
})
},
// 跳转到钻头匹配页面
goToMatching() {
console.log('跳转到钻头匹配页面')
// 使用路由跳转到匹配页面
this.$router.push({
name: 'BitMatching',
query: {
from: 'main',
jh: this.jh,
qk: this.qk
}
})
},
// 跳转到查看选型信息页面
goToSelectionInfo() {
console.log('跳转到查看选型信息页面')
// 使用路由跳转到选型信息页面
this.$router.push({
name: 'BitSelectionInfo',
query: {
from: 'main',
jh: this.jh,
qk: this.qk
}
})
}
}
};
</script>
<style lang="scss" scoped>
.image {
width: 100%;
height: 450px;
}
@media screen and (min-width: 1400px),
screen and (min-height: 800px) {
.image {
height: 650px;
}
}
.box {
margin: 0 5px;
min-height: 600px;
overflow-y: auto;
}
.action-buttons {
display: flex;
gap: 15px;
margin-bottom: 10px;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
}
div#tooltip-container {
z-index: 100;
margin-left: 5px;
opacity: 1;
text-align: left;
color: rgb(73, 73, 73);
padding-left: 5px;
padding-right: 5px;
background: rgba(255, 255, 204, 0.5);
border-radius: 4px;
border-width: 1px;
border-style: solid;
border-color: grey;
border-image: initial;
width: 150px;
}
</style>
...@@ -13,9 +13,12 @@ ...@@ -13,9 +13,12 @@
<el-tab-pane label="地层岩石数据强度分析" name="formationAnalysis"> <el-tab-pane label="地层岩石数据强度分析" name="formationAnalysis">
<formation-analysis v-if="activeTab === 'formationAnalysis'" :jh="wellInfo.jh" /> <formation-analysis v-if="activeTab === 'formationAnalysis'" :jh="wellInfo.jh" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="钻头设计参数推荐" name="bitDesign"> <el-tab-pane label="数推荐" name="bitDesign">
<bit-design v-if="activeTab === 'bitDesign'" :well-info="wellInfo" /> <bit-design v-if="activeTab === 'bitDesign'" :well-info="wellInfo" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="智能推荐" name="bitDesigns">
<BitDesigns v-if="activeTab === 'bitDesigns'" :well-info="wellInfo" />
</el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</template> </template>
...@@ -25,6 +28,7 @@ import WellStructure from './components/WellStructure.vue' ...@@ -25,6 +28,7 @@ import WellStructure from './components/WellStructure.vue'
import AdjacentWell from './components/AdjacentWell.vue' import AdjacentWell from './components/AdjacentWell.vue'
import FormationAnalysis from './components/FormationAnalysis.vue' import FormationAnalysis from './components/FormationAnalysis.vue'
import BitDesign from './components/BitDesign.vue' import BitDesign from './components/BitDesign.vue'
import BitDesigns from './components/BitDesign.vue'
import FormationMaintenance from './components/FormationMaintenance.vue' import FormationMaintenance from './components/FormationMaintenance.vue'
export default { export default {
name: 'WellDesign', name: 'WellDesign',
...@@ -33,6 +37,7 @@ export default { ...@@ -33,6 +37,7 @@ export default {
AdjacentWell, AdjacentWell,
FormationAnalysis, FormationAnalysis,
BitDesign, BitDesign,
BitDesigns,
FormationMaintenance FormationMaintenance
}, },
data() { data() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment