From 381c2a2d7f92138e43c1f82b0afa2aaa363b46b9 Mon Sep 17 00:00:00 2001 From: donghao Date: Fri, 30 Aug 2024 11:28:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=E4=B8=AD=E5=BF=83?= =?UTF-8?q?=E7=82=B9=E4=BD=8D=E5=9D=90=E6=A0=87=E8=B0=83=E6=95=B4=E8=AE=A1?= =?UTF-8?q?=E7=AE=97=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config/attribute/viewType.ts | 1 + .../deviceSetting/components/deviceAttr.vue | 24 +-- .../deviceSetting/components/deviceSelect.vue | 33 ++-- .../components/previewCurrent.vue | 8 +- .../deviceSetting/hooks/useDeviceObject.ts | 169 ++++++++++++------ src/views/deviceSetting/index.vue | 12 +- 6 files changed, 154 insertions(+), 93 deletions(-) create mode 100644 src/config/attribute/viewType.ts diff --git a/src/config/attribute/viewType.ts b/src/config/attribute/viewType.ts new file mode 100644 index 0000000..cb03c2c --- /dev/null +++ b/src/config/attribute/viewType.ts @@ -0,0 +1 @@ +export const workspaceIDConf = "workspace"; diff --git a/src/views/deviceSetting/components/deviceAttr.vue b/src/views/deviceSetting/components/deviceAttr.vue index c5c405d..758a97e 100644 --- a/src/views/deviceSetting/components/deviceAttr.vue +++ b/src/views/deviceSetting/components/deviceAttr.vue @@ -22,7 +22,8 @@ const emit = defineEmits(["afterDelete", "editDevice"]); const event = inject("event"); const update = getCurrentInstance(); const { mixinState, canvasEditor } = useSelect(); -const { fetchViewsBoundaries, isMoveDevice } = useDeviceObject(); +const { fetchViewsBoundaries, isMoveDevice, fetchMoveDeviceObjectOrdinate } = + useDeviceObject(); /**业务属性 */ const formData = ref({ name: "", @@ -103,7 +104,7 @@ const fontAttr = reactive({ }); const constrainObjectWithinCanvas = obj => { - const { startLeft, startTop, moveLeft, moveTop } = fetchViewsBoundaries( + const { startLeft, startTop, endLeft, endTop } = fetchViewsBoundaries( canvasEditor.canvas, obj ); @@ -114,11 +115,11 @@ const constrainObjectWithinCanvas = obj => { if (obj.top < startTop) { obj.top = startTop; } - if (obj.left > moveLeft) { - obj.left = moveLeft; + if (obj.left > endLeft) { + obj.left = endLeft; } - if (obj.top > moveTop) { - obj.top = moveTop; + if (obj.top > endTop) { + obj.top = endTop; } // 更新对象的位置 obj.setCoords(); @@ -183,15 +184,18 @@ async function deleteDeviceObject(deleteObject) { } function startEditDevice(callback) { - const { startLeft, startTop } = fetchViewsBoundaries(canvasEditor.canvas); const activeObject = canvasEditor.canvas.getActiveObject(); const currDeviceInfo = activeObject.get("deviceInfo"); + const { x_ordinate, y_ordinate } = fetchMoveDeviceObjectOrdinate( + canvasEditor.canvas, + activeObject + ); const editParams = { id: currDeviceInfo.id, device_id: currDeviceInfo.device_id, workshop_id: props.pointInfo?.id, - x_ordinate: activeObject.get("left") - startLeft, - y_ordinate: activeObject.get("top") - startTop, + x_ordinate, + y_ordinate, icon: formData.value?.icon }; emit("editDevice", { editParams, callback }); @@ -211,7 +215,7 @@ const init = () => { // 如果没有产生位移,就不调用编辑接口 activeObject && activeObject.get("deviceInfo") && - isMoveDevice(activeObject, canvasEditor.canvas) && + isMoveDevice(canvasEditor.canvas, activeObject) && startEditDevice(); }); canvasEditor.canvas.on("object:modified", getObjectAttr); diff --git a/src/views/deviceSetting/components/deviceSelect.vue b/src/views/deviceSetting/components/deviceSelect.vue index c3bc3a7..e49e780 100644 --- a/src/views/deviceSetting/components/deviceSelect.vue +++ b/src/views/deviceSetting/components/deviceSelect.vue @@ -26,7 +26,7 @@ const { initDeviceGroupObjects, isInViewBoundaries, getDragDeviceObjectOrdinate, - fetchViewsBoundaries + fetchOrdinateByView } = useDeviceObject(); // const { t } = useI18n(); @@ -75,7 +75,6 @@ canvasEditor.getMaterialType("svg").then((list: materialTypeI[]) => { * 处理添加设备&重复添加设备【同点位,不同点位】 */ function deviceSelected(callback, options) { - const { startLeft, startTop } = fetchViewsBoundaries(canvasEditor.canvas); const { targetDeviceItem } = options; console.log(targetDeviceItem, "deviceSelected", props.currDeviceList); currDetailInfo.value = targetDeviceItem; @@ -110,9 +109,13 @@ function deviceSelected(callback, options) { ); canvasEditor.canvas.getObjects().forEach(v => { if (v?.deviceInfo?.device_id === targetDeviceItem.id) { + const { left, top } = fetchOrdinateByView( + canvasEditor.canvas, + targetDeviceItem + ); v.set({ - left: targetDeviceItem.x_ordinate + startLeft, - top: targetDeviceItem.y_ordinate + startTop + left, + top }); canvasEditor.canvas.renderAll(); } @@ -159,10 +162,11 @@ const dragItem = (event, deviceItem) => { ); // 判断是否在边界内 if ( - !isInViewBoundaries( - { ...item, x_ordinate, y_ordinate }, - canvasEditor.canvas - ) + !isInViewBoundaries(canvasEditor.canvas, { + ...item, + x_ordinate, + y_ordinate + }) ) { return; } @@ -174,12 +178,13 @@ const dragItem = (event, deviceItem) => { // canvasEditor.dragAddItem(event, item); deviceSelected( - resData => { + _ => { // 新增完成处理 + // 已改为调用接口刷新 // item.set({ // name: resData?.device_name, // deviceInfo: resData - // }); // 作为无刷新时的标识 + // }); // canvasEditor.dragAddItem(event, item); }, { @@ -219,16 +224,13 @@ const dragItem = (event, deviceItem) => { // 渲染设备到点位图上 function renderDeviceToCanvas(record) { - const { startLeft, startTop } = fetchViewsBoundaries(canvasEditor.canvas); - console.log(startLeft, "renderDeviceToCanvas"); const startArr = record; const finalArr = []; startArr.map(deviceItem => { const fullDeviceItem = { ...defaultPosition, ...deviceItem, - left: Number(deviceItem.x_ordinate) + startLeft, - top: Number(deviceItem.y_ordinate) + startTop, + ...fetchOrdinateByView(canvasEditor.canvas, deviceItem), name: deviceItem.device_name }; finalArr.push({ @@ -253,9 +255,6 @@ watch( allDeviceList.value = toRaw(props.deviceList); console.log(allDeviceList.value, "allDeviceList", props.deviceList); }, - // { - // immediate: true - // }, { deep: true } diff --git a/src/views/deviceSetting/components/previewCurrent.vue b/src/views/deviceSetting/components/previewCurrent.vue index b8c47e9..c398ba0 100644 --- a/src/views/deviceSetting/components/previewCurrent.vue +++ b/src/views/deviceSetting/components/previewCurrent.vue @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-08-26 11:32:07 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-08-28 16:16:06 + * @LastEditTime: 2024-08-30 10:56:13 * @FilePath: \General-AI-Platform-Web-Client\src\views\deviceSetting\components\previewCurrent.vue * @Description: 预览组件 --> @@ -99,7 +99,7 @@ function renderDeviceToCanvas() { const canvasObject = cvs.value; const startArr = props.currDeviceList; const finalArr = []; - const { startLeft, startTop } = getBoundaryPoints(); + // const { startLeft, startTop } = getBoundaryPoints(); startArr.map(deviceItem => { const fullDeviceItem = { @@ -108,8 +108,8 @@ function renderDeviceToCanvas() { shadow: "", fontFamily: "1-1", ...deviceItem, - left: Number(deviceItem.x_ordinate) * scale + startLeft, - top: Number(deviceItem.y_ordinate) * scale + startTop, + left: Number(deviceItem.x_ordinate) * scale + viewData.value.width / 2, + top: viewData.value.height / 2 - Number(deviceItem.y_ordinate) * scale, name: deviceItem.device_name }; finalArr.push({ diff --git a/src/views/deviceSetting/hooks/useDeviceObject.ts b/src/views/deviceSetting/hooks/useDeviceObject.ts index e2bd1be..15e472c 100644 --- a/src/views/deviceSetting/hooks/useDeviceObject.ts +++ b/src/views/deviceSetting/hooks/useDeviceObject.ts @@ -9,76 +9,134 @@ import video_type_3 from "@/assets/modelSetting/video_type_3.png"; import device_video_bg from "@/assets/modelSetting/device_video_bg.png"; import device_video_bg_gray from "@/assets/modelSetting/device_video_bg_gray.png"; import notInVisableIcon from "@/assets/modelSetting/notInVisableIcon.png"; - +import { workspaceIDConf } from "@/config/attribute/viewType"; import { v4 as uuid } from "uuid"; const deviceInfoKey = "deviceInfo"; - +// TODO 设计实现点位绑定设备实体的位置偏移问题 +/** + * @交互说明 + * 1. 基于画布中心点建立坐标系。画布中心点坐标为(0,0) + */ export const useDeviceObject = () => { - // 移动到画布上的设备对象的相对坐标,使用相对图片的左边系,而不是画布的坐标系 + // 拖拽新增获取设备对象在画布上的坐标 function getDragDeviceObjectOrdinate(event, viewObj, deviceObj) { - // const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象 + // 移动到画布上的设备对象的相对坐标,使用相对图片的坐标系,而不是画布的坐标系 + const currWorkSpaceData = document + .getElementById(workspaceIDConf) + .getBoundingClientRect(); + + const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象 const imgObjects = viewObj.getObjects()[1]; // 获取图片对象 - const { left, top } = viewObj.getSelectionElement().getBoundingClientRect(); - const point = { - x: event.x - left - imgObjects.left, - y: event.y - top - imgObjects.top + const { left, top, width, height } = currWorkSpaceData; + // .getSelectionElement() + // .getBoundingClientRect(); + // 该设备基于当前画布的坐标信息 + const currPointView = { + x: event.clientX - left, + y: event.clientY - top + }; + // const pointerVpt = viewObj.restorePointerVpt(currPointView); + const x_ordinate = + currPointView.x - width / 2 - (deviceObj.width * deviceObj.scaleX) / 2; + const y_ordinate = + height / 2 - currPointView.y + (deviceObj.height * deviceObj.scaleY) / 2; + console.log( + "currWorkSpace:", + currWorkSpaceData, + "cvsObjects:", + cvsObjects, + "event:", + event, + "getDragDeviceObjectOrdinate", + "imgObjects:", + imgObjects.getCenterPoint(), + x_ordinate, + y_ordinate + ); + return { + x_ordinate, + y_ordinate + }; + } + // 在画布上移动后设备对象坐标 + function fetchMoveDeviceObjectOrdinate(viewObj, activeObject) { + const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象 + const x_ordinate = activeObject.get("left") - cvsObjects.width / 2; + const y_ordinate = cvsObjects.height / 2 - activeObject.get("top"); + return { + x_ordinate, + y_ordinate }; - const pointerVpt = viewObj.restorePointerVpt(point); - const x_ordinate = pointerVpt.x - (deviceObj.width * deviceObj.scaleX) / 2; - const y_ordinate = pointerVpt.y - (deviceObj.height * deviceObj.scaleY) / 2; - console.log(x_ordinate, y_ordinate, "getDragDeviceObjectOrdinate"); + } + // 使用相对坐标换实际位置的方法 + function fetchOrdinateByView(viewObj, deviceItem) { + const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象 + const { x_ordinate, y_ordinate } = deviceItem; + const left = cvsObjects.width / 2 + parseFloat(x_ordinate); + const top = cvsObjects.height / 2 - parseFloat(y_ordinate); + console.log(cvsObjects, "fetchOrdinateByView", left, top); return { - x_ordinate: x_ordinate, - y_ordinate: y_ordinate + left, + top }; } - // 可操作区域的相对坐标 + // 获取图片对象尺寸 + + // 可操作区域的各点位相对坐标【限定可操作区域边界】 function fetchViewsBoundaries(viewObj, activeObj) { + // 图片原点为中心图标 const cvsObjects = viewObj.getObjects()[0]; // 获取画布对象 const imgObjects = viewObj.getObjects()[1]; // 获取图片对象 + const y_mistake = -8 * activeObj?.scaleY; // 上下边界误差 + const currIconWidth = activeObj?.width * activeObj?.scaleX; + const currIconHeight = activeObj?.height * activeObj?.scaleY; const startLeft = (cvsObjects.width * cvsObjects.scaleX - imgObjects.width * imgObjects.scaleX) / - 2; + 2 - + currIconWidth / 2; const startTop = (cvsObjects.height * cvsObjects.scaleY - imgObjects.height * imgObjects.scaleY) / - 2; + 2 - + currIconHeight - + y_mistake; const endLeft = startLeft + imgObjects.width * imgObjects.scaleX; const endTop = startTop + imgObjects.height * imgObjects.scaleY; + const currImgWidth = imgObjects.width * imgObjects.scaleX; + const currImgHeight = imgObjects.height * imgObjects.scaleY; return { - x_max: imgObjects.width * imgObjects.scaleX, - y_max: imgObjects.height * imgObjects.scaleY, + x_min: -currImgWidth / 2 - currIconWidth / 2, + y_min: -currImgHeight / 2 - currIconHeight, + x_max: currImgWidth / 2 + currIconWidth / 2, + y_max: currImgHeight / 2, startLeft, startTop, endLeft, - endTop, - moveLeft: endLeft - activeObj?.width * activeObj?.scaleX, - moveTop: endTop - activeObj?.height * activeObj?.scaleY + endTop }; } // 判断设备是否在可视区域内 - function isInViewBoundaries(deviceObj, viewObj): boolean { - const { x_max, y_max } = fetchViewsBoundaries(viewObj, deviceObj); + function isInViewBoundaries(viewObj, deviceObj): boolean { + const { x_min, x_max, y_min, y_max } = fetchViewsBoundaries( + viewObj, + deviceObj + ); const { x_ordinate, y_ordinate } = deviceObj; - // 获取对象的当前尺寸和位置 - const objLeft = x_ordinate; - const objTop = y_ordinate; - // 限制对象在画布内移动 - if (objLeft < 0) { + if (x_ordinate < x_min) { return false; } - if (objTop < 0) { + if (y_ordinate < y_min) { return false; } - if (objLeft > x_max) { + if (x_ordinate > x_max) { return false; } - if (objTop > y_max) { + if (y_ordinate > y_max) { return false; } return true; @@ -86,45 +144,38 @@ export const useDeviceObject = () => { // 设备对象是否移动 function isMoveDevice(activeObject, viewObj) { - const { x_ordinate, y_ordinate } = activeObject.get(deviceInfoKey); - const { startLeft, startTop } = fetchViewsBoundaries(viewObj); + const x_ordinate_history = activeObject.get(deviceInfoKey)?.x_ordinate; + const y_ordinate_history = activeObject.get(deviceInfoKey)?.y_ordinate; + const { x_ordinate, y_ordinate } = fetchMoveDeviceObjectOrdinate( + viewObj, + activeObject + ); // 误差设置为 0.1 const errorValue = [1, 1]; let x_move = true; let y_move = true; const x_move_value = Math.abs( - Number(activeObject.left) - Number(x_ordinate) - Number(startLeft) + Number(x_ordinate_history) - Number(x_ordinate) ); const y_move_value = Math.abs( - Number(activeObject.top) - Number(y_ordinate) - Number(startTop) + Number(y_ordinate_history) - Number(y_ordinate) ); - console.log( - "startLeft" + startLeft, - "startTop" + startTop, - "isMoveDevice", - "x_move_value" + x_move_value, - "y_move_value" + y_move_value, - activeObject.left, - x_ordinate, - activeObject.top, - y_ordinate, - Math.abs( - Number(activeObject.top) - Number(y_ordinate) - Number(startTop) - ), - Math.abs( - Number(activeObject.left) - Number(x_ordinate) - Number(startLeft) - ) - ); - // TODO 重新绑定车间的设备没有坐标信息,暂时不判断设备是否移动【默认没有移动】 - if (Number.isNaN(x_move_value) || Number.isNaN(y_move_value)) { - return false; - } + + // 重新绑定车间的设备没有坐标信息,暂时不判断设备是否移动【默认没有移动】 + // if (Number.isNaN(x_move_value) || Number.isNaN(y_move_value)) { + // return false; + // } if (x_move_value < errorValue[0]) { x_move = false; } if (y_move_value < errorValue[1]) { y_move = false; } + console.log( + "isMoveDevice:" + (x_move || y_move), + "x_move_value" + x_move_value, + "y_move_value" + y_move_value + ); return x_move || y_move; } @@ -384,7 +435,9 @@ export const useDeviceObject = () => { isInViewBoundaries, getDragDeviceObjectOrdinate, isMoveDevice, - fetchViewsBoundaries + fetchViewsBoundaries, + fetchOrdinateByView, + fetchMoveDeviceObjectOrdinate // fetchDeviceObjectBySeemKey }; }; diff --git a/src/views/deviceSetting/index.vue b/src/views/deviceSetting/index.vue index 27ea28a..f6ab6a1 100644 --- a/src/views/deviceSetting/index.vue +++ b/src/views/deviceSetting/index.vue @@ -2,7 +2,7 @@ * @Author: donghao donghao@supervision.ltd * @Date: 2024-08-02 10:52:32 * @LastEditors: donghao donghao@supervision.ltd - * @LastEditTime: 2024-08-28 17:36:58 + * @LastEditTime: 2024-08-30 11:11:29 * @FilePath: \General-AI-Platform-Web-Client\src\views\deviceSetting\index.vue * @Description: 设备点位管理设置 @ 交互说明 @@ -116,11 +116,15 @@ const refreshCanvas = (isLoadDevice = true) => { const canvasWidth = cvs.width; const canvasHeight = cvs.height; // Calculate the center position for the image - const left = (canvasWidth - img.width * img.scaleX) / 2; - const top = (canvasHeight - img.height * img.scaleY) / 2; + // TODO 计算合适的缩放比 + const startScale = 0.8; + const left = (canvasWidth - img.width * startScale) / 2; + const top = (canvasHeight - img.height * startScale) / 2; img.set({ left, - top + top, + scaleX: startScale, + scaleY: startScale }); // Re-render the canvas to apply changes canvasEditor.canvas.renderAll();