From 1119a7837323e052d3e6256cddd3283d919bd959 Mon Sep 17 00:00:00 2001 From: guonan <guonan201020@163.com> Date: 星期四, 26 六月 2025 15:44:02 +0800 Subject: [PATCH] 提交 --- src/components/menu/TimeLine.vue | 302 ++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 228 insertions(+), 74 deletions(-) diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue index e18acb9..f4b1380 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" 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"; @@ -174,6 +214,9 @@ new Set(waterTimestamps.value.map((ts) => dayjs(ts).format("YYYY-MM-DD"))) ).map((date) => dayjs(date).toDate()) ); + +// 鎴戦渶瑕佸姞涓�涓垽鏂� +const finishPlay = ref(false); // 鎾斁鎺у埗 const togglePlay = () => { // 杩欓噷搴旇鍐嶈瀹氬嚑涓檺鍒讹紝濡傛灉缂哄皯浠�涔堟暟鎹紝鏃犳硶杩涜浠跨湡 @@ -241,38 +284,96 @@ 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) { + // 绫诲瀷涓� 2锛氭瘡 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; + } - // 瑙﹀彂鏇存柊 - if (selectedScheme.value.type !== 2) { + // 瑙﹀彂杩涘害鏇存柊 + const progress = currentTime.value / totalDuration; + emit("timeUpdate", progress * 100); + + // 濡傛灉闇�瑕佽Е鍙戞煇浜涙洿鏂板嚱鏁帮紝涔熷彲浠ヤ繚鐣� updateWaterColorByTime(); updateWeatherByProgress(); - } + }, 5000); // 姣� 5 绉掓墽琛屼竴娆� + } else { + // 杩欓噷闈㈣繕鏄綘鐨勬挱鏀句唬鐮侊紝涓婇潰鐨刬f涓槸浜旂閽熻烦鍔ㄤ竴娆$殑瀹炴椂妯℃嫙 + playInterval = setInterval(() => { + const currentIndex = findClosestTimestampIndex(currentTime.value); + const nextIndex = currentIndex + 1; - const progress = currentTime.value / duration.value; - emit("timeUpdate", progress * 100); - }, 1000 / playbackRate.value); // 鏍规嵁鎾斁閫熺巼璋冩暣闂撮殧 + 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); + } }; // 闄嶉洦鍙樺寲閮ㄥ垎 // 闄嶉洦鏁版嵁鐩稿叧鍙橀噺 @@ -428,10 +529,10 @@ } // 鍏ㄥ眬鐘舵�佽褰� const colorState = { - maxStage: 0, // 璁板綍鍘嗗彶鏈�楂橀樁娈� - maxAlpha: -0.3, // 璁板綍鍘嗗彶鏈�灏忛�忔槑搴︼紙璐熷�硷級 + maxStage: 0, // 璁板綍鍘嗗彶鏈�楂橀樁娈� + maxAlpha: -0.3, // 璁板綍鍘嗗彶鏈�灏忛�忔槑搴︼紙璐熷�硷級 maxLuminance: 240.4, // 璁板綍鍘嗗彶鏈�浣庝寒搴︼紙瀵瑰簲stage 0鍒濆鍊硷級 - currentColor: "#F5F0E6" // 褰撳墠棰滆壊 + currentColor: "#F5F0E6", // 褰撳墠棰滆壊 }; function updateWaterColorByTime() { @@ -448,16 +549,16 @@ { hex: "#D4B483", luminance: 184.0 }, // stage 3 { hex: "#B78B6A", luminance: 148.4 }, // stage 4 { hex: "#8B5A3A", luminance: 101.0 }, // stage 5 - { hex: "#4A3123", luminance: 54.9 } // stage 6 + { hex: "#4A3123", luminance: 54.9 }, // stage 6 ]; - const alphaStops = [1 - -0.3, // stage 0 - -0.4, // stage 1 - -0.5, // stage 2 - -0.6, // stage 3 - -0.7, // stage 4 - -0.75, // stage 5 - -0.8 // stage 6 + const alphaStops = [ + 1 - 0.3, // stage 0 + -0.4, // stage 1 + -0.5, // stage 2 + -0.6, // stage 3 + -0.7, // stage 4 + -0.75, // stage 5 + -0.8, // stage 6 ]; // 3. 鏇存柊闃舵鐘舵�� updateStageState(intensity, IR); @@ -472,10 +573,15 @@ function calculateRainData() { const initialTimestamp = new Date(rainTotalInfo.value[0].time).getTime(); const currentTimestamp = new Date( - rainTotalInfo.value[Math.min( - Math.floor(currentTime.value / duration.value * (rainTotalInfo.value.length - 1)), - rainTotalInfo.value.length - 2 - )].time + rainTotalInfo.value[ + Math.min( + Math.floor( + (currentTime.value / duration.value) * + (rainTotalInfo.value.length - 1) + ), + rainTotalInfo.value.length - 2 + ) + ].time ).getTime(); // 闄嶉洦寮哄害璁$畻锛堝甫鎻掑�硷級 @@ -486,7 +592,8 @@ index = rainTotalInfo.value.length - 2; // 闃叉 index+1 瓒婄晫 } const lerpAlpha = floatIndex - index; - const intensity = rainTotalInfo.value[index].intensity * (1 - lerpAlpha) + + const intensity = + rainTotalInfo.value[index].intensity * (1 - lerpAlpha) + rainTotalInfo.value[index + 1].intensity * lerpAlpha; // 涓寸晫闄嶉洦寮哄害璁$畻 @@ -524,7 +631,13 @@ const stageThresholds = [0, 0.2, 0.4, 0.6, 0.8, 1.0]; const lowerThreshold = stageThresholds[colorState.maxStage - 1] * IR; const upperThreshold = stageThresholds[colorState.maxStage] * IR; - const ratio = Math.min(1, Math.max(0, (intensity - lowerThreshold) / (upperThreshold - lowerThreshold))); + const ratio = Math.min( + 1, + Math.max( + 0, + (intensity - lowerThreshold) / (upperThreshold - lowerThreshold) + ) + ); // 棰滆壊鎻掑�� const startColor = colorStops[colorState.maxStage]; @@ -538,22 +651,26 @@ colorState.maxLuminance = newLuminance; colorState.maxAlpha = Math.min( colorState.maxAlpha, - lerp(alphaStops[colorState.maxStage], alphaStops[colorState.maxStage + 1], ratio) + lerp( + alphaStops[colorState.maxStage], + alphaStops[colorState.maxStage + 1], + ratio + ) ); } - console.log(`闃舵: ${colorState.maxStage} | 浜害: ${colorState.maxLuminance.toFixed(1)} | 棰滆壊: ${colorState.currentColor}`); + console.log( + `闃舵: ${colorState.maxStage} | 浜害: ${colorState.maxLuminance.toFixed( + 1 + )} | 棰滆壊: ${colorState.currentColor}` + ); } // 棰滆壊鎻掑�煎伐鍏峰嚱鏁� function lerpColor(c1, c2, t) { const [r1, g1, b1] = hexToRgb(c1); const [r2, g2, b2] = hexToRgb(c2); - return rgbToHex( - r1 + (r2 - r1) * t, - g1 + (g2 - g1) * t, - b1 + (b2 - b1) * t - ); + return rgbToHex(r1 + (r2 - r1) * t, g1 + (g2 - g1) * t, b1 + (b2 - b1) * t); } function calculateLuminance(hex) { @@ -567,7 +684,9 @@ } function rgbToHex(r, g, b) { - return `#${[r, g, b].map(x => Math.round(x).toString(16).padStart(2, '0')).join('')}`; + return `#${[r, g, b] + .map((x) => Math.round(x).toString(16).padStart(2, "0")) + .join("")}`; } function lerp(a, b, t) { @@ -774,16 +893,17 @@ { immediate: true } ); -onMounted(async () => { +const jsonFetch = ref(null); + +// 鎻愬彇涓虹嫭绔嬪嚱鏁� +async function initializeSimulationData(force = false) { try { - // 褰撳墠鏂规鐨勬墍鏈変俊鎭� const schemeInfo = selectedScheme.value; - const jsonFetch = ref(null); serviceInfo = schemeInfo.serviceName; - if (selectedScheme.value.type == 2) { + + if (schemeInfo.type == 2) { speedShow.value = false; jsonFetch.value = layerDate.value; - // serviceInfo = layerDate.value; } else { getRainfallData(); speedShow.value = true; @@ -792,19 +912,20 @@ // console.log('鑾峰彇鍒扮殑 serviceName:', serviceInfo); - // 鏍规嵁layer.json鍘昏幏鍙栨椂闂磋酱淇℃伅 + // 鏍规嵁 layer.json 鑾峰彇鏃堕棿杞翠俊鎭� const { waterTimestamps: timestamps, watersMaxHeight, watersMinHeight, } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value); + console.log( "褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�", watersMaxHeight, watersMinHeight ); - // 鐜板湪鏄寜鐓ф�诲叡鏈夊灏戜釜鐐规潵娓叉煋鏃堕棿杞� + // 鏇存柊鏃堕棿杞寸浉鍏虫暟鎹� if (timestamps) { frameNum.value = timestamps.length; waterTimestamps.value = timestamps; @@ -815,6 +936,7 @@ "YYYY-MM-DD HH:mm:ss" ); } + minFlowRate = watersMinHeight; maxFlowRate = watersMaxHeight; } catch (error) { @@ -824,7 +946,36 @@ type: "warning", }); } +} + +// 鎸傝浇鏃惰皟鐢� +onMounted(async () => { + // 鍥犱负杩欎釜鍑芥暟瀹炴椂妯℃嫙鐩戝惉涔熼渶瑕佷娇鐢紝鎵�浠ュ皝瑁呬簡涓�涓嚱鏁� + await initializeSimulationData(); }); + +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; + } +}); + // 鏍规嵁杩斿洖鏁版嵁鐨勪釜鏁板幓娓叉煋鏃堕棿杞� function updateTimelineRange() { if (waterTimestamps.value.length > 0) { @@ -844,6 +995,9 @@ const { endSimulate } = inject("simulateActions"); function handleBack() { endSimulate(); + // 鍋滄瀹炴椂妯℃嫙瀹氭椂鍣� + EventBus.emit("close-time"); + isWaterPrimitiveCreated.value = false; if (ratelevelRef.value) { ratelevelRef.value.endCalculation(); -- Gitblit v1.9.3