cesium实现自定义弹窗

cesium实现自定义弹窗

弹窗内容渲染类

/**
 * @descripion: 弹窗渲染类
 */

import Vue from "vue";

export default class Bubble {

    /**
     *
     * @param viewer 场景
     * @param position  弹窗位置
     * @param propsData 弹窗内部的属性数据值 {k:v}
     * @param bubbleType 弹窗类型 vue组件
     * @param offsetHeight 底部偏移高度,弹窗底部偏移高度需要设置一个合适的值,否则很容易导致场景拖动的时候,弹窗存在偏移
     */
    constructor(viewer, position, bubbleType, propsData, offsetHeight) {
        this.viewer = viewer;
        this.offsetHeight = offsetHeight;
        this.position = position;

        // 判断弹窗内容是否是vue组件文件
        if (!bubbleType || !bubbleType['beforeCreate'] || !bubbleType['render']) {
            throw new Error('弹窗类型不正确!')
        }

        let WindowVm = Vue.extend(bubbleType);

        // 根据模板创建一个面板
        this.vmInstance = new WindowVm({
            propsData: propsData
        }).$mount();
        this.vmInstance.closeEvent = e => {
            this.close();
        }
        // 将字符串模板生成的内容添加到DOM上
        this.viewer.cesiumWidget.container.appendChild(this.vmInstance.$el);

        this.addPostRender();
    }

    //添加场景事件
    addPostRender() {
        this.viewer.scene.postRender.addEventListener(this.postRender, this);
    }

    //场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
    postRender() {
        if (!this.vmInstance.$el || !this.vmInstance.$el.style) return;
        const viewerContainerHeight = this.viewer.cesiumWidget.container.offsetHeight;
        const windowPosition = new Cesium.Cartesian2();
        Cesium.SceneTransforms.wgs84ToWindowCoordinates(
            this.viewer.scene,
            this.position,
            windowPosition
        );
        let elHeight = this.vmInstance.$el.offsetHeight;
        //elHeight 值需要设置一个合适的,否则很容易导致场景拖动的时候,弹窗存在偏移
        if (!!this.offsetHeight) {
            elHeight += this.offsetHeight;
        }
        //console.log(windowPosition,canvasHeight,this.vmInstance.$el.offsetHeight,elHeight, windowPosition.y - elHeight + "px")
        this.vmInstance.$el.style.top = windowPosition.y - elHeight + "px";
        const elWidth = this.vmInstance.$el.offsetWidth;
        this.vmInstance.$el.style.left = windowPosition.x - elWidth / 2 + "px";

        const cameraPosition = this.viewer.camera.position;
        let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(cameraPosition).height;
        height += this.viewer.scene.globe.ellipsoid.maximumRadius;

        if ((!(Cesium.Cartesian3.distance(cameraPosition, this.position) > height)) && this.viewer.camera.positionCartographic.height < 50000000) {
            this.vmInstance.$el.style.display = "block";
        } else {
            this.vmInstance.$el.style.display = "none";
        }
    }

    //关闭
    close() {
        if (this.vmInstance) {
            this.vmInstance.$el.remove();
            this.vmInstance.$destroy();
        }
        //this.vmInstance.$el.style.display = "none"; //删除dom
        this.viewer.scene.postRender.removeEventListener(this.postRender, this); //移除事件监听
    }
}

弹窗内容定义

// 弹窗内容
import BubbleDynamicLabel from "./BubbleDynamicLabel.vue";
import BubbleWaterDetail from "./BubbleWaterDetail"

const BubbleType = {
  BubbleDynamicLabel,
  BubbleWaterDetail,
}

export default BubbleType

弹窗调用

data() {
  return {
    position: {
      x: 102.74053944923936,
      y: 30.984019652124275,
      z: 500
    }
  }
},
methods: {
    initDat() {
      let that = this;
      if (Viewer.terrainProvider) {
        //设置了地形让其高度在地形之上
        let positions = [
          Cesium.Cartographic.fromDegrees(this.position.x, this.position.y),
        ];
        let promise = Cesium.sampleTerrainMostDetailed(Viewer.terrainProvider, positions);
    
        Cesium.when(promise, function (updatedPositions) {
          let terrainHeight = updatedPositions[0].height
          that.position.z = terrainHeight + 20;
          //初始化弹窗
          that.initPopup();
          that.initPoint()
        })
      } else {
        setTimeout(() => {
          that.initPopup();
          that.initPoint()
        }, 1000)
      }
    },
    
    initPopup() {
      let position = Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z)
      const propsData = {
        properties: {labelName: '测试地址点位'}
      }
      let bubbleInstance = new Bubble(Viewer, position, BubbleType.BubbleDynamicLabel, propsData, 260)
      if (bubbleInstance) {
        //关闭弹窗
        // bubbleInstance.close()
      }
    },
    initPoint() {
      //用于调试弹窗是否对得上位置,弹窗对上了该点,不然很容易出现弹窗偏移的问题
      const pointPrimitives = Viewer.scene.primitives.add(
          new Cesium.PointPrimitiveCollection()
      );
      pointPrimitives.add({
        color: Cesium.Color.YELLOW,
        position: Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z),
      });
    
      const labels = Viewer.scene.primitives.add(new Cesium.LabelCollection());
      labels.add({
        position: Cesium.Cartesian3.fromDegrees(this.position.x, this.position.y, this.position.z),
        text: "Philadelphia",
      });
    }
}

效果

在这里插入图片描述

问题:

有些情况会出现弹窗跟随场景拖动在移动,这种情况是由于弹窗的偏移高度不对的问题导致的,这个时候可以在场景上加载出对应弹窗应该在的位置点来对照进行偏移的值的调整设置即可,例如上图中的黄色点。

参考文章:
cesium自定义的弹窗 Popup弹窗

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值