wangjuncheng
2025-04-30 e49c02db91d6438f65d4c9c97b938802c35d435e
Merge branch 'master' of http://103.135.160.14:9034/r/NslWeb

# Conflicts:
# src/components/menu/TimeLine.vue
已修改3个文件
627 ■■■■ 文件已修改
src/components/menu/TimeLine.vue 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/monifangzhen/echartInfo.vue 296 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/GisView.vue 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 @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,21 +35,39 @@
    <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>
@@ -67,10 +95,10 @@
import { fetchWaterSimulationData } from "@/api/trApi.js";
import { EventBus } from "@/eventBus";
import { ElMessage } from "element-plus";
import { useSimStore } from '@/store/simulation'
import { storeToRefs } from 'pinia'
const simStore = useSimStore()
const { selectedScheme } = storeToRefs(simStore)
import { useSimStore } from "@/store/simulation";
import { storeToRefs } from "pinia";
const simStore = useSimStore();
const { selectedScheme } = storeToRefs(simStore);
const emit = defineEmits(["timeUpdate", "isPlaying", "playbackFinished"]);
@@ -301,7 +329,10 @@
  let closestIndex = 0;
  let minDiff = Infinity;
  waterTimestamps.value.forEach((timestamp, index) => {
    const diff = Math.abs(dayjs(timestamp).diff(dayjs(waterTimestamps.value[0]), "second") - currentTimeValue);
    const diff = Math.abs(
      dayjs(timestamp).diff(dayjs(waterTimestamps.value[0]), "second") -
        currentTimeValue
    );
    if (diff < minDiff) {
      minDiff = diff;
      closestIndex = index;
@@ -317,7 +348,7 @@
      console.log('选中方案已改变:', newVal)
    }
  }
)
);
watch(
  () => currentTime.value,
  () => {
@@ -400,7 +431,7 @@
  }, 3000);
  ElMessage({ message: "模拟进程正在关闭中...", type: "success" }); // 显示消息通知用户模拟进程正在关闭
  endSimulate();
  isWaterPrimitiveCreated.value = false
  isWaterPrimitiveCreated.value = false;
  destoryWaterPrimitive();
  EventBus.emit("hide-schemeInfo");
}
src/components/monifangzhen/echartInfo.vue
@@ -13,11 +13,6 @@
      <div class="echartCont">
        <p>断面模拟</p>
        <div class="echartBox">
          <!-- <div>
            <button id="startButton">开始加载</button>
            <button id="pauseButton">暂停加载</button>
            <button id="resetButton">重置加载</button>
          </div> -->
          <div id="echarts2" style="width: 100%; height: 100%"></div>
        </div>
      </div>
@@ -112,19 +107,18 @@
import dayjs from "dayjs";
import { getRainfall } from "@/api";
let dataIntervalId = null; // 定时器 ID
let dataIntervalId = null; // 表格定时器 ID
const jsonData = ref([]); // JSON 数据
const tableData = ref([]); // 表格数据
const currentIndex = ref(0); // 当前加载索引
const isPaused = ref(false); // 是否暂停标志
const chart1Data = ref(null);
const chart2Data = ref(null);
let intervalId1 = null;
let intervalId2 = null;
const chart1Data = ref(null); //降雨数据
const chart2Data = ref(null); //断面数据
let intervalId1 = null; //降雨数据定时器
let intervalId2 = null; //断面数据定时器
// 根据时间轴匹配的x轴的时间显示
const nowTime = ref(null);
const isFinished = ref(true);
const props = defineProps({
  isDynamicMode: {
@@ -138,7 +132,6 @@
watch(
  () => props.isFinish,
  (newVal) => {
    isFinished.value = newVal;
    if (!newVal) {
      resetTable();
      chart1Data.value.resetLoading();
@@ -153,28 +146,13 @@
EventBus.on("reset-table", () => {
  resetTable(); // 调用重置表格的函数
});
// 清除echarts图表
EventBus.on("clear-echart", () => {
  clearEchartData(); // 调用清除函数
  chart1Data.value.resetLoading();
  chart2Data.value.resetLoading();
});
// 清除 echart1/2数据的函数
const clearEchartData = () => {
  if (myChart1) {
    const currentOption = myChart1.getOption(); // 获取当前图表配置
    currentOption.series.forEach((series) => {
      series.data = []; // 清空每个系列的数据
    });
    currentOption.xAxis[0].data = [];
    myChart1.setOption(currentOption);
  }
  if (myChart2) {
    const currentOption = myChart2.getOption();
    currentOption.series.forEach((series) => {
      series.data = [];
    });
    currentOption.xAxis[0].data = [];
    myChart2.setOption(currentOption);
  }
};
// 清除威胁对象中的数据
const resetTable = () => {
  currentIndex.value = 0;
@@ -191,11 +169,9 @@
  if (intervalId1) {
    clearInterval(intervalId1);
    chart1Data.value.stopUpdating(); // 每隔 1 秒更新一次
    intervalId1 = null;
  }
  if (intervalId2) {
    console.log(intervalId2, "暂停");
    clearInterval(intervalId2);
    chart2Data.value.stopUpdating(); // 每隔 1 秒更新一次
    intervalId2 = null;
@@ -205,6 +181,8 @@
    dataIntervalId = null;
  }
};
// 监听时间轴结束模拟
EventBus.on("hide-schemeInfo", handleHideSchemeInfo);
// 监听父组件传递的数据变化
@@ -257,11 +235,7 @@
let myChart1 = null;
let myChart2 = null;
const getRandomInt = (min = 0, max = 100) => {
  const minCeiled = Math.ceil(min);
  const maxFloored = Math.floor(max);
  return Math.floor(Math.random() * (maxFloored - minCeiled) + minCeiled);
};
// 威胁对象数据
const getDangerInfo = async () => {
  try {
    const response = await fetch(
@@ -315,15 +289,6 @@
  });
};
const getRainfallData = async () => {
  try {
    const res = await getRainfall();
    rainfallData.value = res.data;
  } catch (error) {
    console.error("Error fetching rainfall data:", error);
  }
};
const rainClick = () => {
  rainChangeShow.value = !rainChangeShow.value;
  let desc = { func_name: "RainChange", visibility: rainChangeShow.value };
@@ -343,6 +308,7 @@
  charts.style.height = style.height;
};
// 时间轴时间截取处理
const syncTimeWithTimeline = () => {
  // 2025-05-24 00:25
  // // 将时间字符串转换为分钟数 (格式: "YYYY-MM-DD mm:ss")
@@ -351,26 +317,32 @@
  return timeOnly;
};
//初始化并配置第一个ECharts图表(降雨数据图表)
const setEcharts1 = () => {
  // 获取DOM元素并初始化ECharts实例
  const chartDom = document.getElementById("echarts1");
  myChart1 = echarts.init(chartDom);
  let rainfallData = ref([]); // 存储从 JSON 文件中加载的数据
  let data1 = ref([]); // 降雨数据数据
  let data2 = ref([]); // 累计雨量数据
  let xAxisData = ref([]); // 动态时间轴
  let updateInterval = null; // 定时器变量
  let dataIndex = ref(0); // 当前数据索引,用于按顺序更新
  // 响应式数据定义
  let rainfallData = ref([]); // 存储从JSON加载的原始降雨数据
  let data1 = ref([]); // 存储降雨数据(mm/min)
  let data2 = ref([]); // 存储累计雨量数据(mm)
  let xAxisData = ref([]); // 存储x轴时间数据
  let updateInterval = null; // 定时器ID
  let dataIndex = ref(0); // 当前数据索引
  // 加载 JSON 数据
  // 从JSON文件加载降雨数据
  const loadJsonData = async () => {
    try {
      // 发起网络请求获取数据
      const response = await fetch("/json/rainfall.json");
      const result = await response.json();
      // 验证数据格式
      if (result && result.data && Array.isArray(result.data)) {
        rainfallData.value = result.data;
        // 计算 value 和 total 的最大值
        // 计算数据的最大值用于y轴刻度
        const maxValue = Math.max(
          ...rainfallData.value.map((item) => item.value)
        );
@@ -378,18 +350,16 @@
          ...rainfallData.value.map((item) => item.total)
        );
        // 初始化时间轴(从00:00开始)
        xAxisData.value = ["00:00"]; // 初始时间点
        // 初始化图表(仅加载第一个数据点)
        // 初始化时间轴和第一个数据点
        xAxisData.value = ["00:00"]; // 起始时间
        if (rainfallData.value.length > 0) {
          data1.value.push(rainfallData.value[0].value); // 降雨数据
          data2.value.push(rainfallData.value[0].total); // 累计雨量
          data1.value.push(rainfallData.value[0].value); // 添加第一个降雨数据
          data2.value.push(rainfallData.value[0].total); // 添加第一个累计雨量
        }
        // 根据最大值设置 y 轴参数并初始化图表
        const yAxis1Params = calculateYAxisParams(maxValue);
        const yAxis2Params = calculateYAxisParams(maxTotal);
        // 计算y轴参数并更新图表
        const yAxis1Params = calculateYAxisParams(maxValue); // 左侧y轴(降雨数据)
        const yAxis2Params = calculateYAxisParams(maxTotal); // 右侧y轴(累计雨量)
        updateChart(yAxis1Params, yAxis2Params);
      } else {
        console.error(
@@ -401,74 +371,87 @@
    }
  };
  // 计算 y 轴参数(最多有 4 个点)
  /**
   * 计算y轴参数(生成均匀分布的刻度)
   * @param {number} max - 数据最大值
   * @returns {Object} 包含max和interval的对象
   */
  const calculateYAxisParams = (max) => {
    const step = Math.ceil(max / 3); // 最多有 4 个点(包括 0),所以分成 3 份
    const step = Math.ceil(max / 3); // 将范围分成3等份(产生4个刻度点)
    return {
      max: step * 3, // 确保最大值是步长的整数倍
      interval: step,
      interval: step, // 刻度间隔
    };
  };
  // 更新图表配置
  /**
   * 更新图表配置
   * @param {Object} yAxis1Params - 左侧y轴参数
   * @param {Object} yAxis2Params - 右侧y轴参数
   */
  const updateChart = (yAxis1Params, yAxis2Params) => {
    const option = {
      animation: false, // 禁用动画
      animation: false, // 禁用动画提高性能
      // 提示框配置
      tooltip: {
        trigger: "axis",
        trigger: "axis", // 坐标轴触发
        axisPointer: {
          type: "cross",
          crossStyle: {
            color: "#fff",
          },
          // 指示器样式
          type: "cross", // 十字准星指示器
          crossStyle: { color: "#fff" }, // 白色线条
        },
      },
      // 图表布局
      grid: {
        left: "1%",
        right: "1%",
        bottom: "1%",
        containLabel: true,
        bottom: "1%", // 边距
        containLabel: true, // 包含坐标轴标签
      },
      // 图例配置
      legend: {
        data: ["降雨数据", "累计雨量"],
        textStyle: {
          color: "#fff",
        },
        right: "10px", // 将图例靠右贴边
        data: ["降雨数据", "累计雨量"], // 系列名称
        textStyle: { color: "#fff" }, // 白色文字
        right: "10px", // 靠右对齐
      },
      // x轴配置(时间轴)
      xAxis: [
        {
          type: "category",
          data: xAxisData.value, // 使用动态时间轴
          axisPointer: {
            type: "shadow",
          },
          type: "category", // 类目轴
          data: xAxisData.value, // 时间数据
          axisPointer: { type: "shadow" }, // 阴影指示器
          axisLabel: {
            color: "#fff",
            rotate: 0, // 将旋转角度设置为0,取消倾斜
            color: "#fff", // 白色标签
            rotate: 0, // 不旋转
          },
        },
      ],
      // y轴配置(双y轴)
      yAxis: [
        // 左侧y轴(降雨数据)
        {
          type: "value",
          name: "单位:mm",
          min: 0,
          max: yAxis1Params.max,
          interval: yAxis1Params.interval,
          min: 0, // 最小值为0
          max: yAxis1Params.max, // 动态计算的最大值
          interval: yAxis1Params.interval, // 动态计算的间隔
          axisLabel: {
            formatter: "{value}",
            color: "#fff",
            align: "right", // 将标签右对齐
            align: "right", // 标签右对齐
          },
          nameTextStyle: {
            padding: [0, 0, 0, 30], // 在右侧添加一些内边距
            padding: [0, 0, 0, 30], // 名称右侧内边距
            color: "#fff",
          },
          splitLine: {
            show: false, // 关闭左侧 y 轴的横线
          },
          splitLine: { show: false }, // 不显示网格线
        },
        // 右侧y轴(累计雨量)
        {
          type: "value",
          name: "单位:mm",
@@ -478,99 +461,87 @@
          axisLabel: {
            formatter: "{value}",
            color: "#fff",
            align: "left", // 将标签右对齐
            align: "left", // 标签左对齐
          },
          nameTextStyle: {
            padding: [0, 10, 0, 0], // 在右侧添加一些内边距
            padding: [0, 10, 0, 0], // 名称左侧内边距
            color: "#fff",
          },
          splitLine: {
            show: true, // 保留右侧 y 轴的横线
          },
          splitLine: { show: true }, // 显示网格线
        },
      ],
      // 数据系列配置
      series: [
        // 柱状图(降雨数据)
        {
          name: "降雨数据",
          type: "bar",
          type: "bar", // 柱状图
          tooltip: {
            valueFormatter: function (value) {
              return value + " mm/min";
            },
            valueFormatter: (value) => value + " mm/min", // 提示框单位
          },
          data: data1.value,
          itemStyle: {
            color: "#3268fe",
          },
          label: {
            show: false,
            color: "#fff",
          },
          data: data1.value, // 绑定数据
          itemStyle: { color: "#3268fe" }, // 蓝色柱状图
          label: { show: false, color: "#fff" }, // 不显示数据标签
        },
        // 折线图(累计雨量)
        {
          name: "累计雨量",
          type: "line",
          yAxisIndex: 1,
          type: "line", // 折线图
          yAxisIndex: 1, // 使用第二个y轴
          tooltip: {
            valueFormatter: function (value) {
              return value + " mm";
            },
            valueFormatter: (value) => value + " mm", // 提示框单位
          },
          data: data2.value,
          lineStyle: {
            color: "#ffb637",
          },
          label: {
            show: false, // 确保标签不显示
            color: "#fff",
          },
          data: data2.value, // 绑定数据
          lineStyle: { color: "#ffb637" }, // 黄色线条
          label: { show: false, color: "#fff" }, // 不显示数据标签
        },
      ],
    };
    // 应用配置到图表
    myChart1.setOption(option);
  };
  // 定义按顺序更新数据的方法
  // 定时更新图表数据
  const updateData = () => {
    // 检查是否还有数据需要显示
    if (dataIndex.value < rainfallData.value.length) {
      // 获取当前索引的数据项
      const newItem = rainfallData.value[dataIndex.value];
      // 添加新数据
      data1.value.push(newItem.value); // 添加降雨数据
      data2.value.push(newItem.total); // 添加累计雨量
      xAxisData.value.push(syncTimeWithTimeline()); // 添加时间点
      const nextTime = syncTimeWithTimeline();
      xAxisData.value.push(nextTime);
      dataIndex.value++; // 递增索引
      // 更新当前索引
      dataIndex.value++;
      // 更新图表
      // 更新图表(保持原有y轴范围)
      updateChart(
        {
          max: myChart1.getOption().yAxis[0].max,
          interval: myChart1.getOption().yAxis[0].interval,
        }, // 左侧 y 轴保持不变
        },
        {
          max: myChart1.getOption().yAxis[1].max,
          interval: myChart1.getOption().yAxis[1].interval,
        } // 右侧 y 轴保持不变
        }
      );
    } else {
      console.log("All data has been displayed.");
      stopUpdating(); // 停止定时更新
      stopUpdating(); // 数据全部显示完成后停止更新
    }
  };
  // 启动定时更新
  //启动定时更新
  const startUpdating = (interval = 1000) => {
    if (!updateInterval) {
      updateInterval = setInterval(updateData, interval); // 每隔 interval 毫秒更新一次数据
      updateInterval = setInterval(updateData, interval);
      console.log("Started updating...");
    }
  };
  // 停止定时更新
  //停止定时更新
  const stopUpdating = () => {
    if (updateInterval) {
      clearInterval(updateInterval);
@@ -579,43 +550,46 @@
    }
  };
  // 重置加载
  //重置图表数据和状态
  const resetLoading = () => {
    stopUpdating(); // 停止定时器
    dataIndex.value = 0; // 重置数据索引
    data1.value = []; // 清空降雨数据数据
    data2.value = []; // 清空累计雨量数据
    xAxisData.value = ["00:00"]; // 重置时间轴
    stopUpdating(); // 停止当前更新
    // 重新加载第一个数据点
    // 重置状态
    dataIndex.value = 0;
    data1.value = [];
    data2.value = [];
    xAxisData.value = ["00:00"];
    // 重新加载第一个数据点(如果有数据)
    if (rainfallData.value.length > 0) {
      data1.value.push(rainfallData.value[0].value); // 降雨数据
      data2.value.push(rainfallData.value[0].total); // 累计雨量
      data1.value.push(rainfallData.value[0].value);
      data2.value.push(rainfallData.value[0].total);
    }
    // 重新绘制图表
    // 重新绘制图表(保持原有y轴范围)
    updateChart(
      {
        max: myChart1.getOption().yAxis[0].max,
        interval: myChart1.getOption().yAxis[0].interval,
      }, // 左侧 y 轴保持不变
      },
      {
        max: myChart1.getOption().yAxis[1].max,
        interval: myChart1.getOption().yAxis[1].interval,
      } // 右侧 y 轴保持不变
      }
    );
    console.log("Reset loading...");
  };
  // 初始化加载 JSON 数据
  // 初始化:加载数据
  loadJsonData();
  // 返回公共接口
  return {
    myChart1,
    startUpdating,
    stopUpdating,
    resetLoading,
    myChart1, // 图表实例
    startUpdating, // 启动更新方法
    stopUpdating, // 停止更新方法
    resetLoading, // 重置方法
  };
};
@@ -891,7 +865,7 @@
};
onMounted(() => {
  // getRainfallData();
  // 时间轴时间的变化
  EventBus.on("time-update", (time) => {
    nowTime.value = time;
  });
@@ -903,7 +877,6 @@
});
onBeforeUnmount(() => {
  EventBus.off("time-update"); // 清理事件监听
  nowTime.value = null;
  if (intervalId1) clearInterval(intervalId1);
  if (intervalId2) clearInterval(intervalId2);
@@ -915,6 +888,7 @@
onUnmounted(() => {
  EventBus.off("reset-table"); // 移除事件监听
  EventBus.off("clear-echart");
  EventBus.off("time-update"); // 清理事件监听
});
</script>
src/views/GisView.vue
@@ -3,24 +3,43 @@
</template>
<script setup>
import { onMounted, onUnmounted, ref, watch } from "vue"
import { createPoint, initHandler, initView, addTileset, addTerrain } from "@/utils/map.js"
import { loadAreaPolygon } from "@/utils/area.js"
import { loadAreaPolygonAll } from "@/utils/area_all.js"
import { isVisibleDistance } from "@/utils/customEntity"
import { getDistrictCount, getDistrictCountByCity } from "@/api/index"
import { useRoute } from "vue-router"
const route = useRoute()
let handler = null
function initMap () {
  window.Cesium = SmartEarth.Cesium
  window.earthCtrl = new SmartEarth.EarthCtrl("gis-view")
import { onMounted, onUnmounted, ref, watch } from "vue";
import {
  createPoint,
  initHandler,
  initView,
  addTileset,
  addTerrain,
} from "@/utils/map.js";
import { loadAreaPolygon } from "@/utils/area.js";
import { loadAreaPolygonAll } from "@/utils/area_all.js";
import { isVisibleDistance } from "@/utils/customEntity";
import { getDistrictCount, getDistrictCountByCity } from "@/api/index";
import { useRoute } from "vue-router";
const route = useRoute();
let handler = null;
function initMap() {
  window.Cesium = SmartEarth.Cesium;
  window.earthCtrl = new SmartEarth.EarthCtrl("gis-view");
  window.viewer = earthCtrl.viewer;
  const date = new Date(2025, 3, 11, 12, 0, 0, 0);
  // 1. 设置初始时间
  const date = new Date(2025, 3, 11, 16, 0, 0, 0);
  const julianDate = SmartEarth.Cesium.JulianDate.fromDate(date);
  // earthCtrl.viewer.clock.currentTime = julianDate;
  // 2. 配置时钟选项,禁止自动推进时间
  earthCtrl.viewer.clockViewModel.shouldAnimate = false; // 禁用动画
  earthCtrl.viewer.clockViewModel.clockRange =
    SmartEarth.Cesium.ClockRange.CLAMPED; // 限制时间范围
  earthCtrl.viewer.clockViewModel.multiplier = 0; // 设置时间推进速度为0
  // 3. 设置当前时间并锁定
  earthCtrl.viewer.clock.currentTime = julianDate;
  //显示fps
  earthCtrl.showFPS = true
  earthCtrl.showFPS = true;
  earthCtrl.factory.createImageryLayer({
    sourceType: "mapworld",
    url: "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=7eb11c0c503429878691ac917238f87f",
@@ -30,28 +49,31 @@
    maximumLevel: 18,
    layer: "",
    tileMatrixSetID: "",
  })
  });
  // 关闭地形深度检测
  // viewer.scene.globe.depthTestAgainstTerrain = false;
}
function addCityPolygon () {
  const url = `/json/110000.geo.json`
function addCityPolygon() {
  const url = `/json/110000.geo.json`;
  let wallLayer = earthCtrl.factory.createTrailWallLayer({
    url: "/json/110000.geojson",
    color: "LIGHTSTEELBLUE", //颜色
    height: 2000, //高度
    speed: 3,
  })
  });
  const dataSourcePromise = Cesium.GeoJsonDataSource.load(url, {
    clampToGround: true,
  })
  });
  return dataSourcePromise.then(function (dataSource) {
    viewer.dataSources.add(dataSource)
    const polygonEntity = dataSource.entities.values
    viewer.dataSources.add(dataSource);
    const polygonEntity = dataSource.entities.values;
    // console.log("polygonEntity", polygonEntity)
    const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(1000, 50000000)
    polygonEntity.forEach(entity => {
    const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(
      1000,
      50000000
    );
    polygonEntity.forEach((entity) => {
      // console.log("entity", entity)
      entity.polygon.material = new Cesium.ColorMaterialProperty(
@@ -62,24 +84,24 @@
        //     minimumAlpha: 0.2,
        //     maximumAlpha: 0.9,
        // })
      )
      );
      entity.polygon.distanceDisplayCondition = distanceDisplayCondition
      entity.polygon.distanceDisplayCondition = distanceDisplayCondition;
      const properties = entity.properties
      const center = properties.centroid.getValue()
      const fullname = properties.fullname.getValue()
      const districtCount = properties.districtCount.getValue() || 0
      const properties = entity.properties;
      const center = properties.centroid.getValue();
      const fullname = properties.fullname.getValue();
      const districtCount = properties.districtCount.getValue() || 0;
      const position = Cesium.Cartesian3.fromDegrees(center[0], center[1])
      const positions = entity.polygon.hierarchy._value.positions
      const position = Cesium.Cartesian3.fromDegrees(center[0], center[1]);
      const positions = entity.polygon.hierarchy._value.positions;
      entity.position = position
      entity.position = position;
      // 判断是否为东城区或西城区
      let labelText = fullname || "默认标签"
      let labelText = fullname || "默认标签";
      if (fullname === "东城区" || fullname === "西城区") {
        // 将文本拆分为竖列
        labelText = fullname.split("").join("\n")
        labelText = fullname.split("").join("\n");
      }
      entity.label = {
        // 文本。支持显式换行符“ \ n”
@@ -118,7 +140,7 @@
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        // 是否显示
        show: true,
      }
      };
      entity.polyline = {
        positions: positions,
        width: 5,
@@ -132,16 +154,16 @@
        ),
        clampToGround: true,
        distanceDisplayCondition: distanceDisplayCondition,
      }
      };
      viewer.entities.add(entity)
    })
      viewer.entities.add(entity);
    });
    // 获取 GeoJSON 中的第一个 Polygon feature
  })
  });
}
function flyToHomeView () {
function flyToHomeView() {
  const view = {
    destination: {
      x: -2355432.569004413,
@@ -153,27 +175,27 @@
      roll: 0.00031421159527500464,
      heading: 6.140424766644804,
    },
  }
  viewer.scene.camera.flyTo(view)
  };
  viewer.scene.camera.flyTo(view);
}
let htmlEntityList = []
function initDistrictCount () {
  getDistrictCount().then(res => {
    res.data.forEach(item => {
      const { districtName, count, lat, lon } = item
      item.name = `${item.districtName}\n${item.count}`
      item.longitude = item.lon
      item.latitude = item.lat
      item.showBillboard = false
      item.showLabel = true
let htmlEntityList = [];
function initDistrictCount() {
  getDistrictCount().then((res) => {
    res.data.forEach((item) => {
      const { districtName, count, lat, lon } = item;
      item.name = `${item.districtName}\n${item.count}`;
      item.longitude = item.lon;
      item.latitude = item.lat;
      item.showBillboard = false;
      item.showLabel = true;
      item.label = {
        text: item.name,
        backgroundColor: SmartEarth.Cesium.Color.SKYBLUE.withAlpha(0.8),
        font: "14pt Source Han Sans CN",
        fillColor: SmartEarth.Cesium.Color.WHITE,
        showBackground: true,
      }
      };
      // createPoint(item)
      const html = earthCtrl.view.createScreenDialog({
        html: `
@@ -185,41 +207,45 @@
        lon: item.lon,
        lat: item.lat,
        height: 0,
      })
      html.maxVisibleDistance = 69000
      html.minVisibleDistance = 20000
      });
      html.maxVisibleDistance = 69000;
      html.minVisibleDistance = 20000;
      html.element.addEventListener("click", () => {
        viewer.camera.flyTo({
          destination: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 12000),
          destination: Cesium.Cartesian3.fromDegrees(
            item.longitude,
            item.latitude,
            12000
          ),
          orientation: {
            pitch: Cesium.Math.toRadians(-90),
            heading: Cesium.Math.toRadians(0),
            roll: 0,
          },
          duration: 2,
        })
      })
        });
      });
      htmlEntityList.push(html)
    })
  })
      htmlEntityList.push(html);
    });
  });
}
function initDistrictCountByCity () {
  getDistrictCountByCity().then(res => {
    res.data.forEach(item => {
      const { districtName, count, lat, lon } = item
      item.name = `${item.districtName}\n${item.count}`
      item.longitude = item.lon
      item.latitude = item.lat
      item.showBillboard = false
      item.showLabel = true
function initDistrictCountByCity() {
  getDistrictCountByCity().then((res) => {
    res.data.forEach((item) => {
      const { districtName, count, lat, lon } = item;
      item.name = `${item.districtName}\n${item.count}`;
      item.longitude = item.lon;
      item.latitude = item.lat;
      item.showBillboard = false;
      item.showLabel = true;
      item.label = {
        text: item.name,
        backgroundColor: SmartEarth.Cesium.Color.SKYBLUE.withAlpha(0.8),
        font: "14pt Source Han Sans CN",
        fillColor: SmartEarth.Cesium.Color.WHITE,
        showBackground: true,
      }
      };
      // createPoint(item)
      const html = earthCtrl.view.createScreenDialog({
        html: `
@@ -231,80 +257,90 @@
        lon: item.lon,
        lat: item.lat,
        height: 0,
      })
      html.maxVisibleDistance = 50000000
      html.minVisibleDistance = 70000
      });
      html.maxVisibleDistance = 50000000;
      html.minVisibleDistance = 70000;
      html.element.addEventListener("click", () => {
        viewer.camera.flyTo({
          destination: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, 45000),
          destination: Cesium.Cartesian3.fromDegrees(
            item.longitude,
            item.latitude,
            45000
          ),
          orientation: {
            pitch: Cesium.Math.toRadians(-90),
            heading: Cesium.Math.toRadians(0),
            roll: 0,
          },
          duration: 2,
        })
      })
        });
      });
      htmlEntityList.push(html)
    })
  })
      htmlEntityList.push(html);
    });
  });
}
watch(
  () => route.fullPath,
  val => {
  (val) => {
    if (val != "/") {
      // clusterLayer.dataSource.show = false
      htmlEntityList.forEach(item => {
        item.show = false
      })
      removeCameraChange()
      htmlEntityList.forEach((item) => {
        item.show = false;
      });
      removeCameraChange();
    } else {
      handleCameraChange()
      handleCameraChange();
      // clusterLayer.dataSource.show = true
      htmlEntityList.forEach(item => {
        item.show = isVisibleDistance(item.minVisibleDistance, item.maxVisibleDistance)
      })
      htmlEntityList.forEach((item) => {
        item.show = isVisibleDistance(
          item.minVisibleDistance,
          item.maxVisibleDistance
        );
      });
    }
  }
)
function handleCameraChange () {
  viewer.camera.changed.addEventListener(toggleHtmlLayerByVisibleDistance)
);
function handleCameraChange() {
  viewer.camera.changed.addEventListener(toggleHtmlLayerByVisibleDistance);
}
function removeCameraChange () {
  viewer.camera.changed.removeEventListener(toggleHtmlLayerByVisibleDistance)
function removeCameraChange() {
  viewer.camera.changed.removeEventListener(toggleHtmlLayerByVisibleDistance);
}
let cameraChangeTimer = null
let cameraChangeTimer = null;
function toggleHtmlLayerByVisibleDistance () {
function toggleHtmlLayerByVisibleDistance() {
  if (cameraChangeTimer) {
    clearTimeout(cameraChangeTimer)
    cameraChangeTimer = null
    return
    clearTimeout(cameraChangeTimer);
    cameraChangeTimer = null;
    return;
  }
  cameraChangeTimer = setTimeout(() => {
    htmlEntityList.forEach(item => {
      item.show = isVisibleDistance(item.minVisibleDistance, item.maxVisibleDistance)
    })
  }, 100)
    htmlEntityList.forEach((item) => {
      item.show = isVisibleDistance(
        item.minVisibleDistance,
        item.maxVisibleDistance
      );
    });
  }, 100);
}
onMounted(() => {
  initMap()
  addCityPolygon()
  initHandler()
  initMap();
  addCityPolygon();
  initHandler();
  // initView()
  loadAreaPolygon("/json/nsl_area.geojson")
  loadAreaPolygonAll("/json/geometry.json", true)
  flyToHomeView()
  initDistrictCount()
  initDistrictCountByCity()
  handleCameraChange()
  loadAreaPolygon("/json/nsl_area.geojson");
  loadAreaPolygonAll("/json/geometry.json", true);
  flyToHomeView();
  initDistrictCount();
  initDistrictCountByCity();
  handleCameraChange();
  // 设置 billboard 点击事件
})
});
onUnmounted(() => {
  removeCameraChange()
})
  removeCameraChange();
});
</script>
<style lang="less" scoped>