From a57caa72a54efe9de3fe26a6c36d3e8038267377 Mon Sep 17 00:00:00 2001 From: guonan <guonan201020@163.com> Date: 星期四, 17 七月 2025 09:09:49 +0800 Subject: [PATCH] 修改x按钮 --- src/components/menu/TimeLine.vue | 752 ++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 630 insertions(+), 122 deletions(-) diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue index 5f6c297..6951358 100644 --- a/src/components/menu/TimeLine.vue +++ b/src/components/menu/TimeLine.vue @@ -2,20 +2,30 @@ <div class="timeline-container"> <div class="controls"> <div class="control-btn" @click="skipBackward"> - <img src="@/assets/img/timeline/left.png" class="fas fa-step-backward" /> + <img + src="@/assets/img/timeline/left.png" + class="fas fa-step-backward" + /> </div> <div class="control-btn play-btn" @click="togglePlay"> <img v-show="isPlaying" src="@/assets/img/timeline/stop.png" /> <img v-show="!isPlaying" src="@/assets/img/timeline/start.png" /> </div> <div class="control-btn" @click="skipForward"> - <img src="@/assets/img/timeline/right.png" class="fas fa-step-forward" /> + <img + src="@/assets/img/timeline/right.png" + 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 v-for="rate in playbackRates" :key="rate" @click.capture="setPlaybackRate(rate)" - :class="{ active: playbackRate === rate }"> + <div + v-for="rate in playbackRates" + :key="rate" + @click.capture="setPlaybackRate(rate)" + :class="{ active: playbackRate === rate }" + > {{ rate }}X </div> </div> @@ -25,19 +35,33 @@ <div class="timeline"> <div class="dates"> <div class="current-date">褰撳墠鎾斁鏃堕棿锛歿{ currentPlayingTime }}</div> - <div v-for="(date, index) in visibleDates" :key="index" class="date-label"> + <div + v-for="(date, index) in visibleDates" + :key="index" + class="date-label" + > <!-- {{ formatDate(date) }} --> </div> <div> 涓撻娓叉煋: - <el-switch v-model="isColorRenderEnabled" @change="handleColorRenderChange" style="margin-top: -3px" - :disabled="!isPlaying || !isWaterPrimitiveCreated" /> + <el-switch + v-model="isColorRenderEnabled" + @change="handleColorRenderChange" + style="margin-top: -3px" + :disabled="!isPlaying || !isWaterPrimitiveCreated" + /> <!-- active-text="寮�" inactive-text="鍏�" --> </div> </div> <div class="timeline-track" ref="timelineTrack" @click="seekToPosition"> - <div class="timeline-progress" :style="{ width: progressPercentage + '%' }"></div> - <div class="timeline-cursor" :style="{ left: progressPercentage + '%' }"></div> + <div + class="timeline-progress" + :style="{ width: progressPercentage + '%' }" + ></div> + <div + class="timeline-cursor" + :style="{ left: progressPercentage + '%' }" + ></div> <div class="scale-markers"> <div class="scale-marker" style="left: 0%"></div> <div class="scale-marker" style="left: 25%"></div> @@ -46,8 +70,12 @@ <div class="scale-marker" style="left: 100%"></div> </div> <div class="time-markers"> - <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker" - :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }"> + <div + v-for="(time, index) in timeMarkers" + :key="index" + class="time-marker" + :style="{ left: `${index * 25}%`, transform: 'translateX(-50%)' }" + > <div class="date-part">{{ time.split(" ")[0] }}</div> <div class="time-part">{{ time.split(" ")[1] }}</div> </div> @@ -56,27 +84,38 @@ </div> <div> <div style="display: flex"> - <ratelevel ref="ratelevelRef" :playing-time="sendCurrentPlayingTime" - @finish-calculation="handleFinishCalculation" style=" + <ratelevel + ref="ratelevelRef" + :playing-time="sendCurrentPlayingTime" + @finish-calculation="handleFinishCalculation" + style=" margin-top: 12px; margin-left: 28px; margin-right: 10px; justify-content: flex-end; - " /> - <crossanalysis ref="crossRef" style=" + " + /> + <crossanalysis + ref="crossRef" + style=" margin-top: 12px; margin-left: 16px; margin-right: 20px; justify-content: flex-end; - " /> + " + /> </div> - <el-button @click="handleBack" style=" + <el-button + @click="handleBack" + style=" margin-top: 3px; margin-left: 28px; margin-right: 10px; width: 75%; height: 30%; - ">缁撴潫妯℃嫙</el-button> + " + >缁撴潫妯℃嫙</el-button + > </div> </div> </template> @@ -91,6 +130,7 @@ onBeforeUnmount, inject, reactive, + watchEffect, } from "vue"; import ratelevel from "@/components/menu/flowRate_waterLevel.vue"; import crossanalysis from "@/components/menu/CrossSectionalAnalysis.vue"; @@ -106,14 +146,16 @@ updateWaterColor, } from "@/utils/water"; import mapUtils from "@/utils/tools.js"; -import { fetchWaterSimulationData } from "@/api/trApi.js"; +import { fetchWaterSimulationData, stopSim } from "@/api/trApi.js"; import { EventBus } from "@/eventBus"; -import { ElMessage } from "element-plus"; +import { ElMessage, ElMessageBox } from "element-plus"; // 鐘舵�佺鐞嗗櫒 import { useSimStore } from "@/store/simulation"; import { storeToRefs } from "pinia"; const simStore = useSimStore(); -const { selectedScheme, frameNum } = storeToRefs(simStore); +const { selectedScheme, frameNum, layerDate, schemWaterInfo } = + storeToRefs(simStore); +import { clearAllPoints } from "@/utils/map"; const emit = defineEmits([ "timeUpdate", @@ -143,13 +185,16 @@ 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 rainTotalInfo = ([]); +let timeStepInfo = null; +let rainTotalInfo = []; const isRainEnabled = ref(false); const rainParams = reactive({ rainSize: 0.5, @@ -168,6 +213,9 @@ new Set(waterTimestamps.value.map((ts) => dayjs(ts).format("YYYY-MM-DD"))) ).map((date) => dayjs(date).toDate()) ); + +// 鎴戦渶瑕佸姞涓�涓垽鏂� +const finishPlay = ref(false); // 鎾斁鎺у埗 const togglePlay = () => { // 杩欓噷搴旇鍐嶈瀹氬嚑涓檺鍒讹紝濡傛灉缂哄皯浠�涔堟暟鎹紝鏃犳硶杩涜浠跨湡 @@ -235,40 +283,118 @@ 8: 125, // 8鍊嶉�� }; // 鎾斁閫昏緫 +// const startPlayback = () => { +// clearInterval(playInterval); + +// playInterval = setInterval(() => { +// // 鎵惧埌褰撳墠鏃堕棿瀵瑰簲鐨勭储寮� +// const currentIndex = findClosestTimestampIndex(currentTime.value); +// const nextIndex = currentIndex + 1; + +// // 濡傛灉宸茬粡鏄渶鍚庝竴涓椂闂寸偣锛屽仠姝㈡挱鏀� +// if (nextIndex >= waterTimestamps.value.length) { +// currentTime.value = duration.value; +// stopPlayback(); +// isPlaying.value = false; +// emit("isPlaying", false); +// emit("playbackFinished", true); +// return; +// } + +// // 鏇存柊鏃堕棿涓轰笅涓�涓椂闂寸偣鐨勬椂闂村樊锛堢锛� +// const nextTimestamp = waterTimestamps.value[nextIndex]; +// const baseTimestamp = waterTimestamps.value[0]; +// currentTime.value = (nextTimestamp - baseTimestamp) / 1000; + +// // 瑙﹀彂鏇存柊 +// if (selectedScheme.value.type !== 2) { +// updateWaterColorByTime(); +// updateWeatherByProgress(); +// } + +// const progress = currentTime.value / duration.value; +// emit("timeUpdate", progress * 100); +// }, 1000 / playbackRate.value); // 鏍规嵁鎾斁閫熺巼璋冩暣闂撮殧 +// }; const startPlayback = () => { clearInterval(playInterval); - playInterval = setInterval(() => { - // 鎵惧埌褰撳墠鏃堕棿瀵瑰簲鐨勭储寮� - const currentIndex = findClosestTimestampIndex(currentTime.value); - const nextIndex = currentIndex + 1; + // 鏂板缓鏂规涓殑瀹炴椂妯℃嫙涓嶈兘鍊嶉�� + if (selectedScheme.value.type === 2 && simStore.rePlayList.length == 0) { + console.log("鏂板缓鏂规瀹炴椂妯℃嫙浜旂涓�璺�"); + // 瀹炴椂妯℃嫙锛氭瘡 5 绉掕烦鍔ㄤ竴娆� + playInterval = setInterval(() => { + const fiveSeconds = 5; + const totalDuration = duration.value; // 鎬绘椂闀匡紙绉掞級 - // 濡傛灉宸茬粡鏄渶鍚庝竴涓椂闂寸偣锛屽仠姝㈡挱鏀� - if (nextIndex >= waterTimestamps.value.length) { - currentTime.value = duration.value; - stopPlayback(); - isPlaying.value = false; - emit("isPlaying", false); - emit("playbackFinished", true); - return; - } + currentTime.value += fiveSeconds; - // 鏇存柊鏃堕棿涓轰笅涓�涓椂闂寸偣鐨勬椂闂村樊锛堢锛� - const nextTimestamp = waterTimestamps.value[nextIndex]; - const baseTimestamp = waterTimestamps.value[0]; - currentTime.value = (nextTimestamp - baseTimestamp) / 1000; + if (currentTime.value >= totalDuration) { + currentTime.value = totalDuration; + stopPlayback(); + isPlaying.value = false; + finishPlay.value = true; + emit("isPlaying", false); + emit("playbackFinished", true); + return; + } - // 瑙﹀彂鏇存柊 - updateWaterColorByTime() - updateWeatherByProgress(); - const progress = currentTime.value / duration.value; - emit("timeUpdate", progress * 100); - }, 1000 / playbackRate.value); // 鏍规嵁鎾斁閫熺巼璋冩暣闂撮殧 + // 瑙﹀彂杩涘害鏇存柊 + // const progress = currentTime.value / totalDuration; + // 瀹炴椂妯℃嫙搴旇涓嶇敤鏄剧ず寮圭獥鍚� + // emit("timeUpdate", progress * 100); + + // 濡傛灉闇�瑕佽Е鍙戞煇浜涙洿鏂板嚱鏁帮紝涔熷彲浠ヤ繚鐣� + updateWaterColorByTime(); + // updateWeatherByProgress(); + // 淇敼涓哄浐瀹氶樁娈碉紝缂撴參涓嬮洦鐨勭姸鎬� + const rainParams = { + rainSize: 0.5, + rainSpeed: 20, + rainDensity: 15, + rainColor: "#ADD8E6", + }; + console.log("瀹炴椂妯℃嫙寮�濮嬩笅闆�"); + // 璋冪敤宸ュ叿鏂规硶鏇存柊闆ㄦ晥 + mapUtils.toggleRain(rainParams, true); + }, 5000); // 姣� 5 绉掓墽琛屼竴娆� + } else { + // 杩欓噷闈㈣繕鏄綘鐨勬挱鏀句唬鐮侊紝涓婇潰鐨刬f涓槸浜旂閽熻烦鍔ㄤ竴娆$殑瀹炴椂妯℃嫙 + playInterval = setInterval(() => { + const currentIndex = findClosestTimestampIndex(currentTime.value); + const nextIndex = currentIndex + 1; + + if (nextIndex >= waterTimestamps.value.length) { + currentTime.value = duration.value; + stopPlayback(); + isPlaying.value = false; + finishPlay.value = true; + emit("isPlaying", false); + emit("playbackFinished", true); + return; + } + + const nextTimestamp = waterTimestamps.value[nextIndex]; + const baseTimestamp = waterTimestamps.value[0]; + currentTime.value = (nextTimestamp - baseTimestamp) / 1000; + + if (selectedScheme.value.type !== 2) { + updateWaterColorByTime(); + updateWeatherByProgress(); + } + + const progress = currentTime.value / duration.value; + if (selectedScheme.value.type !== 2) { + emit("timeUpdate", progress * 100); + } + }, 1000 / playbackRate.value); + } }; // 闄嶉洦鍙樺寲閮ㄥ垎 // 闄嶉洦鏁版嵁鐩稿叧鍙橀噺 let rainFallValues = ref([]); // 瀛樺偍鍘熷闄嶉洦閲忔暟鎹� let minRainValue = ref(Infinity); +let averageRainIntensity = ref(); let maxRainValue = ref(-Infinity); // 鑾峰彇闄嶉洦鏁版嵁 function getRainfallData() { @@ -276,9 +402,10 @@ console.warn("selectedScheme 鎴� data 涓嶅瓨鍦�"); return; } - // 娉ㄦ剰锛氭湁鏃� data 鍙兘鏄竴涓瓧绗︿覆锛堜緥濡� JSON 瀛楃涓诧級 + let data = selectedScheme.value.data; - // 濡傛灉鏄瓧绗︿覆锛屽垯灏濊瘯瑙f瀽鎴愬璞� + + // 濡傛灉鏄瓧绗︿覆锛屽垯灏濊瘯瑙f瀽涓哄璞� if (typeof data === "string") { try { data = JSON.parse(data); @@ -288,27 +415,82 @@ return; } } - // 鎵撳嵃闄嶉洦寮哄害鐨勫崟浣� + console.log("闄嶉洦寮哄害鐨勫崟浣嶆槸锛�", data.intensityUnit); - // 鏍规嵁 intensityUnit 璋冩暣 rainfalls 涓殑 intensity 鍊� - if (data.intensityUnit === "mm/min") { - data.rainfalls.forEach((r) => (r.intensity *= 60)); - console.log("灏� mm/min 杞崲涓� mm/h 鍚庣殑 rainfalls:", data.rainfalls); - } else if (data.intensityUnit === "mm/5min") { - data.rainfalls.forEach((r) => (r.intensity *= 12)); - console.log("灏� mm/5min 杞崲涓� mm/h 鍚庣殑 rainfalls:", data.rainfalls); - } else if (data.intensityUnit !== "mm/h") { - console.warn("鏈煡鐨� intensity 鍗曚綅锛屾棤娉曡繘琛岃浆鎹�"); + + // 鍒ゆ柇 rainfalls 鏄惁涓哄璞★紝濡傛灉鏄垯杞垚鏁扮粍 + let rainfalls = data.rainfalls; + if (typeof rainfalls === "object" && !Array.isArray(rainfalls)) { + rainfalls = Object.values(rainfalls); + console.warn("鈿狅笍 rainfalls 鏄璞★紝宸茶浆鎹负鏁扮粍"); } - const rainfallList = data.rainfalls; - console.log("鏈�缁堢殑 rainfallList:", rainfallList); - rainTotalInfo.value = rainfallList + // 鎸夊皬鏃惰仛鍚堥檷闆ㄦ暟鎹� + const hourlyRainfallMap = {}; + + rainfalls.forEach((record) => { + const originalTime = new Date(record.time); + if (isNaN(originalTime.getTime())) { + console.warn("鏃犳晥鐨勬椂闂存牸寮忥細", record.time); + return; + } + + // 鏋勯�犫�滃皬鏃垛�濈骇鍒殑鏃堕棿閿紝姣斿锛�2024-08-25 20:00:00 + const hourKey = new Date( + originalTime.getFullYear(), + originalTime.getMonth(), + originalTime.getDate(), + originalTime.getHours() + ); + + const hourStr = hourKey.toISOString().slice(0, 16).replace("T", " "); + + if (!hourlyRainfallMap[hourStr]) { + hourlyRainfallMap[hourStr] = { + intensity: 0, + time: hourStr, + total: record.total, // 榛樿鐢ㄧ涓�涓褰曠殑 total + }; + } + + hourlyRainfallMap[hourStr].intensity += record.intensity; + // 鍙栨渶澶х殑 total锛堝洜涓烘槸绱Н鍊硷級 + if (record.total > hourlyRainfallMap[hourStr].total) { + hourlyRainfallMap[hourStr].total = record.total; + } + }); + + // 杞崲 map 鎴愭暟缁勫苟鎺掑簭 + const hourlyRainfallList = Object.values(hourlyRainfallMap).sort((a, b) => + a.time.localeCompare(b.time) + ); + + console.log("鉁� 鎸夊皬鏃惰仛鍚堝悗鐨勯檷闆ㄦ暟鎹細", hourlyRainfallList); + + // 璁剧疆鍏ㄥ眬鍙橀噺 + rainTotalInfo.value = hourlyRainfallList; + + // 璁$畻鏃堕棿姝ラ暱 + timeStepInfo = calculateTimeStep(rainTotalInfo.value); // 鎻愬彇 intensity 鍊� - rainFallValues.value = rainfallList.map((r) => r.intensity); + rainFallValues.value = hourlyRainfallList.map((r) => r.intensity); + // 璁$畻骞冲潎闆ㄥ己 + if (rainFallValues.value.length > 0) { + const sumIntensity = rainFallValues.value.reduce( + (sum, val) => sum + val, + 0 + ); + averageRainIntensity.value = sumIntensity / rainFallValues.value.length; + } else { + averageRainIntensity.value = 0; // 鎴栬�� null 琛ㄧず鏃犳暟鎹� + } + + console.log("骞冲潎闆ㄥ己涓猴細", averageRainIntensity.value); + minRainValue.value = Math.min(...rainFallValues.value); maxRainValue.value = Math.max(...rainFallValues.value); + console.log( "褰撳墠鏂规涓嬫渶灏忛洦閲忓拰鏈�澶ч洦閲忥細", minRainValue.value, @@ -373,44 +555,259 @@ } } // 榛樿鏃犻洦鐘舵�� - + return { name: "鏃犻洦", size: 0.3, speed: 10, density: 10, color: "#F0F8FF" }; } // 鏍规嵁鎾斁杩涘害鏇存柊澶╂皵鏁堟灉锛堝凡浼樺寲锛� let lastUsedIndex = -1; // 缂撳瓨涓婁竴娆′娇鐢ㄧ殑绱㈠紩锛岄槻姝㈤噸澶嶆洿鏂� let lastRainValue = null; -function updateWaterColorByTime() { - if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return; - 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]; - // 鍚敤鎻掑�硷紙alpha 骞虫粦杩囨浮锛� - const alpha = floatIndex - index; - const currentTotal = currentData.total; - const nextTotal = nextData.total; - const total = currentTotal + (nextTotal - currentTotal) * alpha; - // 鏍规嵁 total 璁剧疆棰滆壊 - let color = '#D4F2E7'; // 榛樿钃濊壊 - if (total >= 150) { - color = '#663300'; // 榛� - 澶ч洦 - } else if (total >= 125) { - color = '#B26633'; // 榛勭豢 - 涓洦 - } else if (total >= 100) { - color = '#CC9966'; // 缁� - 涓洦 - } else if (total >= 75) { - color = '#CCE5FF'; // 闈掔豢 - 灏忛洦 - } else if (total >= 50) { - color = '#99CCFF'; // 澶╄摑 - 灏忛洦 - } else if (total >= 25) { - color = '#66B3FF'; // 娴呰摑 - 寰噺 +function calculateTimeStep(dataArray) { + if (!dataArray || dataArray.length < 2) { + console.warn("鏁版嵁涓嶈冻锛屾棤娉曡绠楁椂闂存闀�"); + return null; } - // console.log(`褰撳墠 total: ${total.toFixed(2)}, 棰滆壊: ${color}`); - // updateWaterColor(color) + + // 瑙f瀽鏃堕棿瀛楃涓蹭负 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; } +// ============================================================================ +// 浼樺寲鏂瑰紡锛屽彲浠ユ眰鍑烘暣涓椂闂磋酱涓婏紝绗竴娆¢亣鍒拌繖鍏釜闃堝�煎緱鏃堕棿鐐癸紝鐒跺悗鍒嗘椂闂存鏄剧ず锛宎鏃堕棿鍐呮樉绀虹姸鎬�1锛岀劧鍚庣姸鎬佷氦鐣屽璁剧疆棰滆壊娓愬彉锛屽叾浣欏悓鐞嗭紝杩欐牱璺宠浆寰楁椂鍊欒兘澶熺洿鎺ヨ烦杞埌褰撳墠寰楅鑹蹭俊鎭樁娈碉紝鐩存帴搴旂敤锛屽嵆鍙� +// ============================================================================ +// 鍏ㄥ眬鐘舵�佽褰� +const colorState = { + currentColor: "#F5F0E6", // 褰撳墠棰滆壊 + currentAlpha: -0.3, // 褰撳墠閫忔槑搴� + colorStages: null, // 棰勮绠楃殑棰滆壊闃舵鏃堕棿鐐� + maxColorTime: null, // 璁板綍杈惧埌鏈�娣遍鑹叉椂鐨勬椂闂寸偣 +}; + +// 棰勮绠楅鑹查樁娈垫椂闂寸偣 +function precomputeColorStages() { + if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return; + // 棰滆壊閰嶇疆锛堜寒搴﹂�掑噺锛� + const COLOR_STOPS = [ + { hex: "#F5F0E6", luminance: 240.4 }, // stage 0 + { hex: "#E6D5B8", luminance: 214.8 }, // stage 1 + { hex: "#D4B483", luminance: 184.0 }, // stage 2 + { hex: "#B78B6A", luminance: 148.4 }, // stage 3 + { hex: "#8B5A3A", luminance: 101.0 }, // stage 4 + { hex: "#744C33", luminance: 84.5 }, // stage 5 + { hex: "#5D3D2C", luminance: 68.1 }, // stage 6 + ]; + const alphaStops = [ + -0.2, // stage 0 + -0.3, // stage 1 + -0.4, // stage 2 + -0.5, // stage 3 + -0.6, // stage 4 + -0.7, // stage 5 + -0.8, // stage 6 + ]; + // 绱闄嶉洦閲忛槇鍊硷紙mm锛� + const R_THRESHOLDS = [0, 200, 240, 280, 310, 350]; // 鍏�6涓樁娈靛搴�6涓槇鍊� + // 鏃堕棿鍜岄檷闆ㄩ噺淇℃伅 + const timeTotals = []; + const initialTimestamp = new Date(rainTotalInfo.value[0].time).getTime(); + for (let i = 0; i < rainTotalInfo.value.length; i++) { + const timestamp = new Date(rainTotalInfo.value[i].time).getTime(); + const time = (timestamp - initialTimestamp) / 1000; + const total = rainTotalInfo.value[i].total; // 浣跨敤 total 鏇夸唬 intensity + timeTotals.push({ + time, + total, + }); + } + + // 鎵惧嚭姣忎釜闃舵棣栨杈惧埌鐨勬椂闂寸偣 + const stages = []; + for (let stage = 1; stage < R_THRESHOLDS.length + 1; stage++) { + const threshold = R_THRESHOLDS[stage - 1]; + for (let i = 0; i < timeTotals.length; i++) { + const { time, total } = timeTotals[i]; + if (total >= threshold) { + stages[stage] = { + startTime: time, + color: COLOR_STOPS[stage].hex, + alpha: alphaStops[stage], + threshold, + }; + break; + } + } + } + + // 濉厖闃舵0 + stages[0] = { + startTime: 0, + color: COLOR_STOPS[0].hex, + alpha: alphaStops[0], + threshold: 0, + }; + + colorState.colorStages = stages; +} + +function updateWaterColorByTime(isForceUpdate = false) { + if (!rainTotalInfo.value || rainTotalInfo.value.length === 0) return; + + // 棣栨璋冪敤鏃堕璁$畻棰滆壊闃舵 + if (colorState.colorStages === null) { + precomputeColorStages(); + } + + // 鏌ユ壘褰撳墠鏃堕棿鐐规墍灞炵殑闃舵 + let currentStage = 0; + for (let i = colorState.colorStages.length - 1; i >= 0; i--) { + if ( + colorState.colorStages[i] && + currentTime.value >= colorState.colorStages[i].startTime + ) { + currentStage = i; + break; + } + } + + // 璁板綍杈惧埌鏈�娣遍鑹茬殑鏃堕棿鐐� + if (currentStage >= colorState.colorStages.length - 1) { + if ( + colorState.maxColorTime === null || + currentTime.value > colorState.maxColorTime + ) { + colorState.maxColorTime = currentTime.value; + } + } + + // 鍒ゆ柇鏄惁闇�瑕佸己鍒舵洿鏂伴鑹� + const isTimeGoingBackward = currentTime.value < colorState.lastTime; + const isBeforeMaxColorTime = + colorState.maxColorTime !== null && + currentTime.value <= colorState.maxColorTime; + const shouldForceUpdate = + isForceUpdate && (isTimeGoingBackward || isBeforeMaxColorTime); + + // 鏇存柊棰滆壊閫昏緫 + if (shouldForceUpdate || isTimeGoingBackward) { + // 寮哄埗鏇存柊鎴栨椂闂村洖閫�鏃讹紝鐩存帴搴旂敤褰撳墠闃舵鐨勯鑹� + colorState.currentColor = colorState.colorStages[currentStage].color; + colorState.currentAlpha = colorState.colorStages[currentStage].alpha; + } else { + // 姝e父鏃堕棿鍓嶈繘鏃讹紝淇濇寔娓愯繘鍙樺寲 + const newColor = colorState.colorStages[currentStage].color; + const newAlpha = colorState.colorStages[currentStage].alpha; + + // 鍙簲鐢ㄦ洿鏆楃殑棰滆壊鍜屾洿浣庣殑閫忔槑搴� + if ( + calculateLuminance(newColor) < calculateLuminance(colorState.currentColor) + ) { + colorState.currentColor = newColor; + } + if (newAlpha < colorState.currentAlpha) { + colorState.currentAlpha = newAlpha; + } + } + + // 鏇存柊鏃堕棿璁板綍 + colorState.lastTime = currentTime.value; + // ====== 鏂板锛氬湪 updateWaterColor 鍓嶆墦鍗板綋鍓嶄俊鎭� ====== + // // 鑾峰彇褰撳墠绱闄嶉洦閲� + let currentTotal = null; + const baseTimestamp = new Date(rainTotalInfo.value[0].time).getTime(); + const currentTimeMs = baseTimestamp + currentTime.value * 1000; + + // 鎵惧埌鏈�鎺ヨ繎鐨勯檷闆ㄦ暟鎹偣 + for (let i = rainTotalInfo.value.length - 1; i >= 0; i--) { + const dataTimeMs = new Date(rainTotalInfo.value[i].time).getTime(); + if (dataTimeMs <= currentTimeMs) { + currentTotal = rainTotalInfo.value[i].total; + break; + } + } + + // 鎵撳嵃淇℃伅 + // console.log("========================================"); + // console.log(`銆愭椂闂存埑銆�: ${new Date(currentTimeMs).toLocaleString()}`); + console.log( + `銆愮疮璁¢檷闆ㄩ噺 R銆�: ${ + currentTotal !== null ? currentTotal.toFixed(2) : "鏈煡" + } mm` + ); + // console.log(`銆愬綋鍓嶉樁娈点��: 绗� ${currentStage} 闃舵`); + console.log( + `銆愰鑹� HEX銆�: ${colorState.colorStages[currentStage]?.color || "鏈畾涔�"}` + ); + // console.log(`銆愰�忔槑搴� Alpha銆�: ${colorState.colorStages[currentStage]?.alpha || '鏈畾涔�'}`); + // console.log("========================================"); + // 搴旂敤棰滆壊 + updateWaterColor(colorState.currentColor, colorState.currentAlpha); +} + +// 杈呭姪鍑芥暟淇濇寔涓嶅彉 +function calculateLuminance(hex) { + const [r, g, b] = hexToRgb(hex); + return 0.299 * r + 0.587 * g + 0.114 * b; +} + +function hexToRgb(hex) { + const bigint = parseInt(hex.slice(1), 16); + return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255]; +} + +// 鏃堕棿杞磋烦杞嚱鏁� +const seekToPosition = (event) => { + if (!isWaterPrimitiveCreated.value) { + ElMessage.warning("璇峰厛鍚姩姘翠綋妯℃嫙鍚庡啀杩涜鏃堕棿杞磋烦杞��"); + return; + } + + const rect = timelineTrack.value.getBoundingClientRect(); + const percentage = (event.clientX - rect.left) / rect.width; + const targetTime = Math.round(percentage * duration.value); + + const closestIndex = findClosestTimestampIndex(targetTime); + const baseTimestamp = waterTimestamps.value[0]; + const newTime = (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000; + + // 鍒ゆ柇鏄惁闇�瑕佸己鍒舵洿鏂伴鑹� + const isGoingBackward = newTime < currentTime.value; + const isBeforeMaxColor = + colorState.maxColorTime !== null && newTime <= colorState.maxColorTime; + const shouldForceUpdate = isGoingBackward || isBeforeMaxColor; + + currentTime.value = newTime; + setTimeForWaterSimulation(closestIndex); + + // 鏍规嵁鏉′欢鏇存柊棰滆壊 + updateWaterColorByTime(shouldForceUpdate); + + if (!isPlaying.value) pauseWaterSimulation(); +}; +// ============================================================================ function updateWeatherByProgress() { if (rainFallValues.value.length === 0) return; @@ -426,7 +823,11 @@ // const rainValue = currentRain + (nextRain - currentRain) * alpha; const rainValue = currentRain + (nextRain - currentRain); // 鎵撳嵃褰撳墠澶勭悊鐨勯洦閲忔暟鎹� - console.log(`姝e湪澶勭悊鐨勯洦閲忔暟鎹偣: 褰撳墠=${currentRain}, 涓嬩竴涓�=${nextRain}, 鎻掑�煎悗=${rainValue.toFixed(2)}, 绱㈠紩=${index}`); + // console.log( + // `姝e湪澶勭悊鐨勯洦閲忔暟鎹偣: 褰撳墠=${currentRain}, 涓嬩竴涓�=${nextRain}, 鎻掑�煎悗=${rainValue.toFixed( + // 2 + // )}, 绱㈠紩=${index}` + // ); // 濡傛灉褰撳墠绱㈠紩鏈彉鍖栦笖鎻掑�煎樊寮備笉澶э紝璺宠繃閲嶅鏇存柊 if (index === lastUsedIndex && Math.abs(rainValue - lastRainValue) < 0.1) { // console.log('鐢变簬鏁版嵁鏃犳樉钁楀彉鍖栵紝璺宠繃鏈鏇存柊'); @@ -516,27 +917,7 @@ EventBus.emit("clear-echart"); EventBus.emit("reset-table"); }; -// 鏃堕棿杞磋烦杞� -const seekToPosition = (event) => { - if (!isWaterPrimitiveCreated.value) { - ElMessage.warning("璇峰厛鍚姩姘翠綋妯℃嫙鍚庡啀杩涜鏃堕棿杞磋烦杞��"); - return; - } - const rect = timelineTrack.value.getBoundingClientRect(); - const percentage = (event.clientX - rect.left) / rect.width; - const targetTime = Math.round(percentage * duration.value); - - // 鐩存帴鎵惧埌鏈�杩戠殑 timestamp 绱㈠紩 - const closestIndex = findClosestTimestampIndex(targetTime); - const baseTimestamp = waterTimestamps.value[0]; - currentTime.value = - (waterTimestamps.value[closestIndex] - baseTimestamp) / 1000; - - // 鏇存柊姘翠綋妯℃嫙鏃堕棿 - setTimeForWaterSimulation(closestIndex); - if (!isPlaying.value) pauseWaterSimulation(); -}; // 杈呭姪鍑芥暟锛氭壘鍒版渶鎺ヨ繎鐨勬椂闂存埑绱㈠紩 function findClosestTimestampIndex(currentTimeValue) { if (waterTimestamps.value.length === 0) return 0; @@ -607,27 +988,52 @@ { immediate: true } ); -onMounted(async () => { +const jsonFetch = ref(null); +const currentReplayIndex = ref(0); // 褰撳墠鎾斁鐨剅ePlayList绱㈠紩 +// 鎻愬彇涓虹嫭绔嬪嚱鏁� +async function initializeSimulationData(replayItem = null) { try { - // 褰撳墠鏂规鐨勬墍鏈変俊鎭� const schemeInfo = selectedScheme.value; serviceInfo = schemeInfo.serviceName; + if (schemeInfo.type == 2) { + if ( + replayItem || + (simStore.rePlayList && simStore.rePlayList.length != 0) + ) { + jsonFetch.value = + replayItem || simStore.rePlayList[currentReplayIndex.value]; + speedShow.value = true; + } else { + jsonFetch.value = layerDate.value; + speedShow.value = false; + } + } else { + getRainfallData(); + speedShow.value = true; + jsonFetch.value = null; + } + // console.log('鑾峰彇鍒扮殑 serviceName:', serviceInfo); - getRainfallData(); - // 鏍规嵁layer.json鍘昏幏鍙栨椂闂磋酱淇℃伅 + // 鏍规嵁 layer.json 鑾峰彇鏃堕棿杞翠俊鎭� const { waterTimestamps: timestamps, watersMaxHeight, watersMinHeight, - } = await fetchWaterSimulationData(serviceInfo); + } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value); + console.log( "褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�", watersMaxHeight, watersMinHeight ); - - // 鐜板湪鏄寜鐓ф�诲叡鏈夊灏戜釜鐐规潵娓叉煋鏃堕棿杞� + const waterInfoArr = [ + watersMaxHeight, + maxRainValue.value, + averageRainIntensity.value, + ]; + schemWaterInfo.value = waterInfoArr; + // 鏇存柊鏃堕棿杞寸浉鍏虫暟鎹� if (timestamps) { frameNum.value = timestamps.length; waterTimestamps.value = timestamps; @@ -647,7 +1053,66 @@ type: "warning", }); } +} +// 鎾斁瀹屾垚鍚庣殑鍥炶皟 +function handlePlayFinished() { + if (selectedScheme.value.type !== 2) return; + finishPlay.value = false; + currentReplayIndex.value++; + + if (currentReplayIndex.value < simStore.rePlayList.length) { + // 鑷姩鎾斁涓嬩竴涓� + initializeSimulationData(simStore.rePlayList[currentReplayIndex.value]); + togglePlay(); + shouldAutoPlay.value = false; + } else { + // 鎵�鏈夐」鐩挱鏀惧畬鎴� + currentReplayIndex.value = 0; // 閲嶇疆绱㈠紩 + isPlaying.value = false; // 鍋滄鎾斁 + emit("timeUpdate", 100); // 鍦ㄦ墍鏈夐」鐩挱鏀惧畬姣曞悗瑙﹀彂 + } +} + +// 鐩戝惉鎾斁瀹屾垚浜嬩欢 +watch( + () => finishPlay.value, + (newVal) => { + if ( + newVal && + selectedScheme.value.type === 2 && + simStore.rePlayList.length > 0 + ) { + handlePlayFinished(); + } + } +); + +const shouldAutoPlay = ref(false); +// 鐩戝惉 layerDate 鍙樺寲鍚庢爣璁板噯澶囨挱鏀� +watch( + () => layerDate.value, + async (newVal) => { + if (selectedScheme.value.type === 2 && newVal) { + shouldAutoPlay.value = true; + } + }, + { deep: true } +); +// 绛夊緟 finishPlay 鎴愬姛鍚庡啀鎾斁 +watchEffect(() => { + if (shouldAutoPlay.value && finishPlay.value && !isPlaying.value) { + initializeSimulationData(); + togglePlay(); + shouldAutoPlay.value = false; + } }); + +// 鎸傝浇鏃惰皟鐢� +onMounted(async () => { + // 鍥犱负杩欎釜鍑芥暟瀹炴椂妯℃嫙鐩戝惉涔熼渶瑕佷娇鐢紝鎵�浠ュ皝瑁呬簡涓�涓嚱鏁� + await initializeSimulationData(); +}); + // 鏍规嵁杩斿洖鏁版嵁鐨勪釜鏁板幓娓叉煋鏃堕棿杞� function updateTimelineRange() { if (waterTimestamps.value.length > 0) { @@ -658,32 +1123,75 @@ duration.value = (last - first) / 1000; // 姣杞 } } - onBeforeUnmount(() => { stopPlayback(); destoryWaterPrimitive(); }); const { endSimulate } = inject("simulateActions"); -function handleBack() { + +async function handleBack() { + // 瀹炴椂妯℃嫙寮圭獥纭鏄繑鍥炴柟妗堝垪琛ㄨ繕鏄仠姝㈡ā鎷� + if (selectedScheme.value.type === 2) { + try { + await ElMessageBox.confirm("鏂规鏈仠姝㈡椂缁撴潫妯℃嫙鍚庯紝鍚庡彴灏嗗仠姝㈣绠�", { + confirmButtonText: "缁撴潫妯℃嫙", + cancelButtonText: "杩斿洖鍒楄〃", + type: "warning", + }); + + const res = await stopSim(selectedScheme.value.id); + if (res.code == 404) { + ElMessage.warning("璇ユ湇鍔″凡鍋滄"); + } else { + ElMessage.success("鏈嶅姟姝e湪鍋滄涓�"); + } + } catch (error) { + // 鐢ㄦ埛鐐瑰嚮浜嗐�愯繑鍥炲垪琛ㄣ�戞垨鑰呭嚭鐜伴敊璇� + return; + } + } + + // 涓嶇 type 鏄笉鏄� 2锛屾渶缁堥兘鎵ц缁撴潫妯℃嫙鎿嶄綔 + endSimulation(); +} + +async function endSimulation() { + clearAllPoints(); + simStore.openDia = true; + simStore.crossSection = []; + // 缁撴潫妯℃嫙涔嬪悗娓呴櫎layer鍒楄〃 + simStore.rePlayList = []; + EventBus.emit("close-time"); endSimulate(); isWaterPrimitiveCreated.value = false; + + // 缁撴潫璁$畻鍜屽仠姝㈡嬀鍙� if (ratelevelRef.value) { ratelevelRef.value.endCalculation(); ratelevelRef.value.stopPicking(); } + + // 娓呴櫎鐐� if (crossRef.value) { crossRef.value.clearPoints(); console.log("鎵ц鍒犻櫎鐐瑰姛鑳�"); } + emit("isColorRender", false); + + // 寤惰繜鍒犻櫎闆ㄩ噺鍥惧眰 setTimeout(() => { mapUtils.delRain(); }, 3000); + destoryWaterPrimitive(); + + // 鍙戦�佷簨浠堕殣钘忕浉鍏充俊鎭� EventBus.emit("hide-schemeInfo"); EventBus.emit("clear-water-depth"); EventBus.emit("clear-water-velocity"); + ElMessage({ message: "妯℃嫙杩涚▼姝e湪鍏抽棴涓�...", type: "success" }); } </script> -- Gitblit v1.9.3