AttributioClassification/src/views/chart/pages/MarkerMap.vue
wangchengming c17568b04b 1
2025-12-11 22:51:25 +08:00

1344 lines
41 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="marker-wrap">
<div id="cesiumContainer">
<!-- 弹窗-->
<div v-if="popupVisible" id="custom-popup" class="custom-popup" :style="popupStyle">
<Line :id="selectedEntity.loc_id" :data="selectedEntity.info.chartData"></Line>
<!--<div class="popup-header">
{{ selectedEntity?.name + ' Info' }}
</div>
<div class="popup-content">
<table class="popup-table">
<tr v-for="(entity, index) in selectedEntity.info">
<td>{{ index }}</td>
<td>{{ entity }}</td>
</tr>
</table>
</div>-->
</div>
</div>
<div class="setting-box-wrap">
<div class="menu-box">
<div v-for="item in settingData" :key="item.id" class="menu-group">
<div v-for="subItem in item.children" :key="subItem.id" class="menu-item"
:class="{ active: subItem.isActive }" @click="menuClick(subItem)">
<img :src="getSetImageUrl(subItem.isActive ? subItem.icon + '-hover' : subItem.icon)" class="menu-icon" />
</div>
</div>
</div>
<div class="setting-box">
<div class="setting-head">设置</div>
<div class="setting-body">
<!--<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-1.png" class="icon" /></span>
IMS RN Station(P)
</div>
<el-checkbox
label=""
v-model="checkData.imsRnStationP"
class="icon-checkbox dark-checkbox"
@change="imsRnStationPChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-1.png" class="icon" /></span>
IMS RN Station(G)
</div>
<el-checkbox
label=""
v-model="checkData.imsRnStationG"
class="icon-checkbox dark-checkbox"
@change="imsRnStationGChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-1.png" class="icon" /></span>
NRL
</div>
<el-checkbox
label=""
v-model="checkData.nrl"
class="icon-checkbox dark-checkbox"
@change="nrlChange"
/>
</div>-->
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-2.png" class="icon" /></span>
Nuclear Facilities
</div>
<el-checkbox label="" v-model="checkData.nuclearFacilities" class="icon-checkbox dark-checkbox"
@change="nuclearFacilitiesChange" />
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-3.png" class="icon" /></span>
Groud monitoring station
</div>
<el-checkbox label="" v-model="checkData.groudMonitoringStation" class="icon-checkbox dark-checkbox"
@change="groudMonitoringStationChange" />
</div>
<!--<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box">
<img src="@/assets/images/setting-icon-4.png" class="icon" />
</span>
car
</div>
<el-checkbox
label=""
v-model="checkData.car"
class="icon-checkbox dark-checkbox"
@change="carChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/setting-icon-5.png" class="icon" /></span>
ship
</div>
<el-checkbox
label=""
v-model="checkData.ship"
class="icon-checkbox dark-checkbox"
@change="shipChange"
/>
</div>
<div class="space-line"></div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/halo-1.png" class="icon" /></span>
Excellent data quality
</div>
<el-checkbox
label=""
v-model="checkData.excellentDataQuality"
class="icon-checkbox dark-checkbox"
@change="excellentDataQualityChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/halo-2.png" class="icon" /></span>
Good data quality
</div>
<el-checkbox
label=""
v-model="checkData.goodDataQuality"
class="icon-checkbox dark-checkbox"
@change="goodDataQualityChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/halo-3.png" class="icon" /></span>
Poor data quality
</div>
<el-checkbox
label=""
v-model="checkData.poorDataQuality"
class="icon-checkbox dark-checkbox"
@change="poorDataQualityChange"
/>
</div>
<div class="setting-icon-check">
<div class="icon-wrap">
<span class="icon-box"><img src="@/assets/images/halo-4.png" class="icon" /></span>
Signal interruption
</div>
<el-checkbox
label=""
v-model="checkData.signalInterruption"
class="icon-checkbox dark-checkbox"
@change="signalInterruptionChange"
/>
</div>-->
</div>
</div>
</div>
</div>
</template>
<script>
import * as Cesium from 'cesium'
import Line from './Line.vue'
export default {
components: {
Line
},
data() {
return {
viewer: null,
popupVisible: false,
selectedEntity: null,
popupStyle: {
left: '0px',
top: '0px',
},
settingData: [
{
id: 'group-1',
children: [
{
id: '1',
icon: 'setting-menu-icon-1',
isActive: false,
},
{
id: '1',
icon: 'setting-menu-icon-2',
isActive: false,
},
{
id: '1',
icon: 'setting-menu-icon-3',
isActive: false,
},
],
},
{
id: 'group-2',
children: [
{
id: '5',
icon: 'setting-menu-icon-5',
isActive: false,
},
{
id: '6',
icon: 'setting-menu-icon-6',
isActive: false,
},
],
},
],
checkData: {
imsRnStationP: false,
imsRnStationG: false,
nrl: false,
nuclearFacilities: false,
groudMonitoringStation: false,
car: false,
ship: false,
excellentDataQuality: false,
goodDataQuality: false,
poorDataQuality: false,
signalInterruption: false,
},
imgData: {
imsRnStationP: [
{
id: 'abc',
lon: 116.39,
lat: 40.8994,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP48',
STATIONID: '148',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
{
id: '222',
lon: 115.39,
lat: 39.8993,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP49',
STATIONID: '149',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
IMS_RN_Station_P_Entities: [],
imsRnStationG: [
{
lon: 117.39,
lat: 38.8995,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP50',
STATIONID: '150',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
{
lon: 117.69,
lat: 38.2995,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP51',
STATIONID: '151',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
IMS_RN_Station_G_Entities: [],
nrl: [
{
lon: 117.99,
lat: 39.2995,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP52',
STATIONID: '152',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
{
lon: 117.39,
lat: 41.2995,
loc_id: 86,
image: 'entities-1.png',
info: {
STATIONCODE: 'NEP53',
STATIONID: '153',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
NRL_Entities: [],
nuclearFacilities: [
{
lon: 117.37,
lat: 39.2993,
loc_id: 86,
image: 'entities-2.png',
info: {
STATIONCODE: 'NEP54',
STATIONID: '154',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
Nuclear_Facilities_Entities: [],
groudMonitoringStation: [
{
lon: 116.42,
lat: 40.2984,
loc_id: 86,
image: 'entities-3.png',
info: {
STATIONCODE: 'NEP55',
STATIONID: '155',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
Groud_monitoring_station_Entities: [],
car: [
{
lon: 117.38,
lat: 40.2915,
loc_id: 86,
image: 'entities-4.png',
info: {
STATIONCODE: 'NEP56',
STATIONID: '156',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
car_Entities: [],
ship: [
{
lon: 115.4,
lat: 40.2998,
loc_id: 86,
image: 'entities-5.png',
info: {
STATIONCODE: 'NEP57',
STATIONID: '157',
COUNTRAYCODE: 'NE',
DATEBEGIN: '--',
DECRIPTION: '--',
ELEVATION: '--',
},
},
],
ship_Entities: [],
excellentDataQuality: [],
Excellent_data_quality_Entities: [],
goodDataQuality: [],
Good_data_quality_Entities: [],
poorDataQuality: [],
Poor_data_quality_Entities: [],
signalInterruption: [],
Signal_interruption_Entities: [],
},
}
},
created() { },
mounted() {
this.initCesium()
this.getData()
},
methods: {
getData() {
this.$axios.get(window.CONFIG.baseUrl + '/nuclide/query_pollution_data', { params: { loc_id: 86 } }).then((res) => {
this.imgData.nrl = []
this.imgData.nuclearFacilities = []
this.imgData.groudMonitoringStation = []
if (res.code === 200) {
res.result.forEach(pItem => {
if (pItem.loc_type === '0') {
pItem.sites?.forEach(item => {
this.imgData.groudMonitoringStation.push({
// id: '',
lon: item.site_lon,
lat: item.site_lat,
image: 'entities-1.png',
info: {
chartData: item.data,
}
})
})
} else if (pItem.loc_type === '1') {
this.imgData.nuclearFacilities.push({
// id: '',
lon: item.site_lon,
lat: item.site_lat,
image: 'entities-1.png',
info: {
chartData: item.data,
}
})
}
})
} else {
console.error(res.msg)
}
})
},
initCesium() {
// 设置Cesium Ion访问令牌需在官网申请
Cesium.Ion.defaultAccessToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0N2FjZGMzOC1kOGRlLTQ2MjgtOTQ3Yy0wZjNhNjU2MWE2YzMiLCJpZCI6MTU2MjMzLCJpYXQiOjE2OTAyNjQ2Mjl9.ek7v5pm-V7zWe5rxLGYIWuavneNk4p-VO40KictHc_Y'
// 初始化Cesium Viewer
this.viewer = new Cesium.Viewer('cesiumContainer', {
homeButton: false, // 不显示Home按钮
sceneModePicker: false, // 不显示场景模式选择器
baseLayerPicker: false, // 不显示底图选择器
animation: false, // 不显示动画控件
timeline: false, // 不显示时间线控件
fullscreenButton: false, // 不显示全屏按钮
geocoder: false, // 不显示地名查找控件
infoBox: false, // 显示信息框
selectionIndicator: false, // 不显示选择指示器
})
// 移除默认的版权信息
this.viewer._cesiumWidget._creditContainer.style.display = 'none'
const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
handler.setInputAction((event) => {
// 拾取点击位置的对象
const pickedObject = this.viewer.scene.pick(event.position)
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id)) {
// 判断是否点击了机器人模型
if (pickedObject.id.name && pickedObject.id.name.startsWith('机器人')) {
console.log('点击了机器人:', pickedObject.id.name)
// 在这里添加机器人点击后的处理逻辑
this.onRobotClick(pickedObject.id)
}
// 判断是否点击了鸭子模型
if (pickedObject.id.name && pickedObject.id.name.startsWith('鸭子')) {
console.log('点击了鸭子:', pickedObject.id.name)
this.onDuckClick(pickedObject.id)
}
// 判断是否点击了咖啡机模型
if (pickedObject.id.name === '咖啡机') {
console.log('点击了咖啡机')
this.onCoffeeMatClick(pickedObject.id)
}
if (
pickedObject.id.name === 'imsRnStationP' ||
pickedObject.id.name === 'imsRnStationG' ||
pickedObject.id.name === 'nrl' ||
pickedObject.id.name === 'nuclearFacilities' ||
pickedObject.id.name === 'groudMonitoringStation' ||
pickedObject.id.name === 'car' ||
pickedObject.id.name === 'ship'
) {
this.imageClick(pickedObject.id, event.position)
}
} else {
// 点击空白区域,隐藏弹窗
this.closePopup()
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 初始化完成后加载模型
this.flyToBeijing()
// this.loadSimpleModel()
},
flyToBeijing() {
// 北京坐标(经度, 纬度, 高度)
const beijingPosition = Cesium.Cartesian3.fromDegrees(116.3903, 39.9001, 600000)
this.viewer.camera.flyTo({
destination: beijingPosition, // 目标位置
orientation: {
heading: Cesium.Math.toRadians(0), // 航向角0度为正北
pitch: Cesium.Math.toRadians(-90), // 俯仰角(-45度为45度俯视
roll: 0.0, // 滚转角(保持水平)
},
duration: 3.0, // 飞行时间(秒)
})
// 飞行完成后添加模型
this.viewer.camera.moveEnd.addEventListener(() => {
console.log('飞行完成')
})
// this.loadModelDucks()
// this.loadImage()
},
imsRnStationPChange(boolean) {
if (boolean) {
this.IMS_RN_Station_P_Entities = this.imgData.imsRnStationP.map((pos) => {
return this.viewer.entities.add({
name: 'imsRnStationP',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.IMS_RN_Station_P_Entities) {
this.IMS_RN_Station_P_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.IMS_RN_Station_P_Entities = []
}
}
},
imsRnStationGChange(boolean) {
if (boolean) {
this.IMS_RN_Station_G_Entities = this.imgData.imsRnStationG.map((pos) => {
return this.viewer.entities.add({
name: 'imsRnStationG',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.IMS_RN_Station_G_Entities) {
this.IMS_RN_Station_G_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.IMS_RN_Station_G_Entities = []
}
}
},
nrlChange(boolean) {
if (boolean) {
this.NRL_Entities = this.imgData.nrl.map((pos) => {
return this.viewer.entities.add({
name: 'nrl',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.NRL_Entities) {
this.NRL_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.NRL_Entities = []
}
}
},
nuclearFacilitiesChange(boolean) {
if (boolean) {
this.Nuclear_Facilities_Entities = this.imgData.nuclearFacilities.map((pos) => {
return this.viewer.entities.add({
name: 'nuclearFacilities',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Nuclear_Facilities_Entities) {
this.Nuclear_Facilities_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Nuclear_Facilities_Entities = []
}
}
},
groudMonitoringStationChange(boolean) {
// debugger
if (boolean) {
this.Groud_monitoring_station_Entities = this.imgData.groudMonitoringStation.map((pos) => {
return this.viewer.entities.add({
name: 'groudMonitoringStation',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Groud_monitoring_station_Entities) {
this.Groud_monitoring_station_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Groud_monitoring_station_Entities = []
}
}
},
carChange(boolean) {
if (boolean) {
this.car_Entities = this.imgData.car.map((pos) => {
return this.viewer.entities.add({
name: 'car',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.car_Entities) {
this.car_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.car_Entities = []
}
}
},
shipChange(boolean) {
if (boolean) {
this.ship_Entities = this.imgData.ship.map((pos) => {
return this.viewer.entities.add({
name: 'ship',
id: pos.id,
lng: pos.lng,
lat: pos.lat,
loc_id: pos.loc_id,
info: pos.info,
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.ship_Entities) {
this.ship_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.ship_Entities = []
}
}
},
excellentDataQualityChange(boolean) {
if (boolean) {
this.Excellent_data_quality_Entities = this.imgData.excellentDataQuality.map((pos) => {
return this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Excellent_data_quality_Entities) {
this.Excellent_data_quality_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Excellent_data_quality_Entities = []
}
}
},
goodDataQualityChange(boolean) {
if (boolean) {
this.Good_data_quality_Entities = this.imgData.goodDataQuality.map((pos) => {
return this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Good_data_quality_Entities) {
this.Good_data_quality_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Good_data_quality_Entities = []
}
}
},
poorDataQualityChange(boolean) {
if (boolean) {
this.Poor_data_quality_Entities = this.imgData.poorDataQuality.map((pos) => {
return this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Poor_data_quality_Entities) {
this.Poor_data_quality_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Poor_data_quality_Entities = []
}
}
},
signalInterruptionChange(boolean) {
if (boolean) {
this.Signal_interruption_Entities = this.imgData.signalInterruption.map((pos) => {
return this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: this.getImageUrl(pos.image),
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
} else {
if (this.Signal_interruption_Entities) {
this.Signal_interruption_Entities.forEach((entity) => {
this.viewer.entities.remove(entity)
})
this.Signal_interruption_Entities = []
}
}
},
loadImage() {
const positions = [
{ lon: 116.39, lat: 40.8994, image: obj },
{ lon: 115.39, lat: 39.8993, image: obj },
{ lon: 117.39, lat: 38.8995, image: obj },
{ lon: 117.69, lat: 38.2995, image: obj },
{ lon: 117.99, lat: 39.2995, image: obj },
{ lon: 117.39, lat: 41.2995, image: obj },
{ lon: 117.38, lat: 42.2995, image: car },
]
positions.forEach((pos) => {
const entity = this.viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
billboard: {
image: pos.image,
scale: 1,
scaleByDistance: new Cesium.NearFarScalar(1, 2.5, 10000, 1.5),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 关键贴地属性
// 关键设置:禁用深度测试,防止近距离被遮挡
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
})
})
},
// loadModelDucks () {
// for (let i = 0; i < 10; i++) {
// const modal = {
// id: 'duck_' + i,
// name: '鸭子' + (i + 1),
// position: Cesium.Cartesian3.fromDegrees(116.39 + Math.random() * 0.0005, 39.9 + Math.random() * 0.0005, 0),
// model: {
// uri: '/duck.glb', // 模型路径
// scale: 7.0,
// minimumPixelSize: 0,
// maximumScale: 200
// }
// }
// this.viewer.entities.add(modal)
// }
// },
onRobotClick(robotEntity) {
// 高亮显示被点击的机器人
this.highlightEntity(robotEntity)
// 显示机器人信息
this.showRobotInfo(robotEntity)
// 飞向被点击的机器人
this.flyToEntity(robotEntity)
},
onDuckClick(duckEntity) {
console.log('鸭子被点击:', duckEntity.name)
this.highlightEntity(duckEntity)
},
onCoffeeMatClick(coffeeMatEntity) {
console.log('咖啡机被点击')
this.highlightEntity(coffeeMatEntity)
},
imageClick(entity, clickPosition) {
// debugger
this.selectedEntity = {
id: entity.id,
name: entity.name,
longitude: entity.lng,
latitude: entity.lat,
loc_id: entity.loc_id,
info: entity.info,
// description: entity.customProperties.description
}
this.popupVisible = true
// 初始定位
this.updatePopupPosition(entity)
// 监听场景渲染事件,实时更新弹窗位置[2,9](@ref)
this.viewer.scene.postRender.addEventListener(this.updatePopupPosition)
},
// 更新弹窗位置(关键功能)
updatePopupPosition() {
if (!this.selectedEntity || !this.viewer) return
// 获取当前选中实体的位置
const entity = this.viewer.entities.getById(this.selectedEntity.id)
if (!entity || !entity.position) return
// 将世界坐标转换为屏幕坐标[9](@ref)
const position = Cesium.SceneTransforms.worldToWindowCoordinates(
this.viewer.scene,
entity.position.getValue(Cesium.JulianDate.now()),
)
if (position) {
// 设置弹窗位置(在标记点上方)
const popupElement = document.getElementById('custom-popup')
if (popupElement) {
const popupWidth = popupElement.offsetWidth
const popupHeight = popupElement.offsetHeight
// 计算弹窗位置,确保不会超出屏幕边界
let left = position.x - popupWidth / 2 + 10
let top = position.y - popupHeight - 60
// // 边界检查
// const canvasRect = this.viewer.canvas.getBoundingClientRect()
//
// // 右侧边界检查
// if (left + popupWidth > canvasRect.width) {
// left = position.x - popupWidth - 10
// }
//
// // 左侧边界检查
// if (left < 0) {
// left = 10
// }
// 上侧边界检查
if (top < 0) {
top = position.y + 10
}
this.popupStyle = {
left: left + 'px',
top: top + 'px',
}
}
}
},
// 关闭弹窗
closePopup() {
this.popupVisible = false
this.selectedEntity = null
// 移除位置更新事件监听
if (this.viewer) {
this.viewer.scene.postRender.removeEventListener(this.updatePopupPosition)
}
},
// 高亮实体
highlightEntity(entity) {
// 先移除所有高亮
this.removeAllHighlights()
// 添加高亮效果(改变模型颜色或缩放)
if (entity.model) {
// 方法1改变模型颜色
entity.model.silhouetteColor = Cesium.Color.YELLOW
entity.model.silhouetteSize = 3
// // 方法2添加缩放动画
// this.animateEntityScale(entity, 1.2, 500)
}
},
// 显示机器人信息
showRobotInfo(robotEntity) {
// 创建信息框
const description = `
<div style="padding: 10px;">
<h3>${robotEntity.name}</h3>
<p>类型: 智能机器人</p>
<p>状态: 正常运行</p>
<p>位置: 北京地区</p>
<button onclick="console.log('控制机器人')">控制</button>
</div>
`
// 显示Cesium自带的信息框
this.viewer.selectedEntity = robotEntity
this.viewer.infoBox.viewModel.description = description
this.viewer.infoBox.viewModel.showInfo = true
},
// 飞向实体
flyToEntity(entity, duration = 1.5) {
this.viewer.flyTo(entity, {
duration: duration,
offset: new Cesium.HeadingPitchRange(0, -0.5, 50), // 相机偏移
})
},
// 实体缩放动画
animateEntityScale(entity, targetScale, duration) {
const originalScale = entity.model.scale.getValue(Cesium.JulianDate.now())
const startTime = Cesium.JulianDate.now()
const stopTime = Cesium.JulianDate.addSeconds(
startTime,
duration / 1000,
new Cesium.JulianDate(),
)
// 创建缩放动画
entity.model.scale = new Cesium.SampledProperty(Number)
entity.model.scale.addSample(startTime, originalScale)
entity.model.scale.addSample(stopTime, targetScale)
// 恢复原始大小
setTimeout(() => {
entity.model.scale = new Cesium.ConstantProperty(originalScale)
}, duration + 200)
},
// 移除所有高亮效果
removeAllHighlights() {
const entities = this.viewer.entities.values
entities.forEach((entity) => {
if (entity.model) {
entity.model.silhouetteColor = undefined
entity.model.silhouetteSize = 0
}
})
},
loadModelRobot() {
// 方法1使用Entity方式加载模型推荐简单模型
const modelEntity = this.viewer.entities.add({
name: '机器人',
position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0),
model: {
uri: '/RobotExpressive.glb', // 模型路径
scale: 1.0,
minimumPixelSize: 64,
maximumScale: 200,
},
})
},
loadSimpleModel() {
// 使用实体(Entity)方式加载GLTF模型
const modelEntity = this.viewer.entities.add({
name: '简单模型',
position: Cesium.Cartesian3.fromDegrees(116.39, 39.9, 0),
model: {
uri: '/coffeemat.glb', // 你的模型路径
scale: 1.0,
minimumPixelSize: 0,
maximumScale: 20000,
},
})
// 飞向模型位置
this.viewer.flyTo(modelEntity)
},
loadModelAsPrimitive() {
const position = Cesium.Cartesian3.fromDegrees(116.39, 39.9, 100)
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position)
const model = this.viewer.scene.primitives.add(
Cesium.Model.fromGltf({
url: '/coffeemat.glb',
modelMatrix: modelMatrix,
scale: 1.0,
minimumPixelSize: 128,
maximumScale: 20000,
}),
)
// 模型加载完成后的回调
model.readyPromise.then(() => {
this.viewer.camera.flyTo({
destination: position,
orientation: {
heading: 0.0,
pitch: -0.5,
roll: 0.0,
},
duration: 2.0,
})
})
},
flyToTarget(lon, lat, height, duration = 2.0) {
this.viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-45),
roll: 0.0,
},
duration: duration,
})
},
getSetImageUrl(name) {
return new URL(`../../../assets/images/${name}.png`, import.meta.url).href
},
getImageUrl(name) {
return new URL(`../../../assets/images/${name}`, import.meta.url).href
},
menuClick(item) {
item.isActive = !item.isActive
},
},
beforeDestroy() {
// 清理事件处理器
if (this.handler && !this.handler.isDestroyed()) {
this.handler.destroy()
}
// 组件销毁时清理Cesium实例
if (this.viewer && !this.viewer.isDestroyed()) {
this.viewer.destroy()
}
},
}
</script>
<style scoped lang="scss">
.marker-wrap {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
#cesiumContainer {
position: relative;
width: 100%;
height: 100%;
::v-deep .cesium-viewer-toolbar {
.cesium-navigationHelpButton-wrapper {
display: none;
}
}
}
.setting-box-wrap {
width: 360px;
position: absolute;
right: 6px;
top: 6px;
z-index: 8;
color: #e2e4e3;
display: flex;
.menu-box {
width: 32px;
.menu-group {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
.menu-item {
width: 100%;
height: 32px;
background-color: rgba(2, 27, 32, 0.9);
border: 1px solid #104f46;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
&+.menu-item {
margin-top: -1px;
}
&:hover {
background-color: #126774;
}
&.active {
background-color: #13a2b6;
}
}
}
.setting-box {
flex: 1;
overflow: hidden;
margin-left: 15px;
background-color: rgba(2, 27, 32, 0.85);
.setting-head {
height: 40px;
line-height: 40px;
padding: 0 14px;
background-color: rgba(6, 61, 68, 0.85);
color: #01e8fc;
}
.setting-body {
padding: 14px;
.setting-icon-check {
margin: 1px 0;
display: flex;
align-items: center;
.icon-wrap {
flex: 1;
overflow: hidden;
display: flex;
align-items: center;
.icon-box {
width: 30px;
margin-right: 12px;
display: flex;
align-items: center;
justify-content: center;
.icon {}
}
}
.icon-checkbox {
width: 20px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.space-line {
height: 1px;
margin: 10px 0;
background-color: #064240;
}
}
}
}
}
.custom-popup {
position: absolute;
z-index: 7;
border-radius: 4px;
min-width: 250px;
//max-width: 300px;
width: 350px;
height: 200px;
background-color: rgba(2, 27, 32, 0.85);
color: #fff;
.popup-header {
padding: 6px 10px;
text-align: center;
color: #a77c11;
}
.popup-content {
padding: 0 5px 5px;
.popup-table {
width: 100%;
height: 100%;
border-collapse: collapse;
th,
td {
padding: 0 10px;
text-align: center;
border: 1px solid #0a4a46;
&:first-child {
color: #6bb5cc;
}
}
}
}
}
</style>