<template>
<div id="cesiumContainer"></div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import * as Cesium from 'cesium';
import CesiumNavigation from 'cesium-navigation-es6'
import api from '@/api/api';
import back from '@/api/back'
import { ElMessage } from 'element-plus';
import emitter from '@/api/eventpus/eventbus';
let socketInfo = ref('ws://192.168.0.45:8089/kunchen-plsms-websocket/webSocket')
let ws = ref(new WebSocket(socketInfo.value))
let pingInterval = ref(null) // 心跳间隔ID
let viewer = ref(null)
let entity = ref(null)
// 定位终端导航实时显示
let tableData = ref([])
// 地图的基础配置
function init() {
viewer.value = new Cesium.Viewer('cesiumContainer', {
//cesium的查看器的基本属性
baseLayerPicker: false,//配置图层底图的图标
//加载谷歌影像地图,UrlTemplateImageryProvider该接口是加载谷歌地图服务的接口
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url: "https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer",
}),
//需要纯色背景必须设置
contextOptions: {
webgl: {
alpha: true,
}
},
infoBox: false,//去除原生自带右上角弹窗
sceneMode: 3,//初始场景模式 1 2D模式 2 2D循环模式 3 3D模式 Cesium.SceneMode
geocoder: false, //查找位置工具
homeButton: true, // 视角返回初始位置
sceneModePicker: true, //选择视角模式,有三种 3D,2D,哥伦比视图
baseLayerPicker: false, //图层选择器,选择要显示的地图服务和地形服务
navigationHelpButton: false, //导航帮助按钮,显示默认的地图控制帮助
animation: false, //动画器件,控制视图动画的播放速度.
// creditContainer: "credit", // 版权显示,显示数据归属
timeline: false, //时间线,指示当前时间,并允许用户跳到特定的时间
fullscreenButton: false, //全屏按钮
vrButton: false,
baseLayerPicker: false,
// terrainProvider: Cesium.createWorldTerrain({ // 设置cesium世界地形
// requestWaterMask: true,//地形的开启
// requestVertexNormals: true,//水面效果的开启
// })
})
// viewer.value.scene.skyBox.show = false //关闭天空盒,否则会显示天空颜色
//背景透明
viewer.value.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0);
//关闭大气
viewer.value.scene.skyAtmosphere.show = false
//抗锯齿
viewer.value.scene.fxaa = true;
viewer.value.scene.postProcessStages.fxaa.enabled = true;
//清除月亮太阳
viewer.value.scene.moon.show = false
viewer.value.scene.sun.show = false
// 去除logo 版权显示,显示数据归属
viewer.value.cesiumWidget.creditContainer.style.display = "none";
// 设置初始默认视角
viewer.value.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(104.22809397, 30.57013838, 300000), // 成都的坐标
orientation: {
heading: 6.283185307179581,//方向 坐标系旋转90度
pitch: 45,//视角 设置俯仰角度为-45度
roll: 0.0
}
});
// 修改homeButton的默认返回位置
viewer.value.homeButton.viewModel.command.beforeExecute.addEventListener(function (e) {
e.cancel = true;
viewer.value.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(104.22809397, 30.57013838, 300000),
})
})
// 显示帧率
viewer.value.scene.debugShowFramesPerSecond = false;
// 添加罗盘,比例尺等控件
//配置项
var options = {
// 用于在使用重置导航重置地图视图时设置默认视图控制。接受的值是Cesium.Cartographic 和 Cesium.Rectangle.
defaultResetView: Cesium.Rectangle.fromDegrees(80, 22, 130, 50),
// 用于启用或禁用罗盘。true是启用罗盘,false是禁用罗盘。默认值为true。
enableCompass: true,
// 用于启用或禁用缩放控件。true是启用,false是禁用。默认值为true。
enableZoomControls: true,
// 用于启用或禁用距离图例。true是启用,false是禁用。默认值为true。
enableDistanceLegend: true,
// 用于启用或禁用指南针外环。true是启用,false是禁用。默认值为true。
enableCompassOuterRing: true
};
// 初始化罗盘
new CesiumNavigation(viewer.value, options);
// --------------------------websocket--------------------------------------------
// 初始Websocket
ws.value.addEventListener('open', () => {
console.log('连接已打开')
const data = JSON.stringify({ command: 1, serializeAlgorithm: 1, token: window.localStorage.getItem('token') })
ws.value.send(data) // 发送JSON字符串
// 设置心跳间隔为5秒
pingInterval.value = window.setInterval(() => {
const pingMessage = JSON.stringify({
command: 2,
serializeAlgorithm: 1
})
ws.value.send(pingMessage)
}, 5000)
})
// var list = []
ws.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data) // 解析JSON字符串
if (data.data == undefined) {
console.log('未响应');
} else {
// list.push(data.data)
// tableData.value = [data.data].splice(1, 1).concat(list)
tableData.value = data.data.latitude
emitter.emit('webDataValue', tableData.value)
console.log('解析后的数据', tableData.value);
}
})
ws.value.addEventListener('close', () => {
window.clearInterval(pingInterval.value) // 清除心跳间隔定时器
console.log('Websocket连接关闭');
})
ws.value.addEventListener('error', (error) => {
console.log('Websocket连接错误');
window.clearInterval(pingInterval.value) // 清除心跳间隔定时器
})
emitter.on('logout', () => {
// 关闭 Websocket 连接
ws.value.close()
window.clearInterval(pingInterval.value) // 清除心跳间隔定时器
})
// 后端返回的经纬度数据
const positions = ref([
{ longitude: 104.227155465, latitude: 30.571566765, },//中心点
{ longitude: 104.22621696, latitude: 30.57299515 }, // 左上角
{ longitude: 104.22809397, latitude: 30.57299515 }, // 右上角
{ longitude: 104.22621696, latitude: 30.57013838 }, // 左下角
{ longitude: 104.22809397, latitude: 30.57013838 }, // 右下角
])
console.log('经纬度', positions.value);
// 添加点
positions.value.forEach((position, index) => {
viewer.value.entities.add({
position: Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude),
point: {
pixelSize: 10,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
},
label: {
text: `点${index + 1}`,
font: '14pt monospace',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth: 2,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -9),
},
});
});
// 添加轨迹线
viewer.value.entities.add({
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray(positions.value.flatMap(pos => [pos.longitude, pos.latitude])),
width: 2,
material: Cesium.Color.RED,
},
});
// 加载模型
let entity = Cesium.Cartesian3.fromDegrees(104.227155465, 30.571566765,)
let model = viewer.value.entities.add({
id: 'model',
position: entity,
model: {
// uri: 'http://127.0.0.1:5501/car/plane3_gltf.gltf',
uri: '/car/parking_space_dae_V0.1.gltf',
minimumPixelSize: 64,
maximumSize: 128,
show: true,
color: Cesium.Color.CORAL,
scale: 100 //放大倍数
},
// scale: 1.0
});
viewer.value.trackedEntity = model
// viewer.value.zoomTo(Cesium.mode)
}
onMounted(() => {
init() //加载3d地图,
})
// 在onUnmounted钩子函数中销毁Cesium Viewer
onUnmounted(() => {
viewer.value.destroy()
})
</script>
要求是通过websocket返回的经纬度,在地图上面根据返回的经纬度绘制点和轨迹线,点和线我弄出来了(目前是用的模拟的固定经纬度),websocket返回的是实时更新的经纬度
我不知道你的外部是什么意思。不过通常来说就几个方案:
- 组件间按层级传递。即子组件传递给父组件,那么
emit('change', value)
即可 - vue 应用内部数据传递。可以用 pinia 构建 store 来处理
- 全局事件总线。可以构建一个全局事件总线,用来传递信息和数据。
- 直接放在全局上。即
window.someVar = yourData
。
最简单的可以使用状态管理库。比如说 Vuex 和 Pinia。
当然如果你的项目比较小,也不想使用状态管理库,可以使用 provide/inject 来处理,但是使用 依赖注入 暴露给后代的变量默认不是响应式的,需要用一些方式来实现响应式。
如果就是一个页面完成所有处理的,就是当前页面里面初始化WS,当前页面接收信息和处理业务。可以直接在当前页面里面做,而不是在外部处理。
我当初用的 vue-native-websocket 这个库,你可以看一下文档里面有关搭配使用 Vuex
的说明。