cesium实现自定义弹窗
弹窗内容渲染类
/**
* @descripion: 弹窗渲染类
*/
import Vue from "vue";
export default class Bubble {
/**
*
* @param viewer 场景
* @param position 弹窗位置
* @param propsData 弹窗内部的属性数据值 {k:v}
* @param bubbleType 弹窗类型 vue组件
* @param offsetHeight 底部偏移高度,弹窗底部偏移高度需要设置一个合适的值,否则很容易导致场景拖动的时候,弹窗存在偏移
*/
constructor(viewer, position, bubbleType, propsData, offsetHeight) {
this.viewer = viewer;
this.offsetHeight = offsetHeight;
this.position = position;
// 判断弹窗内容是否是vue组件文件
if (!bubbleType || !bubbleType['beforeCreate'] || !bubbleType['render']) {
throw new Error('弹窗类型不正确!')
}
let WindowVm = Vue.extend(bubbleType);
// 根据模板创建一个面板
this.vmInstance = new WindowVm({
propsData: propsData
}).$mount();
this.vmInstance.closeEvent = e => {
this.close();
}
// 将字符串模板生成的内容添加到DOM上
this.viewer.cesiumWidget.container.appendChild(this.vmInstance.$el);
this.addPostRender();
}
//添加场景事件
addPostRender() {
this.viewer.scene.postRender.addEventListener(this.postRender, this);
}
//场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
postRender() {
if (!this.vmInstance.$el || !this.vmInstance.$el.style) return;
const viewerContainerHeight = this.viewer.cesiumWidget.container.offsetHeight;
const windowPosition = new Cesium.Cartesian2();
Cesium.SceneTransforms.wgs84ToWindowCoordinates(
this.viewer.scene,
this.position,
windowPosition
);
let elHeight = this.vmInstance.$el.offsetHeight;
//elHeight 值需要设置一个合适的,否则很容易导致场景拖动的时候,弹窗存在偏移
if (!!this.offsetHeight) {
elHeight += this.offsetHeight;
}
//console.log(windowPosition,canvasHeight,this.vmInstance.$el.offsetHeight,elHeight, windowPosition.y - elHeight + "px")
this.vmInstance.$el.style.top = windowPosition.y - elHeight + "px";
const elWidth = this.vmInstance.$el.offsetWidth;
this.vmInstance.$el.style.left = windowPosition.x - elWidth / 2 + "px";
const cameraPosition = this.viewer.camera.position;
let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cameraPosition).height;
height += this.viewer.scene.globe.ellipsoid.maximumRadius;
if ((!(Cesium.Cartesian3.distance(cameraPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
this.vmInstance.$el.style.display = "block";
} else {
this.vmInstance.$el.style.display = "none";
}
}
//关闭
close() {
if (this.vmInstance) {
this.vmInstance.$el.remove();
this.vmInstance.$destroy();
}
//this.vmInstance.$el.style.display = "none"; //删除dom
this.viewer.scene.postRender.removeEventListener(this.postRender, this); //移除事件监听
}
}
弹窗内容定义
// 弹窗内容
import BubbleDynamicLabel from "./BubbleDynamicLabel.vue";
import BubbleWaterDetail from "./BubbleWaterDetail"
const BubbleType = {
BubbleDynamicLabel,
BubbleWaterDetail,
}
export default BubbleType
弹窗调用
data() {
return {
position: {
x: 102.74053944923936,
y: 30.984019652124275,
z: 500
}
}
},
methods: {
initDat() {
let that = this;
if (Viewer.terrainProvider) {
//设置了地形让其高度在地形之上
let positions = [
Cesium.Cartographic.fromDegrees(this.position.x, this.position.y),
];
let promise = Cesium.sampleTerrainMostDetailed(Viewer.terrainProvider, positions);
Cesium.when(promise, function (updatedPositions) {
let terrainHeight = updatedPositions[0].height
that.position.z = terrainHeight + 20;
//初始化弹窗
that.initPopup();
that.initPoint()
})
} else {
setTimeout(() => {
that.initPopup();
that.initPoint()
}, 1000)
}
},
initPopup() {
let position = Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z)
const propsData = {
properties: {labelName: '测试地址点位'}
}
let bubbleInstance = new Bubble(Viewer, position, BubbleType.BubbleDynamicLabel, propsData, 260)
if (bubbleInstance) {
//关闭弹窗
// bubbleInstance.close()
}
},
initPoint() {
//用于调试弹窗是否对得上位置,弹窗对上了该点,不然很容易出现弹窗偏移的问题
const pointPrimitives = Viewer.scene.primitives.add(
new Cesium.PointPrimitiveCollection()
);
pointPrimitives.add({
color: Cesium.Color.YELLOW,
position: Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z),
});
const labels = Viewer.scene.primitives.add(new Cesium.LabelCollection());
labels.add({
position: Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z),
text: "Philadelphia",
});
}
}
效果
问题:
有些情况会出现弹窗跟随场景拖动在移动,这种情况是由于弹窗的偏移高度不对的问题导致的,这个时候可以在场景上加载出对应弹窗应该在的位置点来对照进行偏移的值的调整设置即可,例如上图中的黄色点。
参考文章:
cesium自定义的弹窗 Popup弹窗