修改点云和地图

This commit is contained in:
2025-08-25 15:24:04 +08:00
parent 15a57034ac
commit 6a1cac2d13
9 changed files with 4872 additions and 377 deletions

View File

@@ -14,6 +14,7 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { mapGetters } from 'vuex'
// import { points } from '../../config/point.js'
// import { points1 } from '../../config/point1.js'
// import { points2 } from '../../config/point2.js'
export default {
/* eslint-disable */
data () {
@@ -361,6 +362,10 @@ export default {
// const arr = points1.data
// this.updatePointCloud(arr);
// }, 5000)
// setTimeout(() => {
// const arr = points2.data
// this.updatePointCloud(arr);
// }, 10000)
},
/**
@@ -561,5 +566,4 @@ export default {
display: flex;
align-items: center;
}
</style>
../../config/point copy.js
</style>

View File

@@ -14,11 +14,19 @@
@mouseup="handleMouseUp"
@mouseleave="handleMouseUp"
></canvas>
<!-- <el-row type="flex" justify="end" class="map_tools">
<el-button type="primary" :disabled="zoomPercentage === 2" icon="el-icon-minus" size="mini" style="border: 0;border-radius: 0;" @click="zoomOut"></el-button>
<el-row type="flex" justify="end" class="map_tools">
<el-button
type="primary"
:disabled="!carPosition?.x || !carPosition?.y"
icon="el-icon-location"
size="mini"
style="border-left: 0;border-top: 0;border-bottom: 0;border-radius: 0;"
@click="centerToCar"
></el-button>
<el-button type="primary" :disabled="zoomPercentage === 2" icon="el-icon-minus" size="mini" style="border: 0;border-radius: 0;margin-left: 0" @click="zoomOut"></el-button>
<div class="zoom_data">{{ zoomPercentage }}%</div>
<el-button type="primary" :disabled="zoomPercentage === 200" icon="el-icon-plus" size="mini" style="border: 0;border-radius: 0;" @click="zoomIn"></el-button>
</el-row> -->
</el-row>
</div>
<div
v-if="showPopup"
@@ -120,13 +128,31 @@ export default {
mounted () {
this.preloadMarkerImage()
this.preloadCarImage()
this.loadAllDataInParallel()
this.loadAllDataInParallel().then(() => {
this.waitForResourcesReady().then(() => {
this.centerToCar();
});
});
document.addEventListener('click', this.handleDocumentClick)
},
beforeDestroy () {
document.removeEventListener('click', this.handleDocumentClick)
},
methods: {
waitForResourcesReady() {
return new Promise((resolve) => {
const checkReady = () => {
const isImagesReady = this.imageLoadStatus.map && this.imageLoadStatus.marker && this.imageLoadStatus.car;
const isCanvasReady = this.canvas && this.ctx;
if (isImagesReady && isCanvasReady) {
resolve();
} else {
setTimeout(checkReady, 100);
}
};
checkReady();
});
},
preloadCarImage () {
if (this.cachedImages.car) {
this.imageLoadStatus.car = true
@@ -210,9 +236,11 @@ export default {
this.initCanvas()
await this.loadMapImage()
this.loading.close()
return true
} catch (e) {
this.$message.error(`数据加载失败: ${e.message || '未知错误'}`)
this.loading.close()
return false
}
},
async _getMapInfoByCode () {
@@ -372,7 +400,7 @@ export default {
20,
20
)
// this.ctx.restore()
this.ctx.restore()
},
handleCanvasClick (event) {
const rect = this.canvas.getBoundingClientRect()

View File

@@ -1,295 +0,0 @@
<template>
<div class="point-cloud-map">
<div ref="canvasContainer" class="canvas-container"></div>
<div v-if="isLoading" class="loading-indicator">
<i class="fa fa-circle-o-notch fa-spin"></i> 加载中...
</div>
</div>
</template>
<script>
import { Application, ParticleContainer, Sprite, Graphics, Texture } from 'pixi.js'
import { mapGetters } from 'vuex'
import { points } from '../../config/point.js'
export default {
data() {
return {
// PixiJS核心对象
app: null,
pointContainer: null,
carSprite: null,
// 点云数据
allPoints: [],
pointScale: 1.0,
// 小车资源
vehicleImage: require('../../images/new/agv.png'),
carTexture: null,
// WebSocket
socket: null,
isLoading: true,
// 性能控制
lastUpdateTime: 0,
updateInterval: 800,
isDestroyed: false
}
},
computed: {
...mapGetters(['serverUrl', 'userRole', 'carPosition']),
},
watch: {
carPosition: {
handler(newVal) {
this.updateCarPosition(newVal)
},
deep: true
}
},
mounted() {
// 使用$nextTick确保DOM完全渲染后再初始化
this.$nextTick(() => {
this.initPixi()
// this.initWebSocket()
this.init()
window.addEventListener('resize', this.handleResize)
setTimeout(() => {
this.isLoading = false
}, 1000)
})
},
beforeDestroy() {
this.isDestroyed = true
// 清理WebSocket
if (this.socket) {
this.socket.close()
this.socket = null
}
// 销毁Pixi应用
if (this.app) {
this.app.destroy()
const container = this.$refs.canvasContainer
if (container && container.children.length > 0) {
container.removeChild(container.children[0])
}
this.app = null
}
// 清理资源
if (this.carTexture) {
this.carTexture.destroy()
this.carTexture = null
}
window.removeEventListener('resize', this.handleResize)
this.allPoints = []
},
methods: {
async initPixi() {
// 确保容器元素存在
const container = this.$refs.canvasContainer
if (!container) {
console.error('Canvas容器未找到')
return
}
try {
// PixiJS v8+ 使用 Application.init() 替代 new Application()
this.app = await Application.init({
width: container.clientWidth,
height: container.clientHeight,
backgroundColor: 0x0c0c0c,
antialias: true,
resolution: window.devicePixelRatio || 1,
autoDensity: true,
})
// PixiJS v8+ 使用 canvas 属性替代 view 属性
if (this.app.canvas) {
container.appendChild(this.app.canvas)
} else {
console.error('PixiJS未能创建有效的canvas')
return
}
// 创建点容器 - 使用ParticleContainer提高性能
this.pointContainer = new ParticleContainer(10000, {
position: true,
rotation: true,
tint: true,
alpha: true
})
this.app.stage.addChild(this.pointContainer)
// 加载小车纹理
this.carTexture = await Texture.fromURL(this.vehicleImage)
this.initCar()
} catch (error) {
console.error('Pixi初始化失败:', error)
}
},
initCar() {
if (!this.carTexture) {
console.error('小车纹理未加载')
return
}
this.carSprite = new Sprite(this.carTexture)
this.carSprite.anchor.set(0.5) // 设置锚点为中心
this.carSprite.width = 30
this.carSprite.height = 30
this.app.stage.addChild(this.carSprite)
if (this.carPosition) {
this.updateCarPosition(this.carPosition)
}
},
updateCarPosition(position) {
if (!this.carSprite || !position) return
this.carSprite.x = position.x * this.pointScale
this.carSprite.y = position.y * this.pointScale
this.carSprite.rotation = position.angle * (Math.PI / 180) // 转换为弧度
},
initWebSocket() {
const wsHost = this.serverUrl.replace(/^https?:\/\//, '')
this.socket = new WebSocket(`ws://${wsHost}/webSocket/PointCloudData/${this.userRole}`)
this.socket.onopen = () => {
console.log('WebSocket连接已建立')
this.isLoading = false
}
this.socket.onmessage = (event) => {
if (this.isDestroyed) return
try {
const now = Date.now()
if (now - this.lastUpdateTime < this.updateInterval) return
this.lastUpdateTime = now
const pointData = JSON.parse(event.data)
this.updatePointCloud(pointData.data)
} catch (error) {
console.error('解析点云数据失败:', error)
}
}
this.socket.onclose = (event) => {
console.log('WebSocket连接已关闭代码:', event.code)
this.isLoading = true
setTimeout(() => this.initWebSocket(), 3000)
}
this.socket.onerror = (error) => {
console.error('WebSocket错误:', error)
this.isLoading = true
}
},
updatePointCloud(points) {
if (!Array.isArray(points) || points.length === 0) return
// 去重逻辑
const existingPoints = {}
this.allPoints.forEach(point => {
existingPoints[`${point.x},${point.y}`] = true
})
const newUniquePoints = points.filter(point => {
const key = `${point.x},${point.y}`
if (!existingPoints[key]) {
existingPoints[key] = true
return true
}
return false
})
this.allPoints = [...this.allPoints, ...newUniquePoints]
// 限制总点数
const maxPoints = 5000
if (this.allPoints.length > maxPoints) {
this.allPoints = this.allPoints.slice(-maxPoints)
}
// 清空容器
this.pointContainer.removeChildren()
// 添加新点 - 使用Graphics批量绘制
const graphics = new Graphics()
graphics.beginFill(0xFFFFFF, 0.8)
this.allPoints.forEach(point => {
graphics.drawCircle(
point.x * this.pointScale,
point.y * this.pointScale,
1
)
})
graphics.endFill()
this.pointContainer.addChild(graphics)
},
handleResize() {
if (!this.app || !this.$refs.canvasContainer) return
const container = this.$refs.canvasContainer
this.app.renderer.resize(
container.clientWidth,
container.clientHeight
)
},
init () {
this.isLoading = false
const pointData = points.data
this.updatePointCloud(pointData);
setTimeout(() => {
const arr = [{x: 2, y: 2}, {x: 4, y: 4}]
this.updatePointCloud(arr);
}, 2000)
}
}
}
</script>
<style lang="stylus" scoped>
.point-cloud-map
position relative
width 100%
height calc(100% - 1rem)
margin .14rem 0
background-color rgba(4, 33, 58, 70%)
box-shadow inset 1px 1px 7px 2px #4d9bcd
overflow hidden
.canvas-container
width 100%
height 100%
position relative
z-index 0
.loading-indicator
position absolute
top 50%
left 50%
transform translate(-50%, -50%)
background-color rgba(255, 255, 255, 0.8)
padding .01rem .02rem
border-radius 4px
box-shadow 0 2px 10px rgba(0, 0, 0, 0.1)
font-size .12rem
color #333
z-index 100
display flex
align-items center
</style>