cesium自定义的弹窗 Popup弹窗(可随球放大缩小,移动)_cesium popup-程序员宅基地

技术标签: cesium  vue  

# 效果

在这里插入图片描述
在这里插入图片描述

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

# 基本思路

添加一个鼠标左键点击事件,当鼠标点击时,利用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 = `
            <div style="background:#00ffef66;height:200px;border:"1px soild #08f8a7">${
      data.text}
                <div style="">
            </div>
        `;
        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);
        
    },

第四步的完整解读在https://blog.csdn.net/weixin_46730573/article/details/119061305?spm=1001.2014.3001.5502 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

<template>
  <div :id="id" class="box">
    <div class="pine"></div>
    <div class="box-wrap">
      <div class="close" @click="closeClick">X</div>
      <div class="area">
        <div class="area-title fontColor">{
    {
     title }}</div>
        
      </div>
      <div class="content">
        <div class="data-li">
          <div class="data-label textColor">状态:</div>
          <div class="data-value">
            <span class="label-num yellowColor">{
    {
    state}}</span>
          </div>
        </div>
        <div class="data-li">
          <div class="data-label textColor">实时水位:</div>
          <div class="data-value">
            <span class="label-num yellowColor">100</span>
            <span class="label-unit textColor">/s</span>
          </div>
        </div>
      </div>
    </div>

    <!-- <img src="./layer_border.png" alt="Norway"> -->
  </div>
</template>

<script>
export default {
    
  name: "DynamicLabel",
  data() {
    
    return {
    
      show: true,
    };
  },
  props: {
    
    title: {
    
      type: String,
      default: "标题",
    },
    id: {
    
      type: String,
      default: "001",
    },
    state:{
    
      type: String,
      default: "001",
    }
  },
  methods:{
    
    closeClick(){
    
      if(this.closeEvent){
    
        this.closeEvent();
      }
    }
  }
};
</script>


<style lang="scss">
.box {
    
  width: 200px;
  position: relative;
  bottom: 0;
  left: 0;
}
.close{
    
  position: absolute;
  color: #fff;
  top: 1px;
  right: 10px;
  text-shadow: 2px 2px 2px #022122;
  cursor: pointer;
  animation: fontColor 1s;
}
.box-wrap {
    
  position: absolute;
  left: 21%;
  top: 0;
  width: 100%;
  height: 163px;
  border-radius: 50px 0px 50px 0px;
  border: 1px solid #38e1ff;
  background-color: #38e1ff4a;
  box-shadow: 0 0 10px 2px #29baf1;
  animation: slide 2s;
}
.box-wrap .area {
    
  position: absolute;
  top: 20px;
  right: 0;
  width: 95%;
  height: 30px;
  background-image: linear-gradient(to left, #4cdef9, #4cdef96b);
  border-radius: 30px 0px 0px 0px;
  animation: area 1s;
}
.pine {
    
  position: absolute;
  // left: 0;
  // bottom: -83px;
  width: 100px;
  height: 100px;
  box-sizing: border-box;
  line-height: 120px;
  text-indent: 5px;
}

.pine::before {
    
  content: "";
  position: absolute;
  left: 0;
  bottom: -83px;
  width: 40%;
  height: 60px;
  box-sizing: border-box;
  border-bottom: 1px solid #38e1ff;
  transform-origin: bottom center;
  transform: rotateZ(135deg) scale(1.5);
  animation: slash 0.5s;
  filter: drop-shadow(1px 0px 2px #03abb4);
  /* transition: slash 2s; */
}

.area .area-title {
    
  text-align: center;
  line-height: 30px;
}
.textColor {
    
  font-size: 14px;
  font-weight: 600;
  color: #ffffff;
  text-shadow: 1px 1px 5px #002520d2;
  animation: fontColor 1s;
}
.yellowColor {
    
  font-size: 14px;
  font-weight: 600;
  color: #f09e28;
  text-shadow: 1px 1px 5px #002520d2;
  animation: fontColor 1s;
}

.fontColor {
    
  font-size: 16px;
  font-weight: 800;
  color: #ffffff;
  text-shadow: 1px 1px 5px #002520d2;
  animation: fontColor 1s;
}
.content {
    
  padding: 55px 10px 10px 10px;
}
.content .data-li {
    
  display: flex;
}

@keyframes fontColor {
    
  0% {
    
    color: #ffffff00;
    text-shadow: 1px 1px 5px #00252000;
  }
  40% {
    
    color: #ffffff00;
    text-shadow: 1px 1px 5px #00252000;
  }
  100% {
    
    color: #ffffff;
    text-shadow: 1px 1px 5px #002520d2;
  }
}

@keyframes slide {
    
  0% {
    
    border: 1px solid #38e1ff00;
    background-color: #38e1ff00;
    box-shadow: 0 0 10px 2px #29baf100;
  }

  100% {
    
    border: 1px solid #38e1ff;
    background-color: #38e1ff4a;
    box-shadow: 0 0 10px 2px #29baf1;
  }
}
@keyframes area {
    
  0% {
    
    width: 0%;
  }
  25% {
    
    width: 0%;
  }

  100% {
    
    width: 95%;
  }
}

/* img{
            position:absolute;
            left:30%;
            top:0;
            width: 100%;
            box-shadow: 0 0 10px 2px #29baf1;
        } */

@keyframes slash {
    
  0% {
    
    transform: rotateZ(135deg) scale(0);
  }

  100% {
    
    transform: rotateZ(135deg) scale(1.5);
  }
}
</style>

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_46730573/article/details/119852888

智能推荐

C/C++中open函数的阻塞和非阻塞编程_open 阻塞-程序员宅基地

文章浏览阅读310次。阻塞模式会在open函数调用处等待文件打开完成,而非阻塞模式会立即返回,并在文件无法立即打开时设置errno为EAGAIN或EWOULDBLOCK。当read或write函数在非阻塞模式下读取或写入文件时,如果没有可用数据或无法立即写入,这些函数也会返回-1,并设置errno为EAGAIN或EWOULDBLOCK。open函数可以以阻塞或非阻塞的方式打开文件,这取决于对文件描述符的标志位进行的设置。当以阻塞模式打开文件时,程序会在open函数调用处等待,直到文件打开操作完成。_open 阻塞

编程人员的不二之选 LEGION Y9000X正式发布_y9000x写代码够用吗-程序员宅基地

文章浏览阅读4.6k次。10月11日,联想集团在全球总部未来中心举行了主题为“解密X空间”的新品发布会,正式发布了LEGIONY9000X笔记本电脑,并公布了“联想个人云存储核心测试用户招募”计划。高性能标压轻薄本 LEGION Y9000X赋能内容创造者“你正在用的笔记本是游戏本还是轻薄本?”通过这样的一个问题,联想中国区消费业务笔记本产品规划总监林林,拉开了“解密X空间”的序幕,带来重磅新品——高性能标..._y9000x写代码够用吗

强化学习(reinforcement learning)教程_强化学习教程-程序员宅基地

文章浏览阅读3.4w次,点赞2次,收藏29次。前一阵研究强化学习,发现中文的资料非常少,实例就更少。于是翻译一篇q学习算法的教程,供需要的人学习。原文链接:http://mnemstudio.org/path-finding-q-learning-tutorial.htm正文:Q学习算法是一种用来解决马尔可夫决策过程中最优化问题的方法。Q学习算法最大的特点是它具有选择瞬时奖励和延迟奖励的能力。在每一步中,agent通过观察状态_强化学习教程

SpringBoot+Vue校园二手书交易平台(源码+论文)_基于vue+springboot的校园二手商品交易网站论文-程序员宅基地

文章浏览阅读81次。后端:Java+SpringBoot前端:Vue数据库:MySQL开发软件:Eclipse、MyEclipse、IDEA都可以运行。_基于vue+springboot的校园二手商品交易网站论文

Chrome 开发者工具各种骚技巧-程序员宅基地

文章浏览阅读231次。对于每个前端从业者来说,除了F5键之外,用的最多的另外一个键就是F12了。今天,大神(@小鱼二)推荐我一个网站,才知道chrome还有各种骚姿势。网站是:umaar.com/dev-tip...

【jeecg-boot】jeecg-boot的一些功能扩展:-程序员宅基地

文章浏览阅读2k次。【jeecg-boot】jeecg-boot的一些功能扩展:_jeecg-boot

随便推点

Linux静态链接库与动态链接库_linux里动态链接库和静态链接库-程序员宅基地

文章浏览阅读558次。一、静态库与动态库基本概念:Windows中静态连接库为.lib文件,动态链接库为.dll文件,这两种文件在平时生活中使用Windows我们就见过很多回,而今天我们来说说Linux的动态链接库(又称为共享链接库)(.so文件)与静态链接库(.a文件)。有关于环境变量与编译的基本内容,可参照: Linux环境变量与系统编程学习笔记 Linux环境C语言编译与头文件等知识点小结 1、静态库与共享_linux里动态链接库和静态链接库

可能是最好用的Android引导层库-程序员宅基地

文章浏览阅读586次,点赞19次,收藏25次。着重说明一下setLayoutRes方法,通常其他的类似的库都是通过代码参数来控制说明内容展示在高亮view相对的位置,如下方。经常需要多次运行才能找到满意的位置的参数。大多说明内容只能出现在高亮的上下左右,需要库的支持,自定义的程度不是很高。我所采用的方式是将说明内容通过xml的方式,自定义摆放位置。使得说明内容高度自定义,不管你是简单的图片,还是对话框类型的都可以。.setEverywhereCancelable(false)//是否点击任意位置消失引导页,默认true。

小帅的七个男友 第一章 未恋先失-程序员宅基地

文章浏览阅读164次。第一章 未恋先失&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;初中时代的我,还是一个单纯的女孩,对于爱情,以为是眼泪制造出来的。我的圈子并不大,只有几个要好的女生,彭老二,周薇,秋毛。彭老二是个大嘴,校园里发生了什么事情她总是最先知道,通过她的大嘴,什么八卦新闻都逃..._操小帅

MATLAB db4小波分解与重构,语音降噪-程序员宅基地

文章浏览阅读4.4k次,点赞2次,收藏23次。小波变换3级分解Mallat图:将带噪语音作为输入信号进行逐级DWT小波分解,并将分解出的低频成分cA3cA_3cA3​与强制置0后的高频成分cD3cD_3cD3​,cD2cD_2cD2​,cD1cD_1cD1​进行小波重构。Demo:clc,clear[x,Fs]= audioread('MUsic_Test.wav');snr = 20; %设定信噪比,单位dbnoise = randn(size(x)); % 用randn函数产生高斯白噪声Nx = length(x_db4小波

安装和配置SNMP(windows10和Linux)--附SNMP客户端工具_snmp工具-程序员宅基地

文章浏览阅读8.3k次,点赞5次,收藏34次。首先需要安装 snmp ,使用下面的命令进行安装安装完毕之后,使用下面的命令查看是否安装成功当命令行显示如图即为安装成功。_snmp工具

如何正确的敲键盘(打字习惯改正)_怎么敲键盘-程序员宅基地

文章浏览阅读6.4k次,点赞5次,收藏40次。练习打字的官网:http://dazi.kukuw.com/关于打字的详细介绍:一个过来人的打字指法纠正之路_怎么敲键盘

推荐文章

热门文章

相关标签