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 的位置
    };
  }
}

到此结束......

相关推荐
卸任6 小时前
Vibe coding工具使用心得
前端·ai编程
brien96 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance7 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M7 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写7 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李7 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易7 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding7 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马7 小时前
前沿视界
前端
kyriewen7 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员