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

1 篇文章 0 订阅

项目场景:

需求:项目中使用Cesium制作三维地图,在地图上铺点,对点位进行点击,弹出自定义弹窗(form+charts),且弹窗随地图一起动,思路及代码如下:


思路:

  1. 地图初始化时隐藏cesium自带的弹窗;
  2. 写一个弹窗的vue文件(子),在地图vue文件(父)中引入,通过v-if控制参数popVisiblefalse默认隐藏,并用一个div(弹窗父元素)包起来;
  3. 地图初始化铺点后给点添加点击事件,获取该点的相关属性(也可再调用接口获取更多弹窗需要数据),并获取点击坐标(如代码中的handlePinClick方法);
  4. 弹窗所需数据获取完成之后,找到弹窗父元素,设置其样式:绝对定位,topleft为点击事件获取到的屏幕坐标,同时设置弹窗子组件展示(popVisible=true);

==================这个时候点击地图的点设置自定义弹窗功能就完成了,但是发现地图移动的时候,地图上的点移动了,弹窗没有移动。接下来解决:

  1. 在添加点击事件的时候同时添加一个地图监听(如代码中的bindMapMove方法),监听地图移动之后对应点击的点的地图坐标,转换成新的屏幕坐标,再重新给弹窗vue组件设置定位即可。

代码(详解看代码注释):

html代码:

 <div
      id="cesiumContainer"
      class="boxs"
    />
    <div id="popup">
    <!-- 
    OverlayChart 是引入的弹窗组件,样式自己随便写,也可自己重新命名;
    overlayChartObj是传给弹窗的参数,自行进行引入和注册使用,代码中没有涉及到这一块
    -->
      <OverlayChart
        v-if="popVisible"
        ref="overlay"
        :overlay-chart-obj="overlayChartObj"
      />
    </div>

mounted代码:

  this.cesiumViewer = this.mapCreate();
  this.queryData();
  this.gotoCenter();

methods代码:

 // 底图初始化
    mapCreate() {
      var viewer = new Cesium.Viewer("cesiumContainer", {
        infoBox: false//隐藏cesium自带的弹窗
      });
      return viewer;
    },
    // 回中心点
    gotoCenter() {
      const height = 1100000;
      const viewer=this.cesiumViewer
      viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(gisServer.center[0], gisServer.center[1], height),
        orientation: {
          // heading: Cesium.Math.toRadians(0),
          // pitch: Cesium.Math.toRadians(-45)
        },
        duration: 5
      });
    },
// 获取聚合图层数据
    async queryData() {
      const emstTypeSub = this.emstTypeSub;
      const result = await getEmstWqListByEmstTypeSub({
        params: {
          emstTypeSub
        }
      });
      this.loading = false;
      //加载点位
      this.renderCesiumPoint(this.cesiumViewer, result.data.data);
      //添加点击事件
      this.handlePinClick();
      //添加地图移动监听:使地图移动弹窗跟着移动
      this.bindMapMove();
    },
	// 加载点位
    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.emstLong, pro.emstLat, 1000),
          name: pro.emstName,
          id: pro.emstCode,
          property: pro,//自己加的相关属性,弹窗里需要用到
          billboard: {
            scale: 1,
            image: "这里是图片地址",
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM
          },
          label: { // 文字标签
            text: pro.emstName,
            font: "400 30px MicroSoft YaHei", // 15pt monospace
            scale: 0.6,
            fillColor: "#e4393c",
            show: false,
            outlineWidth: 3,
            outlineColor: "#000",
            pixelOffset: Cesium.Cartesian2(0, -60) // 偏移量
          }
        });
      }
    },
	// 点击地图上的点
    handlePinClick() {
      const cesiumViewer = this.cesiumViewer
      const tt = this;
      const handle3D = new Cesium.ScreenSpaceEventHandler(cesiumViewer.scene.canvas);
      handle3D.setInputAction((movement) => {
      //movement.position 是点击的屏幕坐标
        const pick = cesiumViewer.scene.pick(movement.position);
        if (!pick) {
          return
        }
        const obj = pick.id.property;
        // 解决点击不同点数据不更换问题
        if (tt.overlayChartObj.popForm != {}) {
          tt.popVisible = false;
          tt.overlayChartObj.popForm = {}
        }
  
        const coordinate = movement.position;
        /*overlayChartObj是传给子组件(弹窗)的数据:
        {
        popForm:点渲染的时候就有的数据,
        chartData:点击调用接口获取的数据
        }
        */
        tt.overlayChartObj.popForm = obj;
        tt.getProjDetailPop(coordinate, obj);
        
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
     
    },
    // 点击地图图标展示
    async getProjDetailPop(coordinate, params) {
      const tt = this;
      const result = await getWqgStateLast7Day({
        params: {
          emstCode: params.emstCode
        }
      });
      tt.showOverlayChart(coordinate, result.data.data);
    },
    // 显示图表
    showOverlayChart (position, data) {
      const pop = document.getElementById("popup");
      pop.style.position = "absolute";
      pop.style.top = position.y + "px";
      pop.style.left = position.x + "px";
      pop.style.zIndex = 99;
      this.overlayChartObj.chartData = data;
      this.popVisible = true;
    },
      // 地图移动时弹窗跟随
    bindMapMove() {
      const cesiumViewer = this.cesiumViewer
      const tt = this
      cesiumViewer.scene.preRender.addEventListener(() => { // 一直触发
      	//如果弹窗没有展示,不进行任何操作,只有弹窗本身展示的时候才进行监听
        if (!tt.popVisible) return
        const scratch = Cesium.Cartesian2()
        const position = Cesium.Cartesian3.fromDegrees(Number(tt.overlayChartObj.popForm.emstLong),
            Number(tt.overlayChartObj.popForm.emstLat), 2500)
          // cartesianToCanvasCoordinates 转换三维空间坐标到canvas坐标(窗口坐标)
          const canvasPosition = cesiumViewer.scene.cartesianToCanvasCoordinates(position, scratch)
          if (Cesium.defined(canvasPosition)) {
            tt.setPopPosition(canvasPosition)
          }
        
      })
    },
    setPopPosition(position) {
      const pop = document.getElementById("popup");
      pop.style.top = position.y + "px";
      pop.style.left = position.x + "px";
    },

总结:

写博客是为了记笔记!

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值