cesium鼠标拾取展示信息弹窗

cesium如何展示信息弹窗,效果如下:

一、创建div

首先在html中定义一个div元素,用于存储这个信息弹窗

js 复制代码
<!-- 地图弹框 -->
<div class="dynamic-layer" id="one">
  <div v-html="popData"></div>
</div>
//css
.dynamic-layer {
  display: none;
  user-select: none;
  pointer-events: none;
  position: fixed;
  line-height: 30px;
  border-radius: 20px;
  top: 0;
  left: 0;
  width: 382px;
  z-index: 99990;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  opacity: 0;
  transition: opacity 1s ease-in-out;
}

二、监听鼠标点击事件

Cesium 提供了丰富的鼠标事件处理功能,可以响应用户在地球表面的交互操作。通过new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)定义一个鼠标事件,然后通过handler.setInputAction(()=>{},Cesium.ScreenSpaceEventType.LEFT_CLICK)监听鼠标点击动作,将屏幕坐标转成当前点的经纬度。然后根据拾取的位置是否存在id判断是否有实体。

1. 常用鼠标事件类型

事件类型 描述
LEFT_CLICK 左键单击
LEFT_DOUBLE_CLICK 左键双击
LEFT_DOWN 左键按下
LEFT_UP 左键释放
MIDDLE_CLICK 中键单击
MIDDLE_DOWN 中键按下
MIDDLE_UP 中键释放
RIGHT_CLICK 右键单击
RIGHT_DOWN 右键按下
RIGHT_UP 右键释放
MOUSE_MOVE 鼠标移动
WHEEL 鼠标滚轮滚动
js 复制代码
//鼠标事件
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  handler.setInputAction((click) => {
    console.log("单击事件:", click.position);
    const cartesian = viewer.camera.pickEllipsoid(
      click.position,
      viewer.scene.globe.ellipsoid
    );
    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(5);
    const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(5);
    const pick = viewer.scene.pick(click.position);

    console.log("单击事件:", lon, lat);
    if (pick && pick.id && pick.id._name && pick.id._monitoItems) {
      const data = {
        id: pick.id._id,
        lon: lon,
        lat: lat,
        offset: [100, 0],
        boxHeightMax: 0, // 中间立方体的最大高度
      };
      let tableName = pick.id._name;
      let detail = pick.id._monitoItems;

      document.getElementById("one").style.zIndex = 9990;

      popData.value = createDescription(detail, tableName);

      const div = document.getElementById("one");

      showDynamicLayer(viewer, data, div);
    } else {
      if (document.getElementById("one")) {
        document.getElementById("one").style.zIndex = -1;
        document.getElementById("one").style.opacity = 0;
      }
    }

   
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  
 
// 移除特定事件
handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);

// 销毁整个处理器
handler.destroy();
  

三、展示信息弹窗

将经纬度再次转为坐标轴赋值给div的浮动样式,然后展示信息弹窗。其中用的viewer.scene.preRender,用来监听每次重新渲染时div的位置。 viewer.scene.preRender是 Cesium 中一个非常有用的帧渲染前事件,它允许你在每一帧渲染之前执行自定义逻辑。

Cesium 还提供了其他几个重要的渲染事件:

  1. postRender - 在帧渲染完成后触发
  2. postUpdate - 在场景更新后,渲染前触发
  3. preUpdate - 在场景更新前触发
  4. preRender - 在帧渲染前触发

注意事项

  1. 性能考虑preRender 每帧都会执行,其中的代码应该尽可能高效,避免复杂计算
  2. 避免无限循环:在事件处理函数中不要触发会导致重新渲染的操作
  3. 内存管理:不再需要的事件监听器应该及时移除
  4. 执行顺序 :了解不同事件的触发顺序很重要:
    • preUpdate
    • postUpdate
    • preRender
    • postRender
  5. 与requestAnimationFrame的区别
    • preRender 与 Cesium 的渲染管线集成
    • 通常比直接使用 requestAnimationFrame 更可靠
js 复制代码
const showDynamicLayer = (viewer, data, div) => {
  const lon = data.lon * 1,
        lat = data.lat * 1;
  let position = Cesium.Cartesian3.fromDegrees(lon, lat, data.boxHeightMax);
  const scene = viewer.scene,
  camera = viewer.camera;
  let arr = data.offset
  let scratch = new Cesium.Cartesian2(); // cesium二维笛卡尔 
  
  div.style.opacity = 1;
   
  scene.preRender.addEventListener(() => {
    const canvasPosition = scene.cartesianToCanvasCoordinates(
      position,
      scratch
    );
    if (Cesium.defined(canvasPosition)) {
      element.style.left = canvasPosition.x + arr[0] + "px";
      element.style.top = canvasPosition.y + arr[1] + "px";
      
        var e = position,
          i = camera.position,
          n = scene.globe.ellipsoid.cartesianToCartographic(i).height;
          
        if (
          !((n += 1 * scene.globe.ellipsoid.maximumRadius),
          Cesium.Cartesian3.distance(i, e) > n)
        ) {
          element.style.display = "block";
        } else {
          element.style.display = "none";
        }
     
    }
  });
  
};

遍历detail的对象,生成信息表格

js 复制代码
function createDescription(properties, tableName) {
  let html = '<table class="cesium-infoBox-defaultTable">';
  html += `<tr class="cesium-infoBox-tableName"><th colspan="2">${tableName}</th></tr>`;

  Object.keys(properties).forEach((key) => {
    html += `
            <tr>
                <th>${key}:</th>
                <td>${properties[key]}</td>
            </tr>
        `;
  });

  html += "</table>";
  return html;
}
相关推荐
SunTecTec20 分钟前
IDEA 类上方注释 签名
服务器·前端·intellij-idea
在逃的吗喽1 小时前
黑马头条项目详解
前端·javascript·ajax
袁煦丞1 小时前
有Nextcloud家庭共享不求人:cpolar内网穿透实验室第471个成功挑战
前端·程序员·远程工作
小磊哥er1 小时前
【前端工程化】前端项目开发过程中如何做好通知管理?
前端
拾光拾趣录2 小时前
一次“秒开”变成“转菊花”的线上事故
前端
你我约定有三2 小时前
前端笔记:同源策略、跨域问题
前端·笔记
JHCan3332 小时前
一个没有手动加分号引发的bug
前端·javascript·bug
pe7er2 小时前
懒人的代码片段
前端
没有bug.的程序员2 小时前
《 Spring Boot启动流程图解:自动配置的真相》
前端·spring boot·自动配置·流程图
拾光拾趣录2 小时前
一次诡异的登录失效
前端·浏览器