专栏名称: 小猿猴GISer
GIS遥感交流学习
目录
相关文章推荐
格上财富  ·  广东成立新机构,信号强烈 ·  2 天前  
简七读财  ·  过去100年,这类资产更赚钱 ·  2 天前  
曾星智中线投资  ·  只赚不亏:长线投资成功的关键 ·  2 天前  
曾星智中线投资  ·  只赚不亏:长线投资成功的关键 ·  2 天前  
格上财富  ·  英特尔,偶像的黄昏 ·  4 天前  
格上财富  ·  一个人最大的不靠谱,是沟通没有形成闭环 ·  3 天前  
51好读  ›  专栏  ›  小猿猴GISer

使用 Cesium 实现属性弹窗的功能

小猿猴GISer  · 公众号  ·  · 2024-11-17 19:09

正文

1. 实现效果

实现的弹窗效果如下:点击 Entity 弹窗展示相关信息,点击空白处或者点击关闭按钮即可关闭弹窗。

2. 封装一个弹窗组件

这里我们直接将代码贴出来,样式省略:这里实现的关键要点如下:

  1. 首先,需要监听鼠标点击的位置变化,因此需要监听 position 属性;
  2. 其次,需要给 Scene preRender 添加一个监听器,以便在渲染场景(Scene)之前改变弹窗的位置,有关 preRender 请看下图,翻译一下就是:获取在 更新场景之后 渲染场景之前 将引发的事件。事件的订阅者接收 Scene 实例 作为第一个参数,将 当前时间 作为第二个参数。

  1. 我们在关闭弹窗后则需要解除上述监听器,具体请看 setPopupUndefined()
  2. 我们通过鼠标点击获取的是笛卡尔坐标,需要将其转换为屏幕坐标,借助 SceneTransforms.worldToWindowCoordinates() 方法即可实现。
<template>
  <div class="cs-popup" ref="popupDivRef" v-show="show">
    <div class="cs-popup-header">
      <div class="cs-popup-title">
        {{ title }}
      div>
      <div class="cs-popup-close">
        <i-ep-Close @click="close" />
      div>
    div>
    <div class="cs-popup-content">
      <slot>slot>
    div>
  div>
template>

<script setup>
import { SceneTransforms, defined } from "cesium";

import useCSViewerStore from "@/stores/csViewer.js";

const csViewerStore = useCSViewerStore();

let popupDivRef = ref();
const show = ref(false);

const props = defineProps({
  title: {
    typeString,
    default"标题",
  },
  position: {
    typeObject,
    default() => {},
  },
  yOffset: {
    typeNumber,
    default10,
  },
});

const emits = defineEmits(["close"]);

watch(
  () => props.position,
  (val) => {
    setPosition(val);
  },
  { deeptrue }
);

onBeforeUnmount(() => {
  setPopupUndefined();
});

function setPosition(val{
  if (Object.keys(val).length) {
    setPopupPositon();
  } else {
    setPopupUndefined();
  }
}

function setPopupPositon({
  csViewerStore.viewer.scene.preRender.addEventListener(setPositionListener);
}

function setPositionListener({
  const canvasPosition = getCanvasPos(props.position);
  if (defined(canvasPosition)) {
    if (!show.value) show.value = true;
    setPopupDiv(canvasPosition.x, canvasPosition.y - props.yOffset);
  }
}

function getCanvasPos(cartesian3Pos{
  return Object.keys(cartesian3Pos).length > 0
    ? SceneTransforms.worldToWindowCoordinates(
        csViewerStore.viewer.scene,
        cartesian3Pos
      )
    : undefined;
}

function setPopupUndefined({
  if (show.value) show.value = false;
  csViewerStore.viewer.scene.preRender.removeEventListener(setPositionListener);
}

function setPopupDiv(left, top{
  popupDivRef.value.style.left = left + "px";
  popupDivRef.value.style.top = top + "px";
}

function close({
  emits("close");
}
script>

3. 使用弹窗

本文使用天地图作为底图,这里针对添加天地图的方法不再赘述,感兴趣的自己看代码或看往期文章 Cesium 加载天地图 即可。

  1. 首先,我们在地图组件中添加一个 ScreenSpaceEventType.LEFT_CLICK 事件,然后在父组件中可以具体书写要实现的功能,这里只做一个触发( emits )。

代码如下:

function initEvt({
  viewerRef.value.screenSpaceEventHandler.setInputAction((e) => {
    emits("leftClick", e);
  }, ScreenSpaceEventType.LEFT_CLICK);
}
  1. 而在父组件我们需要添加一个 Entity ,代码如下:
function addEntities({
  const lngLat = [113.55369688330934.8244199026567];
  cvs.viewer.entities.add({
    name"我是一个红色的长方体",
    position: Cartesian3.fromDegrees(...lngLat),
    box: {
      dimensionsnew Cartesian3(100.0100.01000.0),
      material: Color.RED,
    },
    properties: {
      lngLat,
    },
  });
  cvs.viewer.zoomTo(cvs.viewer.entities);
}
  1. 引入 Popup 组件:由于我们在 vite.config.js 中已经配置 components 目录自动引入,这里我们直接使用即可。







请到「今天看啥」查看全文