Koishi 2 روز پیش
والد
کامیت
a8688e7af7
2فایلهای تغییر یافته به همراه363 افزوده شده و 27 حذف شده
  1. 354 18
      src/components/timeControl/index.vue
  2. 9 9
      src/views/cesium.vue

+ 354 - 18
src/components/timeControl/index.vue

@@ -36,15 +36,20 @@
 </template>
 
 <script>
+import * as Cesium from "cesium";
 import cloud from "/public/static/exportData/cloud/layer.json";
-import rainJson from "/public/static/exportData/rain/layer.json";
-import tempJson from "/public/static/exportData/tmp/layer.json";
-import windJson from "/public/static/exportData/wind/layer.json";
+import rain from "/public/static/exportData/rain/layer.json";
+import temp from "/public/static/exportData/tmp/layer.json";
+import wind from "/public/static/exportData/wind/layer.json";
 
 import { VideoPlay, VideoPause } from "@element-plus/icons-vue";
 
 import { ElMessage } from "element-plus";
 
+import { createWind } from "../../assets/wind/Windy.js";
+
+import axios from "axios";
+
 export default {
   props: {
     mode: {
@@ -53,10 +58,17 @@ export default {
         return "";
       },
     },
+    viewer: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
   },
 
   data() {
     return {
+      cv: null,
       sTimeRange: [0, 0],
       sliderMax: 0,
       progressLeft: 0,
@@ -64,16 +76,59 @@ export default {
       percentage: 0,
       marks: {},
       cloudJson: [],
-      setpLeft: 1,
+      rainJson: [],
+      tempJson: [],
+      windJson: [],
+      setpLeft: 0,
       VideoPlay,
       VideoPause,
       isPlay: false,
       playRange: [0, 0],
+      adUrls: [],
+      adLayers: [],
+      CONTROL_COLOR: {
+        uv: [
+          { color: "#f4f4f4", min: 0, max: 5, label: "0m/s ~ 5m/s" },
+          { color: "#fff465", min: 5, max: 10, label: "5m/s ~ 10m/s" },
+          { color: "#c5171e", min: 10, max: 15, label: "10m/s ~ 15m/s" },
+          { color: "#930f00", min: 15, max: 20, label: "15m/s ~ 20m/s" },
+        ],
+        shr: [
+          { color: "#00BFFF", min: 0, max: 0.034, label: "0 ~ 0.034-轻度" },
+          {
+            color: "#1E90FF",
+            min: 0.034,
+            max: 0.068,
+            label: "0.034 ~ 0.068-中度",
+          },
+        ],
+        edr: [
+          { color: "#87CEFA", min: 0, max: 0.22, label: "0 ~ 0.22-轻度" },
+          {
+            color: "#4169E1",
+            min: 0.22,
+            max: 0.35,
+            label: "0.22 ~ 0.35-中度",
+          },
+          {
+            color: "#0000CD",
+            min: 0.35,
+            max: 0.5,
+            label: "0.35 ~ 0.5-重度",
+          },
+        ],
+      },
+      windLayer: null,
+      needClearLayer: false,
     };
   },
 
   created() {
+    this.cv = this.viewer;
     this.cloudJson = cloud.reverse();
+    this.rainJson = rain.reverse();
+    this.tempJson = temp.reverse();
+    this.windJson = wind.reverse();
     this.controlMode = this.mode || "";
     this.sliderMax = this.cloudJson.length - 1;
     this.sTimeRange = [0, this.sliderMax];
@@ -84,26 +139,53 @@ export default {
       }
     });
     this.marks = marks;
+    window.addEventListener("keydown", this.handleKeyDown);
   },
 
   unmounted() {
     clearInterval(this.progressTimmer);
     this.progressTimmer = null;
+    window.removeEventListener("keydown", this.handleKeyDown);
   },
 
   methods: {
+    handleKeyDown(event) {
+      if (!this.isPlay && this.cv.scene.id) {
+        let changeLayer = false;
+        const scrollRange = this.sTimeRange[1] + 1 - (this.sTimeRange[0] + 1);
+        if (event.key.toLowerCase() === "a") {
+          this.setpLeft - 1 < 0
+            ? (this.setpLeft = scrollRange)
+            : (this.setpLeft -= 1);
+          changeLayer = true;
+        } else if (event.key.toLowerCase() === "d") {
+          this.setpLeft + 1 > scrollRange
+            ? (this.setpLeft = 0)
+            : (this.setpLeft += 1);
+          changeLayer = true;
+        }
+
+        if (changeLayer) {
+          let p = parseInt((this.setpLeft / scrollRange) * 100);
+          this.percentage = p >= 100 ? 100 : p;
+
+          this.switchMapLayer();
+        }
+      }
+    },
+
     sliderFormatTooltip(value) {
       let descStr = "";
       if (value === this.sTimeRange[0]) {
-        descStr = "起始时间: ";
+        descStr = "起始时间:";
       } else if (value === this.sTimeRange[1]) {
-        descStr = "截止时间: ";
+        descStr = "截止时间:";
       }
-      return `${descStr}${this.cloudJson[value].date}`;
+      return `${descStr} ${this.cloudJson[value].date}`;
     },
 
     progressFormat() {
-      return this.cloudJson[this.sTimeRange[0] + (this.setpLeft - 1)].date;
+      return this.cloudJson[this.sTimeRange[0] + this.setpLeft].date;
     },
 
     sliderChange(value) {
@@ -112,11 +194,33 @@ export default {
       );
       this.progressWidth =
         (value[1] / (this.cloudJson.length - 1)) * 96 - this.progressLeft;
+      this.setpLeft = 0;
+      this.resetData();
+    },
+
+    resetData() {
       this.percentage = 0;
+      this.adLayers.forEach((ele) => {
+        this.cv.imageryLayers.remove(ele);
+      });
+      if (this.windLayer) {
+        this.windLayer.destroy();
+      }
     },
 
     playProgress() {
       this.isPlay = !this.isPlay;
+
+      if (this.needClearLayer) {
+        this.adLayers.forEach((ele) => {
+          this.cv.imageryLayers.remove(ele);
+        });
+        if (this.windLayer) {
+          this.windLayer.destroy();
+        }
+        this.needClearLayer = false;
+      }
+
       if (this.isPlay) {
         const setpRight = this.sTimeRange[1];
 
@@ -129,36 +233,268 @@ export default {
         ) {
           const [l, r] = this.sTimeRange;
           this.playRange = [l, r];
-          this.setpLeft = 1;
+          // this.setpLeft = 0;
         }
 
         ElMessage({
           type: "primary",
           plain: true,
           showClose: true,
-          message: `开始回滚 ${st} ~ ${et} 之间的数据`,
+          message:
+            st === et
+              ? `开始展示 ${st} 数据`
+              : `开始回滚 ${st} ~ ${et} 之间的数据`,
         });
 
         const scrollRange = this.sTimeRange[1] + 1 - (this.sTimeRange[0] + 1);
 
-        this.progressTimmer = setInterval(() => {
-          if (this.setpLeft > scrollRange) {
-            this.setpLeft = 0;
-          }
-          let p = parseInt((this.setpLeft / scrollRange) * 100);
-          this.percentage = p >= 100 ? 100 : p;
-          this.setpLeft++;
-        }, 1000);
+        const adUrls = this.getAddedUrls(
+          this.sTimeRange[0],
+          this.sTimeRange[1]
+        );
+
+        let adLayers = [];
+
+        adUrls.forEach((url) => {
+          const provider = new Cesium.SingleTileImageryProvider({
+            url,
+            rectangle: Cesium.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0), // 全球覆盖
+            tileWidth: 1440, // 根据你的图片实际宽度修改
+            tileHeight: 721,
+          });
+
+          const layer = this.viewer.imageryLayers.addImageryProvider(provider);
+          layer.alpha = 0.8; // 透明度
+          layer.brightness = 1; // 亮度
+          layer.contrast = 1; // 对比度
+          layer.show = false; // 初始隐藏
+          adLayers.push(layer);
+        });
+
+        this.adUrls = adUrls;
+
+        this.adLayers = adLayers;
+
+        if (this.setpLeft > scrollRange) {
+          this.setpLeft = 0;
+        }
+        let p = parseInt((this.setpLeft / scrollRange) * 100);
+        this.percentage = p >= 100 ? 100 : p;
+        this.switchMapLayer();
+
+        this.progressTimmer = setInterval(
+          () => {
+            this.setpLeft++;
+            if (this.setpLeft > scrollRange) {
+              this.setpLeft = 0;
+            }
+            let p = parseInt((this.setpLeft / scrollRange) * 100);
+            this.percentage = p >= 100 ? 100 : p;
+            this.switchMapLayer();
+          },
+          this.controlMode === "wind" ? 20000 : 2000
+        );
       } else {
         clearInterval(this.progressTimmer);
         this.progressTimmer = null;
       }
     },
+
+    getAddedUrls(starIndex, endIndex) {
+      let imageUrls = [];
+      if (this?.cv?.scene?.id) {
+        if (this.controlMode) {
+          for (let i = starIndex; i <= endIndex; i++) {
+            imageUrls.push(`/static${this[`${this.controlMode}Json`][i].path}`);
+          }
+        }
+      }
+      return imageUrls;
+    },
+
+    async switchMapLayer() {
+      if (this.controlMode === "wind" && this.adUrls?.length) {
+        if (this.windLayer) {
+          this.windLayer.destroy();
+        }
+        const res = await axios.get(this.adUrls[this.setpLeft]);
+        this.windLayer = await createWind(
+          this.cv,
+          this.trJsonData(res.data),
+          this.CONTROL_COLOR
+        );
+      } else {
+        this.adLayers?.forEach((ele, index) => {
+          if (index === this.setpLeft) {
+            ele.show = true;
+          } else {
+            ele.show = false;
+          }
+        });
+      }
+    },
+
+    trJsonData(jsonData) {
+      function arrayMin(arr) {
+        let min = Infinity;
+        for (let i = 0; i < arr.length; i++) {
+          if (arr[i] < min) min = arr[i];
+        }
+        return min;
+      }
+
+      function arrayMax(arr) {
+        let max = -Infinity;
+        for (let i = 0; i < arr.length; i++) {
+          if (arr[i] > max) max = arr[i];
+        }
+        return max;
+      }
+      const uData = jsonData.find((ele) => {
+        return ele.header.parameterNumberName === "U-component_of_wind";
+      });
+      const uMin = arrayMin(uData.data);
+      const uMax = arrayMax(uData.data);
+
+      const vData = jsonData.find((ele) => {
+        return ele.header.parameterNumberName === "V-component_of_wind";
+      });
+      const vMin = arrayMin(vData.data);
+      const vMax = arrayMax(vData.data);
+
+      const bounds = {
+        west: uData.header.lo1,
+        south: uData.header.la2,
+        east: uData.header.lo2,
+        north: uData.header.la1,
+      };
+
+      return {
+        u: {
+          array: uData.data,
+          min: uMin,
+          max: uMax,
+        },
+        v: {
+          array: vData.data,
+          min: vMin,
+          max: vMax,
+        },
+        width: uData.header.nx,
+        height: uData.header.ny,
+        bounds,
+      };
+    },
   },
 
   watch: {
     mode(val) {
       this.controlMode = val;
+
+      this.adLayers.forEach((ele) => {
+        this.cv.imageryLayers.remove(ele);
+      });
+
+      if (this.windLayer) {
+        this.windLayer.destroy();
+      }
+
+      if (this.controlMode) {
+        if (this.isPlay) {
+          clearInterval(this.progressTimmer);
+          this.progressTimmer = null;
+
+          const scrollRange = this.sTimeRange[1] + 1 - (this.sTimeRange[0] + 1);
+
+          const adUrls = this.getAddedUrls(
+            this.sTimeRange[0],
+            this.sTimeRange[1]
+          );
+
+          let adLayers = [];
+
+          adUrls.forEach((url) => {
+            const provider = new Cesium.SingleTileImageryProvider({
+              url,
+              rectangle: Cesium.Rectangle.fromDegrees(
+                -180.0,
+                -90.0,
+                180.0,
+                90.0
+              ), // 全球覆盖
+              tileWidth: 1440, // 根据你的图片实际宽度修改
+              tileHeight: 721,
+            });
+
+            const layer =
+              this.viewer.imageryLayers.addImageryProvider(provider);
+            layer.alpha = 0.8; // 透明度
+            layer.brightness = 1; // 亮度
+            layer.contrast = 1; // 对比度
+            layer.show = false; // 初始隐藏
+            adLayers.push(layer);
+          });
+
+          this.adUrls = adUrls;
+
+          this.adLayers = adLayers;
+
+          this.switchMapLayer();
+          this.progressTimmer = setInterval(
+            () => {
+              this.setpLeft++;
+              if (this.setpLeft > scrollRange) {
+                this.setpLeft = 0;
+              }
+              let p = parseInt((this.setpLeft / scrollRange) * 100);
+              this.percentage = p >= 100 ? 100 : p;
+              this.switchMapLayer();
+            },
+            this.controlMode === "wind" ? 20000 : 2000
+          );
+        } else {
+          const adUrls = this.getAddedUrls(
+            this.sTimeRange[0],
+            this.sTimeRange[1]
+          );
+
+          let adLayers = [];
+
+          adUrls.forEach((url) => {
+            const provider = new Cesium.SingleTileImageryProvider({
+              url,
+              rectangle: Cesium.Rectangle.fromDegrees(
+                -180.0,
+                -90.0,
+                180.0,
+                90.0
+              ), // 全球覆盖
+              tileWidth: 1440, // 根据你的图片实际宽度修改
+              tileHeight: 721,
+            });
+
+            const layer =
+              this.viewer.imageryLayers.addImageryProvider(provider);
+            layer.alpha = 0.8; // 透明度
+            layer.brightness = 1; // 亮度
+            layer.contrast = 1; // 对比度
+            layer.show = false; // 初始隐藏
+            adLayers.push(layer);
+          });
+
+          this.adUrls = adUrls;
+
+          this.adLayers = adLayers;
+
+          this.switchMapLayer();
+
+          this.needClearLayer = true;
+        }
+      }
+    },
+
+    viewer(cv) {
+      this.cv = cv;
     },
   },
 };

+ 9 - 9
src/views/cesium.vue

@@ -78,7 +78,7 @@
       @showDetail="menuComTSty"
       @backStations="backStations"
     />
-    <timeControl class="timeControl" :mode="controlMode" />
+    <timeControl class="timeControl" :mode="controlMode" :viewer="viewer" />
   </div>
 </template>
 
@@ -278,17 +278,17 @@ export default {
     },
     coverOnChange(val) {
       if (val.value === "风场") {
-        this.controlMode = "wind";
-        this.switchWindLayer(val.check);
+        this.controlMode = this.controlMode === "wind" ? "" : "wind";
+        // this.switchWindLayer(val.check);
       } else if (val.value === "云层") {
-        this.controlMode = "cloud";
-        this.switchCloudLayer(val.check);
+        this.controlMode = this.controlMode === "cloud" ? "" : "cloud";
+        // this.switchCloudLayer(val.check);
       } else if (val.value === "降雨") {
-        this.controlMode = "rain";
-        this.switchRainLayer(val.check);
+        this.controlMode = this.controlMode === "rain" ? "" : "rain";
+        // this.switchRainLayer(val.check);
       } else if (val.value === "温度") {
-        this.controlMode = "tmp";
-        this.switchTemperatureLayerr(val.check);
+        this.controlMode = this.controlMode === "temp" ? "" : "temp";
+        // this.switchTemperatureLayerr(val.check);
       }
     },
     test() {