Vue3 结合 Cesium 动态绘制矩形

相关概念

  • Viewer:new Cesium.Viewer (container, options )

  • 介绍:用于构建应用程序的基本小部件。它将所有标准Cesium小部件组合到一个可重用的程序包中。

  • Entity:new Cesium.Entity ( options )

  • 介绍:实体实例将多种形式的可视化聚集到单个高级对象中。可以手动创建它们并将其添加到 Viewer#entities 

  • rectangle:略

  • 介绍:描述 Rectangle 的图形。矩形符合地球的曲率,可以放置在表面或可以选择将其挤出成一定体积。

  • coordinates:Cesium.Rectangle.fromDegrees ( west , south , east , north , result )

  • 介绍:定义了矩形的坐标

  • material:略

  • 介绍:定义了矩形的材质


demo效果


完整代码展示

其中用到了EventBus来进行组件通讯,来触发相应的逻辑,大家可以用点击事件等来代替。

<template>
  <div id="CesiumMapOne"></div>
  <div class="cesium-lnglat-info" v-show="showLngLat">
    {{ lngNum }},{{ latNum }}
  </div>
</template>

<script setup>
// vue
import {
  ref,
  reactive,
  watch,
  watchEffect,
  computed,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  defineProps,
  defineEmits,
} from "vue";

// cesium
import * as Cesium from "cesium";

import "cesium/Build/CesiumUnminified/Widgets/widgets.css";

window.CESIUM_BASE_URL = "../../../node_modules/cesium/Build/CesiumUnminified/";

// eventbus
import EventBus from "@/eventbus";


// 变量
let _viewer = null;

// 经纬度
let lngNum = ref(0);
let latNum = ref(0);

// 是否显示经纬度
let showLngLat = ref(false);

// 裁剪AOI
let drawFlag = false;
// 开始点击位置
let startPoint = null;
// 结束点击位置
let endPoint = null;
// 绘制动态矩形数组
let pointsArr = [];
// 裁剪矩形 实体
let JXBox = null;

// 初始化地图
function initMap() {
  Cesium.Ion.defaultAccessToken =
    "在这里输入你在Cesium申请的开发token";
  //开发token


  const viewer = new Cesium.Viewer("CesiumMapOne", {
    //第二个参数是个对象

    // terrainProvider: Cesium.createWorldTerrainAsync(),
    // 地形服务
    timeline: false,
    // 时间轴控件
    animation: false,
    // 动画控件
    geocoder: false,
    //搜索框控件
    navigationHelpButton: false,
    // 帮助按钮
    sceneModePicker: true,
    // 场景模式选择器
    fullscreenButton: false,
    // 全屏按钮
    baseLayerPicker: false,
    // 底图选择器
    infoBox: false,
    // 信息框
    selectionIndicator: false,
    // 选中指示器
    homeButton: false,
    // 首页按钮
    // scene3DOnly: true,
    // 3D模式
    // creditContainer: "cesiumjsdiv",
    // 显示版权信息
    // creditViewport:"cesiumjsdiv",
    // 显示版权信息
  });
  //关键的一步,之后所有的API从这里开始

  _viewer = viewer;

  // Cesium鼠标移动事件
  _viewer.screenSpaceEventHandler.setInputAction(function (movement) {
    //获取当前鼠标位置
    var cartesian = _viewer.camera.pickEllipsoid(
      movement.endPosition,
      _viewer.scene.globe.ellipsoid
    );
    //判断鼠标位置是否在模型上
    if (cartesian) {
      //获取当前鼠标位置的经纬度
      let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
      // console.log(cartographic, "当前鼠标位置");
      let longitude = Cesium.Math.toDegrees(cartographic.longitude);
      let latitude = Cesium.Math.toDegrees(cartographic.latitude);

      showLngLat.value = true;

      if (longitude < 0) {
        lngNum.value = Math.abs(longitude).toFixed(6) + "°W";
      } else {
        lngNum.value = longitude.toFixed(6) + "°E";
      }

      if (latitude < 0) {
        latNum.value = Math.abs(latitude).toFixed(6) + "°S";
      } else {
        latNum.value = latitude.toFixed(6) + "°N";
      }

      if (drawFlag) {
        endPoint = {
          lng: longitude,
          lat: latitude,
        };
        
        //这段代码允许 以任意方向来动态绘制矩形
        if (endPoint.lng < startPoint.lng && endPoint.lat > startPoint.lat) {
          // 第二象限
          pointsArr = Cesium.Rectangle.fromDegrees(
            endPoint.lng,
            startPoint.lat,
            startPoint.lng,
            endPoint.lat
          );
        } else if (
          endPoint.lng > startPoint.lng &&
          endPoint.lat > startPoint.lat
        ) {
          // 第一象限
          pointsArr = Cesium.Rectangle.fromDegrees(
            startPoint.lng,
            startPoint.lat,
            endPoint.lng,
            endPoint.lat
          );
        } else if (
          endPoint.lng < startPoint.lng &&
          endPoint.lat < startPoint.lat
        ) {
          // 第三象限
          pointsArr = Cesium.Rectangle.fromDegrees(
            endPoint.lng,
            endPoint.lat,
            startPoint.lng,
            startPoint.lat
          );
        } else {
          // 第四象限
          pointsArr = Cesium.Rectangle.fromDegrees(
            startPoint.lng,
            endPoint.lat,
            endPoint.lng,
            startPoint.lat
          );
        }
      }
    } else {
      showLngLat.value = false;
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}

// 开始绘制矩形 函数
function clipAoi() {
  //鼠标左点击 事件
  _viewer.screenSpaceEventHandler.setInputAction(function (e) {
    // 获取鼠标点击位置
    let cartesian = _viewer.camera.pickEllipsoid(
      e.position,
      _viewer.scene.globe.ellipsoid
    );
    // 判断 是否作用在地球上
    if (cartesian && !drawFlag) {
      // 获取经纬度
      let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
      let longitude = Cesium.Math.toDegrees(cartographic.longitude);
      let latitude = Cesium.Math.toDegrees(cartographic.latitude);

      // 获取当前相机高度
      // let height = _viewer.camera.positionCartographic.height;

      startPoint = {
        lng: longitude,
        lat: latitude,
      };

      drawFlag = true;

      // 初始化矩形
      pointsArr = Cesium.Rectangle.fromDegrees(0, 0, 0, 0);

      //删除矩形实体
      if (JXBox) {
        _viewer.entities.remove(JXBox);
      }

      // 添加动态矩形实体
      JXBox = _viewer.entities.add({
        rectangle: {
          coordinates: new Cesium.CallbackProperty(() => {
            return pointsArr;
          }, false),
          material: Cesium.Color.fromCssColorString("rgba(0, 255, 255, .5)"),
          outline: true, //多边形是否显示边缘线
          outlineColor: Cesium.Color.YELLOW.withAlpha(0.8), //定义多边形边缘线的颜色。
          outlineWidth: 2, //控制多边形边缘线的宽度。
          height: 5, //指定多边形相对于椭球表面的高度。
          extrudedHeight: 10, //创建一个拉伸的多边形(即具有高度的立体),可以设置此参数为多边形顶部的高度。
        },
      });
    } else if (cartesian && drawFlag) {
      drawFlag = false;

      EventBus.emit("drawOK", pointsArr);
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

// 重置矩形函数
function resetAoi() {
  if (JXBox) {
    _viewer.entities.remove(JXBox);
  }
  // 移除 Cesium 的鼠标左点击事件
  _viewer.screenSpaceEventHandler.removeInputAction(
    Cesium.ScreenSpaceEventType.LEFT_CLICK
  );
  //
  EventBus.emit("resetAoi");
}

// 页面挂载后
onMounted(() => {
  initMap();

  EventBus.on("header", (data) => {
    console.log(data, "header-msg");
    // 触发 对应逻辑
    switch (data) {
      case "裁剪AOI":
        clipAoi();
        break;
      case "重置AOI":
        resetAoi();
        break;

      default:
        break;
    }
  });
});

// 页面销毁前
onBeforeUnmount(() => {
  //   销毁
  EventBus.off("header");
  if (_viewer) {
    _viewer.destroy();
  }
});
</script>

<style lang="scss" scoped>
#CesiumMapOne {
  width: 100%;
  height: 100%;

  overflow: hidden;
}

.cesium-lnglat-info {
  width: 290px;
  height: 46px;

  font-weight: 600;
  font-size: 18px;
  color: #3bde80;

  display: flex;
  justify-content: center;
  align-items: center;

  border-radius: 23px;
  border: 1px solid #fff;

  background-color: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(10px);
  /* 背景模糊效果 */

  position: absolute;
  bottom: 30px;
  right: 30px;

  z-index: 10;
}
</style>

部分代码描述

  • coordinates是矩形的坐标,它使用callbackProperty来动态更新

  • callbackProperty是一个特殊的属性类型,用于允许属性值动态更新。回调函数返回的是 pointsArr,它表示矩形的坐标数组。

  • 第二个参数 false 表示该回调函数的更新频率是静态的(即不需要每帧都更新),只有当 this.posArr 发生变化时才会重新计算。

Vue 3 和 Cesium 结合可以用来构建交互式的3D地图应用,Cesium是一个强大的WebGL库,专门用于渲染卫星图像、地形和其他地理信息。在 Vue 3 中集成 Cesium,你可以按照以下步骤操作: 1. **安装依赖**:首先,你需要通过npm或yarn安装`@cesium/cesium`库,以及可能需要的Vue CLI插件,如`vue-cesium`或`vue3-cesium`。 ```bash npm install @cesium/cesium vue-cesium (或其他推荐的Vue组件) ``` 2. **创建组件**:在Vue组件中,你会创建一个Cesium视口(viewport)或者其他Cesium元素,然后将`Cesium Viewer`初始化。 ```vue <template> <div> <cesium-viewer :url="cesiumUrl" :options="viewerOptions"></cesium-viewer> </div> </template> <script> import { defineComponent, ref } from 'vue'; import CesiumViewer from '@cesium/cesium/Cesium/Widgets/ViewerWidget'; export default defineComponent({ props: { cesiumUrl: String, viewerOptions: Object, }, setup(props) { const viewer = ref(null); const initializeCesium = async () => { if (!viewer.value) { viewer.value = new CesiumViewer('cesiumContainer', props.viewerOptions); } }; onMounted(() => { initializeCesium(); }); onUnmounted(() => { viewer.value.destroyForCurrentView(); }); return { viewer }; }, }); </script> ``` 3. **配置选项**:`viewerOptions`应该包含地形数据提供商等必要的配置,如你在问题中提到的`new Cesium.CesiumTerrainProvider()`。 4. **管理数据和事件**:你可以通过`ref`来存储状态,监听Cesium的事件(如鼠标交互或加载完成)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值