cesium自定义的弹窗 Popup弹窗(可随球放大缩小,移动)

#.效果

 

 

图中效果源代码在下面的封装栏中 

基本思路 

 添加一个鼠标左键点击事件,当鼠标点击时,利用vue2.0中 Vue.extend() 动态添加一个dom元素,将DOM元素渲染到cesium容器中,并利用cesium中提供的 viewer.scene.postRender 实时更新坐标位置。思路很简单,接下来我们进行实现。

实现方法 

1. 首先我们需要生成一个球体做我们标记的容器 

viewer = new Cesium.Viewer('cesiumContainer',{
            // terrainProvider: Cesium.createWorldTerrain(),
            // animation: false, // 控制场景动画的播放速度控件
            // baseLayerPicker: true, // 底图切换控件
            // baselLayerPicker:false,// 将图层选择的控件关掉,才能添加其他影像数据
            // // fullscreenButton: false, // 全屏控件
            // geocoder: false, // 地理位置查询定位控件
            // homeButton: true, // 默认相机位置控件
            // timeline: false, // 时间滚动条控件
            // infoBox: false, //是否显示信息框
            // sceneModePicker: false, //是否显示3D/2D选择器
            // selectionIndicator: false, // 点击点绿色弹出 是否显示选取指示器组件
            // sceneMode: Cesium.SceneMode.SCENE3D, //设定3维地图的默认场景模式:Cesium.SceneMode.SCENE2D、Cesium.SceneMode.SCENE3D、Cesium.SceneMode.MORPHING
            // navigationHelpButton: false, // 默认的相机控制提示控件
            // scene3DOnly: true, // 每个几何实例仅以3D渲染以节省GPU内存
            // navigationInstructionsInitiallyVisible: false,
            // showRenderLoopErrors: false, //是否显示渲染错误
            // orderIndependentTranslucency:false,//设置背景透明
            
        });

 2. 然后利用cesium中 billboard 来添加目标点位

添加点位的数据格式 

poin :  [{id:'12321321' , name: "北京西路测试点", type: "固定枪机", state: "在线", position: { x: 116.4568, y: 39.8926} ,text:'X'},
         {id:'43244324' , name: "阿乐修理厂门口", type: "固定枪机", state: "在线", position: {  x: 116.4568, y: 39.8944 } ,text:'+'},
         {id:'43764324', name: "裕华路加油站", type: "固定枪机", state: "在线", position: { x: 116.4566, y: 39.8923 } ,text:'?'},
         {id:'437543345', name: "康佳大药房", type: "固定枪机", state: "在线", position: { x: 116.4513, y: 39.8923 }  ,text:'!'},],

 添加点位先上代码(class封装)

//加载点
 dragEntity(){
   let drag = new DragEntity({
     viewer:this.$store.state.viewer, 
   })
   let _this = this
   // this.poin = [{id:234,position:[122.8,39.9],text:"L"},{id:432,position:[122,39],text:"C"}]
   this.poin.forEach(item => {
     let entity = drag.addEntity(item);
     _this.poinEntity[item.id] = entity;
   })
 },
 
/**
 * @param {Viewer} viewer
 * 
*/
export default class DragEntity{
    constructor(val){
        this.viewer = val.viewer,
    }
    addEntity(value){
        //数据格式{id:543595234324_432423,position:[122.8,39.9],text:"L"}
        let pinBuilder = new Cesium.PinBuilder();
        let poin = this.viewer.entities.add({
            id:value.id,
            name: value.name,
            position: Cesium.Cartesian3.fromDegrees(value.position.x, value.position.y),
            billboard: {
              image: pinBuilder.fromText(value.text,Cesium.Color.ROYALBLUE, 48).toDataURL(),
              verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            },
            monitoItems:{
                    data:value
                },
        });
        return poin
    }
    
}

解读一下,我们封装了一个class类,将添加点的方法封装到类中方便调用,我们用“billboard”方法与cesium中PinBuilder来进行添加目标点,"PinBuilder"不会的可以看一下官网https://sandcastle.cesium.com/?src=Map%20Pins.html&label=All,然后我们将创建好的实体,return出来,用一个对象来进行接收,用对象的目的就是为了以后方便查找。来看一眼效果

3. 第三步我们来添加一个左键点击事件,当点击时获取实体,在methods()中添加leftDownAction()方法,mounted掉用 

leftDownAction(){
      let viewer = this.$store.state.viewer
        this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
        let _this = this
        let id
        _this.handler.setInputAction(function (movement) {
            let pick = viewer.scene.pick(movement.position); 
            if (Cesium.defined(pick) && (pick.id.id) ) {
                // _this.leftDownFlag = true;
                id= pick.id.id;
                 console.log(id)
            }
            
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        
    },

 代码解读,我们先创建一个LEFT_CLICK 事件,返回值为经纬度,运用 viewer.scene.pick判断拿到实体,打印到控制台;

4. 第四步我们来完成弹窗部分(下面代码没有优化,优化的代码在封装部分) 

export default class Bubble {
    constructor(val){
        this.viewer = val.viewer
        this.div=document.createElement("div");
        // this.addDynamicLabel({id:1,position:val.position,title:"cl弹窗"});
    }
    addDynamicLabel(data){
        let div = this.div
        div.id = data.id;
        // div.style.display="inline"
        div.style.position = "absolute";
        div.style.width = "300px";
        div.style.height = "30px";
        let HTMLTable = `
            
${data.text}
`; div.innerHTML = HTMLTable; this.viewer.cesiumWidget.container.appendChild(div); let gisPosition = data.position._value this.viewer.scene.postRender.addEventListener(() => { const canvasHeight = this.viewer.scene.canvas.height; const windowPosition = new Cesium.Cartesian2(); Cesium.SceneTransforms.wgs84ToWindowCoordinates( this.viewer.scene, gisPosition, windowPosition ); div.style.bottom = canvasHeight - windowPosition.y +220 + "px"; const elWidth = div.offsetWidth; div.style.left = windowPosition.x - elWidth / 2 + "px"; }, this); } clearDiv(id){ if(this.div){ var parent = this.div.parentElement; parent.removeChild(this.div); // this.div.removeNode(true); this.viewer.scene.postRender.removeEventListener(this.addDynamicLabel,this) } } }

 修改点击事件代码

import Bubble from './bubble/index.js'
leftDownAction(){
      	let viewer = this.$store.state.viewer
      	let bubble = new  Bubble({
			viewer:viewer 
		})
        this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
        let _this = this
        let id
        _this.handler.setInputAction(function (movement) {
            let pick = viewer.scene.pick(movement.position); 
            if (Cesium.defined(pick) && (pick.id.id) ) {
                // _this.leftDownFlag = true;
                id= pick.id.id;
                let entiy = this.poinEntity[id];
                bubble.addDynamicLabel(entiy);
            }else{
				bubble.clearDiv();
			}
            
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        
    },

 第四步的完整解读在cesium 自定义动态标记_cesium 标记特效_GIS-CL的博客-CSDN博客 cesium自定义标记中,本文不做多讲解。当点击时显示弹窗,当点击空白初,删除弹窗。

封装(完整代码) 

1、在vue中

import Bubble from './bubble/index.js'
import DragEntity from './dragentity.js'
data(){
    return{
      fullSizenum:'fullSize',
      poinEntity:{},
      poin :  [{id:'12321321' , name: "北京西路测试点", type: "固定枪机", state: "在线", position: { x: 116.4568, y: 39.8926} ,text:'X'},
            {id:'43244324' , name: "阿乐修理厂门口", type: "固定枪机", state: "在线", position: {  x: 116.4568, y: 39.8944 } ,text:'+'},
            {id:'43764324', name: "裕华路加油站", type: "固定枪机", state: "在线", position: { x: 116.4566, y: 39.8923 } ,text:'?'},
            {id:'437543345', name: "康佳大药房", type: "固定枪机", state: "在线", position: { x: 116.4513, y: 39.8923 }  ,text:'!'},],
    }
},
mounted(){
    this.dragEntity()
    this.leftDownAction()
 },
methods:{
	leftDownAction(){
      let viewer = this.$store.state.viewer
        this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
        let _this = this
        let id
        _this.handler.setInputAction(function (movement) {
            let pick = viewer.scene.pick(movement.position); 
            if (Cesium.defined(pick) && (pick.id.id) ) {
                // _this.leftDownFlag = true;
                id= pick.id.id;
                 _this.bubble(id)
            }else{
              // console.log(_this.bubbles)
              if(_this.bubbles){
                _this.bubbles.windowClose()
              }
              
            }
            
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        
    },
    bubble(id){
      if(this.bubbles){
        this.bubbles.windowClose()
      }
      console.log(this.poinEntity[id])
      this.bubbles = new Bubble(Object.assign(this.poinEntity[id],{
        viewer:this.$store.state.viewer
      }))
      
    },
    //加载点
    dragEntity(){
      let drag = new DragEntity({
        viewer:this.$store.state.viewer, 
      })
      let _this = this
      // this.poin = [{id:234,position:[122.8,39.9],text:"L"},{id:432,position:[122,39],text:"C"}]
      this.poin.forEach(item => {
        let entity = drag.addEntity(item);
        _this.poinEntity[item.id] = entity;
      })
    },
}
	

2、创建dragentity.js文件

/**
 * @param {Viewer} viewer
 * 
*/
export default class DragEntity{
    constructor(val){
        this.viewer = val.viewer,
    }
    addEntity(value){
        let pinBuilder = new Cesium.PinBuilder();
        let poin = this.viewer.entities.add({
            id:value.id,
            name: value.name,
            position: Cesium.Cartesian3.fromDegrees(value.position.x, value.position.y),
            billboard: {
              image: pinBuilder.fromText(value.text,Cesium.Color.ROYALBLUE, 48).toDataURL(),
              verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            },
            monitoItems:{
                    data:value
                },
        });
        return poin
    }
    
}

 3、创建以bubble命名文件夹,里面分别创建一个index.js文件,和index.vue文件
index.js

/**
 * @descripion:
 * @param {Viewer} viewer
 * @param {Cartesian2} position
 * @param {String} title
 * @param {String} id
 * @return {*}
 */

 import Vue from "vue";
 import Label from "./index.vue";
 let WindowVm = Vue.extend(Label);
 export default class Bubble {
     
     constructor(val) {
       console.log(val.monitoItems.data.name)
         this.viewer = val.viewer;
        //  this.height = val.height;
         this.position = val.position._value;
         let title = val.monitoItems.data.name;
         let state = val.monitoItems.data.state;
         let id = val.id
         this.vmInstance = new WindowVm({
           propsData: {
            title,
            state,
             id
           }
         }).$mount(); //根据模板创建一个面板

         this.vmInstance.closeEvent = e => {
           this.windowClose();
         }

         val.viewer.cesiumWidget.container.appendChild(this.vmInstance.$el); //将字符串模板生成的内容添加到DOM上
         
         this.addPostRender();
     }
     
   //添加场景事件
   addPostRender() {
     this.viewer.scene.postRender.addEventListener(this.postRender, this);
   }
 
   //场景渲染事件 实时更新窗口的位置 使其与笛卡尔坐标一致
   postRender() {
     if (!this.vmInstance.$el || !this.vmInstance.$el.style) return;
     const canvasHeight = this.viewer.scene.canvas.height;
     const windowPosition = new Cesium.Cartesian2();
     Cesium.SceneTransforms.wgs84ToWindowCoordinates(
       this.viewer.scene,
       this.position,
       windowPosition
     );
     this.vmInstance.$el.style.bottom =
       canvasHeight - windowPosition.y  +260+ "px";
     const elWidth = this.vmInstance.$el.offsetWidth;
     this.vmInstance.$el.style.left = windowPosition.x - elWidth / 2 +110 + "px";
 
     const camerPosition = this.viewer.camera.position;
     let height = this.viewer.scene.globe.ellipsoid.cartesianToCartographic(camerPosition).height;
     height += this.viewer.scene.globe.ellipsoid.maximumRadius;
     if((!(Cesium.Cartesian3.distance(camerPosition,this.position) > height))&&this.viewer.camera.positionCartographic.height<50000000){
         this.vmInstance.$el.style.display = "block";
     }else{
       this.vmInstance.$el.style.display = "none";
     }
   }
   //关闭 
   windowClose() {
   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); //移除事件监听
    }
 }

index.vue







 然后在封装栏中第一步调用即可,最终效果与展示效果一样。

————————————————

原文链接:https://blog.csdn.net/weixin_46730573/article/details/119852888

 

 

你可能感兴趣的:(javascript,前端)