cesium 添加点位弹窗跟随场景移动

news2024/11/16 10:46:42

cesium 添加点位弹窗并跟随场景移动 完整代码演示可直接copy使用

1 效果图:

2 深入理解

就是原始点位的数据

id>property

点位真实渲染到球体上的笛卡尔坐标系

id>_polyline 的路径下 可以通过

3 代码示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Cesium.js"></script>
  <script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
</head>

<body>
  <div id="app">
    <button @click="mapClick">主动触发点位弹窗</button>
    <button @click="removeLayer('site_layer')">清除点位图层</button>
    <div id="cesiumContainer">
      <div id="popup">
        <div class="cesium-popup" @closeMap="closeMapPop" v-if="popVisible" ref="overlay">
          <div class="pop_header">
            <p class="rhpk_info"> {{ overlayChartObj.name }}基本信息</p>
            <div class="map_close" @click="closeMapPop">x</div>
          </div>
          <sitePop>
            <div class="button_box">
              <div>自动监测</div>
            </div>
          </sitePop>
        </div>
      </div>
    </div>
  </div>

  <script>
    var viewer = null
    new Vue({
      el: '#app',
      data: {
        popVisible: false,
        overlayChartObj: {},
        list: [
          { longitude: 109.306058, latitude: 30.86751, id: 0, name: "标点一" },
          { longitude: 109.306058, latitude: 30.56751, id: 1, name: "标点二" },
        ]
      },
      mounted() {
        this.mapCreate()
      },
      methods: {
        async mapCreate() {
          Cesium.Ion.defaultAccessToken =
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZjZlMzAxNS1jY2ZmLTQ0MzctYTE1MS0zNzMxZjhkZjlhYTgiLCJpZCI6MTIyNTg4LCJpYXQiOjE2NzQ5NzMxNTB9.GKIVHIsKN-AWd4vjLOIPm9Fji8tIEvZd5AXf-rTvFk0";
          viewer = new Cesium.Viewer('cesiumContainer', {
            geocoder: false,
            homeButton: false, 
            animation: false, 
            fullscreenButton: false,
            sceneModePicker: false,
            timeline: true, 。
            navigationHelpButton: false, 
            baseLayerPicker: false, 
            infoBox: false, 
            scene3DOnly: false, 
            selectionIndicator: false,
            baselLayerPicker: false,
          });
          let terrainProvider = Cesium.createWorldTerrain({ //添加世界地形能看到山脉的高低起伏
            requestVertexNormals: true, //开启地形光照
            requestWaterMask: true, // 开启水面波纹
          });
          viewer.terrainProvider = terrainProvider;
          viewer.debugShowFramesPerSecond = true//显示当前的帧率信息,这样你就可以实时观察到地图的渲染性能
          viewer.scene.screenSpaceCameraController.minimumZoomDistance = 1;// 设置了摄像机的最小缩放距离
          viewer.camera.setView({ // 相机视口
            destination: Cesium.Cartesian3.fromDegrees(109.306058, 30.86751, 8000),
            orientation: {
              heading: Cesium.Math.toRadians(0), //控制视口左右旋转,也就是沿Y轴旋转,0时为正北方向
              pitch: Cesium.Math.toRadians(-25), // 控制视口上下旋转,也就是沿X轴旋转,-90时为俯视地面
              roll: 0, // 控制视口翻转角度,也就是沿Z轴旋转,0时为不翻转
            },
            //奉节 坐标
          });
          this.handlePinClick(); // 注册点位点击事件
          this.bindMapMove(); // 注册场景移动事件
          this.renderSiteCesiumPoint(this.list)
        },
      }
    })
  </script>

</body>

</html>

完整代码示例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
  <script src="https://unpkg.com/@turf/turf/turf.min.js"></script>
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.85/Build/Cesium/Cesium.js"></script>
  <script src="https://cdn.staticfile.net/vue/2.7.0/vue.min.js"></script>
  <style>
    #cesiumContainer {
      width: 1920px;
      height: 1080px;
    }

    #cesiumContainer .cesium-widget-credits {
      display: none;
    }

    .cesium-popup {
      position: relative;
      width: 267px;
      min-height: 152px;
      background: pink;
      /* background: url(~@/assets/images/mapPop.png) no-repeat; */
      background-size: cover;
    }

    .cesium-popup .pop_header {
      width: 431px;
      height: 57px;
      line-height: 57px;
      /* background: url(~@/assets/images/mapHeader.png) no-repeat 100% 100%; */
    }

    .cesium-popup .rhpk_info {
      font-size: 18px;
      font-weight: bold;
      color: #fff;
      padding-left: 70px;
      box-sizing: border-box;
    }

    .cesium-popup .map_close {
      position: absolute;
      top: 16px;
      right: 20px;
      width: 29px;
      height: 29px;
      /* background: url(~@/assets/images/mapClose.png) no-repeat 100% 100%; */
      cursor: pointer;
    }

    .cesium-popup .map_con {
      padding: 20px 20px;
      width: 100%;
      box-sizing: border-box;
    }

    .cesium-popup .info {
      display: flex;
      font-size: 16px;
      color: #fff;
      margin-bottom: 20px;
    }

    .cesium-popup .title {
      width: 85px;
      font-weight: 400;
      color: #57bcd2;
    }

    .cesium-popup .button_box {
      position: absolute;
      bottom: 30px;
      left: 0px;
      width: 100%;
      display: flex;
      justify-content: flex-end;
    }

    .cesium-popup .button_box div {
      width: 100px;
      height: 27px;
      /* background: url(~@/assets/images/mapButton.png) no-repeat 100% 100%; */
      line-height: 27px;
      text-align: center;
      cursor: pointer;
      margin: 0 10px;
    }
  </style>
</head>

<body>
  <div id="app">
    <button @click="mapClick">主动触发点位弹窗</button>
    <button @click="removeLayer('site_layer')">清除点位图层</button>
    <div id="cesiumContainer">
      <div id="popup">
        <div class="cesium-popup" @closeMap="closeMapPop" v-if="popVisible" ref="overlay">
          <div class="pop_header">
            <p class="rhpk_info"> {{ overlayChartObj.name }}基本信息</p>
            <div class="map_close" @click="closeMapPop">x</div>
          </div>
          <sitePop>
            <div class="button_box">
              <div>自动监测</div>
            </div>
          </sitePop>
        </div>
      </div>
    </div>
  </div>

  <script>
    var viewer = null
    new Vue({
      el: '#app',
      data: {
        popVisible: false,
        overlayChartObj: {},
        list: [
          { longitude: 109.306058, latitude: 30.86751, id: 0, name: "标点一" },
          { longitude: 109.306058, latitude: 30.56751, id: 1, name: "标点二" },
        ]
      },
      mounted() {
        this.mapCreate()
      },
      methods: {
        async mapCreate() {
          Cesium.Ion.defaultAccessToken =
            "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZjZlMzAxNS1jY2ZmLTQ0MzctYTE1MS0zNzMxZjhkZjlhYTgiLCJpZCI6MTIyNTg4LCJpYXQiOjE2NzQ5NzMxNTB9.GKIVHIsKN-AWd4vjLOIPm9Fji8tIEvZd5AXf-rTvFk0";
          viewer = new Cesium.Viewer('cesiumContainer', {
             geocoder: false,
            homeButton: false, 
            animation: false, 
            fullscreenButton: false,
            sceneModePicker: false,
            timeline: true, 。
            navigationHelpButton: false, 
            baseLayerPicker: false, 
            infoBox: false, 
            scene3DOnly: false, 
            selectionIndicator: false,
            baselLayerPicker: false,
          });
          let terrainProvider = Cesium.createWorldTerrain({ //添加世界地形能看到山脉的高低起伏
            requestVertexNormals: true, //开启地形光照
            requestWaterMask: true, // 开启水面波纹
          });
          viewer.terrainProvider = terrainProvider;
          var lastCameraHeight = 0;
          var heightStableCount = 0;
          var threshold = 5; // 高度稳定的阈值
          var maxStableCount = 30; // 达到稳定的帧数

          function isTerrainProvider() {
            var cameraHeight =
              viewer.camera.positionCartographic.height;
            if (Math.abs(cameraHeight - lastCameraHeight) < threshold) {
              heightStableCount++;
            } else {
              heightStableCount = 0;
            }
            if (heightStableCount >= maxStableCount) {
              console.log("地形加载完成");
              // 在这里执行地形加载完成后的操作
              viewer.scene.preRender.removeEventListener(
                isTerrainProvider
              );
            }

            lastCameraHeight = cameraHeight;
          }
          viewer.debugShowFramesPerSecond = true//显示当前的帧率信息,这样你就可以实时观察到地图的渲染性能
          viewer.scene.screenSpaceCameraController.minimumZoomDistance = 1;// 设置了摄像机的最小缩放距离
          viewer.camera.setView({ // 相机视口
            destination: Cesium.Cartesian3.fromDegrees(109.306058, 30.86751, 8000),
            orientation: {
              heading: Cesium.Math.toRadians(0), //控制视口左右旋转,也就是沿Y轴旋转,0时为正北方向
              pitch: Cesium.Math.toRadians(-25), // 控制视口上下旋转,也就是沿X轴旋转,-90时为俯视地面
              roll: 0, // 控制视口翻转角度,也就是沿Z轴旋转,0时为不翻转
            },
            //奉节 坐标
          });


          this.handlePinClick(); // 注册点位点击事件
          this.bindMapMove(); // 注册场景移动事件
          this.renderSiteCesiumPoint(this.list)


        },
        renderSiteCesiumPoint(projectList) {
          this.removeLayer('site_layer')
          for (let i = 0; i < projectList.length; i++) {
            const pro = projectList[i];
            let longitude = pro.longitude || 0
            let latitude = pro.latitude || 0
            let imgUrl = `./site.png`;
            viewer.entities.add({
              position: Cesium.Cartesian3.fromDegrees( // 设置点位的经纬度和高度
                longitude,
                latitude,
                240
              ),
              name: pro.name,
              id: `site_layer_${pro.id}`, // site_layer就是自定义layerName后续可通过这个移除
              property: pro,
              polyline: {
                show: true, //是否显示,默认显示
                // 关键点在设置一条竖直的线
                positions: Cesium.Cartesian3.fromDegreesArrayHeights([
                  longitude,
                  latitude,
                  0,
                  longitude,
                  latitude,
                  240,
                ]),
                width: 1, //线的宽度(像素),默认为1
                material: Cesium.Color.fromCssColorString("#069BBF").withAlpha(1),
              },
              billboard: {
                width: 33, // 点位的大小
                height: 33,
                image: imgUrl,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 设置垂直方向的对齐方式
              },
            });
          }
        },
        removeLayer(layerName) { // 根据图层名移除对应的图层组
          let entityList = [];
          let count = 0
          while (count < 8) {
            viewer.entities.values.forEach(function (entity) {
              if (entity._id.includes(layerName)) {
                viewer.entities.remove(entity);
              }
            });
            count++;
          }
        },

        // 点击地图上的点
        handlePinClick(data = null, typePop = null) {
          const cesiumViewer = viewer;
          const tt = this;
          if (data != null && typePop != null) {
            console.log('主动触发', data, typePop)

            tt.overlayChartObj = Object.assign(data, {
              layer: typePop
            });
            tt.getProjDetailPop({
              x: 951.25,
              y: 600
            }, data);
            return
          }
          const handle3D = new Cesium.ScreenSpaceEventHandler(
            cesiumViewer.scene.canvas
          );
          handle3D.setInputAction((movement) => {
            const pick = cesiumViewer.scene.pick(movement.position);
            console.log("pick===>", pick, pick.id); // pick.id是点击后获取对应的实体
            console.log("pick===>",pick.id.polyline.positions.value.getValue());
            if (!pick.id) {
              console.log("清除监听事件===>", pick, pick.id);
              this.popVisible = false;
              // 清除监听事件
              cesiumViewer.scene.postRender.removeEventListener(this.bindMapMove);
              return;
            }
            const obj = pick.id.property;
            // 解决点击不同点数据不更换问题
            if (tt.overlayChartObj != {}) {
              tt.popVisible = false;
              tt.overlayChartObj = {};
            }

            const coordinate = movement.position;
            console.log("coordinate===>", coordinate);
            if (pick.id._id.includes("rhpwk_layer")) {
              tt.overlayChartObj = Object.assign(obj, {
                layer: "rhpwk_layer"
              });
              tt.getProjDetailPop(coordinate, obj);
            } else if (pick.id._id.includes("site_layer")) {
              tt.overlayChartObj = Object.assign(obj, {
                layer: "site_layer" //使用site_layer类型的点位弹窗
              });
              tt.getProjDetailPop(coordinate, obj);
            } else if (pick.id._id.includes("camera_layer")) {
              tt.overlayChartObj = Object.assign(obj, {
                layer: "camera_layer"
              });
              tt.getProjDetailPop(coordinate, obj);
            } else if (pick.id._id.includes("wry_layer")) {
              tt.overlayChartObj = Object.assign(obj, {
                layer: "wry_layer"
              });
              tt.getProjDetailPop(coordinate, obj);
            }
          }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
        },
        getProjDetailPop(coordinate, obj) {
          this.showOverlayChart(coordinate, obj);
        },
        // 显示
        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 = data;
          this.popVisible = true;
        },
        bindMapMove() {
          const cesiumViewer = viewer;
          console.log('cesiumViewer', cesiumViewer)

          const tt = this;
          cesiumViewer.scene.preRender.addEventListener(() => {
            if (!tt.popVisible) return;
            const scratch = Cesium.Cartesian2();
            const position = Cesium.Cartesian3.fromDegrees(
              Number(tt.overlayChartObj.longitude),
              Number(tt.overlayChartObj.latitude),
              300
            );
            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";
        },
        closeMapPop() {
          this.popVisible = false;
          // 清除监听事件
          viewer.scene.postRender.removeEventListener(
            this.bindMapMove
          );
        },
        // 主动触发点位弹窗
        mapClick() {
          this.handlePinClick(this.list[0], 'site_layer') // 点位数据 及弹窗类型
        },
      }
    })
  </script>

</body>

</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1712845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

天若OCR 识别 (本地文字识别转换工具)

前言 天若OCR文字识别本地版是一款在天若OCR文字识别工具v5.0免费开源版的基础上采用Chinese-lite框架和Paddle-ocr框架本地化识别接口编译而成,无需联网也无需申请密钥&#xff0c;纯本地运算&#xff0c;识别准确度和速度很快&#xff0c;操作和天若OCR免费版一样&#xff0…

工业工程师日子越来越受不了?IE们都在做什么?

有一位工业工程师&#xff08;IE&#xff09;毕业在一家工厂工作&#xff0c;入职一年了&#xff0c;本科读的是工业工程&#xff0c;他说理想很美好现实很骨感&#xff0c;以为做和本科一样的职业就能够大展宏图&#xff0c;结果上司天天让他盯生产线&#xff0c;在厂房一站就…

【FL Studio至尊版:音乐制作界的“瑞士军刀”】

​ 导语&#xff1a;在音乐制作领域&#xff0c;有一款软件被誉为“瑞士军刀”&#xff0c;它就是FL Studio。本文将为您揭示FL Studio的四大爆点&#xff0c;带您领略这款软件的独特魅力。 一、FL Studio&#xff1a;音乐制作界的“瑞士军刀” FL Studio&#xff0c;全称F…

Redis基础篇二

Redis基础篇二 Redis线程Redis之后为什么引进了多线程 Redis持久化Redis如何实现数据不丢失AOF日志是如何实现的为什么先执行命令&#xff0c;再把数据写入日志呢&#xff1f;AOF 写回策略有几种&#xff1f;AOF日志过大&#xff0c;会触发什么操作重写 AOF 日志的过程是怎样的…

LeetCode72:编辑距离

题目描述 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符 删除一个字符 替换一个字符 解题思想 删除&#xff1a;dp[i][j] dp[i-1][j]1 增加&#xff1a;对word1增…

word-商务报告排版,规格尺寸,版面设置,调整事项

一、规格尺寸 布局-纸张大小 设计出血区域&#xff0c;在上下左右增加3毫米 网格&#xff1a;布局-对齐-网格设置-打开垂直间隔 可自定义网格起点 调整网格间距 通过网格来调整页边距&#xff0c;按alt键进行微细调整&#xff0c;左边距和右边距通过标尺调 二、设置主题字体和…

kafka-守护启动

文章目录 1、kafka守护启动1.1、先启动zookeeper1.1.1、查看 zookeeper-server-start.sh 的地址1.1.2、查看 zookeeper.properties 的地址 1.2、查看 jps -l1.3、再启动kafka1.3.1、查看 kafka-server-start.sh 地址1.3.2、查看 server.properties 地址 1.4、再次查看 jps -l 1…

word如何快速查看某段字数

在底部的状态栏上找到【字数】部分&#xff1b; 单击【字数】部分&#xff0c;Word将显示包括字符数、字数和段落数在内的详细统计信息。

基于Spring Cloud微服务架构的Java CRM客户关系管理系统源码

在当今竞争激烈的市场环境中&#xff0c;企业要想保持持续的增长和稳定的客户基础&#xff0c;高效管理客户关系显得尤为重要。CRM&#xff08;客户关系管理&#xff09;系统作为一种先进的管理工具&#xff0c;正逐渐成为企业不可或缺的一部分。该系统通过集成销售、市场、服务…

1个月备考PMP拿到3A,拒绝无效努力

考完PMP已经是去年的事情&#xff0c;近期好多姐妹也要考PMP&#xff0c;分享 一下我1个月备考PMP拿到3A通过经历。 为什么想考PMP&#xff1f; PMP认证价值在于它整体的一套项目管理知识体系&#xff0c;掌握课学项目管理的基本术语和它的一个知识框架&#xff0c;我主要是为…

人工智能在乳腺癌领域的最新进展|【医学AI·文献速递·05-29】

小罗碎碎念 2024-05-29&#xff5c;文献速递 今天分享的文章&#xff0c;主题是AI乳腺癌。 第三篇文章&#xff0c;个人觉得是今天最有借鉴价值的——临床故事接地气&#xff0c;工科算法赶潮流。这篇文章主要做的事情是利用多模态多组学&#xff0c;去区分乳腺腺病和乳腺癌&a…

C#中结构struct能否继承于一个类class,类class能否继承于一个struct

C#中结构struct能否继承于一个类class&#xff0c;类class能否继承于一个struct 答案是&#xff1a;都不能。 第一种情行&#xff0c;尝试结构继承类 报错&#xff1a;接口列表中的类型"XX"不是接口interface。 一般来说&#xff0c;都是结构只能实现接口&#x…

[UE5]安卓调用外置摄像头拍照(之显示画面)

目录 部分参考文献&#xff08;有些有用的我没标&#xff0c;没放上来&#xff09; 要点 总蓝图 结果 部分参考文献&#xff08;有些有用的我没标&#xff0c;没放上来&#xff09; 【UE】获取USB摄像头画面_虚幻捕获硬件摄像头-CSDN博客 UE4安卓调用摄像头拍照确保打…

SQL注入攻击是什么?如何预防?

一、SQL注入攻击是什么&#xff1f; SQL注入攻击是一种利用Web应用程序中的安全漏洞&#xff0c;将恶意的SQL代码插入到数据库查询中的攻击方式。攻击者通过在Web应用程序的输入字段中插入恶意的SQL代码&#xff0c;然后在后台的数据库服务器上解析执行这些代码&#xff0c;从而…

信息学一周赛事安排

本周比赛提醒 本周有以下几场比赛即将开始&#xff1a; 1.ABC-356 比赛时间&#xff1a;6月1日&#xff08;周六&#xff09;晚20:00 比赛链接&#xff1a;https://atcoder.jp/contests/abc356 2.ARC-179 比赛时间&#xff1a;6月2日&#xff08;周日&#xff09;晚20:00 …

K8s中配置使用ingress

Ingress是什么 在Kubernetes中&#xff0c;Ingress是一种用于将外部流量路由到集群内部服务的API对象。它通常与Ingress控制器一起使用&#xff0c;Ingress控制器负责根据Ingress规则路由外部流量到不同的服务上。   Ingress 提供从集群外部到集群内服务的 HTTP 和 HTTPS 路由…

C++容器之多重映射(std::multimap)

目录 1 概述2 使用实例3 接口使用3.1 construct3.2 assigns3.3 iterators3.4 capacity3.5 insert3.6 erase3.7 swap3.8 clear3.9 emplace3.10 emplace_hint3.11 key_comp3.12 value_comp3.13 find/count3.14 lower_bound/upper_bound/equal_range3.15 get_allocator1 概述 多重…

YOLOv10最详细全面讲解1- 目标检测-准备自己的数据集(YOLOv5,YOLOv8均适用)

YOLOv10没想到出来的如此之快&#xff0c;作为一名YOLO的爱好者&#xff0c;以YOLOv5和YOLOv8的经验&#xff0c;打算出一套从数据集装备->环境配置->训练->验证->目标追踪全系列教程。请大家多多点赞和收藏&#xff01;&#xff01;&#xff01;YOLOv5和YOLOv8亲测…

使用Ollama和Open WebUI管理本地开源大模型的完整指南

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年5月27日12点20分 &#x1f004;️文章质量&#xff1a;96分 目录 ✨️Open-WebUI介绍 优点 &#x1f4a5;部署教程…

linux部署运维1——centos7.9离线安装部署web项目所需的依赖环境,包括mysql8.0,nginx1.20,redis5.0等工具

在实际项目部署运维过程中&#xff0c;如果是云服务器&#xff0c;基本安装项目所需的依赖环境都是通过yum联网拉取网络资源实现自动化安装的&#xff1b;但是对于一些特殊场合&#xff0c;在没有外部网络的情况下&#xff0c;就无法使用yum命令联网操作&#xff0c;只能通过编…