Commit ce84ac38 by zhaopanyu

zpy

parent d86d54cb
......@@ -68,14 +68,17 @@
</div>
<!-- 缩略图 end-->
<!-- 缩略图弹窗 start -->
<!-- 缩略图弹窗 start -->
<el-dialog v-if="shouldShowThumb" title="缩略图预览" :visible.sync="showThumbDialog" width="80%" append-to-body
:z-index="9999999" :modal="true" :close-on-click-modal="true" :close-on-press-escape="true"
custom-class="thumbnail-dialog">
<div style="height: 100%;">
<YsgcIndex :key="'dialog-thumb-' + routeId" :id-override="routeId" @segyLinePick="onThumbLinePick" />
<YsgcIndex :key="'dialog-thumb-' + routeId" :id-override="routeId" :active-segy-index="currentSegyIndex"
@segyLinePick="onThumbLinePick" />
</div>
</el-dialog>
<!-- 缩略图弹窗 end -->
<!-- 缩略图弹窗 end -->
</div>
<!-- 添加加载状态和错误提示 -->
......@@ -86,7 +89,8 @@
<div class="toolbar-left">
</div>
</div>
<div class="split-container" :class="layoutMode === 'vertical' ? 'layout-vertical' : 'layout-horizontal'">
<div class="split-container" :class="layoutMode === 'vertical' ? 'layout-vertical' : 'layout-horizontal'"
v-loading="isLoading" element-loading-text="加载中...">
<div class="sync-section" ref="topScroll" @scroll="onScroll('top')">
<div class="zoom-wrapper" ref="topWrapper"
:style="{ width: baseCanvasWidth + 'px', height: baseCanvasHeight + 'px' }">
......@@ -618,11 +622,16 @@ export default {
},
showCursorInfo: true,
isWidgetReady: false,
isLoading: false,
loadingError: null,
_headers: [],
_colorMap: null,
// 顶部/底部分别维护标注缓存与还原数据
savedAnnotations: [],
savedLineAnnotations: [],
collectedAnnotations: [], // 实时采集缓存
savedAnnotationsBottom: [],
savedLineAnnotationsBottom: [],
collectedAnnotations: [], // 实时采集缓存(将带有 panel 标记)
// savedLineAnnotations: [{
// properties: {
// x: [2390.510986101919, 2313.4866975512905, 2307.7161482461947, 2303.4509596293847, 2298.934877564527,
......@@ -890,6 +899,7 @@ export default {
x: 0,
y: 0
},
_contextMenuClickBound: false, // 标记 document click 事件是否已绑定
contextMenuItems: [
{
text: '撤销',
......@@ -1137,6 +1147,14 @@ export default {
}
},
watch: {
// 监听 currentSegyIndex 变化
currentSegyIndex(newVal, oldVal) {
console.log('[index2] currentSegyIndex 变化:', {
oldVal,
newVal,
segyListLength: this.segyList ? this.segyList.length : 0
})
},
// 监听路由变化,当路由参数改变时重新初始化数据
'$route'(to, from) {
//console.log('[index2] 路由变化:', to.query, from.query);
......@@ -1213,13 +1231,6 @@ export default {
}
}
});
if (this.$refs.plot) {
// 添加右键菜单事件监听
this.$refs.plot.addEventListener('contextmenu', this.showContextMenu);
document.addEventListener('click', this.hideContextMenu);
// 添加键盘事件监听
}
},
mounted() {
// 将缩略图容器移动到body,确保fixed基于视口
......@@ -1227,6 +1238,12 @@ export default {
document.body.appendChild(this.$refs.thumbContainer);
}
this.createScene(this.$refs.plot);
// 在 createScene 之后绑定右键菜单事件监听器
this.$nextTick(() => {
this.bindContextMenuListeners();
});
// 等DOM稳定后再渲染缩略图组件
setTimeout(() => {
this.thumbReady = true;
......@@ -1244,8 +1261,11 @@ export default {
// 移除右键菜单事件监听
if (this.$refs.plot) {
this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
document.removeEventListener('click', this.hideContextMenu);
}
if (this.$refs.plot2) {
this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
}
document.removeEventListener('click', this.hideContextMenu);
// 清理拖动事件监听
document.removeEventListener('mousemove', this.onDrag);
......@@ -1487,6 +1507,22 @@ export default {
return nodes
},
// 判断节点属于哪个面板(top/bottom)
getNodePanel(node) {
try {
const inLayer = (widget) => {
if (!widget) return false;
const overlay = widget.getOverlayLayer && widget.getOverlayLayer();
const manip = widget.getManipulatorLayer && widget.getManipulatorLayer();
const has = (layer) => layer && typeof layer.indexOfChild === 'function' && layer.indexOfChild(node) >= 0;
return has(overlay) || has(manip);
};
if (inLayer(this._seismicWidget)) return 'top';
if (inLayer(this._seismicWidgetBottom)) return 'bottom';
} catch (e) { }
return 'top';
},
// 收集当前注释层(文本/线条)为简单可序列化结构
collectAnnotationData() {
const result = []
......@@ -1633,13 +1669,15 @@ export default {
type: 'text',
text: text || '', // 确保至少是空字符串而不是 undefined
properties: serializedProps,
textStyle: textStyle
textStyle: textStyle,
panel: this.getNodePanel(node)
})
} else {
// 线条/路径(Paint工具创建的Path)
result.push({
type: 'path',
properties: serializedProps
properties: serializedProps,
panel: this.getNodePanel(node)
})
}
}
......@@ -1786,6 +1824,59 @@ export default {
})
}
} catch (e) { }
// 合并原有标注数据(从后台加载的标注)
// 旧版(上图)的文本标注
if (Array.isArray(this.savedAnnotations) && this.savedAnnotations.length > 0) {
this.savedAnnotations.forEach(savedItem => {
bznr.push({
type: 'text',
text: savedItem.text || '',
properties: savedItem.properties || {},
panel: 'top' // 旧版对应上图
})
})
console.log('[submitSegyAnnotations] 合并旧版文本标注,数量:', this.savedAnnotations.length)
}
// 旧版(上图)的线条标注
if (Array.isArray(this.savedLineAnnotations) && this.savedLineAnnotations.length > 0) {
this.savedLineAnnotations.forEach(savedItem => {
bznr.push({
type: 'path',
properties: savedItem.properties || {},
panel: 'top' // 旧版对应上图
})
})
console.log('[submitSegyAnnotations] 合并旧版线条标注,数量:', this.savedLineAnnotations.length)
}
// 新版(下图)的文本标注
if (Array.isArray(this.savedAnnotationsBottom) && this.savedAnnotationsBottom.length > 0) {
this.savedAnnotationsBottom.forEach(savedItem => {
bznr.push({
type: 'text',
text: savedItem.text || '',
properties: savedItem.properties || {},
panel: 'bottom' // 新版对应下图
})
})
console.log('[submitSegyAnnotations] 合并新版文本标注,数量:', this.savedAnnotationsBottom.length)
}
// 新版(下图)的线条标注
if (Array.isArray(this.savedLineAnnotationsBottom) && this.savedLineAnnotationsBottom.length > 0) {
this.savedLineAnnotationsBottom.forEach(savedItem => {
bznr.push({
type: 'path',
properties: savedItem.properties || {},
panel: 'bottom' // 新版对应下图
})
})
console.log('[submitSegyAnnotations] 合并新版线条标注,数量:', this.savedLineAnnotationsBottom.length)
}
// 合并原有标注后,再次检查是否有可提交的数据
if (!bznr || bznr.length === 0) {
this.$message.warning('没有可提交的标注数据')
return
......@@ -1810,10 +1901,11 @@ export default {
// 为每个线条创建独立的数组项
lines.forEach(line => {
const lx = line.panel === 'bottom' ? '新版' : '旧版';
list.push({
xmid: xmid,
segyid: seg.id,
lx: '新版',
lx: lx,
ext1: '线条',
bznr: JSON.stringify([line])
})
......@@ -1821,10 +1913,11 @@ export default {
// 为每个文本创建独立的数组项
texts.forEach(text => {
const lx = text.panel === 'bottom' ? '新版' : '旧版';
list.push({
xmid: xmid,
segyid: seg.id,
lx: '新版',
lx: lx,
ext1: '文本',
bznr: JSON.stringify([text])
})
......@@ -1870,6 +1963,10 @@ export default {
// 重新初始化场景
if (this.$refs.plot) {
this.createScene(this.$refs.plot, { autoloadDemo: false });
// 重新绑定事件监听器
this.$nextTick(() => {
this.bindContextMenuListeners();
});
}
// 重新加载数据
......@@ -1975,6 +2072,7 @@ export default {
const lineIdx = seriesIndex - lineSeriesBaseIndex;
if (lineIdx >= 0 && Array.isArray(this.segyList) && lineIdx < this.segyList.length) {
const seg = this.segyList[lineIdx];
console.log(this.segyList, 'this.segyList');
this.currentSegyIndex = lineIdx;
if (seg) {
// 加载该线对应的新/旧SEGY:jbsegy -> 顶部,xbsegy -> 底部
......@@ -2006,19 +2104,30 @@ export default {
},
async handlePrevTrace() {
//console.log('[index2] 上一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
// 优先使用 ysqqXmxxSegy,兜底使用 segyList
const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy
: this.segyList;
if (!Array.isArray(segList) || segList.length === 0) {
//console.log('[index2] segyList 为空,尝试重新加载');
try {
await this.loadThumbData();
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
}
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
// 重新获取数据源(可能在loadThumbData后更新)
const finalSegList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy
: this.segyList;
if (!Array.isArray(finalSegList) || finalSegList.length === 0) {
console.warn('[index2] 没有可用的segy数据');
return;
}
// 计算上一个索引
this.currentSegyIndex = this.currentSegyIndex > 0 ? this.currentSegyIndex - 1 : this.segyList.length - 1;
this.currentSegyIndex = this.currentSegyIndex > 0 ? this.currentSegyIndex - 1 : finalSegList.length - 1;
//console.log('[index2] 切换到上一道,当前索引:', this.currentSegyIndex);
// 加载当前segy文件
......@@ -2026,19 +2135,30 @@ export default {
},
async handleNextTrace() {
//console.log('[index2] 下一道 clicked');
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
// 优先使用 ysqqXmxxSegy,兜底使用 segyList
const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy
: this.segyList;
if (!Array.isArray(segList) || segList.length === 0) {
//console.log('[index2] segyList 为空,尝试重新加载');
try {
await this.loadThumbData();
} catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
}
if (!Array.isArray(this.segyList) || this.segyList.length === 0) {
// 重新获取数据源(可能在loadThumbData后更新)
const finalSegList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy
: this.segyList;
if (!Array.isArray(finalSegList) || finalSegList.length === 0) {
console.warn('[index2] 没有可用的segy数据');
return;
}
// 计算下一个索引
this.currentSegyIndex = this.currentSegyIndex < this.segyList.length - 1 ? this.currentSegyIndex + 1 : 0;
this.currentSegyIndex = this.currentSegyIndex < finalSegList.length - 1 ? this.currentSegyIndex + 1 : 0;
//console.log('[index2] 切换到下一道,当前索引:', this.currentSegyIndex);
// 加载当前segy文件
......@@ -2046,14 +2166,22 @@ export default {
},
// 加载当前segy文件
async loadCurrentSegy() {
if (this.segyList.length === 0) {
this.isLoading = true;
// 优先使用 ysqqXmxxSegy 获取数据,兜底使用 segyList
const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy // 优先使用从 toDht 接口获取的原始数据
: this.segyList; // 兜底使用 segyList
if (segList.length === 0) {
//console.log('[index2] 没有segy数据可加载');
this.isLoading = false;
return;
}
const currentSegy = this.segyList[this.currentSegyIndex];
const currentSegy = segList[this.currentSegyIndex];
if (!currentSegy) {
//console.log('[index2] 当前segy数据不存在');
console.log('[index2] 当前segy数据不存在');
this.isLoading = false;
return;
}
......@@ -2062,23 +2190,55 @@ export default {
try {
// 双图加载:jbsegy -> 顶部;xbsegy -> 底部
// 根据后台返回的 ysqqXmxxSegy 数据,jbsegy 顶部展示,xbsegy 底部展示
await this.loadDualSegyFiles(currentSegy.jbsegy, currentSegy.xbsegy, currentSegy.jbsegyName, currentSegy.xbsegyName);
console.log('加载');
} catch (error) {
console.error('[index2] 加载segy文件失败:', error);
} finally {
// <-- 自动标注还原
try {
const originSegy = segList[this.currentSegyIndex] || segList[0];
console.log('[loadCurrentSegy] 准备恢复标注,使用数据源:',
Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
'originSegy:', originSegy);
// 顶部用 jbbznr,底部用 xbbznr
await this.renderAnnotationsFromJbbznr(originSegy);
await this.renderAnnotationsFromXbbznr(originSegy);
// 统一在标注恢复后,强制刷新上下两个widget,避免非悬浮状态下显示旧帧
try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
requestAnimationFrame(() => {
try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
});
// 关键修复:切换下一道后,强制将底部 widget 绑定为当前 pipeline,并重新插入绘制工具,防止短暂显示上一道
try {
// 确保 pipeline/路径键为当前
await this.assertBottomPipelineCurrent();
this.refreshBottomDisplay();
// 重新插入底部工具(有些环境下 setPipeline 后工具管理器会丢失已插入的工具)
if (this._seismicWidgetBottom) {
const tm = this._seismicWidgetBottom.getTool && this._seismicWidgetBottom.getTool();
if (tm) {
try { this.pencilToolBottom && tm.remove(this.pencilToolBottom); } catch (e) { }
try { this.annotationToolBottom && tm.remove(this.annotationToolBottom); } catch (e) { }
try { this.pencilToolBottom && tm.insert(0, this.pencilToolBottom); } catch (e) { }
try { this.annotationToolBottom && tm.insert(0, this.annotationToolBottom); } catch (e) { }
}
// 工具启用状态根据当前面板同步
try { this.pencilToolBottom && this.pencilToolBottom.setEnabled(!!this.showLineStylePanel); } catch (e) { }
try { this.annotationToolBottom && this.annotationToolBottom.setEnabled(!!this.isDrawingText); } catch (e) { }
try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
}
} catch (e) { /* ignore */ }
} catch (e) {
console.error('[index2] 标注恢复失败:', e);
} finally {
this.isLoading = false;
}
}
// <-- 自动标注还原
// 优先使用 handleFileSelect 中从 toDht 接口获取并保存的 ysqqXmxxSegy 数据
let segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
? this.ysqqXmxxSegy // 优先使用从 toDht 接口获取的原始数据
: this.segyList; // 兜底使用 segyList
const originSegy = segList[this.currentSegyIndex] || segList[0];
console.log('[loadCurrentSegy] 准备恢复标注,使用数据源:',
Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
'originSegy:', originSegy);
await this.renderAnnotationsFromXbbznr(originSegy);
},
// 从接口返回的 xbbznr 数据中解析并恢复标注
......@@ -2148,9 +2308,9 @@ export default {
console.log('[renderAnnotationsFromXbbznr] 开始解析标注数据,数量:', annotationList.length);
console.log('[renderAnnotationsFromXbbznr] annotationList 详细内容:', JSON.stringify(annotationList, null, 2));
// 清空现有的 savedAnnotations 和 savedLineAnnotations
this.savedAnnotations = [];
this.savedLineAnnotations = [];
// 清空现有的底部 savedAnnotations 和 savedLineAnnotations
this.savedAnnotationsBottom = [];
this.savedLineAnnotationsBottom = [];
// 转换数据格式并存储到对应的数组
console.log('[renderAnnotationsFromXbbznr] 开始转换数据,annotationList 长度:', annotationList.length);
......@@ -2236,7 +2396,7 @@ export default {
properties: properties
};
this.savedAnnotations.push(annotationData);
this.savedAnnotationsBottom.push(annotationData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注 #${index + 1}-${bznrIndex + 1}:`, {
text: annotationData.text,
hasProperties: !!annotationData.properties
......@@ -2250,7 +2410,7 @@ export default {
const lineData = {
properties: bznrItem.properties || {}
};
this.savedLineAnnotations.push(lineData);
this.savedLineAnnotationsBottom.push(lineData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注 #${index + 1}-${bznrIndex + 1}`);
}
});
......@@ -2299,13 +2459,13 @@ export default {
properties: properties
};
this.savedAnnotations.push(annotationData);
this.savedAnnotationsBottom.push(annotationData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注(旧格式) #${index + 1}`);
} else if (item.type === 'path') {
const lineData = {
properties: item.properties || {}
};
this.savedLineAnnotations.push(lineData);
this.savedLineAnnotationsBottom.push(lineData);
console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注(旧格式) #${index + 1}`);
}
}
......@@ -2314,25 +2474,25 @@ export default {
}
});
console.log('[renderAnnotationsFromXbbznr] 转换完成,savedAnnotations 数量:', this.savedAnnotations.length, 'savedLineAnnotations 数量:', this.savedLineAnnotations.length);
console.log('[renderAnnotationsFromXbbznr] savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotations, null, 2));
console.log('[renderAnnotationsFromXbbznr] savedLineAnnotations 完整数据:', JSON.stringify(this.savedLineAnnotations, null, 2));
console.log('[renderAnnotationsFromXbbznr] 转换完成,bottom savedAnnotations 数量:', this.savedAnnotationsBottom.length, 'bottom savedLineAnnotations 数量:', this.savedLineAnnotationsBottom.length);
console.log('[renderAnnotationsFromXbbznr] bottom savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotationsBottom, null, 2));
console.log('[renderAnnotationsFromXbbznr] bottom savedLineAnnotations 完整数据:', JSON.stringify(this.savedLineAnnotationsBottom, null, 2));
// 等待组件就绪后恢复标注
if (this.savedAnnotations.length > 0 || this.savedLineAnnotations.length > 0) {
// 确保 annotations 层已创建
if (!this.annotations && this._seismicWidget) {
this.annotations = new Group();
const manip = this._seismicWidget.getManipulatorLayer && this._seismicWidget.getManipulatorLayer();
const layer = manip || this._seismicWidget.getOverlayLayer();
if (this.savedAnnotationsBottom.length > 0 || this.savedLineAnnotationsBottom.length > 0) {
// 确保底部 annotations 层已创建
if (!this.annotationsBottom && this._seismicWidgetBottom) {
this.annotationsBottom = new Group();
const manip = this._seismicWidgetBottom.getManipulatorLayer && this._seismicWidgetBottom.getManipulatorLayer();
const layer = manip || this._seismicWidgetBottom.getOverlayLayer();
if (layer) {
layer.addChild(this.annotations);
this.annotations.setVisible(true);
layer.addChild(this.annotationsBottom);
this.annotationsBottom.setVisible(true);
}
} else if (this.annotations) {
} else if (this.annotationsBottom) {
// 清空现有的标注节点,避免重复
try {
const children = this.annotations.getChildren ? this.annotations.getChildren() : [];
const children = this.annotationsBottom.getChildren ? this.annotationsBottom.getChildren() : [];
children.forEach(child => {
try {
if (child.dispose && typeof child.dispose === 'function') {
......@@ -2342,7 +2502,7 @@ export default {
console.warn('[renderAnnotationsFromXbbznr] 清理节点失败:', e);
}
});
this.annotations.removeAllChildren && this.annotations.removeAllChildren();
this.annotationsBottom.removeAllChildren && this.annotationsBottom.removeAllChildren();
console.log('[renderAnnotationsFromXbbznr] 已清空现有标注节点');
} catch (e) {
console.warn('[renderAnnotationsFromXbbznr] 清空标注层失败:', e);
......@@ -2352,13 +2512,13 @@ export default {
// 延迟恢复,确保图表已加载完成
this.$nextTick(() => {
setTimeout(() => {
if (this.savedAnnotations.length > 0) {
this.restoreAnnotations();
console.log('[renderAnnotationsFromXbbznr] 文本标注恢复完成,共恢复', this.savedAnnotations.length, '个标注');
if (this.savedAnnotationsBottom.length > 0) {
this.restoreAnnotationsBottom();
console.log('[renderAnnotationsFromXbbznr] 底部文本标注恢复完成,共恢复', this.savedAnnotationsBottom.length, '个标注');
}
if (this.savedLineAnnotations.length > 0) {
this.restoreLineAnnotations();
console.log('[renderAnnotationsFromXbbznr] 线条标注恢复完成,共恢复', this.savedLineAnnotations.length, '个标注');
if (this.savedLineAnnotationsBottom.length > 0) {
this.restoreLineAnnotationsBottom();
console.log('[renderAnnotationsFromXbbznr] 底部线条标注恢复完成,共恢复', this.savedLineAnnotationsBottom.length, '个标注');
}
}, 500);
});
......@@ -2367,17 +2527,149 @@ export default {
console.error('[renderAnnotationsFromXbbznr] 处理 xbbznr 数据时出错:', error);
}
},
// 从接口返回的 jbbznr 数据中解析并恢复到顶部图
async renderAnnotationsFromJbbznr(originSegy) {
try {
if (!originSegy) return;
let jbbznr = originSegy.jbbznr;
if (jbbznr && typeof jbbznr === 'string') {
try { jbbznr = JSON.parse(jbbznr); } catch (e) { return; }
}
if (!jbbznr) return;
const annotationList = Array.isArray(jbbznr) ? jbbznr : [jbbznr];
this.savedAnnotations = [];
this.savedLineAnnotations = [];
annotationList.forEach((item) => {
try {
if (item.ext1 && item.bznr) {
let bznrData = null;
try {
if (typeof item.bznr === 'string') bznrData = JSON.parse(item.bznr);
else if (Array.isArray(item.bznr)) bznrData = item.bznr; else bznrData = [item.bznr];
} catch (e) { return; }
if (!Array.isArray(bznrData)) bznrData = [bznrData];
if (item.ext1 === '文本') {
bznrData.forEach((bznrItem) => {
if (bznrItem.type === 'text') {
const text = bznrItem.text || bznrItem.properties?.text || '';
const properties = { ...bznrItem.properties };
if (bznrItem.properties && bznrItem.properties.textstyle) {
properties.textstyle = bznrItem.properties.textstyle;
} else if (bznrItem.textStyle) {
properties.textstyle = {
Lx: bznrItem.textStyle.color || '#000000',
lH: bznrItem.textStyle.font || '22px Sans-serif',
Vf: bznrItem.textStyle.alignment || 'left',
eZ: bznrItem.textStyle.size || '22px'
};
} else {
properties.textstyle = { Lx: '#000000', lH: '22px Sans-serif', Vf: 'left', eZ: '22px' };
}
properties.text = text;
if (!properties.linestyle) properties.linestyle = { Lx: '#0351ad', fA: 2 };
if (!properties.fillstyle) properties.fillstyle = { Lx: '#c7e1f6' };
this.savedAnnotations.push({ text, properties });
}
});
} else if (item.ext1 === '线条') {
bznrData.forEach((bznrItem) => {
if (bznrItem.type === 'path') this.savedLineAnnotations.push({ properties: bznrItem.properties || {} });
});
}
} else {
if (item.type === 'text') {
const text = item.text || item.properties?.text || '';
const properties = { ...item.properties };
if (item.properties && item.properties.textstyle) properties.textstyle = item.properties.textstyle; else if (item.textStyle) {
properties.textstyle = { Lx: item.textStyle.color || '#000000', lH: item.textStyle.font || '22px Sans-serif', Vf: item.textStyle.alignment || 'left', eZ: item.textStyle.size || '22px' };
} else { properties.textstyle = { Lx: '#000000', lH: '22px Sans-serif', Vf: 'left', eZ: '22px' }; }
properties.text = text;
if (!properties.linestyle) properties.linestyle = { Lx: '#0351ad', fA: 2 };
if (!properties.fillstyle) properties.fillstyle = { Lx: '#c7e1f6' };
this.savedAnnotations.push({ text, properties });
} else if (item.type === 'path') {
this.savedLineAnnotations.push({ properties: item.properties || {} });
}
}
} catch (e) { }
});
if (this.savedAnnotations.length > 0 || this.savedLineAnnotations.length > 0) {
if (!this.annotations && this._seismicWidget) {
this.annotations = new Group();
const manip = this._seismicWidget.getManipulatorLayer && this._seismicWidget.getManipulatorLayer();
const layer = manip || this._seismicWidget.getOverlayLayer();
if (layer) { layer.addChild(this.annotations); this.annotations.setVisible(true); }
} else if (this.annotations) {
// 清空现有顶部标注,避免重复
try {
// const children = this.annotations.getChildren ? this.annotations.getChildren() : [];
// children.forEach(child => { try { child.dispose && child.dispose(); } catch (e) { } });
// this.annotations.removeAllChildren && this.annotations.removeAllChildren();
} catch (e) { }
}
const doRestore = () => {
if (this.savedAnnotations.length > 0) this.restoreAnnotations();
if (this.savedLineAnnotations.length > 0) this.restoreLineAnnotations();
};
this.$nextTick(() => {
setTimeout(() => {
if (!this._seismicWidget) {
setTimeout(doRestore, 400);
} else {
doRestore();
}
}, 500);
});
}
} catch (e) { console.error('[renderAnnotationsFromJbbznr] 处理 jbbznr 数据时出错:', e); }
},
// 清空当前图表
clearCurrentPlots() {
//console.log('[index2] 清空当前图表');
try {
// 清空主图表
// 重置鼠标悬浮状态,避免切换时显示错误的图
this.isHovering = false;
// 清空主图表并强制刷新
if (this._seismicWidget) {
this._seismicWidget.clear();
try {
// 检查 clear 方法是否存在,如果存在则调用
if (typeof this._seismicWidget.clear === 'function') {
this._seismicWidget.clear();
}
// 如果没有 clear 方法,跳过清空操作,后续设置新 pipeline 会覆盖旧数据
} catch (e) {
console.warn('清空顶部widget时出错:', e);
}
// 强制刷新以确保旧数据被清除
try {
if (this._seismicWidget.invalidate) {
this._seismicWidget.invalidate();
}
} catch (e) {
console.warn('刷新顶部widget时出错:', e);
}
}
// 清空底部图表
// 清空底部图表并强制刷新
if (this._seismicWidgetBottom) {
this._seismicWidgetBottom.clear();
try {
// 检查 clear 方法是否存在,如果存在则调用
if (typeof this._seismicWidgetBottom.clear === 'function') {
this._seismicWidgetBottom.clear();
}
// 如果没有 clear 方法,跳过清空操作,后续设置新 pipeline 会覆盖旧数据
} catch (e) {
console.warn('清空底部widget时出错:', e);
}
// 强制刷新以确保旧数据被清除
try {
if (this._seismicWidgetBottom.invalidate) {
this._seismicWidgetBottom.invalidate();
}
} catch (e) {
console.warn('刷新底部widget时出错:', e);
}
}
// 清空plots数据
this.plots = null;
......@@ -2400,6 +2692,10 @@ export default {
this.clearScene(this.$refs.plot);
// 重新创建场景
this.createScene(this.$refs.plot);
// 重新绑定事件监听器
this.$nextTick(() => {
this.bindContextMenuListeners();
});
}
//console.log('[index2] segy文件加载完成');
......@@ -2417,23 +2713,47 @@ export default {
return;
}
// 重置鼠标悬浮状态,避免切换时显示错误的图
this.isHovering = false;
// 打开双图布局
this.showDualChart();
// 不再隐藏容器,避免首次绘制依赖鼠标事件触发
const topScroll = this.$refs.topScroll;
const bottomScroll = this.$refs.bottomScroll;
// 清空现有图表
this.clearCurrentPlots();
// 确保两个画布已初始化
if (this.$refs.plot) this.createScene(this.$refs.plot, { autoloadDemo: false });
if (this.$refs.plot2) this.initSecondWidget(this.$refs.plot2);
// 清空 pipeline 引用,确保旧数据被清除
this.pipeline = null;
this.pipelineBottom = null;
this.plots = null;
this.plotsBottom = null;
// 确保两个画布已初始化(如果widget不存在,才创建新的)
if (this.$refs.plot && !this._seismicWidget) {
this.createScene(this.$refs.plot, { autoloadDemo: false });
}
if (this.$refs.plot2 && !this._seismicWidgetBottom) {
this.initSecondWidget(this.$refs.plot2);
}
// 重新绑定事件监听器
this.$nextTick(() => {
this.bindContextMenuListeners();
});
// 等待一小段时间,确保清空操作完成
await new Promise(resolve => setTimeout(resolve, 50));
// 顺序加载,分别统计成功与失败
// 顺序加载,分别统计成功与失败,但不立即刷新
let topOk = false;
let bottomOk = false;
try {
if (jbPath) {
const topTitle = jbName || this.extractFileName(jbPath) || 'jbsegy';
await this.loadSegyIntoWidget('top', jbPath, topTitle);
await this.loadSegyIntoWidget('top', jbPath, topTitle, false); // 不立即刷新
topOk = true;
}
} catch (e) {
......@@ -2443,21 +2763,74 @@ export default {
try {
if (xbPath) {
const bottomTitle = xbName || this.extractFileName(xbPath) || 'xbsegy';
await this.loadSegyIntoWidget('bottom', xbPath, bottomTitle);
await this.loadSegyIntoWidget('bottom', xbPath, bottomTitle, false); // 不立即刷新
bottomOk = true;
}
} catch (e) {
console.warn('加载下部SEGY失败:', e);
}
if (topOk && bottomOk) {
console.info('[index2] 上/下部SEGY加载完成');
} else if (topOk || bottomOk) {
console.warn('[index2] 一侧SEGY加载成功,另一侧失败');
// 等待所有数据加载完成后再统一刷新
if (topOk || bottomOk) {
// 使用 requestAnimationFrame 确保在下一帧统一刷新
await this.$nextTick();
requestAnimationFrame(() => {
try {
if (topOk && this._seismicWidget) {
if (this._seismicWidget.invalidate) {
this._seismicWidget.invalidate();
}
this.setScrollbarCSS(this._seismicWidget);
this.forceDisableInternalScrollbars();
setTimeout(() => {
try {
if (this._seismicWidget && this._seismicWidget.fitToBounds) {
this._seismicWidget.fitToBounds();
}
} catch (e) { }
}, 100);
}
if (bottomOk && this._seismicWidgetBottom) {
if (this._seismicWidgetBottom.invalidate) {
this._seismicWidgetBottom.invalidate();
}
this.setScrollbarCSS(this._seismicWidgetBottom);
this.forceDisableInternalScrollbars();
setTimeout(() => {
try {
if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) {
this._seismicWidgetBottom.fitToBounds();
}
// 额外在显示前进行一次尺寸同步与重绘
try { this.updateBaseCanvasSize(); } catch (e) { }
try { this.plotsBottom && typeof this.plotsBottom.redraw === 'function' && this.plotsBottom.redraw(); } catch (e) { }
} catch (e) { }
}, 100);
}
} catch (e) {
console.warn('最终刷新widget时出错:', e);
}
});
// 刷新完成后,额外进行一次尺寸同步与重绘,确保无悬浮也正确
setTimeout(() => {
try { this.updateBaseCanvasSize(); } catch (e) { }
try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
requestAnimationFrame(() => {
try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
});
}, 200);
} else {
// 加载失败也做一次重绘尝试
try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
}
},
// 将指定segy加载到顶部/底部widget
async loadSegyIntoWidget(position, segyPath, displayName) {
// skipRefresh: 如果为 true,则不立即刷新,等待统一刷新
async loadSegyIntoWidget(position, segyPath, displayName, skipRefresh = false) {
// 构造可访问的完整URL
const url = this.buildSegyURL(segyPath);
......@@ -2505,21 +2878,131 @@ export default {
try { pipeline.addTraceProcessor(new Reverse({ 'apply': false, 'name': 'Reverse' })); } catch (e) { }
if (position === 'top') {
this.pipeline = pipeline;
if (!this._seismicWidget && this.$refs.plot) this.createScene(this.$refs.plot);
// 先清空旧的 pipeline 数据,避免显示错误的图片
// 无论是否有旧的 pipeline,都要清空,确保切换下一道时显示新图
if (this._seismicWidget) {
try {
// 先移除旧的 pipeline(如果存在)
if (this.pipeline && this._seismicWidget.setPipeline) {
// 尝试移除旧的 pipeline,先设置为 undefined 或空对象来触发清空
try {
// 如果 widget 有 removePipeline 方法,使用它
if (typeof this._seismicWidget.removePipeline === 'function') {
this._seismicWidget.removePipeline();
}
} catch (e) {
// 如果 removePipeline 不存在,忽略错误
}
}
// 检查 clear 方法是否存在,如果存在则调用
if (typeof this._seismicWidget.clear === 'function') {
this._seismicWidget.clear();
}
// 强制刷新以确保旧数据被清除
if (this._seismicWidget.invalidate) {
this._seismicWidget.invalidate();
}
} catch (e) {
console.warn('清空顶部widget数据时出错:', e);
}
}
// 清空旧的 pipeline 引用
this.pipeline = null;
this.plots = null;
if (!this._seismicWidget && this.$refs.plot) {
this.createScene(this.$refs.plot);
// 重新绑定事件监听器
this.$nextTick(() => {
this.bindContextMenuListeners();
});
}
if (!this._seismicWidget) throw new Error('顶部Widget未初始化');
// 设置新的 pipeline
this.pipeline = pipeline;
this._seismicWidget.setPipeline(pipeline);
this._seismicWidget.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || this.extractFileName(segyPath) || pipeline.getName() } } } });
setTimeout(() => { try { this._seismicWidget.fitToBounds(); } catch (e) { } }, 200);
// 如果不跳过刷新,则立即刷新;否则等待统一刷新
if (!skipRefresh) {
// 强制刷新以确保显示新的数据
this.$nextTick(() => {
try {
if (this._seismicWidget.invalidate) {
this._seismicWidget.invalidate();
}
} catch (e) { }
});
setTimeout(() => { try { this._seismicWidget.fitToBounds(); } catch (e) { } }, 200);
}
this.setScrollbarCSS(this._seismicWidget);
this.forceDisableInternalScrollbars();
} else {
this.pipelineBottom = pipeline;
// 先清空旧的 pipeline 数据,避免显示错误的图片
// 无论是否有旧的 pipeline,都要清空,确保切换下一道时显示新图
if (this._seismicWidgetBottom) {
try {
// 先移除旧的 pipeline(如果存在)
if (this.pipelineBottom && this._seismicWidgetBottom.setPipeline) {
// 尝试移除旧的 pipeline,先设置为 undefined 或空对象来触发清空
try {
// 如果 widget 有 removePipeline 方法,使用它
if (typeof this._seismicWidgetBottom.removePipeline === 'function') {
this._seismicWidgetBottom.removePipeline();
}
} catch (e) {
// 如果 removePipeline 不存在,忽略错误
}
}
// 检查 clear 方法是否存在,如果存在则调用
if (typeof this._seismicWidgetBottom.clear === 'function') {
this._seismicWidgetBottom.clear();
}
// 强制刷新以确保旧数据被清除
if (this._seismicWidgetBottom.invalidate) {
this._seismicWidgetBottom.invalidate();
}
} catch (e) {
console.warn('清空底部widget数据时出错:', e);
}
}
// 清空旧的 pipeline 引用
this.pipelineBottom = null;
this.plotsBottom = null;
if (!this._seismicWidgetBottom && this.$refs.plot2) this.initSecondWidget(this.$refs.plot2);
if (!this._seismicWidgetBottom) throw new Error('底部Widget未初始化');
// 设置新的 pipeline,并记录为“当前版本”
this.pipelineBottom = pipeline;
this._bottomSegyKey = displayName || this.extractFileName(segyPath) || pipeline.getName();
this._bottomSegyPath = segyPath;
this._seismicWidgetBottom.setPipeline(pipeline);
this._seismicWidgetBottom.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || this.extractFileName(segyPath) || pipeline.getName() } } } });
setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
// 如果不跳过刷新,则立即刷新;否则等待统一刷新
if (!skipRefresh) {
// 强制刷新以确保显示新的数据
this.$nextTick(() => {
try {
if (this._seismicWidgetBottom.invalidate) {
this._seismicWidgetBottom.invalidate();
}
// 在下一帧再次刷新,避免首次绘制未完成造成的残影
requestAnimationFrame(() => {
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
// 如果 plotsBottom 支持 redraw,额外触发一次重绘
try { this.plotsBottom && typeof this.plotsBottom.redraw === 'function' && this.plotsBottom.redraw(); } catch (e) { }
});
} catch (e) { }
});
setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
}
this.setScrollbarCSS(this._seismicWidgetBottom);
this.forceDisableInternalScrollbars();
}
......@@ -2757,17 +3240,55 @@ export default {
// 处理缩略图(绿色线)点击/双击事件
onThumbLinePick(payload) {
try {
if (!payload || typeof payload.index !== 'number') return;
const lineIdx = payload.index;
if (!Array.isArray(this.segyList) || lineIdx < 0 || lineIdx >= this.segyList.length) return;
if (!payload) return;
console.log('[index2] onThumbLinePick 收到事件:', payload);
console.log('[index2] segyList 长度:', this.segyList ? this.segyList.length : 0);
console.log('[index2] segyList 前3项:', this.segyList ? this.segyList.slice(0, 3).map((s, i) => ({ index: i, id: s && s.id, name: s && (s.name || s.segyName || s.jbsegyName || s.xbsegyName) })) : []);
// 优先通过 ID 匹配,如果没有 ID 则通过索引匹配
let lineIdx = -1;
if (payload.id != null) {
// 通过 ID 查找在 segyList 中的索引
lineIdx = this.segyList.findIndex(seg => seg && seg.id == payload.id);
console.log('[index2] 通过 ID 查找结果:', { id: payload.id, lineIdx });
}
// 如果通过 ID 没找到,则使用原始索引(originalIndex)
if (lineIdx === -1 && payload.originalIndex != null) {
lineIdx = payload.originalIndex;
console.log('[index2] 使用 originalIndex:', { originalIndex: payload.originalIndex, lineIdx });
}
// 如果还是没有找到,使用过滤后的索引作为兜底(兼容旧逻辑)
if (lineIdx === -1 && typeof payload.index === 'number') {
lineIdx = payload.index;
console.log('[index2] 使用过滤后的 index:', { index: payload.index, lineIdx });
}
if (lineIdx === -1 || !Array.isArray(this.segyList) || lineIdx < 0 || lineIdx >= this.segyList.length) {
console.warn('[index2] onThumbLinePick: 无法找到对应的线条', {
payload,
lineIdx,
segyListLength: this.segyList ? this.segyList.length : 0
});
return;
}
const seg = this.segyList[lineIdx];
console.log('[index2] 设置 currentSegyIndex:', { lineIdx, segId: seg && seg.id, segName: seg && (seg.name || seg.segyName || seg.jbsegyName || seg.xbsegyName) });
this.currentSegyIndex = lineIdx;
if (seg) {
this.loadDualSegyFiles(seg.jbsegy, seg.xbsegy, seg.jbsegyName, seg.xbsegyName);
}
} catch (e) { /* ignore */ }
// 如果弹窗是打开的,点击后关闭弹窗
if (this.showThumbDialog) {
this.showThumbDialog = false;
}
} catch (e) {
console.error('[index2] onThumbLinePick error:', e);
}
},
// 确保缩略图渲染
ensureThumbRendered() {
if (!this.thumbReady) {
......@@ -3762,6 +4283,20 @@ export default {
})
});
// 如果已经有当前有效的 bottom pipeline,优先使用它,避免回退到旧数据
if (this.pipelineBottom) {
try {
this._seismicWidgetBottom.setPipeline(this.pipelineBottom);
this._seismicWidgetBottom.setOptions({
'axes': { 'headers': { 'fields': this._headers }, 'samples': { 'title': { 'visible': true, 'text': this.pipelineBottom.getName && this.pipelineBottom.getName() } } }
});
setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
this.setScrollbarCSS(this._seismicWidgetBottom);
try { this.initAnnotationToolsBottom(this._seismicWidgetBottom); } catch (e) { }
return;
} catch (e) { /* 如果失败,再走旧流程 */ }
}
if (this._dataReader && this._dataStatistics && this._fileName && this._colorMap) {
try {
const pipelineBottom = new SeismicPipeline(this._fileName, this._dataReader, this._dataStatistics)
......@@ -3792,6 +4327,8 @@ export default {
}, 800);
// 使用CSS方法彻底禁用下半屏内部滚动条
this.setScrollbarCSS(this._seismicWidgetBottom);
// 初始化底部注释工具
try { this.initAnnotationToolsBottom(this._seismicWidgetBottom); } catch (e) { console.warn('初始化底部注释工具失败:', e); }
} catch (e) {
console.warn('初始化下半屏流水线失败:', e);
}
......@@ -3801,6 +4338,151 @@ export default {
}
},
// 为底部 widget 初始化注释工具(文本/线条)与标注层
initAnnotationToolsBottom(widget) {
if (!widget) return;
try {
// 创建标注层
this.annotationsBottom = new Group();
const overlay = widget.getOverlayLayer();
if (overlay) overlay.addChild(this.annotationsBottom);
// 文本工具(底部)
this.annotationToolBottom = new Paint({
'layer': widget.getManipulatorLayer(),
'node': {
'radius': 10,
'fillstyle': new FillStyle('#c7e1f6'),
'linestyle': new LineStyle({ 'color': '#0351ad', 'width': 2 }),
'textbox': { 'border': true, 'borderradius': 10, 'fixedsize': false, 'wordwrap': true, 'padding': 5 },
'selectable': true,
'movable': true,
'editable': true,
'preserveontextfinish': true,
'preserveonblur': true
}
});
// 选择工具(限制在底部标注层)
const selectionToolBottom = new Selection()
.setNodeFilter((nodes) => nodes.filter((node) => this.annotationsBottom.indexOfChild(node) >= 0));
const toolManager = widget.getTool();
try { toolManager.remove(this.annotationToolBottom); toolManager.remove(selectionToolBottom); } catch (e) { }
toolManager.insert(0, selectionToolBottom);
toolManager.insert(0, this.annotationToolBottom);
// 监听文本结束,缓存并打上 panel 标记为 bottom
this.annotationToolBottom.addListener(EditEvents.End, (tool, node) => {
if (!node) return;
let text = '';
if (node.text && String(node.text).trim() !== '') text = String(node.text);
if (!text && typeof node.getText === 'function') {
try { const t = node.getText(); if (t && String(t).trim() !== '') text = String(t); } catch (e) { }
}
if (!text && typeof node.getProperties === 'function') {
try { const p = node.getProperties(); if (p && p.text && String(p.text).trim() !== '') text = String(p.text); } catch (e) { }
}
if (text) {
const props = node.getProperties ? node.getProperties() : {};
// 确保 properties.text 有值
try { if (typeof node.setProperties === 'function') node.setProperties({ ...props, text }); } catch (e) { }
// 写入缓存(带面板标记)
try {
const textStyle = node.getTextStyle ? node.getTextStyle() : null;
const cacheItem = {
type: 'text',
text,
properties: node.getProperties ? node.getProperties() : {},
textStyle: textStyle ? {
font: textStyle.getFont && textStyle.getFont(),
color: textStyle.getColor && textStyle.getColor(),
size: textStyle.size,
alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null,
panel: 'bottom',
_nodeRef: node
};
const idx = this.collectedAnnotations.findIndex(it => it._nodeRef === node);
if (idx >= 0) this.collectedAnnotations[idx] = cacheItem; else this.collectedAnnotations.push(cacheItem);
} catch (e) { }
}
if (this.annotationsBottom.indexOfChild(node) === -1) this.annotationsBottom.addChild(node);
try { widget.invalidate && widget.invalidate(); } catch (e) { }
});
// 线条工具(底部)
const lineStyle = new LineStyle({ color: this.lineStyle?.color || '#0351ad', width: this.lineStyle?.width || 2, pattern: this.getProcessedLinePattern ? this.getProcessedLinePattern(this.lineStyle?.pattern) : [] });
this.pencilToolBottom = new Paint({
'layer': widget.getManipulatorLayer(),
'mode': PaintMode.Pencil,
'editmode': EditMode.Create,
'node': { 'linestyle': lineStyle, 'selectable': true, 'movable': true, 'editable': true }
});
this.pencilToolBottom
.addListener(EditEvents.Start, (tool, command) => { const node = command.getNode(); if (node) this.annotationsBottom.addChild(node); })
.addListener(EditEvents.End, (tool, node) => {
if (!node) return;
try {
const props = node.getProperties ? node.getProperties() : {};
this.collectedAnnotations.push({ type: 'path', properties: props, panel: 'bottom', _nodeRef: node });
} catch (e) { }
if (this.annotationsBottom.indexOfChild(node) === -1) this.annotationsBottom.addChild(node);
try { tool.setEditMode(EditMode.EditNode); tool.editNode(node); } catch (e) { }
try { widget.invalidate && widget.invalidate(); } catch (e) { }
});
// 默认禁用,按按钮再启用
try { this.annotationToolBottom.setEnabled(false); this.annotationToolBottom.editNode(null); } catch (e) { }
try { this.pencilToolBottom.setEnabled(false); } catch (e) { }
} catch (e) {
console.warn('initAnnotationToolsBottom error:', e);
}
},
// 在工具切换或面板开启时,确保底部显示绑定当前pipeline
refreshBottomDisplay() {
try {
if (this._seismicWidgetBottom && this.pipelineBottom) {
try { this._seismicWidgetBottom.setPipeline(this.pipelineBottom); } catch (e) { }
try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
requestAnimationFrame(() => {
try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
});
}
} catch (e) { /* ignore */ }
},
// 计算当前索引应展示的底部数据键和值
getExpectedBottomInfo() {
const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0) ? this.ysqqXmxxSegy : this.segyList;
const item = Array.isArray(segList) ? segList[this.currentSegyIndex] : null;
if (!item) return null;
const path = item.xbsegy || '';
const name = item.xbsegyName || this.extractFileName(item.xbsegy || '') || 'xbsegy';
return { path, name };
},
// 若底部当前绑定不是当前索引的数据,则立即更正
async assertBottomPipelineCurrent() {
try {
const info = this.getExpectedBottomInfo();
if (!info || !info.path) return;
// 优先用路径判断是否一致
if (!this._bottomSegyPath || this._bottomSegyPath !== info.path) {
await this.loadSegyIntoWidget('bottom', info.path, info.name, false);
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
return;
}
// 其次用名称兜底
const expectedKey = info.name;
if (!this._bottomSegyKey || this._bottomSegyKey !== expectedKey) {
await this.loadSegyIntoWidget('bottom', info.path, info.name, false);
try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
}
} catch (e) { /* ignore */ }
},
// 同步滚动条(左右与上下)- 防死循环版本
onScroll(origin) {
// 多重防护:防止死循环
......@@ -5328,6 +6010,9 @@ export default {
console.log('[handleFileSelect] 准备恢复标注,使用数据源:',
Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
'originSegy:', originSegy);
// 顶部:旧版(jbbznr)
try { this.renderAnnotationsFromJbbznr(originSegy); } catch (e) { console.warn('renderAnnotationsFromJbbznr 调用失败:', e); }
// 底部:新版(xbbznr)
this.renderAnnotationsFromXbbznr(originSegy);
} else {
console.warn('[handleFileSelect] 未找到 originSegy,无法恢复标注');
......@@ -5557,6 +6242,7 @@ export default {
size: textStyle.size,
alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null,
panel: 'top',
_nodeRef: node // 保存节点引用用于后续匹配
};
......@@ -5607,11 +6293,13 @@ export default {
}
},
toggleDrawText() {
async toggleDrawText() {
if (!this.checkWidgetStatus() || !this.isWidgetReady) {
console.warn('Widget or annotation tools not ready');
return;
}
// 在启用工具前确保底部绑定的是当前索引(等待更正完成)
await this.assertBottomPipelineCurrent();
if (!this.annotationTool) {
console.warn('注释工具未初始化');
......@@ -5661,6 +6349,9 @@ export default {
//console.log('文本绘制工具配置:', textProperties);
this.annotationTool.setProperties(textProperties);
if (this.annotationToolBottom) {
try { this.annotationToolBottom.setProperties(textProperties); } catch (e) { }
}
// 添加事件监听器来打印文本绘制数据
this.annotationTool.addListener(EditEvents.Start, (tool, command) => {
......@@ -5814,6 +6505,7 @@ export default {
size: textStyle.size,
alignment: textStyle.getAlignment && textStyle.getAlignment()
} : null,
panel: 'top',
_nodeRef: node // 保存节点引用用于后续匹配
};
......@@ -5844,9 +6536,13 @@ export default {
});
this.annotationTool.setEnabled(true);
if (this.annotationToolBottom) { try { this.annotationToolBottom.setEnabled(true); } catch (e) { } }
// 确保底部仍绑定当前数据
this.refreshBottomDisplay();
} else {
this.annotationTool.setEnabled(false);
this.annotationTool.editNode(null);
if (this.annotationToolBottom) { try { this.annotationToolBottom.setEnabled(false); this.annotationToolBottom.editNode(null); } catch (e) { } }
}
},
......@@ -6639,7 +7335,7 @@ export default {
}
},
toggleLineStylePanel() {
async toggleLineStylePanel() {
// 如果工具已经激活,则停用
if (this.showLineStylePanel) {
this.deactivatePencilTool();
......@@ -6711,7 +7407,7 @@ export default {
properties: props
});
try {
this.collectedAnnotations.push({ type: 'path', properties: props });
this.collectedAnnotations.push({ type: 'path', properties: props, panel: 'top', _nodeRef: node });
console.log('[collect][path][End] cached count:', this.collectedAnnotations.length, 'last:', this.collectedAnnotations[this.collectedAnnotations.length - 1]);
} catch (e) { }
}
......@@ -6739,7 +7435,33 @@ export default {
}
toolManager.insert(0, this.pencilTool);
// 在启用工具前确保底部绑定的是当前索引
await this.assertBottomPipelineCurrent();
// 关键修复:激活线条工具时,确保底部 widget 立即绑定当前 pipeline 并重绘,避免短暂显示上一道
try {
if (this._seismicWidgetBottom && this.pipelineBottom) {
try { this._seismicWidgetBottom.setPipeline(this.pipelineBottom); } catch (e) { }
try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
requestAnimationFrame(() => { try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { } });
}
} catch (e) { /* ignore */ }
this.pencilTool.setEnabled(true);
// 同步启用底部线条工具
if (this.pencilToolBottom && this._seismicWidgetBottom) {
try {
const tm = this._seismicWidgetBottom.getTool && this._seismicWidgetBottom.getTool();
if (tm) {
try { tm.remove(this.pencilToolBottom); } catch (e) { }
tm.insert(0, this.pencilToolBottom);
}
this.pencilToolBottom.setEnabled(true);
} catch (e) { }
}
// 确保底部仍绑定当前数据
this.refreshBottomDisplay();
await this.assertBottomPipelineCurrent();
// 再次校验,若仍被外部影响,强制更正
await this.assertBottomPipelineCurrent();
},
deactivatePencilTool() {
......@@ -6787,6 +7509,45 @@ export default {
},
/**
* 绑定右键菜单事件监听器
*/
bindContextMenuListeners() {
// 先移除旧的监听器(如果存在)
if (this.$refs.plot) {
this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
}
if (this.$refs.plot2) {
this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
}
// 添加新的监听器
if (this.$refs.plot) {
this.$refs.plot.addEventListener('contextmenu', this.showContextMenu);
}
if (this.$refs.plot2) {
this.$refs.plot2.addEventListener('contextmenu', this.showContextMenu);
// 保守修复:在进入/离开底部画布时强制重绘,避免显示旧帧
const bottomEnter = () => { try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { } };
const bottomLeave = () => { try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { } };
try {
this.$refs.plot2.removeEventListener('mouseenter', bottomEnter);
this.$refs.plot2.removeEventListener('mouseleave', bottomLeave);
} catch (e) { }
try {
this.$refs.plot2.addEventListener('mouseenter', bottomEnter);
this.$refs.plot2.addEventListener('mouseleave', bottomLeave);
// 在点击底部画布时强校验绑定的数据是否为当前索引
this.$refs.plot2.addEventListener('mousedown', () => this.assertBottomPipelineCurrent());
} catch (e) { }
}
// document 的 click 事件只需要绑定一次
if (!this._contextMenuClickBound) {
document.addEventListener('click', this.hideContextMenu);
this._contextMenuClickBound = true;
}
},
/**
* 显示右键菜单
*/
showContextMenu(event) {
......@@ -6802,29 +7563,23 @@ export default {
return;
}
// 获取当前选中的形状
const currentShape = activeTool.getShape();
if (!currentShape) {
//console.log('No shape selected');
return;
}
// 获取画布相对于视口的位置
const rect = this.$refs.plot.getBoundingClientRect();
// 获取画布相对于视口的位置(根据事件目标判断是哪个画布)
const targetCanvas = event.target === this.$refs.plot2 ? this.$refs.plot2 : this.$refs.plot;
const rect = targetCanvas ? targetCanvas.getBoundingClientRect() : this.$refs.plot.getBoundingClientRect();
// 计算相对于画布的坐标
this.contextMenu.x = event.clientX - rect.left;
this.contextMenu.y = event.clientY - rect.top;
this.contextMenu.visible = true;
// 记录当前右键菜单使用的工具
// 记录当前右键菜单使用的工具(即使没有选中形状,也记录工具,以便菜单项可以检查状态)
this._contextMenuTool = activeTool;
// //console.log('Context menu shown:', {
// x: this.contextMenu.x,
// y: this.contextMenu.y,
// tool: activeTool.getMode(),
// shape: currentShape ? currentShape.getType() : null
// shape: activeTool.getShape() ? activeTool.getShape().getType() : null
// });
event.stopPropagation();
......@@ -7194,7 +7949,9 @@ export default {
width: data.properties.linestyle.fA,
pattern: []
}),
fillstyle: new FillStyle(data.properties.fillstyle.Lx)
fillstyle: new FillStyle({
color: data.properties.fillstyle && data.properties.fillstyle.Lx ? data.properties.fillstyle.Lx : '#c7e1f6'
})
};
textNode.setProperties(fullProperties);
......@@ -7303,6 +8060,72 @@ export default {
}
},
// 底部:恢复文本标注
restoreAnnotationsBottom() {
if (!this.annotationsBottom || !this._seismicWidgetBottom || !this.savedAnnotationsBottom) return;
try {
this.savedAnnotationsBottom.forEach((data) => {
const textNode = new Text({
text: data.text || data.properties.text,
x: data.properties.ax,
y: data.properties.ay,
width: data.properties.width || 66,
height: data.properties.height || 22,
sizemode: data.properties.sizemode || 5,
selectable: true,
movable: true,
editable: true,
preserveaspectratio: data.properties.preserveaspectratio || false
});
const fullProps = {
...data.properties,
textstyle: new TextStyle({
color: data.properties.textstyle.Lx,
font: data.properties.textstyle.lH,
alignment: data.properties.textstyle.Vf
}),
linestyle: new LineStyle({
color: data.properties.linestyle.Lx,
width: data.properties.linestyle.fA,
pattern: []
}),
fillstyle: new FillStyle({
color: data.properties.fillstyle && data.properties.fillstyle.Lx ? data.properties.fillstyle.Lx : '#c7e1f6'
})
};
textNode.setProperties(fullProps);
this.annotationsBottom.addChild(textNode);
});
this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate();
if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) this._seismicWidgetBottom.fitToBounds();
} catch (e) { console.warn('restoreAnnotationsBottom error:', e); }
},
// 底部:恢复线条标注
restoreLineAnnotationsBottom() {
if (!this.annotationsBottom || !this._seismicWidgetBottom || !this.savedLineAnnotationsBottom) return;
try {
this.savedLineAnnotationsBottom.forEach((data) => {
const path = new Path();
if (data.properties.x && data.properties.x.length > 0) {
path.moveTo(data.properties.x[0], data.properties.y[0]);
for (let i = 1; i < data.properties.x.length; i++) {
path.lineTo(data.properties.x[i], data.properties.y[i]);
}
}
const lineStyle = new LineStyle({
color: data.properties.linestyle.Lx || '#0351ad',
width: data.properties.linestyle.fA || 2,
pattern: []
});
path.setProperties({ linestyle: lineStyle, selectable: true, movable: true, editable: true });
this.annotationsBottom.addChild(path);
});
this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate();
if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) this._seismicWidgetBottom.fitToBounds();
} catch (e) { console.warn('restoreLineAnnotationsBottom error:', e); }
},
// 添加在指定位置创建文本的方法
createTextAtPosition() {
if (!this._seismicWidget || !this.annotations) {
......@@ -7701,13 +8524,22 @@ export default {
this.pencilTool.dispose();
}
// 移除右键菜单事件监听
if (this.$refs.plot) {
this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
}
if (this.$refs.plot2) {
this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
}
if (this._contextMenuClickBound) {
document.removeEventListener('click', this.hideContextMenu);
// 移除键盘事件监听
window.removeEventListener('keydown', this.handleKeyDown);
this._contextMenuClickBound = false;
}
// 移除键盘事件监听
window.removeEventListener('keydown', this.handleKeyDown);
// 移除鼠标悬停相关事件
// 移除鼠标悬停相关事件
if (this.$refs.plot) {
this.$refs.plot.removeEventListener('mouseenter', () => {
this.isHovering = true;
});
......
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