diff --git a/src/views/inspection/cockpit/components/ManualTakeover/index.vue b/src/views/inspection/cockpit/components/ManualTakeover/index.vue
index d82338a..d78e55e 100644
--- a/src/views/inspection/cockpit/components/ManualTakeover/index.vue
+++ b/src/views/inspection/cockpit/components/ManualTakeover/index.vue
@@ -100,7 +100,7 @@
-
+
diff --git a/src/views/inspection/cockpit/components/MapCanvas.vue b/src/views/inspection/cockpit/components/MapCanvas.vue
index 7d630e4..fc29cc2 100644
--- a/src/views/inspection/cockpit/components/MapCanvas.vue
+++ b/src/views/inspection/cockpit/components/MapCanvas.vue
@@ -28,16 +28,11 @@ import {
import { getMapJson } from '@/api/inspection/robot'
import { useInspectionStore } from "@/store/modules/inspection";
import { ElMessage } from 'element-plus';
-import { clear } from 'ace-builds/src-noconflict/ext-code_lens';
const props = defineProps({
robotList: {
type: Array,
default: () => []
- },
- clearMap: {
- type: Boolean,
- default: false
}
})
@@ -78,6 +73,9 @@ const applicationState = {
let mapCanvas; // 主渲染画布 DOM 元素
let canvasCtx; // 2D 渲染上下文
+let animationFrameId;
+let mapLoadVersion = 0;
+
const init = () => {
mapCanvas = document.getElementById('map-canvas');
canvasCtx = mapCanvas.getContext('2d');
@@ -191,7 +189,7 @@ function renderFrame(timestamp) {
// 如果地图未加载,跳过绘制
if (!applicationState.isMapLoaded) {
- requestAnimationFrame(renderFrame); // 继续请求下一帧
+ animationFrameId = requestAnimationFrame(renderFrame); // 继续请求下一帧
return;
}
@@ -241,7 +239,7 @@ function renderFrame(timestamp) {
drawMapBoundary(canvasCtx, map);
// 请求下一帧渲染
- requestAnimationFrame(renderFrame);
+ animationFrameId = requestAnimationFrame(renderFrame);
}
const drawAllRobots = (ctx) => {
@@ -354,14 +352,25 @@ const centerCanvasView = () => {
inspectionStore.camera.centerY = (map.originY + map.maxY) / 2;
}
-const loadSourceMap = async () => {
- const connectedRobot = props.robotList.find(item => item.connectStatus == 1);
+const getConnectedRobot = (robotList = props.robotList) => {
+ return robotList.find(item => item?.connectStatus == 1)
+}
+
+const getMapIdentity = (robotList = props.robotList) => {
+ const robot = getConnectedRobot(robotList)
+ return robot ? `${robot.id ?? ''}:${robot.robotMapName ?? ''}` : ''
+}
+
+const loadSourceMap = async (connectedRobot = getConnectedRobot()) => {
if (!connectedRobot) return;
+ const currentLoadVersion = ++mapLoadVersion;
+
const res = await getMapJson({
robotId: connectedRobot.id,
mapName: connectedRobot.robotMapName
});
+ if (currentLoadVersion !== mapLoadVersion) return;
if (res.code === 200) {
try {
const rawJsonObject = JSON.parse(res.data); // 解析 JSON
@@ -373,20 +382,6 @@ const loadSourceMap = async () => {
}
};
-/**
- *
- * @param id 机器人编号
- * @param name 机器人名称
- * @param angleRad 角度
- * @param color 颜色
- */
-const addRobot = (id, name,x, y, angleRad, color) => {
- const map = applicationState.parsedMap;
- // 放置于地图中央附近
- const robot = new MobileRobot(id, name, x, y, angleRad, color);
- applicationState.robots.push(robot);
-}
-
const parseRobotPosition = (currentPosition) => {
if (!currentPosition) return null
const values = String(currentPosition).split(',').map(Number)
@@ -394,60 +389,58 @@ const parseRobotPosition = (currentPosition) => {
return values
}
-const moveRobot = (robot, dx, dy, dtheta = 0) => {
- robot.x += dx;
- robot.y += dy;
- robot.angle += dtheta;
+const syncRobots = (robotList) => {
+ const previousRobots = new Map(applicationState.robots.map(robot => [robot.id, robot]));
+ const nextRobots = [];
+
+ robotList.forEach(item => {
+ const position = parseRobotPosition(item.currentPosition)
+ if (!position) return
+
+ const [x, y, angle] = position
+ const robot = previousRobots.get(item.id)
+ if (robot) {
+ robot.name = item.robotName
+ robot.x = x
+ robot.y = y
+ robot.angle = angle
+ nextRobots.push(robot)
+ return
+ }
+
+ nextRobots.push(new MobileRobot(
+ item.id,
+ item.robotName,
+ x,
+ y,
+ angle,
+ colorList[nextRobots.length % colorList.length]
+ ))
+ })
+
+ applicationState.robots = nextRobots
}
onMounted(() => {
init()
- if (props.robotList.length > 0) {
- loadSourceMap()
- requestAnimationFrame(renderFrame);
- window.addEventListener('resize', resizeCanvasToContainer); // 监听窗口大小变化
- resizeCanvasToContainer(); // 初始调用一次
- setTimeout(() => {
- bindEvent()
- props.robotList.forEach(item => {
- const position = parseRobotPosition(item.currentPosition)
- if (!position) return
- const [x, y, angle] = position
- addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
- })
- }, 300)
- }
+ window.addEventListener('resize', resizeCanvasToContainer);
+ resizeCanvasToContainer();
+ bindEvent()
+ syncRobots(props.robotList)
+ loadSourceMap()
+ animationFrameId = requestAnimationFrame(renderFrame);
})
const colorList = ['#00D4FF', '#FFB300', '#00FF88', '#ff5100', '#fff', '#15ff00', '#ff00d4', '#00d4ff']
-watch(() => props.robotList,
- (newVal) => {
- if (newVal.length > 0) {
- if (props.clearMap) {
- applicationState.robots = []
- }
- loadSourceMap()
+// 轮询只同步机器人实例,不重新请求、解析或重置地图。
+watch(() => props.robotList, syncRobots)
- const ids = applicationState.robots.map(r => r.id);
- props.robotList.forEach(item => {
- const position = parseRobotPosition(item.currentPosition)
- if (!position) return
- const [x, y, angle] = position
- if (!ids.includes(item.id)) {
- addRobot(item.id, item.robotName, x, y, angle, colorList[applicationState.robots.length % colorList.length])
- } else {
- applicationState.robots.forEach(robot => {
- if (robot.id === item.id) {
- // moveRobot(robot, parseFloat(x) - robot.x, parseFloat(y) - robot.y, parseFloat(angle) - robot.angle)
- robot.x = x
- robot.y = y
- robot.angle = angle
- }
- })
- }
- })
- }
+// 只有用于加载地图的机器人或地图名称改变时,才重新加载底图。
+watch(
+ () => getMapIdentity(props.robotList),
+ (newIdentity, oldIdentity) => {
+ if (newIdentity && newIdentity !== oldIdentity) loadSourceMap()
}
)
@@ -458,6 +451,8 @@ defineExpose({
onUnmounted(() => {
window.removeEventListener('resize', resizeCanvasToContainer)
+ cancelAnimationFrame(animationFrameId)
+ mapLoadVersion += 1
canvasCtx = null
})