husq
2023-10-08 a0d006a8e6734ce1ff08fc5d196266cc2fd27f7d
src/components/cesiumMap/cesium.vue
@@ -1,123 +1,93 @@
<template>
  <div class="height-100 width-100 cesium" id="cesiumContainer"></div>
  <div v-if="centerConfig.type && !centerConfig.latitude" class="pointLongitude">在地图上点击绘制项目中心点</div>
  <!-- <div class="switch">
    <div class="2d" v-if="dimension === 3" @click="switchModel('2D')">2D</div>
    <div class="3d" v-else @click="switchModel('3D')">3D</div>
  </div> -->
</template>
  <div class="search">
    <a-auto-complete v-if="show" v-model:value="searchText" style="width: 200px;height: 100%;" placeholder="请输入地址" @select="enter"
      @change="searchLocation" :options='resultList'>
    </a-auto-complete>
    <span class="search-icon" @click="() => show = !show">
      <SearchOutlined style="fontSize:24px; color: blue;" />
    </span>
  </div>
  <div class="switch">
    <div class="2d" v-if="dimension === 2" @click="switchDimension('3D')">2D</div>
    <div class="3d" v-else @click="switchDimension('2D')">3D</div>
  </div>
</template>\
<script setup lang="ts">
import * as Cesium from 'cesium'
import { onMounted, ref, onUnmounted, } from 'vue'
import { pointCenter, clickPoint } from '/@/hooks/use-center-point'
import { ref, } from 'vue'
import _ from 'lodash'
import { cesiumOperation } from '/@/hooks/use-cesium-tsa'
import { gaodeSearch } from '/@/api/gaode'
import { SearchOutlined } from '@ant-design/icons-vue'
import { useMyStore } from '/@/store'
let viewer: Cesium.Viewer | null = null
let handler: Cesium.ScreenSpaceEventHandler
const dimension = ref(3)
const { appContext } = getCurrentInstance()
const global = appContext.config.globalProperties
// const viewer: { value: Cesium.Viewer | null | undefined } = ref()
import * as Cesium from 'cesium'
type result = {
  label: string,
  value: string,
  location: string,
  district: string,
}
const searchText = ref('')
const resultList = ref<result[]>([])
const store = useMyStore()
const centerConfig = computed(() => {
  return store.state.map.centerConfig
})
const init = () => {
  // Cesium Token
  const cesiumToken = import.meta.env.VITE_CESIUM_TOKEN
  Cesium.Ion.defaultAccessToken = cesiumToken
  Cesium.Camera.DEFAULT_VIEW_FACTOR = -0.45
  // 西南东北,默认显示中国
  Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(110, -25, 110, 90)
  viewer = new Cesium.Viewer('cesiumContainer', {
    infoBox: false, // 禁用沙箱,解决控制台报错
    animation: false, // 左下角的动画仪表盘
    baseLayerPicker: false, // 右上角的图层选择按钮
    geocoder: false, // 搜索框
    homeButton: false, // home按钮
    sceneModePicker: false, // 模式切换按钮
    timeline: false, // 底部的时间轴
    navigationHelpButton: false, // 右上角的帮助按钮,
    selectionIndicator: false, // 是否显示选择指示器
    baseLayer: false,
  })
  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  loadLAYER()
  viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) // 禁用双击
  // viewer.scene.screenSpaceCameraController.minimumZoomDistance = 100
  viewer.scene.screenSpaceCameraController.maximumZoomDistance = 4500000
  global.$viewer = viewer
}
// 加载图层、注解方法
const loadLAYER = () => {
  // 天地图Key
  const TDT_Token = 'c6eea7dad4fa1e2d1e32ec0e7c9735db'
  // 天地图地图
  const TDT_IMG_C = 'https://{s}.tianditu.gov.cn/img_c/wmts?service=wmts&request=GetTile&version=1.0.0' +
    '&LAYER=img&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
    '&style=default&format=tiles&tk=' + TDT_Token
  // 天地图注记
  const TDT_ZJ = 'https://{s}.tianditu.gov.cn/cia_c/wmts?service=wmts&request=GetTile&version=1.0.0' +
    '&LAYER=cia&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}' +
    '&style=default&format=tiles&tk=' + TDT_Token
  // 天地图图层加载
  const imageryProvider = new Cesium.WebMapTileServiceImageryProvider({
    url: TDT_IMG_C,
    layer: 'tdtImg_c',
    style: 'default',
    format: 'tiles',
    tileMatrixSetID: 'c',
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'],
    maximumLevel: 50,
  })
  viewer?.imageryLayers.addImageryProvider(imageryProvider)
  // 天地图中文注记加载
  const annotation = new Cesium.WebMapTileServiceImageryProvider({
    url: TDT_ZJ,
    layer: 'tdtImg_c',
    style: 'default',
    format: 'tiles',
    tileMatrixSetID: 'c',
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'],
    maximumLevel: 50,
  })
  viewer?.imageryLayers.addImageryProvider(annotation)
}
// 切换为二三维模式
const switchModel = (type: string) => {
  switch (type) {
    case '2D':
      viewer.scene.camera.setView({
        orientation: {
          pitch: Cesium.Math.toRadians(-60),
          heading: Cesium.Math.toRadians(0),
        }
      })
      dimension.value = 2
      break
    case '3D':
      viewer.scene.camera.setView({
        orientation: {
          pitch: Cesium.Math.toRadians(-90),
          heading: Cesium.Math.toRadians(0),
        }
      })
      dimension.value = 3
const show = ref(false)
const search = async () => {
  resultList.value = []
  const params = {
    keyword: searchText.value
  }
  const res = await gaodeSearch(params)
  if (res.code !== 0) return
  if (res.data.tips.length > 0) {
    res.data.tips.shift()
    resultList.value = res.data.tips.map((v: any) => {
      return {
        value: `${v.name}(${v.district})`,
        label: v.name,
        location: v.location,
        district: v.district,
      }
    })
  }
}
onMounted(() => {
  console.log('=====执行=====')
  init()
})
// 销毁地图模型
onUnmounted(() => {
  viewer = null
})
const searchLocation = _.debounce(search, 500)
const { flyTo, addPoint, removeById, switchModel, dimension } = cesiumOperation()
const enter = (e: string) => {
  removeById('key')
  const filterItem = resultList.value.find(v => v.value === e)
  const [longitude, latitude] = filterItem?.location.split(',')
  const params = {
    longitude: longitude - 0,
    latitude: latitude - 0,
  }
  const pointParams = {
    point: {
      pixelSize: 20,
      outlineWidth: 4,
      color: Cesium.Color.GREEN,
      outlineColor: Cesium.Color.WHITE,
    },
    label: {
      text: filterItem?.label,
      outlineWidth: 20,
      font: '24px sans-serif',
      heightReference: 80,
      pixelOffset: new Cesium.Cartesian2(0, -35),
      fillColor: Cesium.Color.BROWN
    },
    id: 'key'
  }
  addPoint({ ...pointParams, ...params })
  flyTo(params)
}
const switchDimension = (type: string) => {
  switchModel(type)
}
</script>
<style scoped lang="scss">
@@ -141,6 +111,23 @@
  font-size: 16px;
}
.search {
  position: absolute;
  top: 40px;
  right: 20px;
  color: #fff;
  font-size: 16px;
  display: flex;
  align-items: center;
  height: 32px;
  .search-icon {
    padding: 5px;
    background-color: #fff;
    height: 32px;
    cursor: pointer;
  }
}
.switch {
  position: absolute;
  background-color: #fff;