Browse Source

修改时间轴隐藏问题,解决图层报错

WQQ 2 weeks ago
parent
commit
8ceba5b419

+ 92 - 57
WebVue/TaiHufenglang/src/components/Cesium/CesiumViewer.vue

@@ -18,8 +18,9 @@
   </div>
 
   <!-- 时间轴组件:强制渲染 + 最高层级 -->
-  <div class="timeline-wrapper">
+  <div class="timeline-wrapper" v-show="wmsVisible">
     <TimeSlider
+      ref="timeSliderRef" 
       title="风暴潮WMS时间轴"
       :start-time="startTime.getTime()"
       :end-time="endTime.getTime()"
@@ -56,12 +57,15 @@ import POIVisualization from './POIVisualization.vue';
 import TyphoonVisualization from './TyphoonVisualization.vue';
 import TimeSlider from './TimeSlider.vue';
 
-// 天地图密钥
+// 天地图密钥(保留但不使用)
 const TDTTK = "d9e7aa2ad204aba6aeedea6f5ab48ed9";
 let viewer = ref(null);
 
-// WMS核心配置
-let wmsLayer = null;
+// 👉 新增:时间轴组件引用
+const timeSliderRef = ref(null);
+
+// WMS核心配置:改为ref响应式,修复常量赋值问题
+const wmsLayer = ref(null); 
 const wmsVisible = ref(true);
 // 时间范围:2025102700 ~ 2025110822
 const startTime = ref(new Date('2025-10-27T00:00:00'));
@@ -70,8 +74,8 @@ const currentTime = ref(new Date('2025-10-27T00:00:00'));
 const timeStep = ref(10 * 3600 * 1000); // 10小时步长
 
 // POI/台风状态
-const poiVisible = ref(true);
-const typhoonVisible = ref(true);
+const poiVisible = ref(false);
+const typhoonVisible = ref(false);
 const poiData = ref(JYLData);
 
 // 处理POI选中
@@ -81,7 +85,7 @@ const handlePointSelected = (pointData) => {
 
 // 返回首页视角
 const goToHomeView = () => {
-  if (viewer.value) {
+  if (viewer.value && !viewer.value.isDestroyed()) {
     viewer.value.camera.flyTo({
       destination: Cesium.Cartesian3.fromDegrees(121.75, 31.15, 30000),
       orientation: {
@@ -104,9 +108,9 @@ const handleToggleTyphoon = async () => {
   if (!newState) {
     typhoonVisible.value = newState;
   } else {
-    typhoonVisible.value = newState;
-    await nextTick();
-    if (viewer.value) {
+    if (viewer.value && !viewer.value.isDestroyed()) {
+      typhoonVisible.value = newState;
+      await nextTick();
       viewer.value.camera.flyTo({
         destination: Cesium.Cartesian3.fromDegrees(120, 20, 4025692.0),
       });
@@ -119,15 +123,19 @@ const handleTyphoonToggle = (newState) => {
   typhoonVisible.value = newState;
 };
 
-// 加载/更新WMS图层(带严格类型校验
+// 加载/更新WMS图层(修复常量赋值 + 逻辑错误
 const loadWmsLayer = (time) => {
   try {
-    if (!viewer.value || !viewer.value.imageryLayers) return;
+    if (!viewer.value || viewer.value.isDestroyed() || !viewer.value.imageryLayers) {
+      console.warn('Viewer已销毁或不存在,跳过WMS图层加载');
+      return;
+    }
 
-    // 移除旧图层
-    if (wmsLayer && wmsLayer instanceof Cesium.ImageryLayer) {
-      viewer.value.imageryLayers.remove(wmsLayer);
-      wmsLayer = null;
+    // 先移除旧图层(彻底删除)
+    if (wmsLayer.value && wmsLayer.value instanceof Cesium.ImageryLayer && !wmsLayer.value.isDestroyed()) {
+      viewer.value.imageryLayers.remove(wmsLayer.value);
+      wmsLayer.value.destroy();
+      wmsLayer.value = null;
     }
 
     // 格式化时间
@@ -136,9 +144,9 @@ const loadWmsLayer = (time) => {
                     String(time.getDate()).padStart(2, '0') + 
                     String(time.getHours()).padStart(2, '0');
 
-    // 创建WMS提供者(严格校验)
+    // 创建新的WMS提供者
     const wmsProvider = new Cesium.WebMapServiceImageryProvider({
-      url: 'http://localhost:8080/geoserver/surge_ws/wms',
+      url: 'http://192.168.0.107:8080/geoserver/surge_ws/wms',
       layers: `surge_ws:ZS${timeStr}`,
       parameters: {
         service: 'WMS',
@@ -148,64 +156,93 @@ const loadWmsLayer = (time) => {
         transparent: true,
         srs: 'EPSG:4326'
       },
-      // 核心:强制限定图层的地理范围(必须和你WMS图层的实际范围一致)
       rectangle: Cesium.Rectangle.fromDegrees(121.0, 30.5, 122.5, 31.8),
-      // 禁用Cesium的自动瓦片拆分,按整个范围出单张图
       tilingScheme: new Cesium.GeographicTilingScheme({
         rectangle: Cesium.Rectangle.fromDegrees(121.0, 30.5, 122.5, 31.8)
       }),
-      // 固定瓦片尺寸为图层范围(避免拆分)
       tileWidth: 2048,
       tileHeight: 2048,
-      // 限制缩放级别(避免放大后重复请求)
       maximumLevel: 10,
       minimumLevel: 0,
       enablePickFeatures: false
-
     });
 
-    // 仅当提供者有效时创建图层
+    // 创建并添加新图层
     if (wmsProvider) {
-      wmsLayer = new Cesium.ImageryLayer(wmsProvider); // 显式创建ImageryLayer
-      wmsLayer.alpha = 0.7;
-      wmsLayer.show = wmsVisible.value;
-      viewer.value.imageryLayers.add(wmsLayer); // 加入图层集合
-      console.log(`成功加载WMS图层: surge_ws:ZS${timeStr}`, wmsLayer);
+      wmsLayer.value = new Cesium.ImageryLayer(wmsProvider);
+      wmsLayer.value.alpha = 0.7;
+      wmsLayer.value.show = true; // 显示图层
+      viewer.value.imageryLayers.add(wmsLayer.value);
+      console.log(`成功加载WMS图层: surge_ws:ZS${timeStr}`, wmsLayer.value);
     }
   } catch (error) {
     console.error('加载WMS图层失败:', error);
-    wmsLayer = null;
+    wmsLayer.value = null;
   }
 };
 
-// 切换WMS显示/隐藏
+// 切换WMS显示/隐藏(最终版:隐藏移除图层,显示重新加载+暂停)
 const toggleWmsLayer = () => {
-  console.log('点击WMS按钮,当前图层状态:', wmsLayer);
+  console.log('点击WMS按钮,当前图层状态:', wmsLayer.value);
   
-  if (!wmsLayer) {
-    console.log('WMS图层未初始化,加载默认时间图层');
-    loadWmsLayer(currentTime.value);
+  if (!viewer.value || viewer.value.isDestroyed()) {
+    console.warn('Viewer已销毁,无法切换WMS图层');
     return;
   }
 
+  // 切换WMS显隐状态
   wmsVisible.value = !wmsVisible.value;
-  wmsLayer.show = wmsVisible.value;
+
+  // 1. 隐藏WMS图层:彻底移除图层 + 暂停时间轴
+  if (!wmsVisible.value) {
+    // 暂停时间轴播放
+    timeSliderRef.value?.pausePlay();
+    // 彻底移除图层
+    if (wmsLayer.value && wmsLayer.value instanceof Cesium.ImageryLayer && !wmsLayer.value.isDestroyed()) {
+      viewer.value.imageryLayers.remove(wmsLayer.value);
+      wmsLayer.value.destroy(); // 销毁图层实例
+      wmsLayer.value = null; // 清空引用
+    }
+  } 
+  // 2. 显示WMS图层:重新加载图层 + 时间轴重置(暂停)
+  else {
+    // 重置当前时间到开始时间
+    currentTime.value = new Date(startTime.value);
+    // 重新加载图层
+    loadWmsLayer(currentTime.value);
+    // 时间轴重置到开始时间(默认暂停)
+    timeSliderRef.value?.resetToStart();
+  }
+
   console.log('WMS图层显示状态:', wmsVisible.value);
 };
 
 // 时间轴时间变化响应
 const handleTimeChange = (timeStamp) => {
+  if (!viewer.value || viewer.value.isDestroyed()) return;
+  
   const newTime = new Date(timeStamp);
   currentTime.value = newTime;
   loadWmsLayer(newTime);
 };
 
+// 清理所有自定义图层的方法
+const clearAllLayers = () => {
+  if (viewer.value && !viewer.value.isDestroyed() && viewer.value.imageryLayers) {
+    if (wmsLayer.value && !wmsLayer.value.isDestroyed()) {
+      viewer.value.imageryLayers.remove(wmsLayer.value);
+      wmsLayer.value.destroy();
+      wmsLayer.value = null;
+    }
+  }
+};
+
 onMounted(async () => {
   try {
-    // 👉 核心修复1:禁用baseLayer,手动创建底图(避免布尔值冲突)
+    // 初始化Viewer(关闭天地图
     viewer.value = new Cesium.Viewer('cesiumContainer', {
       timeline: false,
-      baseLayer: false, // 关键:设为false,不自动加载底图
+      baseLayer: false, // 不自动加载底图
       geocoder: false,
       homeButton: false,
       sceneModePicker: false,
@@ -215,29 +252,13 @@ onMounted(async () => {
       vrButton: false,
       selectionIndicator: false,
       infoBox: false,
-      // 地形加载(保留)
+      // 地形加载
       terrainProvider: await Cesium.createWorldTerrainAsync({
         requestVertexNormals: true,
       })
     });
 
-    // 👉 核心修复2:手动创建天地图底图(确保是ImageryLayer实例)
-    if (viewer.value && viewer.value.imageryLayers) {
-      const tdtProvider = new Cesium.WebMapTileServiceImageryProvider({
-        url: `https://t0.tianditu.com/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}&tk=${TDTTK}`,
-        layer: "img",
-        style: "default",
-        format: "image/jpeg",
-        tileMatrixSetID: "w",
-        maximumLevel: 16,
-        show: true
-      });
-      // 显式创建ImageryLayer并添加
-      const tdtLayer = new Cesium.ImageryLayer(tdtProvider);
-      viewer.value.imageryLayers.add(tdtLayer);
-    }
-
-    // 加载倾斜摄影瓦片集
+    // 加载倾斜摄影瓦片集(修复:增加viewer判断)
     const tilesetUrls = [
       "http://localhost:9003/model/TSQ1234/tileset.json",
       "http://localhost:9003/model/SY123/tileset.json",
@@ -245,9 +266,14 @@ onMounted(async () => {
     const loadedTilesets = [];
 
     async function loadMultipleTilesets() {
+      // 先判断viewer是否有效
+      if (!viewer.value || viewer.value.isDestroyed()) return;
+
       try {
         const promises = tilesetUrls.map(async (url, index) => {
           try {
+            if (!viewer.value || viewer.value.isDestroyed()) return null;
+            
             const tileset = await Cesium.Cesium3DTileset.fromUrl(url, {
               maximumScreenSpaceError: 32,
               dynamicScreenSpaceError: true,
@@ -270,6 +296,7 @@ onMounted(async () => {
         console.error("瓦片集批量加载出错:", error);
       }
     }
+    // 执行瓦片集加载
     loadMultipleTilesets();
 
     // 初始化视图
@@ -294,9 +321,17 @@ onMounted(async () => {
 });
 
 onUnmounted(() => {
-  // 销毁Viewer实例,释放资源
+  // 先清理所有图层,再销毁viewer
+  clearAllLayers();
+  
+  // 销毁viewer前先判断状态
   if (viewer.value && !viewer.value.isDestroyed()) {
+    // 清空所有图元(倾斜摄影等)
+    if (viewer.value.scene.primitives) {
+      viewer.value.scene.primitives.removeAll();
+    }
     viewer.value.destroy();
+    viewer.value = null; // 清空引用
   }
 });
 </script>

+ 28 - 4
WebVue/TaiHufenglang/src/components/Cesium/TimeSlider.vue

@@ -94,6 +94,28 @@ const togglePlay = () => {
   }
 };
 
+// 👉 新增:暂停播放(兼容原有stopPlay)
+const pausePlay = () => {
+  clearInterval(playTimer);
+  isPlaying.value = false;
+};
+
+// 👉 新增:重置到开始时间并播放
+const playFromStart = () => {
+  // 1. 暂停当前播放
+  pausePlay();
+  // 2. 触发时间轴回到开始时间
+  emit('timeChange', startTimeStamp.value);
+  // 3. 重新开始播放
+  togglePlay();
+};
+
+// 👉 新增:仅重置到开始时间(不播放)
+const resetToStart = () => {
+  pausePlay();
+  emit('timeChange', startTimeStamp.value);
+};
+
 // 清理定时器(组件卸载时)
 watch(() => isPlaying.value, (newVal) => {
   if (!newVal && playTimer) clearInterval(playTimer);
@@ -105,11 +127,13 @@ onUnmounted(() => {
   isPlaying.value = false;
 });
 
+// 👉 暴露新增方法给父组件
 defineExpose({
-  stopPlay: () => {
-    clearInterval(playTimer);
-    isPlaying.value = false;
-  }
+  stopPlay: pausePlay, // 兼容原有stopPlay方法
+  pausePlay,
+  playFromStart,
+  resetToStart,
+  isPlaying
 });
 </script>
 

+ 1 - 1
WebVue/TaiHufenglang/vite.config.js

@@ -21,7 +21,7 @@ export default defineConfig({
     // 配置代理转发
     proxy: {
       '/geoserver': {
-        target: 'http://127.0.0.1:8080/geoserver', // GeoServer 地址
+        // target: 'http://127.0.0.1:8080/geoserver', // GeoServer 地址
         changeOrigin: true, // 开启跨域
         rewrite: (path) => path.replace(/^\/geoserver/, '') // 重写路径
       }