feat: 实现批量更新机器人数据的功能,优化渲染性能,减少渲染调用次数
This commit is contained in:
parent
0c44af67a0
commit
45b25ac9d3
@ -76,17 +76,73 @@ const monitorScene = async () => {
|
||||
// 用于存储 requestAnimationFrame 的 ID,方便在组件卸载或 WebSocket 关闭时取消动画循环。
|
||||
let animationFrameId: number;
|
||||
|
||||
/**
|
||||
* 批量更新机器人数据,减少渲染调用次数
|
||||
* @param updates 需要更新的机器人数据数组
|
||||
*/
|
||||
const batchUpdateRobots = (updates: Array<{ id: string; data: RobotRealtimeInfo }>) => {
|
||||
if (!editor.value || updates.length === 0) return;
|
||||
|
||||
// 先更新所有机器人的状态信息,包括光圈渲染所需的状态
|
||||
updates.forEach(({ id, data }) => {
|
||||
const { x, y, active, angle, path: points, isWaring, isFault, ...rest } = data;
|
||||
|
||||
// 更新机器人基本信息
|
||||
editor.value?.updateRobot(id, rest);
|
||||
|
||||
// 处理路径坐标转换,参考refreshRobot方法的逻辑
|
||||
let processedPath: Array<{ x: number; y: number }> | undefined;
|
||||
if (points?.length) {
|
||||
// 新路径:相对于机器人中心的坐标
|
||||
const cx = x || 37; // 机器人中心X坐标,默认37
|
||||
const cy = y || 37; // 机器人中心Y坐标,默认37
|
||||
processedPath = points.map((p) => ({ x: p.x - cx, y: p.y - cy }));
|
||||
}
|
||||
|
||||
// 更新机器人状态,触发光圈渲染
|
||||
const robotState = { active, isWaring, isFault, path: processedPath, angle };
|
||||
if (Object.values(robotState).some((v) => v !== undefined)) {
|
||||
editor.value?.setValue({ id, robot: robotState }, { render: false, history: false, doEvent: false });
|
||||
}
|
||||
});
|
||||
|
||||
// 批量设置位置和可见性,只渲染一次
|
||||
const positionUpdates = updates.map(({ id, data }) => {
|
||||
const { x, y, angle } = data;
|
||||
if (isNil(x) || isNil(y)) {
|
||||
return { id, visible: false };
|
||||
} else {
|
||||
const newX = x - 60;
|
||||
const newY = y - 60;
|
||||
const rotate = angle;
|
||||
return { id, x: newX, y: newY, rotate, visible: true };
|
||||
}
|
||||
});
|
||||
|
||||
// 使用Meta2D的批量更新方法,减少渲染调用
|
||||
positionUpdates.forEach((update) => {
|
||||
editor.value?.setValue(update, { render: false, history: false, doEvent: false });
|
||||
});
|
||||
|
||||
// 批量更新完成后,统一渲染一次
|
||||
editor.value?.render();
|
||||
};
|
||||
|
||||
/**
|
||||
* 渲染循环函数。
|
||||
* 通过 requestAnimationFrame 以浏览器的刷新频率被调用。
|
||||
* 采用时间分片(Time Slicing)策略,为每一帧的渲染操作设定一个时间预算(frameBudget),
|
||||
* 避免单帧处理过多数据导致UI阻塞。
|
||||
* 新增批量渲染优化,减少渲染调用次数。
|
||||
*/
|
||||
const renderLoop = () => {
|
||||
const frameBudget = 8; // 每一帧的渲染预算,单位:毫秒。保守设置为8ms,为其他任务留出时间。
|
||||
const startTime = performance.now();
|
||||
|
||||
// 在时间预算内,持续处理机器人数据
|
||||
// 收集所有需要更新的机器人数据,但不立即渲染
|
||||
const updates: Array<{ id: string; data: RobotRealtimeInfo }> = [];
|
||||
|
||||
// 在时间预算内,持续收集机器人数据
|
||||
while (performance.now() - startTime < frameBudget && latestRobotData.size > 0) {
|
||||
// 获取并移除 Map 中的第一条数据
|
||||
const entry = latestRobotData.entries().next().value;
|
||||
@ -94,23 +150,17 @@ const monitorScene = async () => {
|
||||
const [id, data] = entry;
|
||||
latestRobotData.delete(id);
|
||||
|
||||
const { x, y, active, angle, path, isWaring, isFault, ...rest } = data;
|
||||
// 确保机器人仍然存在于编辑器中
|
||||
if (editor.value?.checkRobotById(id)) {
|
||||
// 更新机器人的非位置属性(如状态等)
|
||||
editor.value?.updateRobot(id, rest);
|
||||
|
||||
// 更新机器人的位置和可见性
|
||||
if (isNil(x) || isNil(y)) {
|
||||
// 如果坐标为空,则隐藏机器人
|
||||
editor.value.updatePen(id, { visible: false });
|
||||
} else {
|
||||
// 如果坐标有效,则刷新机器人在画布上的位置、角度等
|
||||
editor.value.refreshRobot(id, { x, y, active, angle, path, isWaring, isFault });
|
||||
}
|
||||
updates.push({ id, data });
|
||||
}
|
||||
}
|
||||
|
||||
// 批量更新机器人,减少渲染调用次数
|
||||
if (updates.length > 0) {
|
||||
batchUpdateRobots(updates);
|
||||
}
|
||||
|
||||
// 处理缓冲的自动门点数据
|
||||
autoDoorSimulationService.processBufferedData(frameBudget, startTime);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user