首页 前端知识 cesium vue3自定义HTML实体弹窗、加高德路网、防实体漂浮、让用户画圆、鹰眼

cesium vue3自定义HTML实体弹窗、加高德路网、防实体漂浮、让用户画圆、鹰眼

2025-03-12 12:03:31 前端知识 前端哥 867 914 我要收藏

一、基础使用:Cesium.js基础使用(vue)-CSDN博客

 1、基础路径

为 Cesium 库设置一个全局变量 CESIUM_BASE_URL,用于指定 Cesium 的资源文件(如 WebGL shaders、纹理、字体等)的

示例场景:假设你在开发一个基于 Cesium 的 3D 地球应用,但不想将 Cesium 的资源文件打包到项目中,而是希望通过 CDN 加载资源。

  window.CESIUM_BASE_URL = 'https://cesium.com/downloads/cesiumjs/releases/1.97/Build/Cesium/';

2、Cesium Ion的默认访问令牌

Cesium.Ion.defaultAccessToken = '';  // 赋值你的访问令牌

二、其他配置

 1、HTML自定义实体弹窗

    // 以下代码都在onMounted钩子函数里

    // 函数用于创建一个新的小点实体和对应的HTML弹窗
    const createPoint = (id, position, info) => {
      // 创建小点实体
      var point = viewer.entities.add({
        position: position, // 位置
        point: {
          // 点的样式
          pixelSize: 10, // 像素大小
        },
        show: false, // 默认隐藏实体
      });

      // 创建HTML弹窗元素
      let element = document.createElement('div');
      element.className = 'locator';
      element.innerHTML = `
            <h3>${info.title}</h3>
            <p>名称:${info.name}</p>
            <p>类型:${info.type}</p>
            <p>时间:${info.time}</p>
        `;

      // 设置初始可见性
      element.style.display = state.eventVisible ? 'block' : 'none';

      // 将HTML弹窗元素添加到Cesium Viewer容器中
      viewer.container.appendChild(element);

      //为弹窗添加点击事件
      element.addEventListener('click', () => {
        state.eventModalVisible = true;
        state.eventId = id;
      });

      // 将小点实体和HTML弹窗元素存入相应的集合
      state.points.push(point);
      state.pointElements[point.id] = element;

      return point;
    };

    //获取事件点数据
    const getEventPoint = async () => {
      state.pointsData = [];
      let res = await getEventTaskList();
      if (res.code === 200) {
        res.data.list.forEach(item => {
          if (item.f_lng !== null && item.f_lat !== null) {
            state.pointsData.push({
              id: item.id,
              position: Cesium.Cartesian3.fromDegrees(parseFloat(item.f_lng), parseFloat(item.f_lat), 0),
              info: { title: item.f_leve, name: item.f_name, type: item.f_from_type, time: item.f_create_time },
            });
          }
        });
        state.pointsData.forEach(function (data) {
          createPoint(data.id, data.position, data.info);
        });
      } else {
        console.log(res.msg);
      }
    };
    getEventPoint();

    //当鼠标拖动地图或放大缩小地图时,更新所有HTML弹窗的位置
    function updateAllElementPositions() {
      var scene = viewer.scene;
      // 如果场景模式不是MORPHING,则更新所有HTML弹窗的位置
      if (scene.mode !== Cesium.SceneMode.MORPHING) {
        // 遍历所有小点实体,更新对应的HTML弹窗的位置
        state.points.forEach(function (point) {
          var canvas = scene.canvas;
          // 获取小点实体的位置
          var cartesian = Cesium.Property.getValueOrUndefined(point.position, scene.lastRenderTime);
          // 将笛卡尔坐标转换为屏幕坐标
          var pixelPosition = scene.cartesianToCanvasCoordinates(cartesian);
          // 如果屏幕坐标存在,则更新HTML弹窗的位置
          if (pixelPosition) {
            // 获取HTML弹窗元素
            var element = state.pointElements[point.id];
            // 设置HTML弹窗元素的位置
            element.style.left = pixelPosition.x + 'px';
            element.style.top = pixelPosition.y + 'px';

            // 检查可见性
            element.style.display = state.eventVisible ? 'flex' : 'none';
          }
        });
      }
    }

    // 监听Cesium场景更新事件,以便在每次渲染时更新所有HTML弹窗的位置
    viewer.scene.postRender.addEventListener(updateAllElementPositions);


    // 函数用于更新所有弹窗的可见性
    function updatePopupVisibility() {
      Object.values(state.pointElements).forEach(element => {
        element.style.display = state.eventVisible ? 'block' : 'none';
      });
    }

    //更新弹框显隐
    watch(
      () => state.eventVisible,
      newVal => {
        updatePopupVisibility();
      },
    );
  onUnmounted(() => {
    //页面卸载时清除事件监听器
    window.removeEventListener('unload', function () {
      viewer.scene.postRender.removeEventListener(updateAllElementPositions);
    });
  }
    :deep(.locator) {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: absolute;
      width: 236px;
      height: 207px;
      margin-top: -190px;
      margin-left: -118px;
      background: url('/src/assets/images/screen/locator.png') no-repeat center center;
      padding: 23px 0;
      cursor: pointer;
    }

 2、让弹框和相关区域同时显隐

    //该函数用于输入多边形顶点坐标,能够绘制多边形在视图上,多边形背景颜色为红色,边框为黄色
    function drawPolygon(points, isShow, entities) {
      let color;
      if (entities === state.irrigationEntities) {
        color = Cesium.Color.BLUE.withAlpha(0.5);
      };
      var polygon = viewer.entities.add({
        polygon: {
          hierarchy: Cesium.Cartesian3.fromDegreesArray(points),
          material: color,
          outline: true,
        },
        show: isShow,
      });
      //将多边形实体ID存入相应的集合
      entities.push(polygon.id);
    }

    //监听showIrrigation,为true时绘制灌区,否则隐藏
    watch(
      () => state.showIrrigation,
      newVal => {
        if (newVal) {
          //移除灌区多边形
          state.irrigationEntities.forEach(id => {
            viewer.entities.removeById(id);
          });
          state.irrigationEntities = [];
          state.irrigationAreaData.forEach(area => {
            drawPolygon(area, true, state.irrigationEntities);
          });
        } else {
          //移除灌区多边形
          state.irrigationEntities.forEach(id => {
            viewer.entities.removeById(id);
          });
          state.irrigationEntities = [];
        }
      },
    );

 3、设置地形关闭,防止漂浮

  • 启用地形:适用于需要展示真实地形的应用场景(如山脉、峡谷等)。
  • 关闭地形:适用于需要简化渲染、提升性能或避免地形干扰的场景。
// 设置地形,关闭
viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider();

注:不关闭地形的话,鼠标拖拽地图移动时,实体会出现类似漂浮的效果(鼠标拖拽一下,实体移动出去更远)

4、鹰眼

    // 创建鹰眼地图的Viewer
    const overviewViewer = new Cesium.Viewer(overviewContainer.value, {
      animation: false, // 禁用动画控件
      geocoder: false, // 开启地理编码控件
      homeButton: false, // 禁用主视图控件
      sceneModePicker: false, // 禁用场景模式切换控件
      // baseLayerPicker: false, // 禁用底图切换控件
      navigationHelpButton: false, // 禁用导航帮助按钮
      timeline: false, // 禁用时间轴控件
    });
    // 隐藏底部版权信息
    overviewViewer._cesiumWidget._creditContainer.style.display = 'none';

    // 添加高德地图路网
    overviewViewer.imageryLayers.addImageryProvider(gaodeLayer);

    // 同步两个地图的视角
    function syncView(longitude, latitude, height) {
      // 确保参数是数值类型
      longitude = parseFloat(longitude);
      latitude = parseFloat(latitude);
      height = parseFloat(height);
      overviewViewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
        orientation: {
          heading: Cesium.Math.toRadians(0), // 方向角度,单位为弧度
          pitch: Cesium.Math.toRadians(-90), // 俯仰角度,单位为弧度
          roll: 0, // 翻滚角度,单位为弧度
        },
        duration: 1, // 动画持续时间,单位为秒
      });
    }
   
    // 设置中心点同样的经纬度
    syncView(state.longitude, state.latitude, state.height * 5);

 5、添加高德地图路网

显示道路和中文的区域名字:

const gaodeLayer = new Cesium.UrlTemplateImageryProvider({
      url: 'http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8',
      maximumLevel: 18,
    });
viewer.imageryLayers.addImageryProvider(gaodeLayer);

 6、让用户画圆

    //开始画圆
    const startDrawingCircle = () => {
      //监听鼠标,后一次点击的位置与前一次点击的位置之间的直线为圆的直径。
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      let positions = [];
      handler.setInputAction(movement => {
        //获取鼠标点击的位置的笛卡尔坐标
        let cartesian = viewer.scene.pickPosition(movement.position);
        //如果cartesian存在且与positions数组中的第一个元素不相等,则将其添加到positions数组中
        if (cartesian && (!positions.length || !Cesium.Cartesian3.equals(cartesian, positions[0]))) {
          positions.push(cartesian);
          if (positions.length === 2) {
            let center = Cesium.Cartesian3.midpoint(positions[0], positions[1], new Cesium.Cartesian3());
            let radius = Cesium.Cartesian3.distance(center, positions[0]);
            var circle = viewer.entities.add({
              position: center,
              ellipse: {
                semiMinorAxis: radius,
                semiMajorAxis: radius,
                material: Cesium.Color.RED.withAlpha(0.5),
                outline: true,
                outlineColor: Cesium.Color.BLACK,
              },
            });
            positions = [];
            state.circleEntities.push(circle.id);
          }
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK); //监听state.drawingCircle,当其值为false时,移除handler

      watch(
        () => state.drawingCircle,
        value => {
          if (value) {
            startDrawingCircle();
          } else {
            handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
          }
        },
      );
    };

7、让用户画多边形

    //开始画多边形
    const startDrawingPolygon = () => {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      let positions = [];
      let polygon = null;
      handler.setInputAction(movement => {
        let cartesian = viewer.scene.pickPosition(movement.position);
        if (cartesian) {
          positions.push(cartesian);
          if (positions.length === 1) {
            polygon = viewer.entities.add({
              polygon: {
                hierarchy: new Cesium.CallbackProperty(() => {
                  return new Cesium.PolygonHierarchy(positions);
                }, false),
                material: Cesium.Color.RED.withAlpha(0.5),
                outline: true,
                outlineColor: Cesium.Color.BLACK,
              },
            });
            state.polygonEntities.push(polygon.id);
          } else {
            polygon.polygon.hierarchy = new Cesium.CallbackProperty(() => {
              return new Cesium.PolygonHierarchy(positions);
            }, false);
          }
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
      watch(
        () => state.drawingPolygon,
        value => {
        if (value) {
          startDrawingPolygon();
        } else {
            handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
          }
        },
      );
    };

8、隐藏底部版权信息

viewer._cesiumWidget._creditContainer.style.display = 'none';

注:创建Cesium Viewer要在onMounted钩子函数内

9、地图深度检测

确保 3D 场景中物体的遮挡关系正确,避免出现物体穿插或遮挡错误的问题。它是实现真实感渲染的关键技术之一,在地形、建筑、飞行器等场景中尤为重要。

viewer.scene.globe.depthTestAgainstTerrain = true;

10、地图颜色

官方本来提供了多种主题,但是仍然想自定义颜色可如下设置:

viewer.scene.globe.baseColor = Cesium.Color.fromCssColorString('#00115F');
let baseLayer = viewer.imageryLayers.get(0);
baseLayer.show = false;

11、禁用双击事件

双击地图上的某个位置,通常会放大视图并聚焦到该点。

viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

12、添加动画效果,飞向指定位置

// 添加动画效果,飞向指定位置,写成函数,方便调用
    function flyToLocation(longitude, latitude, height) {
      viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
        orientation: {
          heading: Cesium.Math.toRadians(0), // 方向角度,单位为弧度
          pitch: Cesium.Math.toRadians(-90), // 俯仰角度,单位为弧度
          roll: 0, // 翻滚角度,单位为弧度
        },
        duration: 1, // 动画持续时间,单位为秒
      });
    }
    flyToLocation(104.69, 30.2183873102, 5000);

三、学习资料参考(感谢大佬分享):

1、cesium中文网

Animation - Cesium Documentation

2、cesium编程入门 | cesium中文网

3、3.Cesium中实体Entity创建(超详细)_new cesium.entity-CSDN博客

转载请注明出处或者链接地址:https://www.qianduange.cn//article/23410.html
标签
arcgis
评论
发布的文章

linux常见操作命令

2025-03-05 18:03:10

GPT-4.5

2025-03-12 12:03:19

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!