From 25035ac4cfb3f9a793d98f0465e3ed65757d8d16 Mon Sep 17 00:00:00 2001 From: yyy <2605810609@qq.com> Date: Mon, 9 Jun 2025 15:45:02 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=96=E8=BE=91=E5=9C=B0=E5=9B=BE=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components-tool/editNodeProperties.vue | 1 + src/views/mapPage/realTimeMap/editMap.vue | 292 ++++++++++++------ src/views/mapPage/realTimeMap/格式.md | 91 ++++++ 3 files changed, 281 insertions(+), 103 deletions(-) create mode 100644 src/views/mapPage/realTimeMap/格式.md diff --git a/src/views/mapPage/realTimeMap/components-tool/editNodeProperties.vue b/src/views/mapPage/realTimeMap/components-tool/editNodeProperties.vue index c0d353ef..ad8b9457 100644 --- a/src/views/mapPage/realTimeMap/components-tool/editNodeProperties.vue +++ b/src/views/mapPage/realTimeMap/components-tool/editNodeProperties.vue @@ -375,6 +375,7 @@ const MathPI = ref(Math.PI) const equipmentList = ref([]) //用过的设备列表 const open = (item, list) => { + console.log(item) form.value = item form.value.layersNumber = item.dataList?.length || '' form.value.positionMapId = props.positionMapId diff --git a/src/views/mapPage/realTimeMap/editMap.vue b/src/views/mapPage/realTimeMap/editMap.vue index ea0a8881..9690344d 100644 --- a/src/views/mapPage/realTimeMap/editMap.vue +++ b/src/views/mapPage/realTimeMap/editMap.vue @@ -1314,8 +1314,11 @@ const handleInputEnd = () => { } //编辑节点成功 const submitNodeSuccess = (form) => { + let actualPoint = disposeEventPoint(form.locationX, form.locationY) form.locationDeepPx = Number(form.locationDeep) / 100 / imgBgObj.resolution form.locationWidePx = Number(form.locationWide) / 100 / imgBgObj.resolution + form.actualLocationX = actualPoint.actualLocationX + form.actualLocationY = actualPoint.actualLocationY state.allMapPointInfo[state.currentItemIndex] = form //节点位置改变 通知路径里面的节点也改变 @@ -2218,7 +2221,19 @@ const resetDrawState = () => { state.currentDrawY = 0 } -//开始框选绘制 +// 节流函数 +const throttle = (fn, delay) => { + let lastTime = 0 + return function (...args) { + const now = Date.now() + if (now - lastTime >= delay) { + lastTime = now + return fn.apply(this, args) + } + } +} + +// 优化后的框选相关函数 const startDrawSelection = (event) => { if ( toolbarSwitchType.value === 'createLineLibrary' || @@ -2227,20 +2242,20 @@ const startDrawSelection = (event) => { toolbarSwitchType.value == 'generateLine' || toolbarSwitchType.value === 'bulkDelete' ) { - const x = disposeEventPoints(event).x - const y = disposeEventPoints(event).y + const { x, y } = disposeEventPoints(event) // 确保点击在背景区域内 if (x >= 0 && x <= imgBgObj.width && y >= 0 && y <= imgBgObj.height) { state.drawSelectionAreaShow = true - state.drawSelectionStartPoint = { x: x, y: y } - state.drawSelectionAreaBox = { x: x, y: y, width: 0, height: 0 } + state.drawSelectionStartPoint = { x, y } + state.drawSelectionAreaBox = { x, y, width: 0, height: 0 } } - event.preventDefault() // 阻止默认行为(避免选中图片或文本) + event.preventDefault() } } -// 更新框选区域 -const updateDrawSelection = (event) => { + +// 使用节流优化更新框选区域 +const updateDrawSelection = throttle((event) => { if ( toolbarSwitchType.value === 'createLineLibrary' || toolbarSwitchType.value === 'createRegion' || @@ -2249,31 +2264,36 @@ const updateDrawSelection = (event) => { toolbarSwitchType.value === 'bulkDelete' ) { if (state.drawSelectionAreaShow) { - const x = disposeEventPoints(event).x - const y = disposeEventPoints(event).y + const { x, y } = disposeEventPoints(event) - state.drawSelectionAreaBox = { - x: Math.min(state.drawSelectionStartPoint.x, x), - y: Math.min(state.drawSelectionStartPoint.y, y), - width: Math.abs(Number(x) - Number(state.drawSelectionStartPoint.x)), - height: Math.abs(Number(y) - Number(state.drawSelectionStartPoint.y)) - } + // 使用 requestAnimationFrame 优化渲染 + requestAnimationFrame(() => { + state.drawSelectionAreaBox = { + x: Math.min(state.drawSelectionStartPoint.x, x), + y: Math.min(state.drawSelectionStartPoint.y, y), + width: Math.abs(x - state.drawSelectionStartPoint.x), + height: Math.abs(y - state.drawSelectionStartPoint.y) + } + }) } - event.preventDefault() // 阻止默认行为(避免选中图片或文本) + event.preventDefault() } + if (toolbarSwitchType.value === 'clickDrawRoute') { - // 实时绘制 if (state.isDrawing) { - const x = disposeEventPoints(event).x - const y = disposeEventPoints(event).y + const { x, y } = disposeEventPoints(event) - state.currentDrawX = x - state.currentDrawY = y + // 使用 requestAnimationFrame 优化渲染 + requestAnimationFrame(() => { + state.currentDrawX = x + state.currentDrawY = y + }) } - event.preventDefault() // 阻止默认行为(避免选中图片或文本) + event.preventDefault() } -} -//结束框选绘制 +}, 16) // 约60fps的更新频率 + +// 优化结束框选 const endDrawSelection = (event) => { if (toolbarSwitchType.value === 'clickDrawRoute') { if (state.isDrawing) { @@ -2331,8 +2351,11 @@ const endDrawSelection = (event) => { endPointSortNum: endPoint.sortNum } - state.mapRouteList.push(newRoute) - addEditHistory() + // 使用 requestAnimationFrame 优化渲染 + requestAnimationFrame(() => { + state.mapRouteList.push(newRoute) + addEditHistory() + }) } } resetDrawState() @@ -2340,6 +2363,7 @@ const endDrawSelection = (event) => { event.preventDefault() return } + if ( toolbarSwitchType.value === 'createLineLibrary' || toolbarSwitchType.value === 'createRegion' || @@ -2347,45 +2371,18 @@ const endDrawSelection = (event) => { toolbarSwitchType.value === 'generateLine' || toolbarSwitchType.value === 'bulkDelete' ) { - state.drawSelectionAreaShow = false - state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox }) - state.drawSelectionAreaBox = { x: 0, y: 0, width: 0, height: 0 } - event.preventDefault() // 阻止默认行为(避免选中图片或文本) - return + // 使用 requestAnimationFrame 优化渲染 + requestAnimationFrame(() => { + state.drawSelectionAreaShow = false + if (state.drawSelectionAreaBox.width > 0 && state.drawSelectionAreaBox.height > 0) { + state.allDrawSelectionAreaBox.push({ ...state.drawSelectionAreaBox }) + } + state.drawSelectionAreaBox = { x: 0, y: 0, width: 0, height: 0 } + }) + event.preventDefault() } } -// 找到最近的点 -const findClosestPoint = (x, y) => { - const list = state.allMapPointInfo - if (!Array.isArray(list) || list.length === 0) return null - const searchRadius = 100 - let minDistance = Infinity - let closestIndex = null - - // 使用空间分区优化:先进行粗略筛选 - const potentialPoints = list.filter((point, index) => { - if (!point?.locationX || !point?.locationY) return false - const dx = Math.abs(point.locationX - x) - const dy = Math.abs(point.locationY - y) - return dx <= searchRadius && dy <= searchRadius - }) - - // 在筛选后的点中找最近的 - potentialPoints.forEach((point, i) => { - const dx = point.locationX - x - const dy = point.locationY - y - const distance = Math.sqrt(dx * dx + dy * dy) - const captureRadius = point.locationWide || 10 - - if (distance < minDistance && distance < captureRadius) { - minDistance = distance - closestIndex = list.findIndex((p) => p.id === point.id) - } - }) - - return closestIndex -} //点击区域 const clickDrawSelectionArea = () => { let points = state.allMapPointInfo @@ -2552,47 +2549,61 @@ const clickDrawSelectionArea = () => { } //生成直线 选择完成开始点和结束点 const GenerateStraightLinesSubmit = (pointList, form) => { - const list = mapPointsToLine(pointList, form.startPointId, form.endPointId) - const idNameMap = {} - list.forEach((item) => { - idNameMap[item.id] = item + // 使用 requestAnimationFrame 优化渲染 + requestAnimationFrame(() => { + const list = mapPointsToLine(pointList, form.startPointId, form.endPointId) + const idNameMap = new Map(list.map((item) => [item.id, item])) + + // 批量更新点位 + const updatedPoints = state.allMapPointInfo.map((item) => { + if (idNameMap.has(item.id)) { + const newPoint = idNameMap.get(item.id) + const actualPoint = disposeEventPoint(newPoint.locationX, newPoint.locationY) + return { + ...item, + locationX: newPoint.locationX, + locationY: newPoint.locationY, + actualLocationX: actualPoint.actualLocationX, + actualLocationY: actualPoint.actualLocationY + } + } + return item + }) + + // 批量更新路线 + const updatedRoutes = state.mapRouteList.map((item) => { + const startPoint = idNameMap.get(item.startingPointId) + const endPoint = idNameMap.get(item.endPointId) + + if (startPoint || endPoint) { + const result = { ...item } + + if (startPoint) { + const actualStartPoint = disposeEventPoint(startPoint.locationX, startPoint.locationY) + result.startPointX = startPoint.locationX + result.startPointY = startPoint.locationY + result.actualStartPointX = actualStartPoint.actualLocationX + result.actualStartPointY = actualStartPoint.actualLocationY + } + + if (endPoint) { + const actualEndPoint = disposeEventPoint(endPoint.locationX, endPoint.locationY) + result.endPointX = endPoint.locationX + result.endPointY = endPoint.locationY + result.actualEndPointX = actualEndPoint.actualLocationX + result.actualEndPointY = actualEndPoint.actualLocationY + } + + return result + } + return item + }) + + // 批量更新状态 + state.allMapPointInfo = updatedPoints + state.mapRouteList = updatedRoutes + addEditHistory() }) - // 遍历第二个数组,更新 name - state.allMapPointInfo.forEach((item) => { - if (idNameMap[item.id]) { - let actualPoint = disposeEventPoint( - idNameMap[item.id].locationX, - idNameMap[item.id].locationY - ) - item.locationX = idNameMap[item.id].locationX - item.locationY = idNameMap[item.id].locationY - item.actualLocationX = actualPoint.actualLocationX - item.actualLocationY = actualPoint.actualLocationY - } - }) - state.mapRouteList.forEach((item) => { - if (idNameMap[item.startingPointId]) { - let actualPoint = disposeEventPoint( - idNameMap[item.startingPointId].locationX, - idNameMap[item.startingPointId].locationY - ) - item.startPointX = idNameMap[item.startingPointId].locationX - item.startPointY = idNameMap[item.startingPointId].locationY - item.actualStartPointX = actualPoint.actualLocationX - item.actualStartPointY = actualPoint.actualLocationY - } - if (idNameMap[item.endPointId]) { - let actualPoint = disposeEventPoint( - idNameMap[item.endPointId].locationX, - idNameMap[item.endPointId].locationY - ) - item.endPointX = idNameMap[item.endPointId].locationX - item.endPointY = idNameMap[item.endPointId].locationY - item.actualEndPointX = actualPoint.actualLocationX - item.actualEndPointY = actualPoint.actualLocationY - } - }) - addEditHistory() } //去重 const deduplicateArrayById = (arr) => { @@ -3695,6 +3706,81 @@ const checkRouteDuplicate = (startPoint, endPoint, routeList) => { (route.startingPointId === endPoint.id && route.endPointId === startPoint.id) ) } + +// 空间分区优化 +const GRID_SIZE = 200 // 网格大小 +const gridMap = new Map() // 网格映射 + +// 获取点所在的网格坐标 +const getGridKey = (x, y) => { + const gridX = Math.floor(x / GRID_SIZE) + const gridY = Math.floor(y / GRID_SIZE) + return `${gridX},${gridY}` +} + +// 更新网格数据 +const updateGridMap = (points) => { + gridMap.clear() + points.forEach((point, index) => { + if (!point?.locationX || !point?.locationY) return + const key = getGridKey(point.locationX, point.locationY) + if (!gridMap.has(key)) { + gridMap.set(key, []) + } + gridMap.get(key).push({ point, index }) + }) +} + +// 获取指定网格及其相邻网格中的点 +const getNearbyPoints = (x, y) => { + const centerKey = getGridKey(x, y) + const [centerX, centerY] = centerKey.split(',').map(Number) + const nearbyPoints = [] + + // 检查中心网格及其相邻网格 + for (let dx = -1; dx <= 1; dx++) { + for (let dy = -1; dy <= 1; dy++) { + const key = `${centerX + dx},${centerY + dy}` + const points = gridMap.get(key) + if (points) { + nearbyPoints.push(...points) + } + } + } + + return nearbyPoints +} + +// 优化后的findClosestPoint函数 +const findClosestPoint = (x, y) => { + const list = state.allMapPointInfo + if (!Array.isArray(list) || list.length === 0) return null + + // 更新网格数据 + updateGridMap(list) + + const searchRadius = 100 + let minDistance = Infinity + let closestIndex = null + + // 获取附近的点 + const nearbyPoints = getNearbyPoints(x, y) + + // 在附近的点中找最近的 + for (const { point, index } of nearbyPoints) { + const dx = point.locationX - x + const dy = point.locationY - y + const distance = Math.sqrt(dx * dx + dy * dy) + const captureRadius = point.locationWide || 10 + + if (distance < minDistance && distance < captureRadius) { + minDistance = distance + closestIndex = index + } + } + + return closestIndex +}