wangjuncheng
2025-05-08 db07d86f01f19683d7adb263139159ffe1e0c9bf
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">
        <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,39 +25,21 @@
    <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>
      <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="time-markers">
          <div
            v-for="(time, index) in timeMarkers"
            :key="index"
            class="time-marker"
          >
          <div v-for="(time, index) in timeMarkers" :key="index" class="time-marker">
            {{ time }}
          </div>
        </div>
      </div>
    </div>
    <el-button
      @click="handleBack"
      style="margin-top: 26px; margin-left: 30px; margin-right: 10px"
      >结束模拟</el-button
    >
    <el-button @click="handleBack" style="margin-top: 26px; margin-left: 30px; margin-right: 10px">结束模拟</el-button>
  </div>
</template>
@@ -215,54 +187,127 @@
    emit("timeUpdate", progress * 100); // 百分比上报
  }, 1000); // 注意使用interval而非固定1000ms
};
let rainFallValues = ref([]); // 用于存储提取的value数组
// 降雨变化部分
// 降雨数据相关变量
// 降雨数据相关变量
let rainFallValues = ref([]); // 存储原始降雨量数据
let minRainValue = ref(Infinity);
let maxRainValue = ref(-Infinity);
// 获取降雨数据
function getRainfallData() {
  getRainfall().then((res) => {
    rainFallValues.value = res;
    // 提取value值
    rainFallValues.value = rainFallValues.value.data.map(item => item.value);
    // 计算min和max雨量值
    rainFallValues.value = res.data.map(item => item.value); // 提取降雨量值
    minRainValue.value = Math.min(...rainFallValues.value);
    maxRainValue.value = Math.max(...rainFallValues.value);
    console.log(minRainValue.value, maxRainValue.value, 'min and max rain values');
  });
}
// 线性映射函数
function mapValue(value, fromLow, fromHigh, toLow, toHigh) {
  return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
}
// 根据当前播放进度更新天气
// 我这里要是接入真实数据后,每个数据
function updateWeatherByProgress() {
  const progress = currentTime.value / duration.value;
  // 计算当前进度对应于 rainFallValues 数组中的位置
  const index = Math.floor(progress * (rainFallValues.value.length - 1));
  const rainValue = rainFallValues.value[index]; // 获取对应的降雨量 value
  // 根据当前雨量动态调整雨的参数
  // const rainParams = {
  //   rainSize: mapValue(rainValue, minRainValue.value, maxRainValue.value, 0.5, 1.5),     // 雨滴大小:从小到大
  //   rainSpeed: mapValue(rainValue, minRainValue.value, maxRainValue.value, 30, 120),      // 雨速:从慢到快
  //   rainDensity: mapValue(rainValue, minRainValue.value, maxRainValue.value, 20, 120),    // 密度:从稀疏到密集
  //   rainColor: "#99B3CC"  // 可以在此基础上增加颜色变化逻辑,例如暴雨为深蓝等
  // };
  // 调用工具方法更新下雨效果
  mapUtils.toggleRain(rainParams, true);
// // 线性映射函数
// function mapValue(value, fromLow, fromHigh, toLow, toHigh) {
//   return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
// }
// 定义降雨等级及其对应的视觉参数
const rainLevels = [
  {
    name: '小雨',
    min: 0.1,
    max: 9.9,
    size: 0.5,     // 雨滴大小:更小
    speed: 20,     // 下落速度:更慢
    density: 15,   // 雨滴密度:更稀疏
    color: '#ADD8E6' // 浅蓝色,象征轻柔的小雨
  },
  {
    name: '中雨',
    min: 10,
    max: 24.9,
    size: 0.7,
    speed: 40,
    density: 35,
    color: '#ADD8E6' // 天蓝色,象征持续的中雨
  },
  {
    name: '大雨',
    min: 25,
    max: 49.9,
    size: 1.0,
    speed: 70,
    density: 60,
    color: '#ADD8E6' // 深蓝色,象征密集的大雨
  },
  {
    name: '暴雨',
    min: 50,
    max: 99.9,
    size: 1.3,
    speed: 90,
    density: 80,
    color: '#ADD8E6' // 深蓝黑色,象征强降雨
  },
  {
    name: '大暴雨',
    min: 100,
    size: 1.6,
    speed: 110,
    density: 100,
    color: '#ADD8E6' // 黑色,象征极端暴雨
  }
];
// 根据降雨量返回对应的雨形配置
function getRainLevel(rainValue) {
  for (let level of rainLevels) {
    if (level.min <= rainValue && (level.max === undefined || rainValue <= level.max)) {
      return level;
    }
  }
  // 默认无雨状态
  return { name: '无雨', size: 0.5, speed: 30, density: 20, color: '#F0F8FF' };
}
// 根据播放进度更新天气效果
function updateWeatherByProgress() {
  const progress = currentTime.value / duration.value;
  const floatIndex = progress * (rainFallValues.value.length - 1);
  const index = Math.floor(floatIndex);
  const nextIndex = Math.min(index + 1, rainFallValues.value.length - 1);
  const currentRain = rainFallValues.value[index];
  const nextRain = rainFallValues.value[nextIndex];
  // 插值因子 [0, 1]
  // const alpha = floatIndex - index;
  // 插值得到当前降雨量
  // const rainValue = currentRain + (nextRain - currentRain) * alpha;
  const rainValue = currentRain + (nextRain - currentRain);
  // 获取对应的雨形配置
  const rainLevel = getRainLevel(rainValue);
  if (rainLevel.name === '无雨') {
    mapUtils.delRain();
    return;
  }
  // 非无雨状态:构建雨滴参数并更新雨效
  const rainParams = {
    rainSize: rainLevel.size,
    rainSpeed: rainLevel.speed,
    rainDensity: rainLevel.density,
    rainColor: rainLevel.color
  };
  console.log('当前雨量数据:', rainValue);
  console.log('当前雨形:', rainLevel);
  // 调用工具方法更新雨效
  mapUtils.toggleRain(rainParams, true);
}
const stopPlayback = () => {
  clearInterval(playInterval);
};
const skipForward = () =>
  (currentTime.value = Math.min(currentTime.value + 1, duration.value)); // 向前跳转1秒
const skipBackward = () =>
  (currentTime.value = Math.max(currentTime.value - 1, 0)); // 向后跳转1秒
const toggleSpeedMenu = () => (showSpeedMenu.value = !showSpeedMenu.value);
// 设置播放速率
const setPlaybackRate = (rate) => {
  playbackRate.value = rate;
@@ -270,14 +315,13 @@
  // 停止当前播放
  stopPlayback();
  setTimeout(() => {
        mapUtils.delRain();
      }, 3000);
    mapUtils.delRain();
  }, 3000);
  // 重置时间轴到初始状态
  currentTime.value = 0; // 时间归零
  emit("timeUpdate", progressPercentage.value);
  isPlaying.value = false;
  emit("isPlaying", false);
  // 销毁现有的水体模拟层
  if (isWaterPrimitiveCreated.value) {
    destoryWaterPrimitive();
@@ -298,7 +342,7 @@
      message: "请先启动水体模拟后再进行时间轴跳转。",
      type: "warning",
    });
    return; // 阻止后续逻辑执行
    return;
  }
  const rect = timelineTrack.value.getBoundingClientRect();
  const percentage = (event.clientX - rect.left) / rect.width;
@@ -314,10 +358,7 @@
      "Time:",
      dayjs(waterTimestamps.value[closestIndex]).format("YYYY-MM-DD HH:mm:ss")
    );
    // 调用跳转接口,传递索引值
    setTimeForWaterSimulation(closestIndex);
    // 如果当前是暂停状态,调用 pauseWaterSimulation
    if (!isPlaying.value) {
      pauseWaterSimulation();
    }
@@ -331,7 +372,7 @@
  waterTimestamps.value.forEach((timestamp, index) => {
    const diff = Math.abs(
      dayjs(timestamp).diff(dayjs(waterTimestamps.value[0]), "second") -
        currentTimeValue
      currentTimeValue
    );
    if (diff < minDiff) {
      minDiff = diff;
@@ -446,7 +487,7 @@
  left: 50%;
  transform: translateX(-50%);
  z-index: 99;
  width: 878px;
  width: 678px;
  height: 108px;
  /* background-color: #1a2634; */
  background: url("@/assets/img/menubar/bar.png");