This commit is contained in:
2025-08-06 10:00:01 +08:00
parent 3ac985e57d
commit 7367906a45
2 changed files with 113 additions and 34 deletions

View File

@@ -40,7 +40,9 @@ export default {
viewSize: 20,
animationId: null,
lastUpdateTime: 0,
updateInterval: 100, // 限制更新频率,毫秒
updateInterval: 800, // 限制更新频率,毫秒
// 标记组件是否已销毁
isDestroyed: false
}
},
computed: {
@@ -76,19 +78,76 @@ export default {
}, 1000);
},
beforeDestroy () {
// 清理资源
// 先标记组件已销毁,阻止新消息处理
this.isDestroyed = true;
// 1. 清理WebSocket先移除事件监听再关闭连接
if (this.socket) {
this.socket.close();
this.socket.onopen = null;
this.socket.onmessage = null;
this.socket.onclose = null;
this.socket.onerror = null;
this.socket.close(1000, '组件销毁');
this.socket = null;
}
// 2. 停止动画循环并清理
if (this.animationId) {
cancelAnimationFrame(this.animationId);
this.animationId = null;
}
// 3. 清理OrbitControls关键控制器有内部事件监听
if (this.controls) {
this.controls.dispose(); // 控制器自带的清理方法,移除事件监听
this.controls = null;
}
// 4. 清理Three.js场景对象先从场景移除再释放资源
if (this.scene) {
// 移除点云网格
if (this.pointCloudMesh) {
this.scene.remove(this.pointCloudMesh);
}
// 移除小车模型
if (this.carMesh) {
this.scene.remove(this.carMesh);
}
// 清空场景(彻底释放所有子对象引用)
this.scene.clear();
this.scene = null;
}
// 5. 释放Three.js渲染器及DOM
if (this.renderer) {
// 从DOM中移除canvas元素避免残留DOM节点
const container = this.$refs.canvasContainer;
if (container && this.renderer.domElement) {
container.removeChild(this.renderer.domElement);
}
// 释放渲染器资源
this.renderer.dispose();
this.renderer.forceContextLoss(); // 强制释放WebGL上下文关键
this.renderer = null;
}
// 6. 释放几何体和材质(确保先移除引用)
if (this.pointCloudGeometry) {
this.pointCloudGeometry.dispose();
this.pointCloudGeometry = null;
}
if (this.pointCloudMaterial) {
// 先清除材质的纹理引用(避免纹理无法释放)
this.pointCloudMaterial.map = null;
this.pointCloudMaterial.dispose();
this.pointCloudMaterial = null;
}
// 7. 释放小车纹理(确保材质不再引用)
if (this.carTexture) {
this.carTexture.dispose();
this.carTexture = null;
}
// 8. 移除窗口大小变化监听(避免重复监听)
window.removeEventListener('resize', this.handleResize);
// 清理Three.js资源
if (this.renderer) this.renderer.dispose();
if (this.pointCloudGeometry) this.pointCloudGeometry.dispose();
if (this.pointCloudMaterial) this.pointCloudMaterial.dispose();
if (this.carTexture) this.carTexture.dispose();
// 9. 清空其他引用帮助GC回收
this.allPoints = [];
this.camera = null;
this.carMesh = null;
this.pointCloudMesh = null;
},
methods: {
/**
@@ -130,7 +189,7 @@ export default {
*/
initControls() {
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.controls.enableRotate = true; // 禁用旋转保持2D视图
this.controls.enableRotate = false; // 禁用旋转保持2D视图
this.controls.enableZoom = true; // 启用缩放
this.controls.enablePan = true; // 启用平移(拖动)
this.controls.screenSpacePanning = true; // 2D平移模式
@@ -245,6 +304,8 @@ export default {
};
this.socket.onmessage = (event) => {
// 组件已销毁则直接返回,不处理消息
if (this.isDestroyed) return
try {
// 限制更新频率,优化性能
const now = Date.now();
@@ -254,7 +315,6 @@ export default {
this.lastUpdateTime = now;
const pointData = JSON.parse(event.data);
console.log(pointData.data)
this.updatePointCloud(pointData.data);
} catch (error) {
console.error('解析点云数据失败:', error);
@@ -277,6 +337,10 @@ export default {
init () {
const pointData = points.data
this.updatePointCloud(pointData);
setTimeout(() => {
const arr = [{x: 2, y: 2}, {x: 4, y: 4}]
this.updatePointCloud(arr);
}, 2000)
},
/**
@@ -306,28 +370,46 @@ export default {
this.allPoints = [...this.allPoints, ...newUniquePoints];
this.pointCount = this.allPoints.length; // 更新总点数
// 重新创建缓冲区(因数据量变化,需重新分配内存)
const pointPositions = new Float32Array(this.pointCount * 3); // x, y, z各占1位
this.pointCloudGeometry.setAttribute(
'position',
new THREE.BufferAttribute(pointPositions, 3)
);
// 获取位置缓冲区并更新数据
// 动态扩展缓冲区
const positionAttribute = this.pointCloudGeometry.getAttribute('position');
const positions = positionAttribute.array;
// 填充数据z始终为0
for (let i = 0; i < this.pointCount; i++) {
const point = this.allPoints[i];
// 假设点数据格式为 {x: number, y: number}
positions[i * 3] = (point.x || 0) * this.pointScale;
positions[i * 3 + 1] = (point.y || 0) * this.pointScale;
positions[i * 3 + 2] = 0; // Z轴固定为0
let positions;
if (!positionAttribute) {
// 首次初始化:创建缓冲区
positions = new Float32Array(this.pointCount * 3);
this.pointCloudGeometry.setAttribute(
'position',
new THREE.BufferAttribute(positions, 3)
);
} else {
// 后续更新:扩展现有缓冲区(避免重建)
positions = positionAttribute.array;
const newLength = this.pointCount * 3;
if (newLength > positions.length) {
// 扩展时多预留20%空间,减少频繁扩展
const newPositions = new Float32Array(Math.ceil(newLength * 1.2));
newPositions.set(positions); // 复制原有数据
positions = newPositions;
this.pointCloudGeometry.setAttribute(
'position',
new THREE.BufferAttribute(positions, 3)
);
}
}
// 标记属性需要更新
positionAttribute.needsUpdate = true;
// 填充新数据(仅更新新增部分,减少重复计算)
const startIndex = (this.pointCount - newUniquePoints.length) * 3; // 从新增点开始
for (let i = 0; i < newUniquePoints.length; i++) {
const point = newUniquePoints[i];
const index = startIndex + i * 3;
positions[index] = (point.x || 0) * this.pointScale;
positions[index + 1] = (point.y || 0) * this.pointScale;
positions[index + 2] = 0;
}
// 标记更新
this.pointCloudGeometry.getAttribute('position').needsUpdate = true;
},
/**