Cesium简单案例

一、Cesium组件

1、HTML
<template>
  <div id="cesiumContainer">
    <!-- 地图工具栏 -->
    <ul class="mapTools">
      <li v-for="item in toolsData" :key="item.id" @click="toolsClick(item)">
        <!-- 显示label -->
        <el-tooltip
          v-if="item.id == 1"
          class="item"
          effect="dark"
          :content="item.label"
          placement="left">
          <span class="label">{{ item.text }}</span>
        </el-tooltip>

        <el-tooltip
          v-else
          class="item"
          effect="dark"
          :content="item.label"
          placement="left">
          <!-- 显示icon -->
          <span :class="item.icon" class="icon"></span>
        </el-tooltip>
      </li>
    </ul>

    <!-- 模型信息弹窗-全局注册 -->
    <Popup
      ref="Popup"
      :popupInfo="popupInfo"
      :popupPs="popupPs"
      @message="popupMsg"></Popup>
  </div>
</template>

2、Script
<script>
import * as turf from "@turf/turf";
export default {
  name: "Cesium",
  components: {
    Popup: () => import("./popup.vue"),
  },
  props: {},
  data() {
    return {
      // ----------------------<<地图>>----------------------
      // cesium相机初始位置
      ps: {
        lon: 100,
        lat: 30,
        height: 1000,
      },
      // 地图工具栏列表
      toolsData: [
        {
          id: 1,
          text: "2D",
          label: "2D/3D切换",
          icon: "",
        },
        {
          id: 2,
          label: "开始记录数据",
          icon: "el-icon-video-camera",
        },
        {
          id: 3,
          label: "隐藏模拟航迹",
          icon: "el-icon-s-promotion",
        },
        {
          id: 4,
          label: "暂停飞行",
          icon: "el-icon-video-pause",
        },
        {
          id: 5,
          label: "清除所有模型",
          icon: "el-icon-delete",
        },
      ],

      // -----------测试数据-----------
      // 是否创建测试模型
      isCreate: false,
      // 飞行时间
      flyTime: 0,
      // 点位数组
      pointArr: [
        {
          lon: 100.957787,
          lat: 30.739748,
          height: 100,
          time: 0,
        },
        {
          lon: 100.959787,
          lat: 30.739748,
          height: 100,
          time: 5,
        },
        {
          lon: 100.961787,
          lat: 30.739748,
          height: 100,
          time: 10,
        },
        {
          lon: 100.963787,
          lat: 30.739748,
          height: 100,
          time: 15,
        },
        {
          lon: 100.965787,
          lat: 30.739748,
          height: 100,
          time: 20,
        },
        {
          lon: 100.965787,
          lat: 30.737748,
          height: 100,
          time: 15,
        },
        {
          lon: 100.965787,
          lat: 30.735748,
          height: 100,
          time: 25,
        },
        {
          lon: 100.965787,
          lat: 30.733748,
          height: 100,
          time: 30,
        },
        {
          lon: 100.963787,
          lat: 30.733748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.961787,
          lat: 30.733748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.959787,
          lat: 30.733748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.957787,
          lat: 30.733748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.957787,
          lat: 30.735748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.957787,
          lat: 30.737748,
          height: 100,
          time: 35,
        },
        {
          lon: 100.957787,
          lat: 30.739748,
          height: 100,
          time: 35,
        },
      ],
      // 线条数组
      lineArr: [],
      // 起始时间
      start: "",
      // 结束时间
      stop: "",
      // -----------测试数据-----------

      // 弹窗详细信息
      popupInfo: {},
      // 弹窗位置
      popupPs: {
        x: 0,
        y: 0,
      },
      // 选中模型id
      selModelId: "",
    };
  },
  mounted() {
    // 初始化地图
    this.initMap();
    this.addArrow();
  },
  methods: {
    // -------------------------<<地图>>------------------------
    // 初始化地图
    initMap() {
      // 配置在线地图token
      Cesium.Ion.defaultAccessToken ="在线地图token";

      let imageryProvider;

      // 离线地图-nginx服务
      // const url = `http://127.0.0.1:9000`;
      // imageryProvider = new Cesium.UrlTemplateImageryProvider({
      //   url: `${url}/{z}/{x}/{y}.png`,
      // });

      //在线地图
      // if (window.navigator.onLine){}
      imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
        url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
      });

      window.viewer = new Cesium.Viewer("cesiumContainer", {
        geocoder: false, //右上角搜索
        homeButton: false, //右上角home
        sceneModePicker: false, //右上角2D/3D切换
        baseLayerPicker: false, //右上角地形
        navigationHelpButton: false, //右上角帮助
        animation: true, //左下角圆盘动画控件
        timeline: true, //底部时间轴
        fullscreenButton: false, //右下角全屏控件
        vrButton: false, //如果设置为true,将创建VRButton小部件。
        scene3DOnly: false, // 每个几何实例仅以3D渲染以节省GPU内存
        infoBox: false, //隐藏点击要素后的提示信息
        imageryProvider: imageryProvider, //地图地址
        selectionIndicator: false,
      });

      // 隐藏左下角商标信息
      viewer._cesiumWidget._creditContainer.style.display = "none";
      // 隐藏底部时间轴
      viewer.timeline.container.style.display = "none";
      viewer.scene.globe.depthTestAgainstTerrain = false; //开启深度检测

      // 设置最小缩放级别,以米为单位
      viewer.scene.screenSpaceCameraController.minimumZoomDistance = 500.0;

      // 设置最大缩放级别,以米为单位
      viewer.scene.screenSpaceCameraController.maximumZoomDistance = 20000000.0;

      // 隐藏动画控件
      const animationContainer = document.querySelector(
        ".cesium-viewer-animationContainer"
      );
      animationContainer.style.display = "none";

      // 自动播放动画
      viewer.clock.shouldAnimate = true;

      // 启用光照
      viewer.scene.globe.enableLighting = true;

      // 设置相机初始位置
      viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(
          this.ps.lon,
          this.ps.lat,
          this.ps.height
        ),
        // 设置相机方向,俯视和仰视的视角
        orientation: {
          heading: Cesium.Math.toRadians(0), //坐标系旋转0度
          pitch: Cesium.Math.toRadians(-90), //设置俯仰角度为-90度
        },
      });

      // --------<<鼠标事件>>--------
      // 移除左键双击默认事件
      // viewer.screenSpaceEventHandler.removeInputAction(
      //   Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
      // );
      // 注册左键单击事件
      this.leftClick();
      // 注册右键单击事件
      // this.rightClick();
      // 注册地图拖拽事件
      this.setMouseEvent();
      // 相机移动事件
      viewer.scene.camera.moveEnd.addEventListener(this.updatePopup);
      // 注册地图缩放事件
      this.setWheelEvent();
    },

    // -----------------------<<模型操作>>-----------------------
    // 创建新模型
    addModel(info) {
      if (viewer.entities.getById(info.desc.id)) {
        return;
      }

      // 转换笛卡尔空间直角坐标
      const position = new Cesium.Cartesian3.fromDegrees(
        info.desc.position.lon,
        info.desc.position.lat,
        info.desc.position.height
      );

      //模型朝向
      const heading = Cesium.Math.toRadians(90); // 方位
      const pitch = 0; // 俯仰
      const roll = 0; // 偏移角度
      const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
      const orientation = Cesium.Transforms.headingPitchRollQuaternion(
        position,
        hpr
      );

      // ++++++++++<<创建模型>>++++++++++
      const entity = viewer.entities.add({
        id: info.desc.id, //模型id
        name: info.type, // 模型名称,这里用作模型类型,方便模型增删改查
        position: position, //模型位置,高度
        orientation: orientation,
        model: {
          uri: info.desc.path, //模型文件
          minimumPixelSize: 50, //模型最小像素大小
          maximumScale: 100, //模型最大像素大小
          color: Cesium.Color.WHITE,
        },
        description: info.desc, // 模型详细信息
      });
    },

    // 创建点位
    addPoint(ps) {
      // 添加点位
      viewer.entities.add({
        name: "point", // 所属的父级id
        position: Cesium.Cartesian3.fromDegrees(
          ps.lon,
          ps.lat,
          ps.height // 高度可以自己定义,也可以根据传进来的高度进行绘制
        ),
        point: {
          pixelSize: 5,
          // 点位颜色,fromCssColorString 可以直接使用CSS颜色
          color: Cesium.Color.fromCssColorString("tomato"),
          // 边框颜色
          outlineColor: Cesium.Color.fromCssColorString("#fff"),
          // 边框宽度(像素)
          outlineWidth: 2,
          // 显示在距相机的距离处的属性,多少区间内是可以显示的
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
            0,
            15000000
          ),

          // 是否开启深度监测
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
      });
    },

    // 创建线条
    addLine() {
      if (this.lineArr.length == 0) {
        return;
      }

      // 航迹线id
      let id = `line`;

      viewer.entities.add({
        id, //  模型id
        name: "line", // 所属的父级id
        // polyline 折线
        polyline: {
          // 参数依次为[经度1, 纬度1, 高度1, 经度2, 纬度2, 高度2]
          positions: Cesium.Cartesian3.fromDegreesArrayHeights(this.lineArr),
          // 注:线条起止,可以获取鼠标点击位置的经纬度进行线条绘制

          // 宽度
          width: 2,

          // 线的颜色
          material: Cesium.Color.fromCssColorString("tomato"), //  "tomato"

          clampToGround: false, // 不紧贴地面

          // 线的顺序,仅当`clampToGround`为true并且支持地形上的折线时才有效。
          zIndex: 999,

          // 显示在距相机的距离处的属性,多少区间内是可以显示的
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
            0,
            15000000
          ),

          // 是否显示
          show: true,
        },
      });
    },

    // 添加箭头
    addArrow() {
      let arr = [0, 45, 90, 135, 180, -135, -90, -45];
      var pixelOffset, endPs, entity, labelEntity;
      arr.forEach((item) => {
        // 计算箭头结束点
        endPs = this.calcArrowEndPosition([100.9621, 30.7368], 0.1, item);

        entity = viewer.entities.add({
          polyline: {
            name: "arrow",
            positions: [
              Cesium.Cartesian3.fromDegrees(100.9621, 30.7368),
              Cesium.Cartesian3.fromDegrees(endPs.lon, endPs.lat),
            ],
            width: 10,
            material: new Cesium.PolylineArrowMaterialProperty(
              Cesium.Color.CYAN
            ),
            vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT,
          },
          // 显示在距相机的距离处的属性,多少区间内是可以显示的
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
            0,
            15000000
          ),
        });

        // 调整label偏移位置
        if (item == 45 || item == -45 || item == 0) {
          pixelOffset = new Cesium.Cartesian2(0, -10);
        } else if (item == 135 || item == -135 || item == 180) {
          pixelOffset = new Cesium.Cartesian2(0, 10);
        } else if (item == 90) {
          pixelOffset = new Cesium.Cartesian2(20, 0);
        } else if (item == -90) {
          pixelOffset = new Cesium.Cartesian2(-20, 0);
        }

        // 创建标签实体
        labelEntity = viewer.entities.add({
          position: Cesium.Cartesian3.fromDegrees(endPs.lon, endPs.lat), // 点位坐标
          point: {
            pixelSize: 0, // 点位大小
            color: Cesium.Color.WHITE.withAlpha(0), // 点位颜色,透明
          },
          label: {
            text: `${item}度`, // 文本内容
            font: "18px monospace", // 字体样式
            style: Cesium.LabelStyle.FILL_AND_OUTLINE, // label样式
            outlineWidth: 2, // 外边框宽度
            verticalOrigin: Cesium.VerticalOrigin.CENTER, // 文字对齐方式BOTTOM,TOP,CENTER
            pixelOffset: pixelOffset, // (0:经度偏移,0:纬度偏移)
          },
        });
        labelEntity.label.fillColor = Cesium.Color.WHITE; // 设置填充颜色为白色
        labelEntity.label.outlineColor = Cesium.Color.RED; // 设置轮廓颜色为红色
      });
    },

    // 计算箭头结束点
    calcArrowEndPosition(ps, range, angel) {
      var pt = turf.point(ps, { "marker-color": "F00" }); // 起始点
      var distance = range; // 距离
      var bearing = angel; // 角度
      var options = { units: "miles" }; // 英里
      var destination = turf.rhumbDestination(pt, distance, bearing, options);

      return {
        lon: destination.geometry.coordinates[0],
        lat: destination.geometry.coordinates[1],
      };
    },

    // 根据id删除模型
    removeEntitiesById(id) {
      // 根据id获取实体
      let entities = viewer.entities.getById(id);
      // 删除实体
      viewer.entities.remove(entities);
    },

    // 删除所有模型
    delAllModel() {
      // 删除所有模型
      viewer.entities.removeAll();

      // 关闭popup
      this.$refs.Popup.closePopup();

      this.lineArr = [];

      if (this.isCreate) {
        this.addTrack();
        this.addModels();
      }
    },

    // 选中模型
    clickModel(id, type, row = {}) {
      // 取消选中模型
      this.cancelPopup();

      // 选中模型id
      this.selModelId = id;

      // 获取点击模型的实体
      let entities = viewer.entities.getById(id);

      // 点击模型添加选中颜色
      entities.model.color = Cesium.Color.RED;

      switch (type) {
        case 1:
          // 显示弹窗
          this.$refs.Popup.openPopup();
          break;
        case 2:
          // 获取模型信息
          this.popupInfo = JSON.parse(JSON.stringify(row));

          // 获取cartesian3坐标
          const cartesian3 = Cesium.Cartesian3.fromDegrees(
            row.position.lon,
            row.position.lat,
            row.position.height
          );

          // cartesian3转换为cartesian2坐标(屏幕坐标)
          this.popupPs = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
            viewer.scene,
            cartesian3
          );

          // 显示弹窗
          this.$refs.Popup.openPopup();
          break;
      }
    },

    // 取消选中模型
    cancelPopup() {
      this.selModelId = "";

      // 获取所有模型的实体集合
      const entitiesArr = viewer.entities.values;

      if (entitiesArr.length !== 0) {
        // 取消所有模型选中颜色
        for (let i = 0; i < entitiesArr.length; i++) {
          if (entitiesArr[i]._name == "model") {
            entitiesArr[i].model.color = Cesium.Color.WHITE;
          }
        }
      }

      // 关闭消息显示框
      this.$refs.Popup.closePopup();
    },

    // -----------------------<<鼠标事件>>-----------------------
    // 左键单击
    leftClick() {
      // 添加用户输入监听范围(element)
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

      // 处理用户输入事件
      handler.setInputAction((event) => {
        let pick = viewer.scene.pick(event.position);

        if (Cesium.defined(pick)) {
          if (pick.id._name !== "model") {
            return;
          }

          // 选中模型样式
          this.clickModel(pick.id._id, 1);

          // 获取模型信息
          this.popupInfo = JSON.parse(
            JSON.stringify(pick.id._description._value)
          );

          // 获取cartesian3坐标
          const cartesian3 = pick.id._position._value;

          // cartesian3转换为cartesian2坐标(屏幕坐标)
          this.popupPs = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
            viewer.scene,
            cartesian3
          );
        } else {
          this.cancelPopup();
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    },

    // 右键单击
    rightClick() {
      // 添加用户输入监听范围(element)
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      // 处理用户输入事件
      handler.setInputAction((event) => {
        // 获取pick拾取对象
        let pick = viewer.scene.pick(event.position);
        // 判断是否获取到了pick,获取到了,拾取模型信息,未获取到,添加点位
        if (!Cesium.defined(pick)) {
          const position = viewer.scene.camera.pickEllipsoid(
            event.position,
            viewer.scene.globe.ellipsoid
          );

          // 笛卡尔坐标转弧度
          let cartographic = Cesium.Cartographic.fromCartesian(
            position,
            viewer.scene.globe.ellipsoid,
            new Cesium.Cartographic()
          );

          // Cesium.Math.toDegrees 弧度转度,将弧度转换成经纬度
          let lon = Cesium.Math.toDegrees(cartographic.longitude);
          let lat = Cesium.Math.toDegrees(cartographic.latitude);

          console.log(lon + "," + lat);

          // 创建点位
          this.addPoint({
            lon,
            lat,
            height: 10,
          });

          // 存储点位
          this.pointArr.push({
            lon,
            lat,
            height: 10,
            time: "",
          });
          // 存储线条点位
          this.lineArr.push(lon, lat, 10);
        }
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    },

    // 地图拖拽
    setMouseEvent() {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

      // *****注册鼠标右键按下事件*****
      handler.setInputAction((event) => {
        let pick = viewer.scene.pick(event.position);

        // *****注册鼠标移动事件*****
        viewer.screenSpaceEventHandler.setInputAction((arg) => {
          // 更新弹框位置
          this.updatePopup();
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

        // *****注册鼠标抬起事件*****
        viewer.screenSpaceEventHandler.setInputAction(({ position }) => {
          // *****解除viewer的MOUSE_MOVE事件监听器*****
          viewer.screenSpaceEventHandler.removeInputAction(
            Cesium.ScreenSpaceEventType.MOUSE_MOVE
          );

          // 解除相机锁定
          viewer.scene.screenSpaceCameraController.enableZoom = true;
        }, Cesium.ScreenSpaceEventType.LEFT_UP);
      }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
    },

    // 地图缩放事件
    setWheelEvent() {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

      // 处理用户输入事件
      handler.setInputAction((event) => {
        // 更新弹框位置
        this.updatePopup();
      }, Cesium.ScreenSpaceEventType.WHEEL);
    },

    // 鼠标双击事件
    leftDoubleClick() {
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

      // 处理用户输入事件
      handler.setInputAction((event) => {
        let pick = viewer.scene.pick(event.position);

        if (Cesium.defined(pick)) {
        }
      }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
    },

    // -----------------------<<其他操作>>-----------------------
    // 更新信息弹框位置
    updatePopup() {
      // 获取选中模型
      if (!this.selModelId) {
        return;
      }

      let entities = viewer.entities.getById(this.selModelId);

      this.popupPs = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
        viewer.scene,
        entities._position._value
      );
    },

    // 子组件消息
    popupMsg() {
      // 取消选中模型
      this.cancelPopup();
    },

    // 工具栏点击事件
    toolsClick(item) {
      switch (item.id) {
        case 1: // 2D/3D切换
          if (item.text == "3D") {
            item.text = "2D";

            // 切换为3D
            viewer.scene.morphTo3D(0);
          } else {
            item.text = "3D";

            // 切换为2D
            viewer.scene.morphTo2D(0);
          }
          break;

        case 2: // 数据记录
          if (item.icon == "el-icon-video-camera") {
            item.icon = "el-icon-video-camera-solid";
            item.label = "停止记录数据";

            this.$message.success("开始记录数据");
          } else {
            item.icon = "el-icon-video-camera";
            item.label = "开始记录数据";

            this.$message.success("停止记录数据");
          }

          break;

        case 3: // 隐藏模拟航迹
          // 获取所有模型的实体集合
          const entitiesArrS = viewer.entities.values;

          // 临时数组
          const tempS = [];

          // 将模型实体深拷贝
          if (entitiesArrS.length !== 0) {
            for (let i = 0; i < entitiesArrS.length; i++) {
              if (
                entitiesArrS[i]._name == "point" ||
                entitiesArrS[i]._id == "line"
              ) {
                tempS.push(entitiesArrS[i]);
              }
            }
          }

          // 如果有航迹-隐藏航迹,否则显示航迹
          if (tempS.length !== 0) {
            item.icon = "el-icon-position";
            item.label = "显示模拟航迹";

            // 航迹点清空
            this.lineArr = [];

            // 删除航迹点
            tempS.forEach((item) => {
              this.removeEntitiesById(item._id);
            });
          } else {
            item.icon = "el-icon-s-promotion";
            item.label = "隐藏模拟航迹";

            // 添加航迹
            this.addTrack();
          }
          break;

        case 4: // 飞机飞行控制
          // 停止动画
          if (viewer.clock.multiplier == 1) {
            viewer.clock.multiplier = 0;
            item.icon = "el-icon-video-play";
            item.label = "继续飞行";
          } else {
            viewer.clock.multiplier = 1;
            item.icon = "el-icon-video-pause";
            item.label = "暂停飞行";
          }
          break;

        case 5: // 清除所有模型
          this.delAllModel();
          break;
      }

      this.cancelPopup();
    },

    // ----------<<自动飞行测试>>----------
    addTrack() {
      if (this.lineArr.length !== 0) {
        return;
      }
      // 创建航迹点
      for (let i = 0; i < this.pointArr.length; i++) {
        // 绘制点位
        this.addPoint({
          lon: this.pointArr[i].lon,
          lat: this.pointArr[i].lat,
          height: this.pointArr[i].height,
        });

        // 存储点位绘制航迹
        this.lineArr.push(
          this.pointArr[i].lon,
          this.pointArr[i].lat,
          this.pointArr[i].height
        );
      }

      // 绘制航迹
      this.addLine();
    },
    addModels() {
      this.isCreate = true;
      // 计算时间飞行数据
      let property = this.computeFlight(this.pointArr);

      // ++++++++++<<创建模型>>++++++++++
      const entity = viewer.entities.add({
        id: `testModel`, //模型id
        name: "model", // 模型名称,这里用作模型类型,方便场景模型增删改查
        // 和时间轴关联
        availability: new Cesium.TimeIntervalCollection([
          new Cesium.TimeInterval({
            start: this.start,
            stop: this.stop,
          }),
        ]),
        position: property, //模型位置,高度
        orientation: new Cesium.VelocityOrientationProperty(property),
        model: {
          uri: "./Cesium/model/air/test1.gltf", //模型文件
          minimumPixelSize: 80, //模型最小像素大小
          maximumScale: 100, //模型最大像素大小
        },
      });
    },
    // 移动
    modelMove() {
      if (this.lineArr.length == 0) {
        return;
      }

      for (let i = 0; i < this.pointArr.length; i++) {
        this.pointArr[i].time = this.flyTime;

        this.flyTime += 3;
      }

      // 起始时间
      this.start = Cesium.JulianDate.fromDate(new Date());
      // 结束时间
      this.stop = Cesium.JulianDate.addSeconds(
        this.start,
        this.pointArr[this.pointArr.length - 1].time,
        new Cesium.JulianDate()
      );

      // 设置始时钟始时间
      viewer.clock.startTime = this.start.clone();
      // 设置时钟当前时间
      viewer.clock.currentTime = this.start.clone();
      // 设置始终停止时间
      viewer.clock.stopTime = this.stop.clone();
      // 时间速率,数字越大时间过的越快
      viewer.clock.multiplier = 1;
      // 时间轴
      viewer.timeline.zoomTo(this.start, this.stop);
      // 循环执行,即为2,到达终止时间,重新从起点时间开始LOOP_STOP
      // viewer.clock.clockRange = Cesium.ClockRange.CLAMPED;
      viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;

      // 创建模型
      this.addModels();
    },
    // 计算飞行
    computeFlight(source) {
      // 取样位置 相当于一个集合
      let property = new Cesium.SampledPositionProperty();
      for (let i = 0; i < source.length; i++) {
        let time = Cesium.JulianDate.addSeconds(
          this.start,
          source[i].time,
          new Cesium.JulianDate()
        );
        let position = Cesium.Cartesian3.fromDegrees(
          source[i].lon,
          source[i].lat,
          source[i].height
        );
        // 添加位置,和时间对应
        property.addSample(time, position);
      }
      return property;
    },
    // ----------<<自动飞行测试>>----------
  },
};
</script>

3、Css
<style lang="less" scoped>
#cesiumContainer {
  width: 100%;
  height: 100%;
  position: relative;

  .mapTools {
    position: absolute;
    top: 10px;
    right: 10px;
    border-radius: 5px;
    // background: rgba(255, 255, 255, 0.9);
    background-color: rgba(#001c22, 0.8);
    z-index: 999;

    li {
      width: 35px;
      height: 35px;
      color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      border-radius: 5px;
      cursor: pointer;

      .icon {
        font-size: 20px;
      }

      &:hover {
        background: #087b7a;
        color: #fff;
      }
    }
  }
}
</style>

二、Popup组件

1、HTML
<template>
  <div
    class="cesiumPopup"
    :style="{ top: popupPs.y + 'px', left: popupPs.x + 'px' }"
    v-if="show">
    <!-- 头部 -->
    <ul class="head">
      <li>
        <span>设备信息</span>
      </li>
      <li>
        <span class="el-icon-close" @click="closePopup"></span>
      </li>
    </ul>

    <!-- 模型内容 -->
    <ul class="content">
      <li>
        <span class="subTitle">模型标识</span>
        <span class="subValue">{{ popupInfo.id }}</span>
      </li>
      <li>
        <span class="subTitle">模型名称</span>
        <span class="subValue">{{ popupInfo.name }}</span>
      </li>
      <li>
        <span class="subTitle">模型地址</span>
        <span class="subValue">{{ popupInfo.ip }}</span>
      </li>
      <li>
        <span class="subTitle">模型端口</span>
        <span class="subValue">{{ popupInfo.port }}</span>
      </li>
      <li>
        <span class="subTitle">模型位置</span>
        <span class="subValue">{{
          `${filterNumber(popupInfo.position.lon, 6)},${filterNumber(
            popupInfo.position.lat,
            6
          )},${popupInfo.position.height}`
        }}</span>
      </li>
      <li>
        <span class="subTitle">模型状态</span>
        <span
          class="subValue"
          :style="popupInfo.status == 1 ? 'color:#04F44C' : 'color:#F52E2E'"
          >{{ popupInfo.status == 1 ? "正常" : "异常" }}</span
        >
      </li>
    </ul>
  </div>
</template>

2、Script
<script>
export default {
  name: "Popup",
  components: {},
  props: {
    popupInfo: {
      type: Object,
      default: () => {
        return {
          id: "",
          position: {
            lon: "",
            lat: "",
            alt: "",
          },
          status: "",
          ip: "",
          isSelect: "",
          name: "",
          port: "",
        };
      },
    },
    popupPs: {
      type: Object,
      default: () => {
        return {
          x: 0,
          y: 0,
        };
      },
    },
  },
  data() {
    return {
      show: false,
    };
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {
    openPopup() {
      this.show = true;
    },
    closePopup() {
      this.show = false;
    },
    // 过滤数据
    filterNumber(val, digit) {
      return val.toFixed(digit);
    },
  },
};
</script>

3、Css
<style lang="less" scoped>
.cesiumPopup {
  min-width: 300px;
  position: absolute;
  transform: translate(-50%, -130%);
  z-index: 1;
  background-color: rgba(#001c22, 0.8);
  color: #fff;
  font-size: 12px;
  box-sizing: border-box;

  .head {
    height: 30px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    background-color: #048197;
    padding: 0px 10px;
    box-sizing: border-box;
    box-shadow: inset -2px 0px 2px rgba(#333, 0.5),
      inset 2px 2px 2px rgba(#fff, 0.5);

    .el-icon-close {
      font-size: 16px;
      cursor: pointer;

      &:hover {
        color: tomato;
      }
    }
  }

  .content {
    height: 85%;
    padding: 10px;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    box-shadow: inset -2px -2px 2px rgba(#333, 0.5),
      inset 2px 0px 2px rgba(#5696a2, 0.7);

    li {
      margin: 5px 0px;
      display: flex;
      align-items: center;

      .subTitle {
        width: 20%;
        display: inline-block;
        background-color: #013946;
        border: 1px solid #119ea0;
        margin-right: 5px;
        padding: 1px 5px;
      }
      .subValue {
        width: 80%;
        display: inline-block;
        border: 1px solid #119ea0;
        box-sizing: border-box;
        padding: 1px 5px;
      }
    }
  }
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

提升测试效率,专业方案揭秘

提升测试效率是软件开发中一个永恒的主题&#xff0c;它不仅关乎项目能否按期完成&#xff0c;更影响着软件产品的质量与用户体验。随着敏捷开发、持续集成等方法论的普及&#xff0c;如何在有限的时间内进行高效、全面的测试成为了开发者和测试人员面临的挑战。 在传统模式中&…

Windows 平台上面管理服务器程式的高级 QoS 策略

在 Windows 平台上面&#xff0c;目前有两个办法来调整应用程式的 QoS 策略设置&#xff0c;一种是通过程式设置&#xff0c;一种是通过 “Windows 组策略控制”。 在阅读本文之前&#xff0c;您需要先查阅本人以下的几篇文献&#xff0c;作为前情提示&#xff1a; VC Windows…

数据质量与策略:解锁生成式AI潜力的关键步骤

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

每日一题(L2-011):玩转二叉树--建树+层序遍历

与L2-006近乎相同&#xff0c;先建树&#xff0c;然后遍历 #include<bits/stdc.h> using namespace std; int in[35]; int pre[35]; typedef struct Tree{int num;Tree* left;Tree* right; }T;T * build(int in1,int in2,int pre1,int pre2){T * tnew T;t->numpre[pr…

战姬物语部署

一.准备环境 #关闭seliunx和防火墙 setenforce 0 systemctl stop firewalld systemctl disable firewalld #配置源&#xff0c;并安装常用工 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo curl -o /etc/yum.repos.d/epel.repo …

Leetcode 86. 分隔链表

题目链接&#xff1a; 86. 分隔链表 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/partition-list/description/ 题目&#xff1a; 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出…

深入探究图像增强(C语言实现)

我们将从基础出发使用C语言进行图像处理与分析&#xff0c;重点讨论图像增强和平滑技术。图像增强技术旨在通过增加对比度、亮度和整体清晰度来改善图像的视觉质量。另一方面&#xff0c;图像平滑方法则用于减少噪声并减少图像中的突变&#xff0c;使图像更加均匀和视觉上吸引人…

利用二维码定位技术实现桌面机器人简易定位方案(上篇)

目录 1、前言2、二维码的定位标签识别原理3、生成定位标签3、基于定位标签的物体识别与定位 1、前言 机械手臂尤其是工业场景下大部分的应用是在一个平面&#xff08;桌面&#xff09;内完成一些抓取工作。一般可以用示教方式完成重复步骤。但是示教方式&#xff0c;对于一些活…

过氧化氢滴定方法可用的PFA器皿有哪些?

滴定液:KMnO4标准溶液 试液:H2O2商品液(3%)&#xff0c;H2SO4 (3.0mol/L ) 指示剂:酚酞指示剂 仪器:分析天平&#xff0c;PFA酸式滴定管50mL&#xff0c;PFA 移液管10mL/25mL、PFA 容量瓶250mL、PFA锥形瓶250mL 1、KMnO4标准溶液浓度的标定(见实验:高锰酸钾标准溶液的配制与…

记一次普通的单表查询sql优化,去掉文件排序

一现象&#xff1a; 有空观察了线上某个sql语句执行计划&#xff0c;发现在500多毫秒左右&#xff0c;打算进行下优化。 二步骤&#xff1a; 对查询列assessment_periodic_id、assessment_user_id、create_time添加了组合索引并指定了倒叙。加入create_time 使查询结果不需要在…

阿里云OSS 存储对象的注册与使用

目录 一、什么是阿里云OSS 二、 点击免费试用 2.1 选择第一个&#xff0c;点击免费试用 ​编辑 2.2 登录管理控制台 2.3 进入Bucket 2.4、在阿里云网站上的个人中心配置Accesskey,查询accessKeyId和accessKeySecret。 2.5、进入AccssKey管理页面应该会出现下图提示&…

通用大模型研究重点之五:llama family

LLAMA Family decoder-only类型 LLaMA&#xff08;Large Language Model AI&#xff09;在4月18日公布旗下最大模型LLAMA3&#xff0c;参数高达4000亿。目前meta已经开源了80亿和700亿版本模型&#xff0c;主要升级是多模态、长文本方面工作。 模型特点&#xff1a;采用标准的…

Java面试八股之Java异常处理完成后,Exception对象会发生什么变化

Java异常处理完成后&#xff0c;Exception对象会发生什么变化 这个题的难度在于&#xff0c;看到题之后可能不知道面试官想问什么。在面试中&#xff0c;如果实在没明白&#xff0c;可以让面试官再深入阐述一下。 Java异常处理完成后&#xff0c;Exception对象失去了程序中的…

自定义Blazor单文件Web程序端口

#接 上篇 Mysql快速迁移版的制作过程# 上一篇《Mysql8快速迁移版的制作过程》完成了快速迁移的数据库的准备&#xff0c;今天接着讲基于Blazor的Web程序快速迁移版的制作。 单文件发布的难点不在发布而是因为程序系统默认给了个5001的端口&#xff0c;而是如何能够让用户自定…

Leetcode 11.盛最多水的容器(暴力->双指针)

给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。 示例 …

Postman调用OpenApi接口

首先你需要科学上网。。。。。 请求方式&#xff1a;post 请求地址&#xff1a;https://api.openai.com/v1/chat/completions 请求头&#xff1a; Authorization : Bearer key Content-Type : application/json Body : { "messages": [{ "role": &quo…

【精简改造版】大型多人在线游戏BrowserQuest服务器Golang框架解析(1)——功能清单

1.匿名登录 2.服务连接 3.新手引导 4.随机出生点 5.界面布局 6.玩法帮助 7.NPC会话 8.成就系统 9.成就达成 10.用户聊天 11.战斗&信息展示 12.药水使用 13.副本传送 14.玩家死亡 15.超时断开

OpenHarmony 视图缩放组件—subsampling-scale-image-view

简介 深度缩放视图&#xff0c;图像显示&#xff0c;手势平移缩放双击等 效果图&#xff08;旋转、缩放、平移&#xff09; 下载安装 ohpm install ohos/subsampling-scale-image-view OpenHarmony ohpm 环境配置等更多内容&#xff0c;请参考如何安装 OpenHarmony ohpm 包 使…

Servlet第四篇【request对象常用方法、应用】

什么是HttpServletRequest HttpServletRequest对象代表客户端的请求&#xff0c;当客户端通过HTTP协议访问服务器时&#xff0c;HTTP请求头中的所有信息都封装在这个对象中&#xff0c;开发人员通过这个对象的方法&#xff0c;可以获得客户这些信息。 简单来说&#xff0c;要得…

mysql四种引擎区别

MySQL 提供了多种不同的数据库引擎&#xff0c;其中最常见的有 MyISAM、InnoDB、MEMORY 和 BLACKHOLE。这四个引擎分别有以下特点&#xff1a; 1. MyISAM MyISAM 是 MySQL 的默认引擎。它对于只有较少的修改、大量读取的应用场景具有良好的性能。它不支持事务处理&#xff0c;也…