src/views/GisView.vue
@@ -3,24 +3,44 @@
</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";
import { EventBus } from "@/eventBus"; // 引入事件总线
const route = useRoute();
let handler = null;
function initMap() {
  window.Cesium = SmartEarth.Cesium;
  window.earthCtrl = new SmartEarth.EarthCtrl("gis-view");
  window.viewer = earthCtrl.viewer;
  // 1. 设置初始时间
  const date = new Date(2025, 3, 11, 12, 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 +50,149 @@
    maximumLevel: 18,
    layer: "",
    tileMatrixSetID: "",
  })
  });
  // 关闭地形深度检测
  // viewer.scene.globe.depthTestAgainstTerrain = false;
}
function addCityPolygon () {
  const url = `/json/110000.geo.json`
const MULTIPOLYGON_COORDS = ref([]);
let previousEntities = []; // 用于存储之前创建的实体
const flyToHeight = ref(null);
// 监听新建方案选择的区域范围
EventBus.on("select-geom", ({ geom, flyHeight }) => {
  flyToHeight.value = flyHeight;
  const coordsStr = geom
    .replace("MULTIPOLYGON(((", "") // 去掉开头
    .replace(")))", ""); // 去掉结尾
  // 分割成 ["lon lat", "lon lat", ...]
  const coordPairs = coordsStr.split(",");
  // 转换为 [[[lon, lat], [lon, lat], ...]] 格式
  MULTIPOLYGON_COORDS.value = [
    coordPairs.map((pair) => {
      const [lon, lat] = pair.trim().split(" ").map(Number);
      return [lon, lat];
    }),
  ];
  // 检查是否是空多边形,如果是空,则去掉面片颜色,并飞回初始位置
  if (geom === "MULTIPOLYGON EMPTY") {
    clearPreviousEntities();
    flyToHomeView();
    return; // 不执行后续操作
  }
  // 清除之前的所有实体
  clearPreviousEntities();
  // 选中区域标色
  addCustomPolygon();
});
// 清除之前的所有实体
function clearPreviousEntities() {
  previousEntities.forEach((entity) => {
    viewer.entities.remove(entity);
  });
  previousEntities = [];
}
// 计算选中区域中心点
function calculateCenter(coordinates) {
  const lons = coordinates.flat().map((coord) => coord[0]);
  const lats = coordinates.flat().map((coord) => coord[1]);
  return {
    lon: (Math.min(...lons) + Math.max(...lons)) / 2,
    lat: (Math.min(...lats) + Math.max(...lats)) / 2,
  };
}
function convertToGeoJson(coords) {
  return {
    type: "Feature",
    id: 0,
    bbox: calculateCenter(MULTIPOLYGON_COORDS.value), // 可选
    properties: {
      center: calculateCenter(MULTIPOLYGON_COORDS.value), // 第一个点作为 center
      centroid: MULTIPOLYGON_COORDS.value[0][0], // 可选
      level: "district",
      code: 123456,
      districtCount: 0,
    },
    geometry: {
      type: "MultiPolygon",
      coordinates: [coords], // 包装成 MultiPolygon
    },
  };
}
function addCustomPolygon() {
  // 将 MULTIPOLYGON_COORDS.value 转换为 GeoJSON 格式
  const geoJson = convertToGeoJson(MULTIPOLYGON_COORDS.value);
  const center = geoJson.properties.center;
  // 创建多边形实体
  const polygonEntity = viewer.entities.add({
    // name: "自定义区域",
    polygon: {
      hierarchy: Cesium.Cartesian3.fromDegreesArray(
        geoJson.geometry.coordinates[0][0].flat()
      ),
      material: Cesium.Color.RED.withAlpha(0.3), // 半透明红色填充
      outline: true,
      outlineColor: Cesium.Color.RED, // 红色边框
      outlineWidth: 5,
      clampToGround: true, // 贴地显示
    },
  });
  previousEntities.push(polygonEntity);
  // 飞向中心点
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(
      center.lon,
      center.lat,
      flyToHeight.value
    ), // 提高到 100000米高度
    orientation: {
      heading: Cesium.Math.toRadians(0), // 正北方向
      pitch: Cesium.Math.toRadians(-90), // 向下倾斜90度(垂直俯视)
      roll: 0.0,
    },
  });
  console.log(
    flyToHeight.value,
    "flyToHeight.value flyToHeight.value flyToHeight.value "
  );
}
EventBus.on("close-selectArea", () => {
  clearPreviousEntities();
  flyToHomeView();
});
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
    console.log("polygonEntity", polygonEntity)
    const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(1000, 50000000)
    polygonEntity.forEach(entity => {
    viewer.dataSources.add(dataSource);
    // 所有的数据
    const polygonEntity = dataSource.entities.values;
    const distanceDisplayCondition = new Cesium.DistanceDisplayCondition(
      1000,
      50000000
    );
    polygonEntity.forEach((entity) => {
      // console.log("entity", entity)
      entity.polygon.material = new Cesium.ColorMaterialProperty(
@@ -62,24 +203,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 +259,7 @@
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
        // 是否显示
        show: true,
      }
      };
      entity.polyline = {
        positions: positions,
        width: 5,
@@ -132,16 +273,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 +294,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 +326,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 +376,93 @@
        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();
  EventBus.off("select-geom");
  EventBus.off("close-selectArea");
});
</script>
<style lang="less" scoped>