|
|
|
|
|
<!--
|
|
|
|
|
|
绘制图件的组件
|
|
|
|
|
|
|
|
|
|
|
|
add by RYG
|
|
|
|
|
|
-->
|
|
|
|
|
|
<template>
|
|
|
|
|
|
<!-- <ClientOnly> -->
|
|
|
|
|
|
<!-- 绘图区域 -->
|
|
|
|
|
|
<div class="canvas-container" ref="containerRef" @wheel.prevent="" v-bind="$attrs">
|
|
|
|
|
|
<!-- 水平刻度尺 -->
|
|
|
|
|
|
<canvas id="ruler-horizontal" ref="hRulerRef" :width="viewSize.width * 2 + 'px'" :height="rulerHeight * 2 + 'px'"
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
width: viewSize.width + 'px',
|
|
|
|
|
|
height: rulerHeight + 'px',
|
|
|
|
|
|
left: rulerHeight + 'px',
|
|
|
|
|
|
}" class="ruler horizontal">
|
|
|
|
|
|
</canvas>
|
|
|
|
|
|
<!-- 水平刻度指示 -->
|
|
|
|
|
|
<div ref="rulerHorizontalIndicator" width="1px" :style="{ height: rulerHeight + 'px' }" style="
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
top: 0px;
|
|
|
|
|
|
width: 1px;
|
|
|
|
|
|
background-color: #3e8e41;
|
|
|
|
|
|
z-index: 99;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 垂直刻度尺 -->
|
|
|
|
|
|
<canvas id="ruler-vertical" ref="vRulerRef" :width="rulerHeight * 2 + 'px'" :height="viewSize.height * 2 + 'px'"
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
height: viewSize.height + 'px',
|
|
|
|
|
|
width: rulerHeight + 'px',
|
|
|
|
|
|
top: rulerHeight + 'px',
|
|
|
|
|
|
}" class="ruler vertical">
|
|
|
|
|
|
</canvas>
|
|
|
|
|
|
<!-- 垂直刻度指示 -->
|
|
|
|
|
|
<div width="1px" :style="{ width: rulerHeight + 'px' }" style="
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
left: 0px;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
background-color: #3e8e41;
|
|
|
|
|
|
z-index: 99;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
"></div>
|
|
|
|
|
|
<div v-if="rubberVisible" ref="rubberbandDiv" :style="{
|
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
|
left: rubberbandRectangle.left + 'px',
|
|
|
|
|
|
top: rubberbandRectangle.top + 'px',
|
|
|
|
|
|
width: rubberbandRectangle.width + 'px',
|
|
|
|
|
|
height: rubberbandRectangle.height + 'px',
|
|
|
|
|
|
}" style="
|
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
|
border: 2px dashed rgb(81, 153, 212);
|
|
|
|
|
|
cursor: crosshair;
|
|
|
|
|
|
opacity: 0.5;
|
|
|
|
|
|
display: inline;
|
|
|
|
|
|
z-index: 999;
|
|
|
|
|
|
"></div>
|
|
|
|
|
|
<canvas ref="canvasRef" @mousedown="canvasMouseDown" @mouseup="canvasMouseUp" @mousemove="canvasMouseMove"
|
|
|
|
|
|
@wheel="canvasMouseWheel" @contextmenu.prevent="handleWellContextMenu" :style="{ cursor: GetCursor() }"
|
|
|
|
|
|
class="main-canvas"></canvas>
|
|
|
|
|
|
<div class="context-menu" :class="{ visible: contextMenu.visible }"
|
|
|
|
|
|
:style="{ top: contextMenu.y + 'px', left: contextMenu.x + 'px' }" v-if="contextMenu.visible">
|
|
|
|
|
|
<div class="menu-item" @click="handleMenuAction('edit')">
|
|
|
|
|
|
<el-icon>
|
|
|
|
|
|
<Edit />
|
|
|
|
|
|
</el-icon>编辑
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<!-- <hr class="divider" /> -->
|
|
|
|
|
|
<div class="menu-item" @click="handleMenuAction('wellGroupClone')">
|
|
|
|
|
|
<el-icon>
|
|
|
|
|
|
<CopyDocument />
|
|
|
|
|
|
</el-icon>应用井组参数到其它井组
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="menu-item" @click="handleMenuAction('wellGroupData')">
|
|
|
|
|
|
<el-icon>
|
|
|
|
|
|
<View />
|
|
|
|
|
|
</el-icon>井组数据
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<img v-if="imgVisible" ref="image" :style="{
|
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
|
left: imgPosition.x + 'px',
|
|
|
|
|
|
top: imgPosition.y + 'px',
|
|
|
|
|
|
}" style="pointer-events: none; z-index: 8" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<LoadingDialog v-model="loading" ref="loadingRef" :timeout="10000" message="正在加载图件……" @timeout="onTimeout" />
|
|
|
|
|
|
<WellGroupDataHandle :showDialog="showDialog" v-model="showDialog" class="wellGroupData" />
|
|
|
|
|
|
|
|
|
|
|
|
<WellGroupEditDialog v-model="editVisible" ref="editRef" :parentToken="currentToken" v-if="wellGroupData"
|
|
|
|
|
|
:wellGroupData="wellGroupData" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
|
import { ref, onMounted, onUnmounted, watch } from "vue";
|
|
|
|
|
|
import { emitter } from "~/utils/eventBus";
|
|
|
|
|
|
import { canvasToolType, MouseIcons, SelectHandle } from "~/enums/common.enum";
|
|
|
|
|
|
import { generateGUID } from "~/utils/common";
|
|
|
|
|
|
import { Edit, CopyDocument, View } from "@element-plus/icons-vue";
|
|
|
|
|
|
import { COMMAND, EMIT_COMMAND } from '~/utils/commandTypes'
|
|
|
|
|
|
import { LRUCache } from 'lru-cache';
|
|
|
|
|
|
import { useWebSocket } from '@/composables/useWebSocket'
|
|
|
|
|
|
|
|
|
|
|
|
const { $toastMessage } = useNuxtApp();
|
|
|
|
|
|
const config = useRuntimeConfig();
|
|
|
|
|
|
|
|
|
|
|
|
const EXPIRE_TIME = 5 * 60 * 1000;// 5 分钟
|
|
|
|
|
|
|
|
|
|
|
|
const cache = new LRUCache({
|
|
|
|
|
|
max: 1000, // 最多 1000 个条目
|
|
|
|
|
|
ttl: EXPIRE_TIME // 5 分钟过期
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const loading = ref(false);
|
|
|
|
|
|
const loadingRef = ref(null);
|
|
|
|
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
autoResize: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
default: true, // 是否自动调整画布大小
|
|
|
|
|
|
},
|
|
|
|
|
|
// 页面的 图件存储的 token 的 key
|
|
|
|
|
|
tokenKey: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: 'drawerToken'
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const currentTabTokenKey = computed(() => props.tokenKey);
|
|
|
|
|
|
|
|
|
|
|
|
const editVisible = ref(false);
|
|
|
|
|
|
const editRef = ref(null);
|
|
|
|
|
|
const cmdIds = ref([]);
|
|
|
|
|
|
|
|
|
|
|
|
// 接收到的消息中的token
|
|
|
|
|
|
const receivedToken = ref('');
|
|
|
|
|
|
|
|
|
|
|
|
const currentToken = ref(computed(() => receivedToken.value || localStorage.getItem(currentTabTokenKey.value)));
|
|
|
|
|
|
|
|
|
|
|
|
const { onMessage, status, messages, send } = useWebSocket();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 标尺间隔
|
|
|
|
|
|
let ruler_metrics = [
|
|
|
|
|
|
1,
|
|
|
|
|
|
2,
|
|
|
|
|
|
5,
|
|
|
|
|
|
10,
|
|
|
|
|
|
25,
|
|
|
|
|
|
50,
|
|
|
|
|
|
100,
|
|
|
|
|
|
250,
|
|
|
|
|
|
500,
|
|
|
|
|
|
1000,
|
|
|
|
|
|
2500,
|
|
|
|
|
|
5000,
|
|
|
|
|
|
10000,
|
|
|
|
|
|
25000,
|
|
|
|
|
|
50000,
|
|
|
|
|
|
100000,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
// 水平标尺的起止值
|
|
|
|
|
|
const hRulerSize = reactive({ startX: 0, endX: 0 });
|
|
|
|
|
|
// 垂直标尺的起止值
|
|
|
|
|
|
const vRulerSize = reactive({ startY: 0, endY: 0 });
|
|
|
|
|
|
|
|
|
|
|
|
// 水平标尺的范围
|
|
|
|
|
|
const xRange = computed(() => hRulerSize.endX - hRulerSize.startX);
|
|
|
|
|
|
// 垂直标尺的范围
|
|
|
|
|
|
const yRange = computed(() => vRulerSize.startY - vRulerSize.endY - 35);
|
|
|
|
|
|
|
|
|
|
|
|
// 水平主刻度
|
|
|
|
|
|
const hMainStep = computed(() =>
|
|
|
|
|
|
calculateInterval(hRulerSize.endX, hRulerSize.startX, viewSize.width, false)
|
|
|
|
|
|
);
|
|
|
|
|
|
// 水平中刻度
|
|
|
|
|
|
const hMiddleStep = computed(() => hMainStep.value / 2);
|
|
|
|
|
|
// 水平最小刻度
|
|
|
|
|
|
const hMinStep = computed(() => hMainStep.value / 10);
|
|
|
|
|
|
// 水平刻度取整数值
|
|
|
|
|
|
const hRulerStart = computed(
|
|
|
|
|
|
() => Math.floor(hRulerSize.startX / hMainStep.value) * hMainStep.value
|
|
|
|
|
|
);
|
|
|
|
|
|
const hRulerEnd = computed(
|
|
|
|
|
|
() => Math.round(hRulerSize.endX / hMainStep.value) * hMainStep.value
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 垂直主刻度
|
|
|
|
|
|
const vMainStep = computed(() =>
|
|
|
|
|
|
calculateInterval(vRulerSize.startY, vRulerSize.endY, viewSize.height, true)
|
|
|
|
|
|
);
|
|
|
|
|
|
// 垂直中刻度
|
|
|
|
|
|
const vMiddleStep = computed(() => vMainStep.value / 2);
|
|
|
|
|
|
// 垂直最小刻度
|
|
|
|
|
|
const vMinStep = computed(() => vMainStep.value / 10);
|
|
|
|
|
|
// 垂直刻度取整数值
|
|
|
|
|
|
const vRulerStart = computed(
|
|
|
|
|
|
() => Math.round(vRulerSize.startY / vMainStep.value) * vMainStep.value
|
|
|
|
|
|
);
|
|
|
|
|
|
const vRulerEnd = computed(
|
|
|
|
|
|
() => Math.floor(vRulerSize.endY / vMainStep.value) * vMainStep.value
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const imgPath = ref(""); // 图片路径
|
|
|
|
|
|
const imgVisible = ref(false);
|
|
|
|
|
|
let imgData = null;
|
|
|
|
|
|
const queryDrawRuler = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
const imgPosition = reactive({ x: 0, y: 0 });
|
|
|
|
|
|
const viewSize = reactive({ width: 1024, height: 768 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 选中的图件元素ID
|
|
|
|
|
|
let selectedElementId = "";
|
|
|
|
|
|
// 选中的图件元素
|
|
|
|
|
|
let selectedElement = null;
|
|
|
|
|
|
|
|
|
|
|
|
const wellGroupData = ref(null);
|
|
|
|
|
|
|
|
|
|
|
|
// 右键菜单状态
|
|
|
|
|
|
const contextMenu = ref({
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// const dragImageVisible = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
// 标尺高度/宽度
|
|
|
|
|
|
let rulerHeight = 20;
|
|
|
|
|
|
|
|
|
|
|
|
const mouseStartX = ref(0);
|
|
|
|
|
|
const mouseStartY = ref(0);
|
|
|
|
|
|
|
|
|
|
|
|
const mouseHorizontal = ref(0);
|
|
|
|
|
|
const mouseVertical = ref(0);
|
|
|
|
|
|
|
|
|
|
|
|
let imgX = 0;
|
|
|
|
|
|
let imgY = 0;
|
|
|
|
|
|
|
|
|
|
|
|
let lastX;
|
|
|
|
|
|
let lastY;
|
|
|
|
|
|
const isDragFirst = ref(true);
|
|
|
|
|
|
|
|
|
|
|
|
const mouseDown = ref(false);
|
|
|
|
|
|
// 橡皮筋选框
|
|
|
|
|
|
const rubberVisible = ref(false);
|
|
|
|
|
|
const rubberbandDiv = ref(null);
|
|
|
|
|
|
const rubberbandRectangle = reactive({ left: 10, top: 10, width: 100, height: 100 });
|
|
|
|
|
|
|
|
|
|
|
|
/* 选择轮廓图 */
|
|
|
|
|
|
const initialRect = reactive({ left: 0, top: 0, width: 0, height: 0 });
|
|
|
|
|
|
|
|
|
|
|
|
const pressedKeyCode = ref(null);
|
|
|
|
|
|
|
|
|
|
|
|
const drawerToolType = ref(canvasToolType.Default);
|
|
|
|
|
|
const handleIndex = ref(-1);
|
|
|
|
|
|
// 缩放比例
|
|
|
|
|
|
const scale = ref(1);
|
|
|
|
|
|
|
|
|
|
|
|
// const store = useBtnClickStore();
|
|
|
|
|
|
const containerRef = ref(null);
|
|
|
|
|
|
const canvasRef = ref(null);
|
|
|
|
|
|
const hRulerRef = ref(null);
|
|
|
|
|
|
const vRulerRef = ref(null);
|
|
|
|
|
|
const image = ref(null);
|
|
|
|
|
|
const dpr = ref(1); // 设备像素比
|
|
|
|
|
|
let frameId = 0;
|
|
|
|
|
|
|
|
|
|
|
|
const showDialog = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
const dataDir = config.public.dataDir;
|
|
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(["resize", "init", "openFile", "editWellGroup"]);
|
|
|
|
|
|
|
|
|
|
|
|
const isView = ref(false);
|
|
|
|
|
|
|
|
|
|
|
|
let mainCtx = null;
|
|
|
|
|
|
|
|
|
|
|
|
const unsubscribe = onMessage((data) => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
if (!data) return; // 如果没有新消息,直接返回
|
|
|
|
|
|
// console.log("收到消息:", data);
|
|
|
|
|
|
const json = JSON.parse(data);
|
|
|
|
|
|
const evtType = json.type;
|
|
|
|
|
|
if (evtType !== COMMAND.SELECT_HANDLE) {
|
|
|
|
|
|
// console.log("接收到DrawServer的消息:", json)
|
|
|
|
|
|
// console.log("判断:", json.cmdID, currentTabTokenKey.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (json.cmdID && json.cmdID !== currentTabTokenKey.value) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const msgId = `${evtType}-${json.dateTime}`;
|
|
|
|
|
|
if (cache.has(msgId) && (evtType !== COMMAND.SELECT_HANDLE && evtType !== COMMAND.DRAG_ELEMENT)) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
cache.set(msgId, true);
|
|
|
|
|
|
|
|
|
|
|
|
// 只有第一次打开文件时才存储token
|
|
|
|
|
|
if (Object.hasOwn(json, "drawerToken") && json.drawerToken && evtType === COMMAND.NEW_TOKEN) {
|
|
|
|
|
|
receivedToken.value = json.drawerToken;
|
|
|
|
|
|
localStorage.setItem(currentTabTokenKey.value, json.drawerToken);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (evtType) {
|
|
|
|
|
|
case COMMAND.REDRAW:
|
|
|
|
|
|
refreshImg(json);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case COMMAND.OPEN_ERROR:
|
|
|
|
|
|
localStorage.removeItem(currentTabTokenKey.value);
|
|
|
|
|
|
closeLoading();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case COMMAND.SELECT_HANDLE:
|
|
|
|
|
|
if (json.data !== -2) {
|
|
|
|
|
|
handleIndex.value = json.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case COMMAND.DRAG_ELEMENT:
|
|
|
|
|
|
let imgContent = json.data;
|
|
|
|
|
|
if (!imgContent && imgContent.Data) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
imgVisible.value = true;
|
|
|
|
|
|
Object.assign(imgPosition, {
|
|
|
|
|
|
x: imgContent.ImgLeft + rulerHeight,
|
|
|
|
|
|
y: imgContent.ImgTop + rulerHeight
|
|
|
|
|
|
});
|
|
|
|
|
|
Object.assign(initialRect, { left: imgPosition.x, top: imgPosition.y, width: imgContent.ImgWidth, height: imgContent.ImgHeight });
|
|
|
|
|
|
console.log("initialRect:", initialRect, imgPosition)
|
|
|
|
|
|
// imgPath.value = imgContent.Data + "?_=" + Math.random();
|
|
|
|
|
|
// let imgTmp = image.value;
|
|
|
|
|
|
// imgTmp.src = `${config.public.imgUrl}/${imgPath.value}`;
|
|
|
|
|
|
// imgX = json.data.ImgLeft;
|
|
|
|
|
|
// imgY = json.data.ImgTop;
|
|
|
|
|
|
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
let imgTmp = image.value;
|
|
|
|
|
|
imgTmp.src = `${config.public.imgUrl}/${imgContent.Data}`;
|
|
|
|
|
|
// console.log("图件地址:", imgTmp.src);
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case COMMAND.ELEMENT_PROPERTY:
|
|
|
|
|
|
// console.log("当前KEY:", currentTabTokenKey.value, "\t cmdID", json.cmdID)
|
|
|
|
|
|
if (currentTabTokenKey.value !== json.cmdID) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
let wellGroupProp = json.data;
|
|
|
|
|
|
wellGroupData.value = json.data;
|
|
|
|
|
|
selectedElement = wellGroupProp.ElementData;
|
|
|
|
|
|
selectedElementId = wellGroupProp.ElementID;
|
|
|
|
|
|
if (selectedElement) {
|
|
|
|
|
|
emitter.emit(EMIT_COMMAND.WELL_GROUP_DATA, {
|
|
|
|
|
|
propData: selectedElement,
|
|
|
|
|
|
id: selectedElementId,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case COMMAND.WELL_GROUP_DATA:
|
|
|
|
|
|
// console.log("井组数据:", json.data);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case COMMAND.MAP_RANGE_REAL:
|
|
|
|
|
|
if (queryDrawRuler.value) {
|
|
|
|
|
|
let imgRect = json.data;
|
|
|
|
|
|
hRulerSize.startX = Math.round(imgRect.left);
|
|
|
|
|
|
hRulerSize.endX = Math.round(imgRect.right);
|
|
|
|
|
|
|
|
|
|
|
|
vRulerSize.startY = Math.round(imgRect.top);
|
|
|
|
|
|
vRulerSize.endY = Math.round(imgRect.bottom);
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("标尺属性:", hRulerSize, vRulerSize);
|
|
|
|
|
|
|
|
|
|
|
|
drawRulers();
|
|
|
|
|
|
queryDrawRuler.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
closeLoading();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "center":
|
|
|
|
|
|
break;
|
|
|
|
|
|
case COMMAND.SAVE:
|
|
|
|
|
|
if (json.data) {
|
|
|
|
|
|
$toastMessage.success("保存成功!");
|
|
|
|
|
|
doRedraw();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$toastMessage.error("保存失败!");
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case COMMAND.MERGE_FILE:
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
doRedraw();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const doRedraw = () => {
|
|
|
|
|
|
sendCmd(COMMAND.REDRAW, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const handleWellContextMenu = (e) => {
|
|
|
|
|
|
// 阻止默认的右键菜单
|
|
|
|
|
|
// event.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
if (selectedElementId === "") {
|
|
|
|
|
|
console.warn("没有选中任何井组");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
contextMenu.value = {
|
|
|
|
|
|
visible: true,
|
|
|
|
|
|
x: e.offsetX,
|
|
|
|
|
|
y: e.offsetY,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 阻止事件冒泡,避免触发 mouseup 事件
|
|
|
|
|
|
// event.stopPropagation();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭右键菜单
|
|
|
|
|
|
const closeContextMenu = () => {
|
|
|
|
|
|
contextMenu.value = {
|
|
|
|
|
|
visible: false,
|
|
|
|
|
|
x: 0,
|
|
|
|
|
|
y: 0,
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleMenuAction = (action) => {
|
|
|
|
|
|
switch (action) {
|
|
|
|
|
|
// 应用井组参数
|
|
|
|
|
|
case "wellGroupClone":
|
|
|
|
|
|
sendCmd(COMMAND.WELL_GROUP_CLONE, { elementID: selectedElementId });
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "wellGroupData":
|
|
|
|
|
|
|
|
|
|
|
|
showDialog.value = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 取消操作
|
|
|
|
|
|
case "cancel":
|
|
|
|
|
|
break;
|
|
|
|
|
|
// 编辑操作
|
|
|
|
|
|
case "edit":
|
|
|
|
|
|
editVisible.value = true;
|
|
|
|
|
|
// 修改为左右对比模式
|
|
|
|
|
|
// emit("editWellGroup", currentToken.value, wellGroupData.value);
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
console.warn("未知操作:", action);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 隐藏右键菜单
|
|
|
|
|
|
closeContextMenu();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标按下
|
|
|
|
|
|
const canvasMouseDown = (event) => {
|
|
|
|
|
|
if (event.button !== 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
mouseDown.value = true;
|
|
|
|
|
|
lastX = event.offsetX;
|
|
|
|
|
|
lastY = event.offsetY;
|
|
|
|
|
|
mouseStartX.value = event.offsetX;
|
|
|
|
|
|
mouseStartY.value = event.offsetY;
|
|
|
|
|
|
const rect = canvasRef.value.getBoundingClientRect();
|
|
|
|
|
|
console.log("鼠标按下:", drawerToolType.value, handleIndex.value);
|
|
|
|
|
|
switch (drawerToolType.value) {
|
|
|
|
|
|
case canvasToolType.ViewPan:
|
|
|
|
|
|
isDragFirst.value = true;
|
|
|
|
|
|
imgVisible.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
Object.assign(imgPosition, { x: 0, y: 0 });
|
|
|
|
|
|
mouseStartX.value = event.clientX - rect.left;
|
|
|
|
|
|
mouseStartY.value = event.clientY - rect.top;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.ViewWindow:
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
rubberVisible.value = true;
|
|
|
|
|
|
|
|
|
|
|
|
mouseStartX.value = event.clientX - rect.left;
|
|
|
|
|
|
mouseStartY.value = event.clientY - rect.top;
|
|
|
|
|
|
rubberbandRectangle.left = mouseStartX.value;
|
|
|
|
|
|
rubberbandRectangle.top = mouseStartY.value;
|
|
|
|
|
|
rubberbandRectangle.width = 1;
|
|
|
|
|
|
rubberbandRectangle.height = 1;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.Select:
|
|
|
|
|
|
imgVisible.value = true;
|
|
|
|
|
|
// mouseStartX.value = event.clientX - rect.left;
|
|
|
|
|
|
// mouseStartY.value = event.clientY - rect.top;
|
|
|
|
|
|
console.log("canvasToolType.Select:", mouseStartX.value, mouseStartY.value, event.offsetX, event.offsetY);
|
|
|
|
|
|
if (handleIndex.value >= 0 && handleIndex.value <= 9) {
|
|
|
|
|
|
// console.log("SELECT_DRAG_START", event.offsetX, event.offsetY);
|
|
|
|
|
|
// 发送拖动开始消息
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_DRAG_START, { x: event.offsetX, y: event.offsetY });
|
|
|
|
|
|
}
|
|
|
|
|
|
// imgVisible.value = true;
|
|
|
|
|
|
// mouseStartX.value = event.clientX - rect.left;
|
|
|
|
|
|
// mouseStartY.value = event.clientY - rect.top;
|
|
|
|
|
|
// sendCmd(COMMAND.SELECT_MOUSE_DOWN, { x: mouseStartX.value, y: mouseStartY.value });
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
closeContextMenu();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标按键抬起
|
|
|
|
|
|
const canvasMouseUp = (event) => {
|
|
|
|
|
|
if (event.button !== 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const rect = canvasRef.value.getBoundingClientRect();
|
|
|
|
|
|
let endX = 0;
|
|
|
|
|
|
let endY = 0;
|
|
|
|
|
|
|
|
|
|
|
|
console.log("鼠标抬起:", drawerToolType.value, handleIndex.value);
|
|
|
|
|
|
|
|
|
|
|
|
switch (drawerToolType.value) {
|
|
|
|
|
|
case canvasToolType.ViewPan:
|
|
|
|
|
|
endX = event.clientX - rect.left;
|
|
|
|
|
|
endY = event.clientY - rect.top;
|
|
|
|
|
|
// 必须释放,否则图件显示不出来
|
|
|
|
|
|
cancelAnimationFrame(frameId);
|
|
|
|
|
|
sendCmd(COMMAND.VIEW_PAN, {
|
|
|
|
|
|
startX: mouseStartX.value,
|
|
|
|
|
|
startY: mouseStartY.value,
|
|
|
|
|
|
endX: endX,
|
|
|
|
|
|
endY: endY,
|
|
|
|
|
|
width: viewSize.width,
|
|
|
|
|
|
height: viewSize.height,
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.ViewWindow:
|
|
|
|
|
|
rubberVisible.value = false;
|
|
|
|
|
|
endX = event.clientX - rect.left;
|
|
|
|
|
|
endY = event.clientY - rect.top;
|
|
|
|
|
|
sendCmd(COMMAND.VIEW_WINDOW, {
|
|
|
|
|
|
startX: mouseStartX.value,
|
|
|
|
|
|
startY: mouseStartY.value,
|
|
|
|
|
|
endX: endX,
|
|
|
|
|
|
endY: endY,
|
|
|
|
|
|
width: viewSize.width,
|
|
|
|
|
|
height: viewSize.height,
|
|
|
|
|
|
});
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.Select:
|
|
|
|
|
|
endX = event.offsetX;
|
|
|
|
|
|
endY = event.offsetY;
|
|
|
|
|
|
|
|
|
|
|
|
console.log("endX=", endX);
|
|
|
|
|
|
console.log("endY=", endY);
|
|
|
|
|
|
console.log("lastX=", lastX);
|
|
|
|
|
|
console.log("lastY=", lastY);
|
|
|
|
|
|
console.log("mouseStartX=", mouseStartX.value);
|
|
|
|
|
|
console.log("mouseStartY=", mouseStartY.value);
|
|
|
|
|
|
// 拖动结束
|
|
|
|
|
|
if (handleIndex.value === SelectHandle.Body) {
|
|
|
|
|
|
imgVisible.value = false;
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_TRANSFORM_ELEMENTS, {
|
|
|
|
|
|
handle: handleIndex.value,
|
|
|
|
|
|
startX: mouseStartX.value,
|
|
|
|
|
|
startY: mouseStartY.value,
|
|
|
|
|
|
endX: endX,
|
|
|
|
|
|
endY: endY
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
// 变形处理
|
|
|
|
|
|
else if (handleIndex.value >= 0 && handleIndex.value < 8) {
|
|
|
|
|
|
imgVisible.value = false;
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_TRANSFORM_ELEMENTS, {
|
|
|
|
|
|
handle: handleIndex.value,
|
|
|
|
|
|
startX: mouseStartX.value,
|
|
|
|
|
|
startY: mouseStartY.value,
|
|
|
|
|
|
endX: endX,
|
|
|
|
|
|
endY: endY
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (handleIndex.value === SelectHandle.Nothing) {
|
|
|
|
|
|
rubberVisible.value = false;
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_REGION, {
|
|
|
|
|
|
startX: lastX,
|
|
|
|
|
|
startY: lastY,
|
|
|
|
|
|
endX: endX,
|
|
|
|
|
|
endY: endY,
|
|
|
|
|
|
isAdd: false
|
|
|
|
|
|
});
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_MOUSE_UP, { x: lastX, y: lastY, keyCode: pressedKeyCode.value });
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
sendCmd(COMMAND.SELECT_MOUSE_UP, { x: lastX, y: lastY, keyCode: pressedKeyCode.value });
|
|
|
|
|
|
}
|
|
|
|
|
|
// endX = event.offsetX;
|
|
|
|
|
|
// endY = event.offsetY;
|
|
|
|
|
|
// if (handleIndex.value == 5) {
|
|
|
|
|
|
// sendCmd(COMMAND.DRAG_ELEMENT, { x: endX, y: endY });
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// // 图元选择
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mouseDown.value = false;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标移动
|
|
|
|
|
|
const canvasMouseMove = (event) => {
|
|
|
|
|
|
mouseHorizontal.value = event.offsetX + rulerHeight;
|
|
|
|
|
|
mouseVertical.value = event.offsetY + rulerHeight;
|
|
|
|
|
|
if (!mouseDown.value) {
|
|
|
|
|
|
if (drawerToolType.value === canvasToolType.Select) {
|
|
|
|
|
|
sendCmd(COMMAND.MOUSE_MOVE, {
|
|
|
|
|
|
x: event.offsetX - rulerHeight,
|
|
|
|
|
|
y: event.offsetY - rulerHeight,
|
|
|
|
|
|
handleIndex: handleIndex.value,
|
|
|
|
|
|
});
|
|
|
|
|
|
// console.log("位置:", event.offsetX, event.offsetY, handleIndex.value, mouseStartX.value, mouseStartY.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// console.log("鼠标移动:", drawerToolType.value, handleIndex.value);
|
|
|
|
|
|
|
|
|
|
|
|
const rect = canvasRef.value.getBoundingClientRect();
|
|
|
|
|
|
let dragStartX = 0;
|
|
|
|
|
|
let dragStartY = 0;
|
|
|
|
|
|
switch (drawerToolType.value) {
|
|
|
|
|
|
case canvasToolType.ViewPan:
|
|
|
|
|
|
let offsetX = event.offsetX - lastX;
|
|
|
|
|
|
let offsetY = event.offsetY - lastY;
|
|
|
|
|
|
|
|
|
|
|
|
if (isDragFirst.value) {
|
|
|
|
|
|
isDragFirst.value = false;
|
|
|
|
|
|
const dataURL = canvasRef.value.toDataURL("image/png");
|
|
|
|
|
|
image.value.src = dataURL;
|
|
|
|
|
|
Object.assign(imgPosition, {
|
|
|
|
|
|
x: imgPosition.x + offsetX,
|
|
|
|
|
|
y: imgPosition.y + offsetY,
|
|
|
|
|
|
});
|
|
|
|
|
|
// draw();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Object.assign(imgPosition, {
|
|
|
|
|
|
x: imgPosition.x + offsetX,
|
|
|
|
|
|
y: imgPosition.y + offsetY,
|
|
|
|
|
|
});
|
|
|
|
|
|
// draw();
|
|
|
|
|
|
}
|
|
|
|
|
|
lastX = event.offsetX;
|
|
|
|
|
|
lastY = event.offsetY;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.ViewWindow:
|
|
|
|
|
|
let endX = event.clientX - rect.left;
|
|
|
|
|
|
let endY = event.clientY - rect.top;
|
|
|
|
|
|
dragStartX = mouseStartX.value;
|
|
|
|
|
|
dragStartY = mouseStartY.value;
|
|
|
|
|
|
if (endX < dragStartX) {
|
|
|
|
|
|
dragStartX = endX;
|
|
|
|
|
|
endX = mouseStartX.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (endY < dragStartY) {
|
|
|
|
|
|
dragStartY = endY;
|
|
|
|
|
|
endY = mouseStartY.value;
|
|
|
|
|
|
}
|
|
|
|
|
|
rubberbandRectangle.left = dragStartX;
|
|
|
|
|
|
rubberbandRectangle.top = dragStartY;
|
|
|
|
|
|
rubberbandRectangle.width = endX - dragStartX;
|
|
|
|
|
|
rubberbandRectangle.height = endY - dragStartY;
|
|
|
|
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.Select:
|
|
|
|
|
|
let currentX = event.offsetX;
|
|
|
|
|
|
let currentY = event.offsetY;
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
let imgTmp = image.value;
|
|
|
|
|
|
switch (handleIndex.value) {
|
|
|
|
|
|
case SelectHandle.Nothing:
|
|
|
|
|
|
dragStartX = lastX;
|
|
|
|
|
|
dragStartY = lastY;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保坐标按左上->右下排列
|
|
|
|
|
|
var left = Math.min(dragStartX, currentX);
|
|
|
|
|
|
var top = Math.min(dragStartY, currentY);
|
|
|
|
|
|
var right = Math.max(dragStartX, currentX);
|
|
|
|
|
|
var bottom = Math.max(dragStartY, currentY);
|
|
|
|
|
|
|
|
|
|
|
|
var rbWidth = right - left;
|
|
|
|
|
|
var rbHeight = bottom - top;
|
|
|
|
|
|
if (rbWidth > 0 || rbHeight > 0) {
|
|
|
|
|
|
if (!rubberVisible.value) {
|
|
|
|
|
|
rubberVisible.value = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rubberbandRectangle.left = left;
|
|
|
|
|
|
rubberbandRectangle.top = top;
|
|
|
|
|
|
rubberbandRectangle.width = rbWidth;
|
|
|
|
|
|
rubberbandRectangle.height = rbHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
rubberVisible.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.Right:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width + (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height}px`;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.Left:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width - (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height}px`;
|
|
|
|
|
|
|
|
|
|
|
|
imgPosition.x = initialRect.left + (currentX - mouseStartX.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.Bottom:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height + (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.Top:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height - (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
|
|
|
|
|
|
imgPosition.y = initialRect.top + (currentY - mouseStartY.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.BottomRight:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width + (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height + (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.BottomLeft:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width - (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height + (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
|
|
|
|
|
|
imgPosition.x = initialRect.left + (currentX - mouseStartX.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.TopRight:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width + (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height - (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
|
|
|
|
|
|
// imgPosition.x = initialRect.left + (currentX - mouseStartX.value);
|
|
|
|
|
|
imgPosition.y = initialRect.top + (currentY - mouseStartY.value);
|
|
|
|
|
|
|
|
|
|
|
|
console.log("位置:", initialRect, currentX, currentY, mouseStartX.value, mouseStartY.value, imgPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.TopLeft:
|
|
|
|
|
|
if (imgTmp && imgVisible.value) {
|
|
|
|
|
|
imgTmp.style.objectFit = 'fill'; // 允许拉伸填充
|
|
|
|
|
|
imgTmp.style.width = `${initialRect.width - (currentX - mouseStartX.value)}px`;
|
|
|
|
|
|
imgTmp.style.height = `${initialRect.height - (currentY - mouseStartY.value)}px`;
|
|
|
|
|
|
|
|
|
|
|
|
imgPosition.x = initialRect.left + (currentX - mouseStartX.value);
|
|
|
|
|
|
imgPosition.y = initialRect.top + (currentY - mouseStartY.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case SelectHandle.Body:
|
|
|
|
|
|
// 拖动
|
|
|
|
|
|
let offsetX = event.offsetX - lastX;
|
|
|
|
|
|
let offsetY = event.offsetY - lastY;
|
|
|
|
|
|
if (Math.abs(offsetX) > 0 || Math.abs(offsetY) > 0) {
|
|
|
|
|
|
Object.assign(imgPosition, { x: imgPosition.x + offsetX, y: imgPosition.y + offsetY });
|
|
|
|
|
|
lastX = event.offsetX;
|
|
|
|
|
|
lastY = event.offsetY;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
// console.log("拖动:", moveX, moveY);
|
|
|
|
|
|
// Object.assign(imgPosition, {
|
|
|
|
|
|
// x: imgX + moveX,
|
|
|
|
|
|
// y: imgY + moveY
|
|
|
|
|
|
// })
|
|
|
|
|
|
|
|
|
|
|
|
// lastX = event.offsetX;
|
|
|
|
|
|
// lastY = event.offsetY;
|
|
|
|
|
|
// break;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const draw = () => {
|
|
|
|
|
|
if (!mainCtx) return;
|
|
|
|
|
|
mainCtx.clearRect(0, 0, viewSize.width, viewSize.height);
|
|
|
|
|
|
frameId = requestAnimationFrame(draw);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const canvasMouseWheel = (event) => {
|
|
|
|
|
|
scale.value = scale.value + 1;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const refreshImg = (data) => {
|
|
|
|
|
|
// console.log("refreshImg:", data);
|
|
|
|
|
|
imgPath.value = data.data + "?_=" + Math.random();
|
|
|
|
|
|
redrawCanvas(imgPath.value);
|
|
|
|
|
|
closeLoading();
|
|
|
|
|
|
if (currentTabTokenKey.value !== data.cmdID) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
emitter.emit(EMIT_COMMAND.REFRESH_LAYER);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制图片
|
|
|
|
|
|
const redrawCanvas = async (data) => {
|
|
|
|
|
|
if (data.length === 0) return;
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await fetch(`${config.public.imgUrl}/${data}`, {
|
|
|
|
|
|
cache: "no-store",
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
|
$toastMessage.error("Network response was not ok");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const { pixelWidth, pixelHeight } = getDrawingAreaSize();
|
|
|
|
|
|
viewSize.width = pixelWidth;
|
|
|
|
|
|
viewSize.height = pixelHeight;
|
|
|
|
|
|
|
|
|
|
|
|
const blob = await response.blob();
|
|
|
|
|
|
imgData = await createImageBitmap(blob);
|
|
|
|
|
|
|
|
|
|
|
|
if (!mainCtx) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
mainCtx.clearRect(0, 0, viewSize.width, viewSize.height - rulerHeight);
|
|
|
|
|
|
mainCtx.drawImage(imgData, rulerHeight, rulerHeight);
|
|
|
|
|
|
imgVisible.value = false;
|
|
|
|
|
|
queryDrawRuler.value = true;
|
|
|
|
|
|
sendCmd(COMMAND.QUERY_RANGE_SCREEN_TO_REAL, {
|
|
|
|
|
|
startX: rulerHeight,
|
|
|
|
|
|
endX: viewSize.width,
|
|
|
|
|
|
startY: rulerHeight,
|
|
|
|
|
|
endY: viewSize.height,
|
|
|
|
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error("Failed to load the image:", error);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 默认
|
|
|
|
|
|
const toolDefault = () => {
|
|
|
|
|
|
drawerToolType.value = canvasToolType.Default;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toolViewMove = () => {
|
|
|
|
|
|
drawerToolType.value = canvasToolType.ViewPan;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toolViewWindow = () => {
|
|
|
|
|
|
drawerToolType.value = canvasToolType.ViewWindow;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const toolSelect = () => {
|
|
|
|
|
|
drawerToolType.value = canvasToolType.Select;
|
|
|
|
|
|
toolSwitch(drawerToolType.value);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 工具切换
|
|
|
|
|
|
const toolSwitch = (newToolType) => {
|
|
|
|
|
|
sendCmd(COMMAND.SWITCH_TOOL_TYPE, { toolType: newToolType });
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 放大
|
|
|
|
|
|
const drawZoomIn = () => {
|
|
|
|
|
|
sendCmd(COMMAND.ZOOM_IN, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 缩小
|
|
|
|
|
|
const drawZoomOut = () => {
|
|
|
|
|
|
sendCmd(COMMAND.ZOOM_OUT, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新
|
|
|
|
|
|
const drawRefresh = () => {
|
|
|
|
|
|
// redrawCanvas(imgPath.value);
|
|
|
|
|
|
sendCmd(COMMAND.REFRESH, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 居中
|
|
|
|
|
|
const drawCenter = () => {
|
|
|
|
|
|
sendCmd(COMMAND.CENTER, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 全部
|
|
|
|
|
|
const viewAll = () => {
|
|
|
|
|
|
sendCmd(COMMAND.VIEW_ALL, { width: viewSize.width, height: viewSize.height });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const GetCursor = () => {
|
|
|
|
|
|
let iconName = "default";
|
|
|
|
|
|
// console.log("GetCursor:", drawerToolType.value, handleIndex.value)
|
|
|
|
|
|
switch (drawerToolType.value) {
|
|
|
|
|
|
case canvasToolType.Select:
|
|
|
|
|
|
// if (handleIndex.value == 5) {
|
|
|
|
|
|
// iconName = `url('./assets/move.svg') 24 24 auto`;
|
|
|
|
|
|
// } else {
|
|
|
|
|
|
// iconName = MouseIcons.pointerSelect;
|
|
|
|
|
|
// }
|
|
|
|
|
|
if (handleIndex.value === SelectHandle.Body || handleIndex.value === SelectHandle.Center) {
|
|
|
|
|
|
iconName = `url('./assets/move.svg') 24 24 auto`;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (handleIndex.value === SelectHandle.TopLeft || handleIndex.value === SelectHandle.BottomRight) {
|
|
|
|
|
|
return MouseIcons.resizenw;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (handleIndex.value === SelectHandle.TopRight || handleIndex.value === SelectHandle.BottomLeft) {
|
|
|
|
|
|
return MouseIcons.resizene;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (handleIndex.value === SelectHandle.Left || handleIndex.value === SelectHandle.Right) {
|
|
|
|
|
|
return MouseIcons.resizee;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (handleIndex.value === SelectHandle.Top || handleIndex.value === SelectHandle.Bottom) {
|
|
|
|
|
|
return MouseIcons.resizen;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
return MouseIcons.pointerSelect;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.ViewPan:
|
|
|
|
|
|
iconName = MouseIcons.viewPan;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case canvasToolType.ViewWindow:
|
|
|
|
|
|
iconName = MouseIcons.crosshair;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
return iconName;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const showLayers = () => {
|
|
|
|
|
|
emitter.emit(EMIT_COMMAND.SHOW_LAYERS);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 按键
|
|
|
|
|
|
const handleKeyDown = (event) => {
|
|
|
|
|
|
pressedKeyCode.value = event.keyCode;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleKeyUp = (event) => {
|
|
|
|
|
|
pressedKeyCode.value = null;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 打开文件
|
|
|
|
|
|
const openFile = (fileUrl, token) => {
|
|
|
|
|
|
if (!fileUrl) return;
|
|
|
|
|
|
if (!canvasRef.value) return;
|
|
|
|
|
|
|
|
|
|
|
|
loading.value = true;
|
|
|
|
|
|
// 获取画布大小
|
|
|
|
|
|
let rect = getDrawingAreaSize();
|
|
|
|
|
|
// console.log("当前tokenkey:", currentTabTokenKey.value, token)
|
|
|
|
|
|
if (token) {
|
|
|
|
|
|
localStorage.setItem(currentTabTokenKey.value, token);
|
|
|
|
|
|
}
|
|
|
|
|
|
// console.log("画布尺寸:", viewSize);
|
|
|
|
|
|
sendCmd(COMMAND.OPEN_FILE, {
|
|
|
|
|
|
file: fileUrl,
|
|
|
|
|
|
token: token,
|
|
|
|
|
|
width: rect.pixelWidth,
|
|
|
|
|
|
height: rect.pixelHeight,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function save() {
|
|
|
|
|
|
sendCmd(COMMAND.SAVE_FILE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 安全获取 devicePixelRatio
|
|
|
|
|
|
const getDevicePixelRatio = () => {
|
|
|
|
|
|
return (typeof window !== "undefined" && window.devicePixelRatio) || 1;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设备像素比
|
|
|
|
|
|
const getDrawingAreaSize = () => {
|
|
|
|
|
|
if (!containerRef.value) return { width: 0, height: 0 };
|
|
|
|
|
|
|
|
|
|
|
|
const { clientWidth: width, clientHeight: height } = containerRef.value;
|
|
|
|
|
|
dpr.value = getDevicePixelRatio(); // 获取设备像素比
|
|
|
|
|
|
return {
|
|
|
|
|
|
pixelWidth: width * dpr.value, // 实际像素宽度
|
|
|
|
|
|
pixelHeight: height * dpr.value, // 实际像素高度
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化画布大小
|
|
|
|
|
|
const initCanvasSize = () => {
|
|
|
|
|
|
const canvas = canvasRef.value;
|
|
|
|
|
|
|
|
|
|
|
|
if (!canvas) return;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("Canvas加载完成")
|
|
|
|
|
|
|
|
|
|
|
|
// 获取容器尺寸
|
|
|
|
|
|
const { pixelWidth, pixelHeight } = getDrawingAreaSize();
|
|
|
|
|
|
viewSize.width = pixelWidth;
|
|
|
|
|
|
viewSize.height = pixelHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("initCanvasSize:", viewSize)
|
|
|
|
|
|
|
|
|
|
|
|
// 设置画布大小
|
|
|
|
|
|
canvas.width = pixelWidth * dpr.value; // 实际像素宽度
|
|
|
|
|
|
canvas.height = pixelHeight * dpr.value; // 实际像素高度
|
|
|
|
|
|
canvas.style.width = `${pixelWidth}px`;
|
|
|
|
|
|
canvas.style.height = `${pixelHeight}px`;
|
|
|
|
|
|
// 获取2D上下文
|
|
|
|
|
|
mainCtx = canvas.getContext("2d");
|
|
|
|
|
|
if (!mainCtx) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
mainCtx.scale(dpr.value, dpr.value); // 缩放上下文以适应设备像素比
|
|
|
|
|
|
// 关闭图像平滑处理
|
|
|
|
|
|
mainCtx.imageSmoothingEnabled = false;
|
|
|
|
|
|
mainCtx.fillStyle = "#FFFFFF";
|
|
|
|
|
|
mainCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
|
|
let rect = canvas.getBoundingClientRect();
|
|
|
|
|
|
|
|
|
|
|
|
Object.assign(imgPosition, {
|
|
|
|
|
|
x: rect.left,
|
|
|
|
|
|
y: rect.top,
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制刻度尺
|
|
|
|
|
|
const drawRulers = () => {
|
|
|
|
|
|
// 获取容器尺寸
|
|
|
|
|
|
const { pixelWidth, pixelHeight } = getDrawingAreaSize();
|
|
|
|
|
|
viewSize.width = pixelWidth;
|
|
|
|
|
|
viewSize.height = pixelHeight;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("窗口尺寸:", viewSize);
|
|
|
|
|
|
|
|
|
|
|
|
drawHRuler();
|
|
|
|
|
|
drawVRuler();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 水平标尺绘制
|
|
|
|
|
|
const drawHRuler = () => {
|
|
|
|
|
|
const width = viewSize.width * 2;
|
|
|
|
|
|
const hRulerCanvas = hRulerRef.value;
|
|
|
|
|
|
const ctx = hRulerCanvas.getContext("2d");
|
|
|
|
|
|
ctx.clearRect(0, 0, width, rulerHeight * 2);
|
|
|
|
|
|
ctx.lineWidth = 1;
|
|
|
|
|
|
ctx.font = "16px Arial";
|
|
|
|
|
|
ctx.textAlign = "left";
|
|
|
|
|
|
ctx.fillStyle = "#333";
|
|
|
|
|
|
// 计算像素比例
|
|
|
|
|
|
const pxPerUnit = width / xRange.value;
|
|
|
|
|
|
|
|
|
|
|
|
// console.log("水平标尺属性:", hRulerStart.value, hRulerEnd.value, hMainStep.value);
|
|
|
|
|
|
// 主刻度
|
|
|
|
|
|
for (
|
|
|
|
|
|
let value = hRulerStart.value;
|
|
|
|
|
|
value <= hRulerEnd.value;
|
|
|
|
|
|
value += hMainStep.value
|
|
|
|
|
|
) {
|
|
|
|
|
|
const x = (((value - hRulerStart.value) / xRange.value) * width) / scale.value;
|
|
|
|
|
|
// console.log("X主刻度:", x);
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(x, 0);
|
|
|
|
|
|
ctx.lineTo(x, 20);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
ctx.fillText(value, x + 5, rulerHeight + 10);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 次刻度
|
|
|
|
|
|
for (
|
|
|
|
|
|
let value = hRulerStart.value;
|
|
|
|
|
|
value <= hRulerEnd.value;
|
|
|
|
|
|
value += hMiddleStep.value
|
|
|
|
|
|
) {
|
|
|
|
|
|
if (value % hMainStep.value === 0) continue;
|
|
|
|
|
|
const x = ((value - hRulerStart.value) / xRange.value) * width;
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(x, 0);
|
|
|
|
|
|
ctx.lineTo(x, 15);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最小刻度
|
|
|
|
|
|
for (let value = hRulerStart.value; value <= hRulerEnd.value; value += hMinStep.value) {
|
|
|
|
|
|
if (value % hMainStep.value === 0 || value % hMiddleStep.value === 0) continue;
|
|
|
|
|
|
|
|
|
|
|
|
const x = ((value - hRulerStart.value) / xRange.value) * width;
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(x, 0);
|
|
|
|
|
|
ctx.lineTo(x, 10);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 垂直标尺绘制
|
|
|
|
|
|
const drawVRuler = () => {
|
|
|
|
|
|
const height = viewSize.height * 2;
|
|
|
|
|
|
const vRulerCanvas = vRulerRef.value;
|
|
|
|
|
|
const ctx = vRulerCanvas.getContext("2d");
|
|
|
|
|
|
ctx.clearRect(0, 0, rulerHeight * 2, height);
|
|
|
|
|
|
ctx.lineWidth = 1;
|
|
|
|
|
|
ctx.font = "16px Arial";
|
|
|
|
|
|
ctx.textAlign = "left";
|
|
|
|
|
|
ctx.fillStyle = "#333";
|
|
|
|
|
|
// 计算像素比例
|
|
|
|
|
|
// const pxPerUnit = height / yRange.value;
|
|
|
|
|
|
// 主刻度
|
|
|
|
|
|
for (
|
|
|
|
|
|
let value = vRulerStart.value;
|
|
|
|
|
|
value >= vRulerEnd.value;
|
|
|
|
|
|
value -= vMainStep.value
|
|
|
|
|
|
) {
|
|
|
|
|
|
const y = (((vRulerStart.value - value) / yRange.value) * height) / scale.value;
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(0, y);
|
|
|
|
|
|
ctx.lineTo(20, y);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
|
|
|
|
|
|
// 旋转文字
|
|
|
|
|
|
ctx.save();
|
|
|
|
|
|
ctx.translate(20, y);
|
|
|
|
|
|
ctx.rotate(-Math.PI / 2);
|
|
|
|
|
|
ctx.fillText(value, 10, 10);
|
|
|
|
|
|
ctx.restore();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 次刻度
|
|
|
|
|
|
for (
|
|
|
|
|
|
let value = vRulerStart.value;
|
|
|
|
|
|
value >= vRulerEnd.value;
|
|
|
|
|
|
value -= vMiddleStep.value
|
|
|
|
|
|
) {
|
|
|
|
|
|
if (value % vMainStep.value === 0) continue;
|
|
|
|
|
|
const y = ((vRulerStart.value - value) / yRange.value) * height;
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(0, y);
|
|
|
|
|
|
ctx.lineTo(15, y);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 最小刻度
|
|
|
|
|
|
for (let value = vRulerStart.value; value >= vRulerEnd.value; value -= vMinStep.value) {
|
|
|
|
|
|
if (value % vMainStep.value === 0 || value % vMiddleStep.value === 0) continue;
|
|
|
|
|
|
|
|
|
|
|
|
const y = ((vRulerStart.value - value) / yRange.value) * height;
|
|
|
|
|
|
ctx.beginPath();
|
|
|
|
|
|
ctx.moveTo(0, y);
|
|
|
|
|
|
ctx.lineTo(10, y);
|
|
|
|
|
|
ctx.stroke();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const calculateInterval = (start, end, length, isV) => {
|
|
|
|
|
|
const range = Math.abs(end - start);
|
|
|
|
|
|
// 橫标尺每200像素1个,纵标尺每150像素1个
|
|
|
|
|
|
let rulerCount = Math.ceil(isV ? length / 200 : length / 150);
|
|
|
|
|
|
if (rulerCount < 5) {
|
|
|
|
|
|
rulerCount = rulerCount * 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
let magnitude = range / rulerCount;
|
|
|
|
|
|
let step = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < ruler_metrics.length; i++) {
|
|
|
|
|
|
if (magnitude > ruler_metrics[i] && magnitude <= ruler_metrics[i + 1]) {
|
|
|
|
|
|
step = ruler_metrics[i];
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 按比例换算
|
|
|
|
|
|
let realCount = range / step;
|
|
|
|
|
|
if (isV) {
|
|
|
|
|
|
if (realCount >= 15) {
|
|
|
|
|
|
step = step * 2;
|
|
|
|
|
|
} else if (realCount <= 5) {
|
|
|
|
|
|
step = step / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isV) {
|
|
|
|
|
|
if (realCount >= 20) {
|
|
|
|
|
|
step = step * 2;
|
|
|
|
|
|
} else if (realCount <= 10) {
|
|
|
|
|
|
step = step / 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return step;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const handleResize = debounce(() => {
|
|
|
|
|
|
if (!canvasRef.value) return;
|
|
|
|
|
|
redrawCanvas(imgPath.value);
|
|
|
|
|
|
}, 150);
|
|
|
|
|
|
|
|
|
|
|
|
const clearCanvas = () => {
|
|
|
|
|
|
if (!mainCtx) return;
|
|
|
|
|
|
mainCtx.clearRect(0, 0, viewSize.width, viewSize.height);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function doOpenFile(item) {
|
|
|
|
|
|
// console.log("执行方法:doOpenFile", item)
|
|
|
|
|
|
clearCanvas();
|
|
|
|
|
|
let drawerToken = generateGUID();
|
|
|
|
|
|
openFile(`${dataDir}/${item}`, drawerToken);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生命周期钩子
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
image.value = new Image();
|
|
|
|
|
|
initCanvasSize();
|
|
|
|
|
|
window.addEventListener("resize", handleResize);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 全局监听键盘事件
|
|
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
|
|
|
|
window.addEventListener("keyup", handleKeyUp);
|
|
|
|
|
|
|
|
|
|
|
|
emitter.on(EMIT_COMMAND.REFRESH_IMG, (data) => {
|
|
|
|
|
|
refreshImg(data);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
emitter.on(EMIT_COMMAND.EVT_TYPE, (data) => {
|
|
|
|
|
|
const json = JSON.parse(data.data);
|
|
|
|
|
|
|
|
|
|
|
|
const cmdId = data.cmdID;
|
|
|
|
|
|
|
|
|
|
|
|
console.log("接收到 EMIT_COMMAND.EVT_TYPE 的消息:", cmdId, currentTabTokenKey.value, json)
|
|
|
|
|
|
if (cmdId !== currentTabTokenKey.value) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
switch (data.type) {
|
|
|
|
|
|
// case COMMAND.REDRAW:
|
|
|
|
|
|
// refreshImg(json);
|
|
|
|
|
|
// break;
|
|
|
|
|
|
case EMIT_COMMAND.OPEN_FILE:
|
|
|
|
|
|
clearCanvas();
|
|
|
|
|
|
let drawerToken = json.drawerToken || generateGUID();
|
|
|
|
|
|
openFile(`${dataDir}/${json.fileName}`, drawerToken);
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case "calcRedraw":
|
|
|
|
|
|
doRedraw();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "viewFile":
|
|
|
|
|
|
isView.value = true;
|
|
|
|
|
|
openFile(`${dataDir}/${json.fileUrl}`, json.viewerToken);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EMIT_COMMAND.VIEW_ALL:
|
|
|
|
|
|
viewAll();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case EMIT_COMMAND.CLEAR_CANVAS:
|
|
|
|
|
|
clearCanvas();
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
// case COMMAND.EDIT_WELL_GROUP:
|
|
|
|
|
|
// if (currentToken.value === STORAGE_KEYS.WELL_GROUP_EDIT_TOKEN) {
|
|
|
|
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
// console.log("收到编辑井组回应:", json);
|
|
|
|
|
|
// break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
emitter.on(EMIT_COMMAND.SOURCE_CHANGED, sourceChanged);
|
|
|
|
|
|
|
|
|
|
|
|
// emitter.on(EMIT_COMMAND.EDIT_REDRAW, (json) => {
|
|
|
|
|
|
// console.log("收到编辑井组回应 CanvasRenderer:", json);
|
|
|
|
|
|
// refreshImg(json);
|
|
|
|
|
|
// });
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const sourceChanged = () => {
|
|
|
|
|
|
localStorage.removeItem(currentTabTokenKey.value);
|
|
|
|
|
|
clearCanvas();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
onBeforeUnmount(() => {
|
|
|
|
|
|
// emitter.off(EMIT_COMMAND.BUTTON_CLICK);
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.EVT_TYPE);
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.SOURCE_CHANGED);
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.REFRESH_IMG);
|
|
|
|
|
|
emitter.off(EMIT_COMMAND.EDIT_GROUP);
|
|
|
|
|
|
// emitter.off(EMIT_COMMAND.EDIT_REDRAW);
|
|
|
|
|
|
|
|
|
|
|
|
window.removeEventListener("resize", handleResize);
|
|
|
|
|
|
// 全局监听键盘事件
|
|
|
|
|
|
window.removeEventListener("keydown", handleKeyDown);
|
|
|
|
|
|
window.removeEventListener("keyup", handleKeyUp);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
unsubscribe();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载数据超时处理
|
|
|
|
|
|
const onTimeout = () => {
|
|
|
|
|
|
$toastMessage.error("加载数据失败,请稍后重试!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭加载窗口
|
|
|
|
|
|
const closeLoading = () => {
|
|
|
|
|
|
if (loadingRef.value) {
|
|
|
|
|
|
loadingRef.value.close();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
loading.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const sendCmd = (type, data = {}) => {
|
|
|
|
|
|
// const cmdid = generateGUID();
|
|
|
|
|
|
// cmdIds.value.push(cmdid);
|
|
|
|
|
|
if (type != COMMAND.MOUSE_MOVE) {
|
|
|
|
|
|
// console.log("发送命令:", type, data);
|
|
|
|
|
|
}
|
|
|
|
|
|
send(type, data, currentToken.value, currentTabTokenKey.value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const getCanvasSize = () => {
|
|
|
|
|
|
if (canvasRef.value) {
|
|
|
|
|
|
return canvasRef.value.getBoundingClientRect();
|
|
|
|
|
|
// console.log("getCanvasSize:", canvasRef.value.width, canvasRef.value.height);
|
|
|
|
|
|
// return getDrawingAreaSize();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 防抖函数
|
|
|
|
|
|
function debounce(fn, delay) {
|
|
|
|
|
|
let timer = null
|
|
|
|
|
|
return function (...args) {
|
|
|
|
|
|
if (timer) {
|
|
|
|
|
|
clearTimeout(timer)
|
|
|
|
|
|
}
|
|
|
|
|
|
timer = setTimeout(() => {
|
|
|
|
|
|
fn.apply(this, args)
|
|
|
|
|
|
}, delay)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
defineExpose({
|
|
|
|
|
|
// width: computed(() => canvasRef.value?.width),
|
|
|
|
|
|
// height: computed(() => canvasRef.value?.height),
|
|
|
|
|
|
getCanvasSize,
|
|
|
|
|
|
// 处理默认按钮点击
|
|
|
|
|
|
toolDefault,
|
|
|
|
|
|
// 处理放大按钮点击
|
|
|
|
|
|
drawZoomIn,
|
|
|
|
|
|
// 处理缩小按钮点击
|
|
|
|
|
|
drawZoomOut,
|
|
|
|
|
|
// 处理刷新按钮点击
|
|
|
|
|
|
drawRefresh,
|
|
|
|
|
|
// 处理居中按钮点击
|
|
|
|
|
|
drawCenter,
|
|
|
|
|
|
// 处理局部按钮点击
|
|
|
|
|
|
toolViewWindow,
|
|
|
|
|
|
// 处理全部按钮点击
|
|
|
|
|
|
viewAll,
|
|
|
|
|
|
// 处理移动按钮点击
|
|
|
|
|
|
toolViewMove,
|
|
|
|
|
|
// 处理选择按钮点击
|
|
|
|
|
|
toolSelect,
|
|
|
|
|
|
// 处理保存按钮点击
|
|
|
|
|
|
save,
|
|
|
|
|
|
// 处理图层按钮点击
|
|
|
|
|
|
showLayers,
|
|
|
|
|
|
// 打开文件
|
|
|
|
|
|
doOpenFile
|
|
|
|
|
|
})
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
|
.canvas-container {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
/* min-width: 800px;
|
|
|
|
|
|
min-height: 550px; */
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
/* 防止内容溢出 */
|
|
|
|
|
|
background-color: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.ruler {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
/* 标尺置于顶层 */
|
|
|
|
|
|
background: rgb(245, 245, 245);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.horizontal {
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
height: 20px;
|
|
|
|
|
|
/* 水平标尺高度 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.vertical {
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
width: 20px;
|
|
|
|
|
|
/* 垂直标尺宽度 */
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.main-canvas {
|
|
|
|
|
|
display: block;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
/* 确保画布是块级元素 */
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border: 0;
|
|
|
|
|
|
/* position: relative; */
|
|
|
|
|
|
z-index: 1;
|
|
|
|
|
|
top: 20px;
|
|
|
|
|
|
/* 避开水平标尺 */
|
|
|
|
|
|
left: 20px;
|
|
|
|
|
|
/* 避开垂直标尺 */
|
|
|
|
|
|
/* width: calc(100vw - 20px);
|
|
|
|
|
|
height: calc(100vh - 20px); */
|
|
|
|
|
|
resize: both;
|
|
|
|
|
|
image-rendering: -webkit-optimize-contrast;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*自定义右键菜单样式*/
|
|
|
|
|
|
.context-menu {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
background: white;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
|
|
|
|
|
z-index: 1000;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
opacity: 0;
|
|
|
|
|
|
transform: scale(0.95);
|
|
|
|
|
|
transition: all 0.2s ease-out;
|
|
|
|
|
|
min-width: 200px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.context-menu.visible {
|
|
|
|
|
|
opacity: 1;
|
|
|
|
|
|
transform: scale(1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item {
|
|
|
|
|
|
padding: 8px 15px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 12px;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
transition: all 0.2s;
|
|
|
|
|
|
border-bottom: 1px solid #f0f4f8;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item:last-child {
|
|
|
|
|
|
border-bottom: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item:hover {
|
|
|
|
|
|
background: #f0f7ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item .icon {
|
|
|
|
|
|
width: 24px;
|
|
|
|
|
|
height: 24px;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
background: #e3f2fd;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
color: #3498db;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item.danger {
|
|
|
|
|
|
color: #e74c3c;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.menu-item.danger .icon {
|
|
|
|
|
|
background: #fdecea;
|
|
|
|
|
|
color: #e74c3c;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*分隔线样式*/
|
|
|
|
|
|
.divider {
|
|
|
|
|
|
border: none;
|
|
|
|
|
|
height: 1px;
|
|
|
|
|
|
background: #ccc;
|
|
|
|
|
|
margin: 3px 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.wellGroupData {
|
|
|
|
|
|
width: calc(100vw - 100px);
|
|
|
|
|
|
height: calc(100vh - 100px);
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|