Vue3+cesium添加自定义弹窗并设置随地图移动位置移动

        需求:点击三维地图上的标注展示弹窗,随着地图移动弹窗也需要移动,缩小地图比例要隐藏,反之显示。

        效果图如下:

 话不多说,直接上代码:

父组件:

<template>
  <div id="cesiumContainer" />
  <div id="popup">
    <OverlayChart
      v-if="cesiumGather.popVisible"
      :overlay-chart-obj="cesiumGather.overlayChartObj"
    />
  </div>
</template>

<script setup>
import * as Cesium from "cesium";
import { reactive, onMounted } from "vue";
import OverlayChart from "../../components/overlayChart.vue";

const cesiumGather = reactive({
  popVisible: false,
  overlayChartObj: {},
  cesiumViewer: null,
});

onMounted(() => {
  cesiumGather.cesiumViewer = mapCreate();
  mapCesiumData();
});
// 初始化地图
const mapCreate = () => {
  // 添加图层
  const viewer = new Cesium.Viewer("cesiumContainer", {
    geocoder: false, //搜索框
    homeButton: false, //home键
    animation: false, //动画控件
    fullscreenButton: false, //全屏按钮
    sceneModePicker: false, //场景模式选择器
    timeline: false, //时间轴
    navigationHelpButton: false, //导航提示
    baseLayerPicker: false, //地图选择器
    infoBox: false, //是否显示信息框
    scene3DOnly: false, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
    selectionIndicator: false, //是否显示选取指示器组件
    baselLayerPicker: false, // 将图层选择的控件关掉,才能添加其他影像数据
  });
  viewer._cesiumWidget._creditContainer.style.display = "none";
  return viewer;
};

// 获取聚合数据
const mapCesiumData = () => {
  let queryData = [
    { lng: 104.023442, lat: 23.44321, name: "标点一" },
    { lng: 134.023442, lat: 27.44321, name: "标点二" },
    { lng: 105.023442, lat: 32.44321, name: "标点三" },
    { lng: 104.023442, lat: 23.44221, name: "标点四" },
    { lng: 105.023442, lat: 13.44321, name: "标点五" },
    { lng: 114.023442, lat: 33.44321, name: "标点六" },
    { lng: 124.023442, lat: 43.42321, name: "标点七" },
    { lng: 134.023442, lat: 33.42321, name: "标点八" },
    { lng: 144.023442, lat: 53.14321, name: "标点九" },
    { lng: 101.023442, lat: 23.44321, name: "标点十" },
  ];
  //  加载点位
  renderCesiumPoint(cesiumGather.cesiumViewer, queryData);

  // 添加点击事件
  handlePinClick();
};

// 加载点位
const renderCesiumPoint = (cesiumViewer, projectList) => {
  cesiumViewer.entities.removeAll();
  for (let i = 0; i < projectList.length; i++) {
    const pro = projectList[i];
    cesiumViewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(pro.lng, pro.lat, 1000),
      name: pro.name,
      property: pro, //自己加的相关属性,弹窗里需要用到
      billboard: {
        //图标
        image: "./static/images/markers/4.png",
        scale: 1, //图标比例
        width: 36,
        height: 36,
        // 垂直方向
        verticalOrigin: Cesium.VerticalOrigin.BASELINE,
        //水平方向
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
      label: {
        // 文字标签
        text: pro.name,
        scale: 1,
        font: "16px monospace",
        fillColor: Cesium.Color.WHITE,
        showBackground: true, //设置背景颜色
        pixelOffset: new Cesium.Cartesian2(0, -44), //设置左右、上下移动
        // 垂直方向
        verticalOrigin: Cesium.VerticalOrigin.BASELINE,
        //水平方向
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
    });
  }
};

// 点击地图上的点
const handlePinClick = () => {
  const cesiumViewer = cesiumGather.cesiumViewer;
  const handle3D = new Cesium.ScreenSpaceEventHandler(
    cesiumViewer.scene.canvas
  );
  handle3D.setInputAction((movement) => {
    const pick = cesiumViewer.scene.pick(movement.position);
    console.log(pick);
    if (!pick) {
      cesiumGather.popVisible = false;
      // 清除监听事件
      cesiumViewer.scene.postRender.removeEventListener(infoWindowPostRender);
      return;
    }
    const obj = pick.id.property;
    const coordinate = movement.position;
    // 解决点击不同点数据不更换问题
    if (cesiumGather.overlayChartObj != {}) {
      cesiumGather.popVisible = false;
      cesiumGather.overlayChartObj = {};
    }
    /*overlayChartObj是传给子组件(弹窗)的数据*/
    cesiumGather.overlayChartObj = obj;
    showOverlayChart(coordinate);
    // 添加地图移动监听:使地图移动弹窗跟着移动
    cesiumViewer.scene.postRender.addEventListener(infoWindowPostRender);
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};

//显示图表
const showOverlayChart = (position) => {
  const pop = document.getElementById("popup");
  pop.style.position = "absolute";
  pop.style.top = position.y - 100 + "px";
  pop.style.left = position.x - 120 + "px";
  pop.style.zIndex = 99;
  cesiumGather.popVisible = true;
};
// 地图移动时弹窗跟随
const infoWindowPostRender = () => {
  const cesiumViewer = cesiumGather.cesiumViewer;
  //经纬度转为世界坐标
  const gisPosition = Cesium.Cartesian3.fromDegrees(
    Number(cesiumGather.overlayChartObj.lng),
    Number(cesiumGather.overlayChartObj.lat),
    2500
  );
  //转化为屏幕坐标
  var windowPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
    cesiumViewer.scene,
    gisPosition
  );
  //解决滚动不隐藏问题
  const camerPosition = cesiumViewer.camera.position;
  let height =
    cesiumViewer.scene.globe.ellipsoid.cartesianToCartographic(
      camerPosition
    ).height;
  height += cesiumViewer.scene.globe.ellipsoid.maximumRadius;

  if (
    !(Cesium.Cartesian3.distance(camerPosition, gisPosition) > height) &&
    cesiumViewer.camera.positionCartographic.height < 50000000
  ) {
    cesiumGather.popVisible = true;
  } else {
    cesiumGather.popVisible = false;
  }
  if (Cesium.defined(windowPosition)) {
    setPopPosition(windowPosition);
  }
};
const setPopPosition = (position) => {
  const pop = document.getElementById("popup");
  pop.style.top = position.y - 100 + "px";
  pop.style.left = position.x - 120 + "px";
};
</script>

<style scoped></style>

子组件:

<template>
  <div class="cesium-popup">
    <span>姓名:{{ overlayChartObj.name }}</span><br/>
    <span>坐标:X:{{ overlayChartObj.lat }},Y:{{ overlayChartObj.lng }}</span>
  </div>
</template>
<script setup>
// props父传子
const props = defineProps({
  overlayChartObj: {
    type: Object,
    default: function () {
      return {};
    },
  },
});
</script>
<style lang="scss" scoped>
.cesium-popup{
  width: 240px;
  height: 50px;
  background-color: #3df;
  span{
    font-size: 14px;
  }
}
</style>

 这里的弹窗样式笔者随便弄了一下,你们可以自行发挥,有哪块不懂的随时联系笔者。

借鉴文章:cesium自定义弹窗

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值