|
|
@@ -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>
|