| | |
| | | class="fas fa-step-forward" |
| | | /> |
| | | </div> |
| | | <div class="speed-control"> |
| | | <div class="speed-control" v-show="speedShow"> |
| | | <div @click="toggleSpeedMenu">{{ playbackRate }}X</div> |
| | | <div class="speed-menu" v-show="showSpeedMenu"> |
| | | <div |
| | |
| | | resumeWaterSimulation, |
| | | setTimeForWaterSimulation, |
| | | toggleWaterColorRender, |
| | | updateWaterColor, |
| | | } from "@/utils/water"; |
| | | import mapUtils from "@/utils/tools.js"; |
| | | import { fetchWaterSimulationData } from "@/api/trApi.js"; |
| | |
| | | import { useSimStore } from "@/store/simulation"; |
| | | import { storeToRefs } from "pinia"; |
| | | const simStore = useSimStore(); |
| | | const { selectedScheme, frameNum } = storeToRefs(simStore); |
| | | const { selectedScheme, frameNum, layerDate } = storeToRefs(simStore); |
| | | |
| | | const emit = defineEmits([ |
| | | "timeUpdate", |
| | |
| | | const playbackRate = ref(1); |
| | | const playbackRates = ref([1, 2, 4, 8]); |
| | | const showSpeedMenu = ref(false); |
| | | const speedShow = ref(false); |
| | | |
| | | const waterTimestamps = ref([]); // 存储时间轴数据 |
| | | const timeMarkers = ref([]); |
| | | const timelineTrack = ref(null); |
| | | const isColorRenderEnabled = ref(false); // 假设这是你的颜色渲染开关状态 |
| | | const isWaterPrimitiveCreated = ref(false); |
| | | let playInterval = null; |
| | | let timeStepInfo = null; |
| | | let rainTotalInfo = []; |
| | | const isRainEnabled = ref(false); |
| | | const rainParams = reactive({ |
| | | rainSize: 0.5, |
| | |
| | | }); |
| | | let minFlowRate = ref(); |
| | | let maxFlowRate = ref(); |
| | | let maxStage = null; |
| | | // 计算属性 |
| | | const progressPercentage = computed( |
| | | () => (currentTime.value / duration.value) * 100 |
| | |
| | | currentTime.value = (nextTimestamp - baseTimestamp) / 1000; |
| | | |
| | | // 触发更新 |
| | | updateWeatherByProgress(); |
| | | if (selectedScheme.value.type !== 2) { |
| | | updateWaterColorByTime(); |
| | | updateWeatherByProgress(); |
| | | } |
| | | |
| | | const progress = currentTime.value / duration.value; |
| | | emit("timeUpdate", progress * 100); |
| | | }, 1000 / playbackRate.value); // 根据播放速率调整间隔 |
| | |
| | | |
| | | const rainfallList = data.rainfalls; |
| | | console.log("最终的 rainfallList:", rainfallList); |
| | | rainTotalInfo.value = rainfallList; |
| | | calculateTimeStep(rainTotalInfo.value); |
| | | // 使用示例 |
| | | timeStepInfo = calculateTimeStep(rainTotalInfo.value); |
| | | |
| | | // 提取 intensity 值 |
| | | rainFallValues.value = rainfallList.map((r) => r.intensity); |
| | |
| | | name: "中雨", |
| | | min: 10, |
| | | max: 24.9, |
| | | size: 0.7, |
| | | speed: 28, |
| | | density: 23, |
| | | size: 0.6, |
| | | speed: 24, |
| | | density: 18, |
| | | color: "#ADD8E6", |
| | | }, |
| | | { |
| | | name: "大雨", |
| | | min: 25, |
| | | max: 49.9, |
| | | size: 1.0, |
| | | speed: 36, |
| | | density: 31, |
| | | size: 0.7, |
| | | speed: 28, |
| | | density: 21, |
| | | color: "#ADD8E6", |
| | | }, |
| | | { |
| | | name: "暴雨", |
| | | min: 50, |
| | | max: 99.9, |
| | | size: 1.3, |
| | | speed: 42, |
| | | density: 39, |
| | | size: 0.8, |
| | | speed: 32, |
| | | density: 24, |
| | | color: "#ADD8E6", |
| | | }, |
| | | { |
| | | name: "大暴雨", |
| | | min: 100, |
| | | size: 1.6, |
| | | speed: 50, |
| | | density: 47, |
| | | size: 0.9, |
| | | speed: 36, |
| | | density: 27, |
| | | color: "#ADD8E6", |
| | | }, |
| | | ]; |
| | |
| | | } |
| | | } |
| | | // 默认无雨状态 |
| | | |
| | | return { name: "无雨", size: 0.3, speed: 10, density: 10, color: "#F0F8FF" }; |
| | | } |
| | | // 根据播放进度更新天气效果(已优化) |
| | | let lastUsedIndex = -1; // 缓存上一次使用的索引,防止重复更新 |
| | | let lastRainValue = null; |
| | | |
| | | function calculateTimeStep(dataArray) { |
| | | if (!dataArray || dataArray.length < 2) { |
| | | console.warn("数据不足,无法计算时间步长"); |
| | | return null; |
| | | } |
| | | |
| | | // 解析时间字符串为 Date 对象 |
| | | function parseTime(timeStr) { |
| | | return new Date(timeStr.replace(" ", "T")); // 兼容 ISO 格式 |
| | | } |
| | | |
| | | const firstTime = parseTime(dataArray[0].time); |
| | | const secondTime = parseTime(dataArray[1].time); |
| | | |
| | | // 计算时间差(毫秒) |
| | | const diffMs = Math.abs(secondTime - firstTime); |
| | | |
| | | // 转换为小时数(保留小数) |
| | | let timeStepHours = diffMs / (1000 * 60 * 60); // 毫秒 -> 小时 |
| | | |
| | | // 可选:遍历所有相邻项检查是否一致 |
| | | for (let i = 1; i < dataArray.length - 1; i++) { |
| | | const current = parseTime(dataArray[i].time); |
| | | const next = parseTime(dataArray[i + 1].time); |
| | | const step = Math.abs(next - current) / (1000 * 60 * 60); // 毫秒 -> 小时 |
| | | if (Math.abs(step - timeStepHours) > 0.01) { |
| | | console.warn( |
| | | `在索引 ${i} 处发现了不同的时间步长: ${step.toFixed(2)} 小时` |
| | | ); |
| | | } |
| | | } |
| | | |
| | | return timeStepHours; |
| | | } |
| | | |
| | | function updateWaterColorByTime() { |
| | | if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return; |
| | | |
| | | // 辅助函数:将 "YYYY-MM-DD HH:mm:ss" 转换为 JavaScript Date 对象 |
| | | const timeToTimestamp = (timeStr) => new Date(timeStr).getTime(); |
| | | |
| | | // 获取初始时间戳(第一个数据点的时间) |
| | | const initialTimestamp = timeToTimestamp(rainTotalInfo.value[0].time); |
| | | |
| | | // 计算当前进度 |
| | | const progress = currentTime.value / duration.value; |
| | | const floatIndex = progress * (rainTotalInfo.value.length - 1); |
| | | const index = Math.floor(floatIndex); |
| | | const nextIndex = Math.min(index + 1, rainTotalInfo.value.length - 1); |
| | | const currentData = rainTotalInfo.value[index]; |
| | | const nextData = rainTotalInfo.value[nextIndex]; |
| | | const currentTimestamp = timeToTimestamp(currentData.time); |
| | | |
| | | // 已过去的时间(小时) |
| | | const elapsedTimeInHours = parseFloat( |
| | | (currentTimestamp - initialTimestamp) / (1000 * 60 * 60) |
| | | ); |
| | | |
| | | console.log(`持续了 ${elapsedTimeInHours} 小时`); |
| | | |
| | | // 启用插值(alpha 平滑过渡) |
| | | const alpha = floatIndex - index; |
| | | const currentIntensity = currentData.intensity; |
| | | const nextIntensity = nextData.intensity; |
| | | const intensity = currentIntensity + (nextIntensity - currentIntensity); |
| | | // 计算 IR(t) |
| | | const D = elapsedTimeInHours + 0.0001; // 加一个极小量防止除零 |
| | | const IR = 56.9 * Math.pow(D, -0.746); // 单位 mm/h |
| | | |
| | | // 判断当前阶段 |
| | | let stage = 0; |
| | | if (intensity >= 1.0 * IR) { |
| | | stage = 6; |
| | | } else if (intensity >= 0.8 * IR) { |
| | | stage = 5; |
| | | } else if (intensity >= 0.6 * IR) { |
| | | stage = 4; |
| | | } else if (intensity >= 0.4 * IR) { |
| | | stage = 3; |
| | | } else if (intensity >= 0.2 * IR) { |
| | | stage = 2; |
| | | } else if (intensity > 0) { |
| | | stage = 1; |
| | | } |
| | | |
| | | // 更新全局最大阶段(不会回退) |
| | | if (!maxStage) maxStage = 0; |
| | | maxStage = Math.max(maxStage, stage); |
| | | |
| | | // 输出关键信息 |
| | | console.table({ |
| | | 当前时间: currentData.time, |
| | | "累计时长 D(t) (h)": D.toFixed(2), |
| | | "雨强阈值 IR(t) (mm/h)": IR.toFixed(2), |
| | | "当前降雨强度 I(t) (mm/h)": intensity.toFixed(2), |
| | | 当前阶段编号: stage, |
| | | 最大阶段编号: maxStage, |
| | | 是否触发泥石流: stage >= 5 ? "是" : "否", |
| | | }); |
| | | |
| | | // 根据最大阶段设置颜色 |
| | | let color = "#D4F2E7"; |
| | | switch (maxStage) { |
| | | case 0: |
| | | color = "#D4F2E7"; |
| | | break; |
| | | case 1: |
| | | color = "#66B3FF"; |
| | | break; |
| | | case 2: |
| | | color = "#99CCFF"; |
| | | break; |
| | | case 3: |
| | | color = "#CCE5FF"; |
| | | break; |
| | | case 4: |
| | | color = "#CC9966"; |
| | | break; |
| | | case 5: |
| | | color = "#B26633"; |
| | | break; |
| | | case 6: |
| | | color = "#663300"; |
| | | break; |
| | | } |
| | | |
| | | updateWaterColor(color); |
| | | } |
| | | |
| | | function updateWeatherByProgress() { |
| | | if (rainFallValues.value.length === 0) return; |
| | | // console.log(`时间轴总时长: ${duration.value}, 当前时间: ${currentTime.value}`); // 打印时间轴信息 |
| | |
| | | // const rainValue = currentRain + (nextRain - currentRain) * alpha; |
| | | const rainValue = currentRain + (nextRain - currentRain); |
| | | // 打印当前处理的雨量数据 |
| | | // console.log(`正在处理的雨量数据点: 当前=${currentRain}, 下一个=${nextRain}, 插值后=${rainValue.toFixed(2)}, 索引=${index}`); |
| | | // console.log( |
| | | // `正在处理的雨量数据点: 当前=${currentRain}, 下一个=${nextRain}, 插值后=${rainValue.toFixed( |
| | | // 2 |
| | | // )}, 索引=${index}` |
| | | // ); |
| | | // 如果当前索引未变化且插值差异不大,跳过重复更新 |
| | | if (index === lastUsedIndex && Math.abs(rainValue - lastRainValue) < 0.1) { |
| | | // console.log('由于数据无显著变化,跳过本次更新'); |
| | |
| | | try { |
| | | // 当前方案的所有信息 |
| | | const schemeInfo = selectedScheme.value; |
| | | const jsonFetch = ref(null); |
| | | serviceInfo = schemeInfo.serviceName; |
| | | if (selectedScheme.value.type == 2) { |
| | | speedShow.value = false; |
| | | jsonFetch.value = layerDate.value; |
| | | // serviceInfo = layerDate.value; |
| | | } else { |
| | | getRainfallData(); |
| | | speedShow.value = true; |
| | | jsonFetch.value = null; |
| | | } |
| | | |
| | | // console.log('获取到的 serviceName:', serviceInfo); |
| | | getRainfallData(); |
| | | |
| | | // 根据layer.json去获取时间轴信息 |
| | | const { |
| | | waterTimestamps: timestamps, |
| | | watersMaxHeight, |
| | | watersMinHeight, |
| | | } = await fetchWaterSimulationData(serviceInfo); |
| | | } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value); |
| | | console.log( |
| | | "当前方案下的最大水位深度和最小水位深度", |
| | | watersMaxHeight, |