jihongshun
2025-09-15 30b48fcf76bf2c8a5bdaa2ca5f539c6e905b2f73
优化时间轴中文 和右侧视角十字效果
已修改2个文件
225 ■■■■ 文件已修改
src/utils/components/cesium-map.vue 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/flightRouteSimulation/index.vue 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/components/cesium-map.vue
@@ -2,6 +2,22 @@
  <div :style="{height: cesiumContainer}">
    <div :id="cesiumId"></div>
     <CesiumCompass v-if="viewer  && showAnimation" :viewer="viewer" />
     <div id="crosshair"
      v-if="showCrosshair"
      style="
        position:absolute;
        left:50%;
        top:50%;
        transform:translate(-50%,-50%);
        pointer-events:none;  /* 不阻挡鼠标事件 */
      ">
        <svg viewBox="0 0 24 24" width="32" height="32" style="color:red;">
          <path d="M12 2v6M12 16v6M2 12h6M16 12h6"
                stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
          <circle cx="12" cy="12" r="1.5" fill="currentColor"/>
        </svg>
  </div>
  </div>
</template>
@@ -36,6 +52,10 @@
      default: false,
    },
    showCesiumCompass: {
      type: Boolean,
      default: false,
    },
    showCrosshair: {
      type: Boolean,
      default: false,
    },
@@ -172,7 +192,33 @@
      viewer.scene.globe.depthTestAgainstTerrain = true;
      viewer.scene.globe.showGroundAtmosphere = true;
      viewer.scene._hdr = false;
      if (viewer.timeline) {
        viewer.timeline.makeLabel = function(time) {
          let jsDate = Cesium.JulianDate.toDate(time);
          console.log(jsDate)
          let Y = jsDate.getFullYear();
          let M = (jsDate.getMonth() + 1).toString().padStart(2, '0');
          let D = jsDate.getDate().toString().padStart(2, '0');
          let h = jsDate.getHours().toString().padStart(2, '0');
          let m = jsDate.getMinutes().toString().padStart(2, '0');
          let s = jsDate.getSeconds().toString().padStart(2, '0');
          return `${Y}年${M}月${D}日 ${h}:${m}:${s}`;
        };
      }
      
      // ===== 修改左上角动画控件显示的时间 =====
      if (viewer.animation) {
        viewer.animation.viewModel.dateFormatter = function(julianDate, viewModel) {
          let jsDate = Cesium.JulianDate.toDate(julianDate); // 转成 JS Date
          let Y = jsDate.getFullYear();
          let M = (jsDate.getMonth() + 1).toString().padStart(2, '0');
          let D = jsDate.getDate().toString().padStart(2, '0');
          let h = jsDate.getHours().toString().padStart(2, '0');
          let m = jsDate.getMinutes().toString().padStart(2, '0');
          let s = jsDate.getSeconds().toString().padStart(2, '0');
          return `${Y}年${M}月${D}日 ${h}:${m}:${s}`;
        };
      }
      // 去掉entity的点击事件
      viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
src/views/system/flightRouteSimulation/index.vue
@@ -1,6 +1,6 @@
<template>
   <div class="app-container">
    <a @click="showGZ">显示视锥体</a>
    <!-- <a @click="showGZ">显示视锥体</a> -->
    <input @change="handleKMZUpload" type="file" id="kmzFile" accept=".kmz" class="block w-full text-sm text-gray-500
    file:mr-4 file:py-2 file:px-4
    file:rounded-md file:border-0
@@ -8,7 +8,7 @@
    file:bg-blue-50 file:text-blue-700
    hover:file:bg-blue-100">
    <CesiumMap style="height: 790px;" :showAnimation = true :showCesiumCompass = true :cesiumId="'cesiumContainer'"></CesiumMap>
    <CesiumMap style="height: 324px;width: 576px;" :showAnimation = false :showCesiumCompass = false :cesiumId="'cesiumContainerYY'" class="eagleye"></CesiumMap>
    <CesiumMap style="height: 324px;width: 576px;" :showAnimation = false :showCesiumCompass = false :showCrosshair = true :cesiumId="'cesiumContainerYY'" class="eagleye"></CesiumMap>
   </div>
</template>
@@ -110,7 +110,9 @@
      holderHeadingProperty : new Cesium.SampledProperty(Number),//云台朝向heading
      holderPitchProperty : new Cesium.SampledProperty(Number),//云台朝向pitch
      holderRollProperty : new Cesium.SampledProperty(Number),//云台朝向roll
      // flyHeadingProperty : new Cesium.SampledProperty(Number),//无人机heading
      holderZoomProperty : new Cesium.SampledProperty(Number),//变倍
      currentZoom:1,
      filename :''
    }
  },
  mounted() {
@@ -124,7 +126,7 @@
        this.waypoints = await this.parseKMZ(arrayBuffer);
        //加点逻辑 比如向第2-n-1中插入元素  经纬度为当前的  heading pitch roll 下一个的
        const dealArr = [];
        console.log(">> this.waypoints:", this.waypoints);
        // console.log(">> this.waypoints:", this.waypoints);
        for (let i = 0; i < this.waypoints.length - 1; i++) {
            dealArr.push(this.waypoints[i]); // Push the current element
            const current = this.waypoints[i];
@@ -136,28 +138,34 @@
                'flyHeading':next.flyHeading,
                "heading": current.heading,
                "pitch": current.pitch,
                "roll": current.roll
                "roll": current.roll,
                "zoom":next.zoom || 1
            });
        }
        // Push the last element without any change
        dealArr.push(this.waypoints[this.waypoints.length - 1]);
        console.log(dealArr)
        this.waypoints = dealArr
        console.log(">> this.waypoints:", this.waypoints);
        this.fileInfo = `
          航点:${this.waypoints.length}个 <br/>
          距离:${this.calculateTotalDistance(this.waypoints).toFixed(2)}公里
        `;
        this.showFlightPath()
        this.getTowerData()
        const startDate = new Date("2025-04-01T13:00:00Z");
        const speeds = [10, 10, 20, 30, 80, 100, 60, 50, 40, 30, 20, 10]; // 自定义速度
        // const startDate = new Date("2025-04-01T13:00:00Z");
        const match = this.filename.match(/(\d{4}-\d{2}-\d{2})_(\d{2}-\d{2}-\d{2})/);
        // const result = this.waypoints.map((item, index) => {
        console.log(result)
        if (match) {
          const datePart = match[1]; // 2025-09-08
          const timePart = match[2]; // 16-36-01
          // 替换时间部分的 '-' 为 ':'
          const isoString = `${datePart}T${timePart.replace(/-/g, ':')}Z`;
          var date = new Date(isoString);
        }
        // const startDate = new Date("2025-04-01T13:00:00Z");
        const startDate = new Date(date.toISOString());
        const result = dealArr.map((item, index) => {
        // const result = this.waypoints.map((item, index) => {
          // 每次加一天
@@ -173,22 +181,25 @@
            heading:item.heading|| 0,
            pitch:item.pitch|| 0,
            roll:item.roll || 0,
            // speed: speeds[index] || 0,
            speed: 80,
            zoom:item.zoom,
            flyHeading:item.flyHeading
          };
        });
        this.trajectoryData = result
        console.log(this.trajectoryData)
        // console.log(result);
        // console.log(this.trajectoryData)
        this.loadTimeLine()
      } catch (error) {
        console.error(error);
        this.fileInfo = `<p style="color:red">解析失败: ${error.message}</p>`;
      }
      setTimeout(()=>{
        this.showGZ()
      },1000)
    },
    // 读取文件为ArrayBuffer
    readFileAsArrayBuffer(file) {
      this.filename = file.name
      return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
@@ -212,7 +223,7 @@
      // xml2js 从 CDN 引入后是 window.xml2js
      const parser = new xml2js.Parser();
      const result = await parser.parseStringPromise(kmlContent);
      console.log(">> result:", result);
      // console.log(">> result:", result);
      const placemarks =
        result.kml.Document[0].Folder[0].Placemark || [];
@@ -223,13 +234,12 @@
        const height = placemark["wpml:height"]?.[0];
        // 提取 aircraftHeading
        // 提取 action 里的参数
        let heading = null;
        let gimbalPitch = null, gimbalRoll = null, gimbalYaw = null;
        // 初始化 Pitch, Roll 和 Heading
        let totalPitch = 0;
        let totalRoll = 0;
        let totalHeading = 0;
        let flyHeadingData = 0;
        let currentzoom = 1
        if (placemark["wpml:actionGroup"]?.[0]?.["wpml:action"]) {
          placemark["wpml:actionGroup"][0]["wpml:action"].forEach(action => {
            // 处理 gimbalRotate 和 rotateYaw 函数
@@ -243,29 +253,26 @@
                totalPitch += gimbalPitch;
                totalRoll += gimbalRoll;
                totalHeading += gimbalYaw;
                console.log('totalHeading里面循环' + totalHeading)
            }
            // 处理 rotateYaw 函数
            if (action['wpml:actionActuatorFunc'].includes("rotateYaw")) {
                // 获取 aircraftHeading
                const aircraftHeading = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:aircraftHeading"][0]);
                console.log(aircraftHeading)
                flyHeadingData = aircraftHeading
                // 将 aircraftHeading 累加到 totalHeading
                totalHeading += aircraftHeading;
                console.log('totalHeading外层外层外层外层外层循环' + totalHeading)
            }
            // 处理 rotateYaw 函数
            if (action['wpml:actionActuatorFunc'].includes("zoom")) {
               const aircraftHeading = parseFloat(action['wpml:actionActuatorFuncParam'][0]["wpml:focalLength"][0]);
                currentzoom = aircraftHeading
            }
          });
        }
        // 输出结果
      console.log("Total Pitch:", totalPitch);
      console.log("Total Roll:", totalRoll);
      console.log("Total Heading:", totalHeading);
        if (coords) {
          coords.trim().split(" ").forEach(coord => {
            console.log(coord)
            const [lng, lat] = coord.split(",").map(Number);
            points.push({ lng, lat, alt: height,heading:totalHeading  || 0,pitch:totalPitch || 0,roll:totalRoll|| 0 ,flyHeading:flyHeadingData});
            points.push({ lng, lat, alt: height,heading:totalHeading  || 0,pitch:totalPitch || 0,roll:totalRoll|| 0 ,flyHeading:flyHeadingData,zoom : currentzoom || 1});
          });
        }
      });
@@ -305,7 +312,7 @@
    },
    showFlightPath() {
      let viewer = window['cesiumContainer'].viewer
      console.log(">> this.waypoints:", this.waypoints);
      // console.log(">> this.waypoints:", this.waypoints);
      if (this.waypoints.length === 0) return alert('请先上传KMZ文件');
      // 转换坐标
      const positions = this.waypoints.map(wp =>
@@ -343,8 +350,6 @@
          }
        });
      });
      //viewer.zoomTo(viewer.entities);
    },
    getTowerData(){
      let lon = this.waypoints[0].lng
@@ -412,37 +417,19 @@
    loadTimeLine(){
      let viewer = window['cesiumContainer'].viewer
      // 设置时间范围
      console.log(this.trajectoryData)
      const allTimes = this.trajectoryData.map(item => Cesium.JulianDate.fromIso8601(item.time))
      // 获取所有时间,并减去8小时
      // const allTimes = this.trajectoryData.map(item => {
      //     const time = Cesium.JulianDate.fromIso8601(item.time)
      //     return Cesium.JulianDate.addHours(time, +8, new Cesium.JulianDate())
      // })
      console.log(allTimes)
      const startTime = allTimes[0]
      const stopTime = allTimes[allTimes.length - 1]
      console.log(startTime)
      console.log(stopTime)
      // const startTime = Cesium.JulianDate.minimum(...allTimes)
      // const stopTime = Cesium.JulianDate.maximum(...allTimes)
      viewer.clock.startTime = startTime.clone()
      viewer.clock.stopTime = stopTime.clone()
      viewer.clock.currentTime = startTime.clone()
      viewer.clock.clockRange = Cesium.ClockRange.CLAMPED
      viewer.timeline.zoomTo(startTime, stopTime)
      const duration = Cesium.JulianDate.secondsDifference(stopTime, startTime);
      console.log(`时间轴总时长: ${duration} 秒`)
      // 创建位置和速度属性
      const speedProperty = new Cesium.SampledProperty(Number)
      console.log(">> this.trajectoryData:", this.trajectoryData);
      // 添加采样点
      this.trajectoryData.forEach(data => {
        const time = Cesium.JulianDate.fromIso8601(data.time)
        console.log("存储的时间:", Cesium.JulianDate.toDate(time))
        const position = Cesium.Cartesian3.fromDegrees(
          data.position.longitude,
          data.position.latitude,
@@ -451,11 +438,6 @@
        this.positionProperty.addSample(time, position)
        speedProperty.addSample(time, data.speed)
            // 计算朝向四元数
        // const hpr = new Cesium.HeadingPitchRoll(
        //     Cesium.Math.toRadians(data.flyHeading),
        //     Cesium.Math.toRadians(data.pitch),
        //     Cesium.Math.toRadians(data.roll)
        // );
        const hpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(data.flyHeading),
            Cesium.Math.toRadians(0),
@@ -465,27 +447,13 @@
        
        // // 添加飞机朝向采样
        this.orientation.addSample(time, quaternion);
        //无人机heading
        //  this.flyHeadingProperty.addSample(time, data.flyHeading)
        //云台
        const szthpr = new Cesium.HeadingPitchRoll(
            Cesium.Math.toRadians(data.heading),
            Cesium.Math.toRadians(data.pitch),
            Cesium.Math.toRadians(data.roll)
        );
        console.log(szthpr)
        // console.log( Cesium.Math.toRadians(data.heading))
        const sztquaternion = Cesium.Transforms.headingPitchRollQuaternion(position, szthpr);
        console.log(sztquaternion)
        // this.sztOrientation.addSample(time, sztquaternion);
        this.holderHeadingProperty.addSample(time, data.heading)
        this.holderPitchProperty.addSample(time, data.pitch)
        this.holderRollProperty.addSample(time, data.roll)
        // console.log(this.sztOrientation)
        // console.log(this.orientation)
      })
      // console.log(">> positionProperty:",this.positionProperty );
        //变倍
        this.holderZoomProperty.addSample(time,data.zoom)
      })
      let entity = viewer.entities.add({
        show: true,
        position: this.positionProperty,
@@ -515,11 +483,6 @@
          trailTime: 60
        },
        orientation:this.orientation
        // orientation: {
        //   heading: Cesium.Math.toRadians(this.flyHeadingProperty),
        //   pitch: Cesium.Math.toRadians(0),
        //   roll: Cesium.Math.toRadians(0),
        // }
      })
    },
     // 更新视锥体位置和朝向
@@ -552,6 +515,7 @@
          }
        }
      )
      this.updateFov()
    },
    listenChange() {
      let viewer =  window['cesiumContainer'].viewer;
@@ -559,30 +523,16 @@
        if (viewer.clock.shouldAnimate) {
          this.getCurrentPosition()
        // 执行动作
        // console.log("Clock is running, performing action...");
        // 你的代码逻
        } else {
            // 时钟暂停时不执行
            // console.log("Clock is paused, no action performed.");
        }
      });
    },
    getCurrentPosition() {
      let viewer =  window['cesiumContainer'].viewer;
      // console.log(this.sztOrientation)
      // 获取当前时间
      const currentTime = viewer.clock.currentTime;
      console.log("当前时间:", Cesium.JulianDate.toDate(currentTime));
      // console.log(Cesium.JulianDate.toDate(currentTime))
      // console.log('start:', Cesium.JulianDate.toDate(this.positionProperty._property._times[0]));
      // console.log('stop:', Cesium.JulianDate.toDate(this.positionProperty._property._times.slice(-1)[0]));
      // const currentTime = Cesium.JulianDate.addHours(currentTime, -8, new Cesium.JulianDate());
      // console.log(currentTime)
      // 从 positionProperty 中获取当前位置
      const currentPosition = this.positionProperty.getValue(currentTime);
      
      // console.log('currentPosition>>>>>>>>>>>>>>>>>>>>>>>' + currentPosition)
      // 如果获取到位置
      if (currentPosition) {
        // 将位置从 Cartesian 转换为 Cartographic
@@ -599,48 +549,32 @@
          this.heading = holderUavHeading
        }
        //云台变化
        // const sztquaternion = this.sztOrientation.getValue(currentTime)
        // console.log(sztquaternion)
        // if (sztquaternion) {
        //   const hpr = Cesium.HeadingPitchRoll.fromQuaternion(sztquaternion)
        //   console.log(hpr)
        //   this.heading = (Cesium.Math.toDegrees(hpr.heading).toFixed(2)-143.32384000000002 )
        //   // this.heading = 180
        //   this.pitch = (Cesium.Math.toDegrees(hpr.pitch).toFixed(2) - 14.33)
        //   // this.roll = Cesium.Math.toDegrees(hpr.roll).toFixed(2)
        //   this.roll = 0
        //   // console.log('当前位置 - heading ' + this.heading)
        //   console.log(`当前位置 - heading: ${this.heading}, pitch: ${this.pitch}, roll: ${this.roll}`);
        // }
        const holderYtHeading = this.holderHeadingProperty.getValue(currentTime)
        const holderYtPitch = this.holderPitchProperty.getValue(currentTime)
        const holderYtRoll = this.holderRollProperty.getValue(currentTime)
        if(holderYtHeading) {
          // this.heading = Cesium.Math.toDegrees(holderYtHeading).toFixed(2)
          // this.pitch = Cesium.Math.toDegrees(holderYtPitch).toFixed(2)
          // this.roll = Cesium.Math.toDegrees(holderYtRoll).toFixed(2)
          this.heading = holderYtHeading
          this.pitch = holderYtPitch
          this.roll = holderYtRoll
           console.log('当前位置 - heading ' + this.heading)
           console.log(`当前位置 - heading: ${this.heading}, pitch: ${this.pitch}, roll: ${this.roll}`);
        }
        // console.log(sztquaternion)
        // if (sztquaternion) {
        //   const hpr = Cesium.HeadingPitchRoll.fromQuaternion(sztquaternion)
        //   console.log(hpr)
        //   this.heading = (Cesium.Math.toDegrees(hpr.heading).toFixed(2)-143.32384000000002 )
        //   // this.heading = 180
        //   this.pitch = (Cesium.Math.toDegrees(hpr.pitch).toFixed(2) - 14.33)
        //   // this.roll = Cesium.Math.toDegrees(hpr.roll).toFixed(2)
        //   this.roll = 0
        //   // console.log('当前位置 - heading ' + this.heading)
          //  console.log('当前位置 - heading ' + this.heading)
        //   console.log(`当前位置 - heading: ${this.heading}, pitch: ${this.pitch}, roll: ${this.roll}`);
        // }
        }
        //变倍
        const  holderZoom = this.holderZoomProperty.getValue(currentTime)
        if(holderZoom) {
          this.currentZoom = holderZoom ==1? 1 :(holderZoom  /23.76237623)
        }
        
        this.updateFrustum();
      } else {
        console.log("无法获取当前位置");
      }
    },
    updateFov(deg) {
      if (this.camera && this.camera.frustum) {
        let originalFov = Cesium.Math.toRadians(60); // 1.047 rad
        let newFov = originalFov / this.currentZoom; // 约 0.1047 rad
        this.camera.frustum.fov = newFov
      }
    },
    showGZ(){
@@ -648,8 +582,8 @@
      this.camera = new Cesium.Camera(viewer.scene)
      // 视锥体参数
      this.camera.frustum = new Cesium.PerspectiveFrustum({
        fov: Cesium.Math.PI_OVER_THREE,
        // aspectRatio: this.aspectRatio,
        // fov: Cesium.Math.PI_OVER_THREE,
        fov:Cesium.Math.toRadians(60),
        aspectRatio: 1920 / 1080,
      });
      this.camera.setView({
@@ -670,6 +604,7 @@
        updateOnChange: true,
      })
      viewer.scene.primitives.add(this.frustumOutline);
      this.listenChange()
    }