Cesium.js实现显示点位对应的自定义信息弹窗(数据面板)

零、相关技术选型:

Vue2 Vuecli5 Cesium.js 天地图

一、需求说明

在使用2D地图(天地图、高德地图等)基于官方文档可以实现下面需求:

实现添加点位,并在点位附近显示对应的信息弹窗。

一般信息弹窗的显示方式有两种:

第一种:鼠标点击图标显示信息弹窗,点击其他地方隐藏信息弹窗;

第二种:鼠标移入图标显示信息弹窗,鼠标移出图标隐藏信息弹窗;

**本次实现:**现在需要在利用Cesium.js来实现三维地图中,点位的信息弹窗的展示。

二、基础建设

1、信息弹窗的结构

CommonPanel.vue

javascript 复制代码
<template>
  <div class="videoMonitorWin" v-if="visible" :style="styleObject">
    <div class="info-title">
      <div class="info-title-txt">信息面板</div>
    </div>
    <div class="info-content">
      <div class="info-item">
        <span class="info-item-title">设备名称</span>
        <span class="info-item-data">测试设备01</span>
      </div>
      <div class="info-item">
        <span class="info-item-title">设备编号</span>
        <span class="info-item-data">#R1782</span>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    visible: Boolean,
    data: Object,
    position: { type: Object, default: () => ({ x: 0, y: 0 }) }
  },
  computed: {
    styleObject() {
      return {
        position: "absolute",
        left: `${this.position.x}px`,
        top: `${this.position.y}px`
      };
    }
  },
};
</script>

其中组件props传值:

visible用来实现信息弹窗的显示与隐藏;

data用来传递展示数据;

position用来实现信息弹窗随点位图标的位置而变化。

2、父组件(Cesium viewer展示)

javascript 复制代码
<template>
  <div id="cesiumContainer">
    <CommomPanel ref="commomPanel" :visible="popupVisible" :position="popupPosition" />
  </div>
</template>
<script>
// ...导入组件等...
export default {
  data() {
    return {
      popupVisible: false, // 弹窗的显示与隐藏
      popupData: null, // 弹窗数据
      popupPosition: { x: 0, y: 0 }, // 弹窗显示位置
      selectedEntity: null, // 选中的实体
    };
  },
  mounted() {
    this.viewer = new Cesium.Viewer("cesiumContainer");
    // ...初始化 Cesium Viewer 和添加点位...
    this.addLayer(); // 添加图层
  },
  methods: {
      addLayer(){  }, // 添加图层
      updatePopupPosition(){  }, // 更新弹窗的位置
  }
};
</script>    

三、需求实现

你需要实现的顺序是:

  1. 先实现对点位的操作是否可以将信息弹窗显示出来;
  2. 确保没问题都再实现信息弹窗跟随图标移动的问题;

1、需求一:鼠标点击图标,显示弹窗

在点击实体时的判断:

Cesium.defined(pickedEntity) 判断实体是否为空;

this.selectedEntity === point 判断实体对应的是否为点位;

注意:pickedEntity?.id 才是你对应的图标实体。

javascript 复制代码
addLayer() {
  const point = this.viewer.entities.add( /* 点位参数 */ );
  // 鼠标点击事件
  this.viewer.screenSpaceEventHandler.setInputAction(click => {
    let pickedEntity = this.viewer.scene.pick(click.position);
    this.selectedEntity = pickedEntity?.id;
    // 判断点击物体是否为图标实体
    if (Cesium.defined(pickedEntity) && this.selectedEntity === point) {
      this.updatePopupPosition(); // 更新弹窗的位置
      this.popupVisible = true; // 显示弹窗
      this.popupData = {
        /* 提取并设置数据 */
      };
    } else {
      this.popupVisible = false; // 隐藏弹窗
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

  // 监听鼠标移动事件来更新弹窗位置
  this.viewer.screenSpaceEventHandler.setInputAction(movement => {
    if (this.popupVisible && this.selectedEntity) {
      this.updatePopupPosition(); // 更新弹窗的位置
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
},

2、需求二:鼠标移入,弹窗显示;鼠标移出,弹窗隐藏

javascript 复制代码
// 添加图层
addLayer() {
  const point = this.viewer.entities.add( /* 点位参数 */ );
  // 鼠标移动
  this.viewer.screenSpaceEventHandler.setInputAction(movement => {
    const pickedEntity = this.viewer.scene.pick(movement.endPosition);
    this.selectedEntity = pickedEntity?.id;
    // 判断移入物体是否为图标实体
    if (Cesium.defined(pickedEntity) && this.selectedEntity === point) {
      // 鼠标移入图标
      this.updatePopupPosition(); // 更新弹窗的位置
      this.popupVisible = true;
    } else {
      // 鼠标移出图标
      this.popupVisible = false;
      this.selectedEntity = null;
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
},

四、信息弹窗跟随图标移动

实现该功能,需要将Cesium世界坐标转为屏幕坐标,进而更新弹窗的位置。

首先,获取当前选择的实体(例如点位或图标)在 Cesium 世界坐标系中的位置;

然后,将 3D 世界中的点位转换为 2D 屏幕上的像素位置;

最后,将弹窗的位置设置为计算出的屏幕坐标。

`Cesium.SceneTransforms.wgs84ToWindowCoordinates` 方法负责3D点位转换2D屏幕像素。

javascript 复制代码
// 更新弹窗的位置
updatePopupPosition() {
  // 计算弹窗位置
  // 这里获取当前选择的实体(例如点位或图标)在 Cesium 世界坐标系中的位置。
  // `this.selectedEntity.position.getValue` 方法根据当前时间返回实体的位置。
  const cesiumPosition = this.selectedEntity.position.getValue(
    this.viewer.clock.currentTime
  );

  // 将 Cesium 世界坐标转换为屏幕坐标。
  // 这一步是将 3D 世界中的点位转换为 2D 屏幕上的像素位置。
  const canvasPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
    this.viewer.scene,
    cesiumPosition
  );

  // 检查转换是否成功。有时候,如果点位不在当前视图中,则转换可能失败。
  if (canvasPosition) {
    // 更新弹窗位置
    this.popupPosition = {
      x: canvasPosition.x + 20,
      y: canvasPosition.y - 60 // 假设弹窗应该在图标上方 50px 的位置
    };
  }
}

到此结束......

相关推荐
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
CodeClimb5 小时前
【华为OD-E卷 - 第k个排列 100分(python、java、c++、js、c)】
java·javascript·c++·python·华为od
沈梦研5 小时前
【Vscode】Vscode不能执行vue脚本的原因及解决方法
ide·vue.js·vscode
hunter2062065 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb5 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角5 小时前
CSS 颜色
前端·css
轻口味6 小时前
Vue.js 组件之间的通信模式
vue.js
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5
lee5767 小时前
npm run dev 时直接打开Chrome浏览器
前端·chrome·npm
2401_897579657 小时前
AI赋能Flutter开发:ScriptEcho助你高效构建跨端应用
前端·人工智能·flutter