|
|
|
@ -50,6 +50,19 @@ const props = defineProps({ |
|
|
|
); |
|
|
|
} |
|
|
|
}, |
|
|
|
distributionDataList: { |
|
|
|
type: Array, |
|
|
|
required: true, |
|
|
|
// 可选:添加自定义 validator(更严格) |
|
|
|
validator(value) { |
|
|
|
return Array.isArray(value) && value.every(item => |
|
|
|
typeof item === 'object' && |
|
|
|
item !== null && |
|
|
|
typeof item.position === 'string' |
|
|
|
// 注意:无法验证是否符合 ShorePowerBerth 结构(因为 JS 没有接口) |
|
|
|
); |
|
|
|
} |
|
|
|
}, |
|
|
|
onInstanceClick: { |
|
|
|
type: Function, |
|
|
|
default: (data) => { } |
|
|
|
@ -315,19 +328,10 @@ onMounted(async () => { |
|
|
|
maximumLevel: 16 |
|
|
|
}); |
|
|
|
const dataInfo = history.value ? history.value : await MapApi.getAllData() |
|
|
|
console.log(dataInfo) |
|
|
|
const shipData = props.shipDataList |
|
|
|
const shorePowerList = props.shorePowerList |
|
|
|
|
|
|
|
// const unitedData = |
|
|
|
|
|
|
|
// 通用添加函数,遍历dataInfo并创建标记 |
|
|
|
let arr = { |
|
|
|
arr1: [], |
|
|
|
arr2: [], |
|
|
|
arr3: [], |
|
|
|
arr4: [], |
|
|
|
arr5: [] |
|
|
|
} |
|
|
|
const distributionDataList = props.distributionDataList |
|
|
|
|
|
|
|
// 步骤 3: 将图层添加到 Viewer 中 |
|
|
|
viewer.imageryLayers.addImageryProvider(gaodeImage); |
|
|
|
@ -343,10 +347,107 @@ onMounted(async () => { |
|
|
|
const oneTitleInstance = [] |
|
|
|
const twoTitleInstance = [] |
|
|
|
const tempShorePowerInstance = [] |
|
|
|
const tempDistributionBoxInstance = [] |
|
|
|
const ShorePowerAndShipInstance = [] |
|
|
|
const distributionBoxAndShorePowerInstance = [] |
|
|
|
distributionDataList.forEach((item) => { |
|
|
|
const itemDistribution = dataInfo.filter(mapitem => (item.id === mapitem.parentId) && mapitem.type === 3) |
|
|
|
const result = itemDistribution |
|
|
|
.filter(item => { |
|
|
|
try { |
|
|
|
const data = JSON.parse(item.data); |
|
|
|
return data.type === 'icon'; |
|
|
|
} catch (e) { |
|
|
|
return false; // 忽略无法解析的 data |
|
|
|
} |
|
|
|
}) |
|
|
|
.map(item => JSON.parse(item.data)); |
|
|
|
console.log(result) |
|
|
|
if (!result || result.length === 0) return |
|
|
|
const dataObj = result[0] |
|
|
|
let longitude, latitude; |
|
|
|
let wgsLon, wgsLat; |
|
|
|
const wgsCoords = coordtransform.gcj02towgs84(dataObj.xy[1], dataObj.xy[0]); |
|
|
|
wgsLon = wgsCoords[0]; |
|
|
|
wgsLat = wgsCoords[1]; |
|
|
|
latitude = wgsLat; |
|
|
|
longitude = wgsLon; |
|
|
|
const xposition = Cesium.Cartesian3.fromDegrees(longitude, latitude, 1); |
|
|
|
console.log(xposition) |
|
|
|
const xelectricalBoxModel = viewer.entities.add({ |
|
|
|
name: '配电箱', |
|
|
|
position: xposition, |
|
|
|
// 添加唯一标识用于识别点击事件 |
|
|
|
properties: { |
|
|
|
modelType: 'distribution_box', |
|
|
|
data: item |
|
|
|
}, |
|
|
|
orientation: Cesium.Transforms.headingPitchRollQuaternion( |
|
|
|
xposition, |
|
|
|
new Cesium.HeadingPitchRoll( |
|
|
|
Cesium.Math.toRadians(dataObj.rotationAngle), // 航向角 (绕Z轴旋转) |
|
|
|
Cesium.Math.toRadians(0), // 俯仰角 (绕Y轴旋转) |
|
|
|
Cesium.Math.toRadians(0) // 翻滚角 (绕X轴旋转) |
|
|
|
) |
|
|
|
), |
|
|
|
model: { |
|
|
|
uri: '/model/electrical_box.glb', |
|
|
|
scale: 2, |
|
|
|
enableDepthTest: true, |
|
|
|
backFaceCulling: true |
|
|
|
}, |
|
|
|
}); |
|
|
|
|
|
|
|
tempDistributionBoxInstance.push({ distributionId: item.id, distributionBoxModel: xelectricalBoxModel }) |
|
|
|
|
|
|
|
modelInstance.push({ |
|
|
|
model: xelectricalBoxModel, |
|
|
|
type: 'shorepower_box', |
|
|
|
data: item |
|
|
|
}) |
|
|
|
|
|
|
|
const MODEL_HEIGHT_METERS = 80; |
|
|
|
const cartographic = Cesium.Cartographic.fromCartesian(xposition); |
|
|
|
const labelAltitude = cartographic.height + MODEL_HEIGHT_METERS; |
|
|
|
const labelPosition = Cesium.Cartesian3.fromRadians( |
|
|
|
cartographic.longitude, |
|
|
|
cartographic.latitude, |
|
|
|
labelAltitude |
|
|
|
); |
|
|
|
const xelectricalBoxLabel = viewer.entities.add({ |
|
|
|
// 使用 3D 空间计算出的新位置 |
|
|
|
position: labelPosition, |
|
|
|
properties: { |
|
|
|
modelType: 'shorepower_box', |
|
|
|
data: item |
|
|
|
}, |
|
|
|
name: '岸电箱 Label', |
|
|
|
label: { |
|
|
|
text: item.name ? item.name.replace(/(.*)#(.*)/g, '$1#\n$2') : '', |
|
|
|
font: '24px sans-serif', |
|
|
|
fillColor: Cesium.Color.WHITE, |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
|
|
|
|
// *** 关键设置 1:禁用深度测试,确保标签显示在模型上方 *** |
|
|
|
// 确保它不会被模型或地球遮挡。 |
|
|
|
disableDepthTest: true, |
|
|
|
|
|
|
|
// 关键设置 2:移除 pixelOffset(因为我们使用了 3D 位置偏移) |
|
|
|
// pixelOffset: new Cesium.Cartesian2(0, 0), |
|
|
|
|
|
|
|
// 关键设置 3:控制文字大小随距离缩放 (实现“真实大小”效果) |
|
|
|
// 使用 near/far scalar 控制,避免缩放地图时文字过大 |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(1000, 1.0, 50000, 0.1) |
|
|
|
// ⚠️ 请根据您的场景调整这四个参数 |
|
|
|
} |
|
|
|
}); |
|
|
|
}) |
|
|
|
console.log(distributionDataList) |
|
|
|
shorePowerList.forEach((item) => { |
|
|
|
console.log(item.id) |
|
|
|
const itemShipInfo = dataInfo.filter(mapitem => (item.id === mapitem.parentId) && mapitem.type === 5) |
|
|
|
console.log(item) |
|
|
|
const result = itemShipInfo |
|
|
|
.filter(item => { |
|
|
|
try { |
|
|
|
@ -391,29 +492,16 @@ onMounted(async () => { |
|
|
|
}, |
|
|
|
}); |
|
|
|
tempShorePowerInstance.push({ storePowerId: item.id, storePowerInstance: xelectricalBoxModel }) |
|
|
|
if (['国投-206#泊位-高压', '国投-207#泊位-高压', '国投-208#泊位-高压'].includes(item.name)) { |
|
|
|
const status = item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
arr.arr1.push({ xelectricalBoxModel, status }) |
|
|
|
} |
|
|
|
if (['国投-209#泊位-高压', '国投-210#泊位-高压'].includes(item.name)) { |
|
|
|
const status = item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
arr.arr2.push({ xelectricalBoxModel, status }) |
|
|
|
} |
|
|
|
if (['国投-203#泊位-高压', '国投-204#泊位-高压', '国投-205#泊位-高压'].includes(item.name)) { |
|
|
|
const status = item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
arr.arr3.push({ xelectricalBoxModel, status }) |
|
|
|
} |
|
|
|
if (['华电-806#泊位-高压', '华电-807#泊位-高压'].includes(item.name)) { |
|
|
|
const status = item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
arr.arr4.push({ xelectricalBoxModel, status }) |
|
|
|
} |
|
|
|
if (['华电-808#泊位-高压', '华电-809#泊位-高压', '华电-810#泊位-高压'].includes(item.name)) { |
|
|
|
const status = item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
arr.arr5.push({ xelectricalBoxModel, status }) |
|
|
|
const foundShorePower = tempDistributionBoxInstance.find(tempDistributionBoxItem => tempDistributionBoxItem.distributionId === item.equipmentId); |
|
|
|
if (foundShorePower) { |
|
|
|
distributionBoxAndShorePowerInstance.push({ |
|
|
|
...foundShorePower, |
|
|
|
storePowerInstance: xelectricalBoxModel, |
|
|
|
storePowerId: item.id, |
|
|
|
status: item.storePowerStatus == '在⽤' ? 1 : 0 |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modelInstance.push({ |
|
|
|
model: xelectricalBoxModel, |
|
|
|
type: 'shorepower_box', |
|
|
|
@ -673,24 +761,16 @@ onMounted(async () => { |
|
|
|
labelInstance, |
|
|
|
oneTitleInstance, |
|
|
|
twoTitleInstance, |
|
|
|
ShorePowerAndShipInstance |
|
|
|
ShorePowerAndShipInstance, |
|
|
|
distributionBoxAndShorePowerInstance, |
|
|
|
} |
|
|
|
} |
|
|
|
const { modelInstance, labelInstance, oneTitleInstance, twoTitleInstance, ShorePowerAndShipInstance } = createMarker() |
|
|
|
console.log('ShorePowerAndShipInstance', ShorePowerAndShipInstance) |
|
|
|
const { modelInstance, labelInstance, oneTitleInstance, twoTitleInstance, ShorePowerAndShipInstance, distributionBoxAndShorePowerInstance } = createMarker() |
|
|
|
globalModelInstance = modelInstance |
|
|
|
// const xitemShipInfo = shipData.find(shipItem => (shipItem.shorePower.id === item.parentId) && item.type === 5) |
|
|
|
const tempExe = [ |
|
|
|
{ lat: 38.948008652494806, lon: 118.46346061248573 }, |
|
|
|
{ lat: 38.94642526558039, lon: 118.46849658668688 }, |
|
|
|
{ lat: 38.95748975990655, lon: 118.46023595213505 }, |
|
|
|
{ lat: 38.98213095396909, lon: 118.46052532224263 }, |
|
|
|
{ lat: 38.98924677121887, lon: 118.46049790935167 }, |
|
|
|
] |
|
|
|
|
|
|
|
// 创建流动线材质 |
|
|
|
function createFlowMaterial(status) { |
|
|
|
console.log(status) |
|
|
|
return new PolylineFlowMaterialProperty({ |
|
|
|
color: status ? Cesium.Color.LIME : Cesium.Color.YELLOW, |
|
|
|
duration: 5000, // 动画持续时间(毫秒) |
|
|
|
@ -737,109 +817,36 @@ onMounted(async () => { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
createShipAndShorePowerLine() |
|
|
|
function tempCreate(item) { |
|
|
|
tempExe.forEach((exeItem, index) => { |
|
|
|
const wgsCoords = coordtransform.wgs84togcj02(exeItem.lon, exeItem.lat); |
|
|
|
const xposition = Cesium.Cartesian3.fromDegrees(exeItem.lon, exeItem.lat, 1); |
|
|
|
const xelectricalBoxModel = viewer.entities.add({ |
|
|
|
name: '岸电箱', |
|
|
|
position: xposition, |
|
|
|
// 添加唯一标识用于识别点击事件 |
|
|
|
properties: { |
|
|
|
modelType: 'electrical_box', |
|
|
|
// data: itemWithModel |
|
|
|
}, |
|
|
|
orientation: Cesium.Transforms.headingPitchRollQuaternion( |
|
|
|
xposition, |
|
|
|
new Cesium.HeadingPitchRoll( |
|
|
|
Cesium.Math.toRadians(150), // 航向角 (绕Z轴旋转) |
|
|
|
Cesium.Math.toRadians(0), // 俯仰角 (绕Y轴旋转) |
|
|
|
Cesium.Math.toRadians(0) // 翻滚角 (绕X轴旋转) |
|
|
|
) |
|
|
|
), |
|
|
|
model: { |
|
|
|
uri: '/model/electrical_box.glb', |
|
|
|
scale: 1.5, |
|
|
|
enableDepthTest: true, |
|
|
|
backFaceCulling: true |
|
|
|
}, |
|
|
|
}); |
|
|
|
const MODEL_HEIGHT_METERS = 80; |
|
|
|
|
|
|
|
// 1. 获取模型的世界坐标 (xposition) |
|
|
|
// xposition = Cesium.Cartesian3.fromDegrees(wgsCoords[0], wgsCoords[1], 1); |
|
|
|
|
|
|
|
// 2. 将标签的位置计算为:模型位置 + 高度偏移 |
|
|
|
// 我们需要沿着地球的法线方向(即向上)偏移。 |
|
|
|
|
|
|
|
// 获取模型位置的地理坐标 (经度, 纬度, 高度) |
|
|
|
const cartographic = Cesium.Cartographic.fromCartesian(xposition); |
|
|
|
|
|
|
|
// 增加高度,将标签放置在模型顶部上方 |
|
|
|
const labelAltitude = cartographic.height + MODEL_HEIGHT_METERS; |
|
|
|
|
|
|
|
// 将新的地理坐标转换回世界坐标作为标签的位置 |
|
|
|
const labelPosition = Cesium.Cartesian3.fromRadians( |
|
|
|
cartographic.longitude, |
|
|
|
cartographic.latitude, |
|
|
|
labelAltitude |
|
|
|
); |
|
|
|
|
|
|
|
// 添加 Label 实体 |
|
|
|
viewer.entities.add({ |
|
|
|
// 使用 3D 空间计算出的新位置 |
|
|
|
position: labelPosition, |
|
|
|
name: '配电室', |
|
|
|
label: { |
|
|
|
text: '配电室', |
|
|
|
font: '24px sans-serif', |
|
|
|
fillColor: Cesium.Color.WHITE, |
|
|
|
outlineColor: Cesium.Color.BLACK, |
|
|
|
outlineWidth: 2, |
|
|
|
style: Cesium.LabelStyle.FILL_AND_OUTLINE, |
|
|
|
|
|
|
|
// *** 关键设置 1:禁用深度测试,确保标签显示在模型上方 *** |
|
|
|
// 确保它不会被模型或地球遮挡。 |
|
|
|
disableDepthTest: true, |
|
|
|
|
|
|
|
// 关键设置 2:移除 pixelOffset(因为我们使用了 3D 位置偏移) |
|
|
|
// pixelOffset: new Cesium.Cartesian2(0, 0), |
|
|
|
function createDistributionBoxAndShorePowerLine() { |
|
|
|
distributionBoxAndShorePowerInstance.forEach((entityItem, idx) => { |
|
|
|
console.log('distributionBoxAndShorePowerInstance', entityItem) |
|
|
|
const distributionBoxEntity = entityItem.distributionBoxModel |
|
|
|
const shorePowerEntity = entityItem.storePowerInstance |
|
|
|
// const entity = entityItem.xelectricalBoxModel |
|
|
|
// 创建唯一的线实体ID |
|
|
|
const lineEntity = viewer.entities.add({ |
|
|
|
name: `connection_line_${idx}`, |
|
|
|
polyline: { |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
// 获取主岸电箱的位置 |
|
|
|
const mainPosition = distributionBoxEntity.position.getValue(viewer.clock.currentTime); |
|
|
|
// 获取目标实体的位置 |
|
|
|
const targetPosition = shorePowerEntity.position.getValue(viewer.clock.currentTime); |
|
|
|
|
|
|
|
// 关键设置 3:控制文字大小随距离缩放 (实现“真实大小”效果) |
|
|
|
// 使用 near/far scalar 控制,避免缩放地图时文字过大 |
|
|
|
scaleByDistance: new Cesium.NearFarScalar(1000, 1.0, 50000, 0.1) |
|
|
|
// ⚠️ 请根据您的场景调整这四个参数 |
|
|
|
// 返回包含两个点的数组(起点和终点) |
|
|
|
return [mainPosition, targetPosition]; |
|
|
|
}, false), |
|
|
|
width: 3, |
|
|
|
material: createFlowMaterial(0), |
|
|
|
// 启用深度测试,使线条能够被地形遮挡 |
|
|
|
enableDepthTest: true |
|
|
|
} |
|
|
|
}); |
|
|
|
// 创建连接线:将xelectricalBoxModel与arr中的每个实体连接 |
|
|
|
arr[`arr${index + 1}`].forEach((entityItem, idx) => { |
|
|
|
console.log(entityItem) |
|
|
|
const entity = entityItem.xelectricalBoxModel |
|
|
|
// 创建唯一的线实体ID |
|
|
|
const lineEntity = viewer.entities.add({ |
|
|
|
name: `connection_line_${idx}`, |
|
|
|
polyline: { |
|
|
|
positions: new Cesium.CallbackProperty(() => { |
|
|
|
// 获取主岸电箱的位置 |
|
|
|
const mainPosition = xelectricalBoxModel.position.getValue(viewer.clock.currentTime); |
|
|
|
// 获取目标实体的位置 |
|
|
|
const targetPosition = entity.position.getValue(viewer.clock.currentTime); |
|
|
|
|
|
|
|
// 返回包含两个点的数组(起点和终点) |
|
|
|
return [mainPosition, targetPosition]; |
|
|
|
}, false), |
|
|
|
width: 3, |
|
|
|
material: createFlowMaterial(0), |
|
|
|
// 启用深度测试,使线条能够被地形遮挡 |
|
|
|
enableDepthTest: true |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
}) |
|
|
|
}); |
|
|
|
} |
|
|
|
tempCreate() |
|
|
|
|
|
|
|
createShipAndShorePowerLine() |
|
|
|
createDistributionBoxAndShorePowerLine() |
|
|
|
|
|
|
|
// 设置初始视角 |
|
|
|
viewer.camera.flyTo(createView(presetViews.overview)); |
|
|
|
@ -883,7 +890,8 @@ onMounted(async () => { |
|
|
|
const cartographic = Cesium.Cartographic.fromCartesian(cartesian); |
|
|
|
const longitude = Cesium.Math.toDegrees(cartographic.longitude); |
|
|
|
const latitude = Cesium.Math.toDegrees(cartographic.latitude); |
|
|
|
console.log(`当前点击位置的经纬度: 经度 ${longitude}°, 纬度 ${latitude}°`); |
|
|
|
const gcj02 = coordtransform.wgs84togcj02(longitude, latitude); |
|
|
|
console.log(`当前点击位置的经纬度: 经度 ${gcj02[0]}°, 纬度 ${gcj02[1]}°`); |
|
|
|
} |
|
|
|
|
|
|
|
if (Cesium.defined(pickedObject)) { |
|
|
|
@ -894,7 +902,7 @@ onMounted(async () => { |
|
|
|
const type = entity.properties.modelType.getValue(); |
|
|
|
|
|
|
|
console.log(`点击了一个实体。类型是: ${type}`); |
|
|
|
if (type === 'shorepower_box' || type === 'ship') { |
|
|
|
if (type === 'shorepower_box' || type === 'ship' || type === 'distribution_box') { |
|
|
|
console.log(entity.properties.data.getValue()) |
|
|
|
// onElectricalBoxClick(entity.properties.data.getValue()) |
|
|
|
// 触发自定义点击事件 |
|
|
|
|