feat: 处理轮询时地图刷新的问题
This commit is contained in:
parent
2159b7f228
commit
f5b1b70274
@ -100,7 +100,7 @@
|
||||
</div>
|
||||
<div class="video-container">
|
||||
<div v-if="activeMode === 'auto' || activeController === 1" class="map-container">
|
||||
<MapCanvas v-if="robotList.length > 0" :clearMap="true" :robotList="currentRobot" ref="mapCanvasRef" />
|
||||
<MapCanvas v-if="robotList.length > 0" :robotList="currentRobot" ref="mapCanvasRef" />
|
||||
</div>
|
||||
<div v-if="activeMode === 'artificial' && activeController === 2" class="model-container">
|
||||
<UrdfViewer ref="urdfViewerRef" modelPath="/inspection/elfin10/elfin10.urdf.xacro" />
|
||||
|
||||
@ -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
|
||||
})
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user