From fa541dda36e58de1d491b3ff4073c51b16606515 Mon Sep 17 00:00:00 2001 From: wangjuncheng <1> Date: 星期三, 25 六月 2025 17:29:42 +0800 Subject: [PATCH] 2 --- src/components/menu/TimeLine.vue | 282 ++++++++++++++++++++++++++++++++++++------------------- 1 files changed, 183 insertions(+), 99 deletions(-) diff --git a/src/components/menu/TimeLine.vue b/src/components/menu/TimeLine.vue index 91d7acb..e18acb9 100644 --- a/src/components/menu/TimeLine.vue +++ b/src/components/menu/TimeLine.vue @@ -2,30 +2,20 @@ <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> @@ -35,33 +25,19 @@ <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> @@ -70,12 +46,8 @@ <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> @@ -84,38 +56,27 @@ </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> @@ -152,7 +113,7 @@ 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", @@ -191,7 +152,7 @@ const isWaterPrimitiveCreated = ref(false); let playInterval = null; let timeStepInfo = null; -let rainTotalInfo = ([]); +let rainTotalInfo = []; const isRainEnabled = ref(false); const rainParams = reactive({ rainSize: 0.5, @@ -201,6 +162,9 @@ }); let minFlowRate = ref(); let maxFlowRate = ref(); +// 鍏ㄥ眬鍙橀噺璁板綍鏈�澶ч樁娈靛拰閫忔槑搴� +let maxStage = 0; +let maxAlpha = -0.3; // 鍒濆閫忔槑搴﹀搴攕tage 0 // 璁$畻灞炴�� const progressPercentage = computed( () => (currentTime.value / duration.value) * 100 @@ -348,10 +312,10 @@ const rainfallList = data.rainfalls; console.log("鏈�缁堢殑 rainfallList:", rainfallList); - rainTotalInfo.value = rainfallList - calculateTimeStep(rainTotalInfo.value) + rainTotalInfo.value = rainfallList; + calculateTimeStep(rainTotalInfo.value); // 浣跨敤绀轰緥 - timeStepInfo = calculateTimeStep(rainTotalInfo.value); + timeStepInfo = calculateTimeStep(rainTotalInfo.value); // 鎻愬彇 intensity 鍊� rainFallValues.value = rainfallList.map((r) => r.intensity); @@ -430,13 +394,13 @@ function calculateTimeStep(dataArray) { if (!dataArray || dataArray.length < 2) { - console.warn('鏁版嵁涓嶈冻锛屾棤娉曡绠楁椂闂存闀�'); + console.warn("鏁版嵁涓嶈冻锛屾棤娉曡绠楁椂闂存闀�"); return null; } // 瑙f瀽鏃堕棿瀛楃涓蹭负 Date 瀵硅薄 function parseTime(timeStr) { - return new Date(timeStr.replace(' ', 'T')); // 鍏煎 ISO 鏍煎紡 + return new Date(timeStr.replace(" ", "T")); // 鍏煎 ISO 鏍煎紡 } const firstTime = parseTime(dataArray[0].time); @@ -454,45 +418,161 @@ 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)} 灏忔椂`); + console.warn( + `鍦ㄧ储寮� ${i} 澶勫彂鐜颁簡涓嶅悓鐨勬椂闂存闀�: ${step.toFixed(2)} 灏忔椂` + ); } } return timeStepHours; } +// 鍏ㄥ眬鐘舵�佽褰� +const colorState = { + maxStage: 0, // 璁板綍鍘嗗彶鏈�楂橀樁娈� + maxAlpha: -0.3, // 璁板綍鍘嗗彶鏈�灏忛�忔槑搴︼紙璐熷�硷級 + maxLuminance: 240.4, // 璁板綍鍘嗗彶鏈�浣庝寒搴︼紙瀵瑰簲stage 0鍒濆鍊硷級 + currentColor: "#F5F0E6" // 褰撳墠棰滆壊 +}; 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; - console.log(`璁$畻寰楀埌鐨勬椂闂存闀夸负: ${timeStepInfo} 灏忔椂`); - // 鏍规嵁 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'; + // 1. 璁$畻鍩虹鏁版嵁 + const { intensity, IR } = calculateRainData(); + + // 2. 棰滆壊閰嶇疆锛堜寒搴︿弗鏍奸�掑噺锛� + const COLOR_STOPS = [ + { hex: "#F5F0E6", luminance: 240.4 }, // stage 0 + { hex: "#D4F2E7", luminance: 231.8 }, // stage 1 + { hex: "#E6D5B8", luminance: 214.8 }, // stage 2 + { 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 + ]; + 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); + + // 4. 璁$畻骞堕攣瀹氶鑹诧紙纭繚浜害涓嶅洖鍗囷級 + updateColorState(COLOR_STOPS, intensity, IR); + + // 5. 搴旂敤棰滆壊 + updateWaterColor(colorState.currentColor, colorState.maxAlpha); + + // --- 杈呭姪鍑芥暟 --- + 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 + ).getTime(); + + // 闄嶉洦寮哄害璁$畻锛堝甫鎻掑�硷級 + const progress = currentTime.value / duration.value; + const floatIndex = progress * (rainTotalInfo.value.length - 1); + let index = Math.floor(floatIndex); + if (index >= rainTotalInfo.value.length - 1) { + index = rainTotalInfo.value.length - 2; // 闃叉 index+1 瓒婄晫 + } + const lerpAlpha = floatIndex - index; + const intensity = rainTotalInfo.value[index].intensity * (1 - lerpAlpha) + + rainTotalInfo.value[index + 1].intensity * lerpAlpha; + + // 涓寸晫闄嶉洦寮哄害璁$畻 + const D = (currentTimestamp - initialTimestamp) / (1000 * 60 * 60) + 0.0001; + const IR = 56.9 * Math.pow(D, -0.746); + + return { intensity, IR }; } - // console.log(`褰撳墠 total: ${total.toFixed(2)}, 棰滆壊: ${color}`); - // updateWaterColor(color) + + function updateStageState(intensity, IR) { + // 璁$畻鐞嗚闃舵 + let stage = 0; + const thresholds = [0, 0.2, 0.4, 0.6, 0.8, 1.0]; + for (let i = thresholds.length - 1; i >= 0; i--) { + if (intensity >= thresholds[i] * IR) { + stage = i + 1; + break; + } + } + + // 鏇存柊鏈�澶ч樁娈碉紙鍗曞悜閫掑锛� + colorState.maxStage = Math.max(colorState.maxStage, stage); + } + + function updateColorState(colorStops, intensity, IR) { + // 宸茶揪鏈�缁堥樁娈� + if (colorState.maxStage >= colorStops.length - 1) { + colorState.currentColor = colorStops[colorStops.length - 1].hex; + colorState.maxAlpha = -0.8; + colorState.maxLuminance = colorStops[colorStops.length - 1].luminance; + return; + } + + // 璁$畻褰撳墠闃舵杩涘害 + 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 startColor = colorStops[colorState.maxStage]; + const endColor = colorStops[colorState.maxStage + 1]; + const newColor = lerpColor(startColor.hex, endColor.hex, ratio); + const newLuminance = calculateLuminance(newColor); + + // 鍙帴鍙楁洿鏆楃殑棰滆壊锛堜寒搴︽洿浣庯級 + if (newLuminance < colorState.maxLuminance) { + colorState.currentColor = newColor; + colorState.maxLuminance = newLuminance; + colorState.maxAlpha = Math.min( + colorState.maxAlpha, + lerp(alphaStops[colorState.maxStage], alphaStops[colorState.maxStage + 1], ratio) + ); + } + + 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 + ); + } + + 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]; + } + + function rgbToHex(r, g, b) { + return `#${[r, g, b].map(x => Math.round(x).toString(16).padStart(2, '0')).join('')}`; + } + + function lerp(a, b, t) { + return a + (b - a) * t; + } } function updateWeatherByProgress() { @@ -509,11 +589,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('鐢变簬鏁版嵁鏃犳樉钁楀彉鍖栵紝璺宠繃鏈鏇存柊'); @@ -698,12 +778,16 @@ 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); @@ -713,7 +797,7 @@ waterTimestamps: timestamps, watersMaxHeight, watersMinHeight, - } = await fetchWaterSimulationData(serviceInfo); + } = await fetchWaterSimulationData(serviceInfo, jsonFetch.value); console.log( "褰撳墠鏂规涓嬬殑鏈�澶ф按浣嶆繁搴﹀拰鏈�灏忔按浣嶆繁搴�", watersMaxHeight, -- Gitblit v1.9.3