cesium,supermap 影像图层卷帘对比

96 阅读4分钟

坑点在于addS3MTilesLayerByScpCesium.loadJson加载的图层使用splitDirectionsplitPisotion无效,普通的图层没问题

仅需要加载普通图层进行对比的就不需要用到本文的方法

絮絮叨叨:

感谢cesium控制及效果(六):卷帘对比的文章,用在cesium官方的库上,很轻松就实现了效果,可是使用超图的cesium怎么都实现不了,排查问题,寻找解决方案花了我一天时间,看了 官方的demo, 看了很多博客 超图Cesium卷帘遇到的坑 都不行。偏偏网上的技术文章都是用普通的图层做的演示。

今早改用简单粗暴的两个地图叠加分别加载图层,卷帘效果改用简单粗暴地container.style.clipPath控制显示区域,再通过监听viewer.camera.changed.addEventListener实现两个地图的联动。 最后就简单粗暴地解决了。

p.s. 这byd超图new Cesium.WebMapTileServiceImageryProvider方法不能自动组合拼接里面的参数,我之前copy过来的添加天地图的方法没起效,f12一看网络才发现。 只能手动把url里面的参数写全了。

<!--卷帘-->
<template>
<div class="relative w-full h-full">
  <div id="cesiumContainer">
  </div>
  <div id="cesiumContainer2">
  </div>
  <div id="slider"></div>
</div>
</template>

<script lang="ts" setup>
import { onMounted, nextTick, computed } from 'vue'
import { useMapStore } from '/@/pinia'
declare const Cesium: any
let viewer: any = null
let viewer2: any = null
const mapStore = useMapStore()
const mapUrlList = computed(() => mapStore.compareLayers)
const serverHttp = import.meta.env.VITE_APP_MAP_GIS

const imageryProvider = new Cesium.SuperMapImageryProvider({
  url: serverHttp + '/iserver/services/map-tianditu/rest/maps/影像底图_经纬度',
  maximumLevel: 17,
})

const initViewer = async (id: string) => {
  viewer = new Cesium.Viewer(id, {
    navigationHelpButton: false,
    sceneModePicker: false,
    geocoder: false,
    homeButton: false,
    fullscreenButton: false,
    imageryProvider: new Cesium.UrlTemplateImageryProvider({
      url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
    }),
    baseLayerPicker: false,
    selectionIndicator: false, // 鼠标点击wms选择框
    infoBox: false,
    timeline: false,
    animation: false
  })
  const dom = viewer.cesiumWidget.creditContainer as HTMLElement
  dom.style.display = 'none'
  viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(120.62494755, 30.97611891, 150000),
    orientation: {
      heading: Cesium.Math.toRadians(0),
      pitch: Cesium.Math.toRadians(-83),
      roll: Cesium.Math.toRadians(0)
    }
  })
  // const imgLayer = new Cesium.WebMapTileServiceImageryProvider({
  //   url: `http://t1.tianditu.gov.cn/${layer}_w/wmts?tk=${tdtToekn}&SERVICE=WMTS&tileMatrixSetID=w&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&FORMAT=tiles`,
  //   layer: 'img',
  //   style: 'default',
  //   format: 'tiles',
  //   tileMatrixSetID: 'w',
  //   subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
  //   maximumLevel: 18
  // })
  // viewer.imageryLayers.addImageryProvider(imgLayer)
  // 远程机改用iserver底图
  // viewer.imageryLayers.addImageryProvider(imageryProvider)
  setBaseLayer(viewer, mapUrlList.value[0])
}
const initViewer2 = (id: string) => {
  viewer2 = new Cesium.Viewer(id, {
    navigationHelpButton: false,
    sceneModePicker: false,
    geocoder: false,
    homeButton: false,
    fullscreenButton: false,
    imageryProvider: new Cesium.UrlTemplateImageryProvider({
      url: 'https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
    }),
    baseLayerPicker: false,
    selectionIndicator: false, // 鼠标点击wms选择框
    infoBox: false,
    timeline: false,
    animation: false
  })
  // console.log('%c[🚀🚀🚀 viewer2 ----swipe.vue- line 95]', 'color: red;font-size:x-large', viewer2)
  const dom = viewer2.cesiumWidget.creditContainer as HTMLElement
  dom.style.display = 'none'
  viewer2.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(120.62494755, 30.97611891, 150000),
    orientation: {
      heading: Cesium.Math.toRadians(0),
      pitch: Cesium.Math.toRadians(-83),
      roll: Cesium.Math.toRadians(0)
    }
  })
  //  远程机改用iserver底图
  // viewer.imageryLayers.addImageryProvider(imageryProvider)
  setBaseLayer(viewer2, mapUrlList.value[1])
  bindSliderEvt()
}

/**
 * 注册卷帘分割条的拖拽事件。
 * @param viewer。
 * @param rollerShutterConfig 卷帘配置参数。
 */
function bindSliderEvt () {
  const verticalSlider = document.getElementById('slider') as any // 垂直分割条
  const container = document.getElementById('cesiumContainer2') as any
  const containerRect = container.getBoundingClientRect()
  // 初始设置两个地图半分容器
  container.style.clipPath = `inset(0 0 0 ${containerRect.width / 2}px)`
  verticalSlider.addEventListener('mousedown', mouseDown, false)
  document.addEventListener('mouseup', mouseUp, false)

  function mouseUp (e: any) {
    document.removeEventListener('mousemove', sliderMove, false)
  }
  function mouseDown (e: any) {
    document.addEventListener('mousemove', sliderMove, false)
  }
  function sliderMove (e: any) {
    if (e.preventDefault) {
      e.preventDefault()
    } else {
      e.returnValue = false
    }

    // 计算相对于容器的位置
    const relativeX = e.clientX - containerRect.left
    // 确保滑块不会超出容器范围
    const maxX = containerRect.width
    const boundedX = Math.max(0, Math.min(relativeX, maxX))
    verticalSlider.style.left = boundedX + 'px'

    // 使用 clip-path 裁剪右侧地图
    container.style.clipPath = `inset(0 0 0 ${boundedX}px)`
  }
}
const syncViews = () => {
  // 同步两个视图的相机
  viewer2.camera.percentageChanged = 0.01
  viewer.camera.changed.addEventListener(() => {
    viewer2.camera.setView({
      destination: viewer.camera.position,
      orientation: {
        heading: viewer.camera.heading,
        pitch: viewer.camera.pitch,
        roll: viewer.camera.roll
      }
    })
  })

  viewer.camera.percentageChanged = 0.01
  viewer2.camera.changed.addEventListener(() => {
    viewer.camera.setView({
      destination: viewer2.camera.position,
      orientation: {
        heading: viewer2.camera.heading,
        pitch: viewer2.camera.pitch,
        roll: viewer2.camera.roll
      }
    })
  })
}
onMounted(() => {
  nextTick(async () => {
    console.log('%c[🚀🚀🚀 mapUrlList - line 111]', 'color: red;font-size:x-large', 'mapUrlListmapUrlList', mapUrlList.value)
    initViewer('cesiumContainer')
    initViewer2('cesiumContainer2')
    syncViews() // 同步两个视图
  })
})

const setBaseLayer = (viewer: any, item: any) => {
  let leftLayer:any
  const mapParams = item?.mapParams
  if (item.parentId === '1') {
    const zslayer = new Cesium.UrlTemplateImageryProvider({
      url: item.mapUrl,
    })
    leftLayer = viewer.scene.imageryLayers.addImageryProvider(zslayer)
  }
  if (item.parentId === '2') {
    const promise = viewer.scene.addS3MTilesLayerByScp(item.mapUrl, {
      name: item.mapId
    })
    Cesium.when(promise, (layer: any) => {
      if (mapParams) {
        const mapParamsJson = JSON.parse(mapParams || '{}')
        const keysList = Object.keys(mapParamsJson)
        keysList.forEach((item) => {
          const keyValue = mapParamsJson[item]
          if (keyValue instanceof Object) {
            const childKeys = Object.keys(keyValue)
            childKeys.forEach((child) => {
              layer[item][child] = keyValue[child]
            })
          }else{
          layer[item] = keyValue
          }

        })
      }
      leftLayer = layer
    })
  }
  if (item.parentId === '3') {
    const mapParams = item.mapParams

    const scene = viewer.scene
    const mapUrl = item.mapUrl
    const promise = scene.open(mapUrl, {
      autoSetView: false
    })
    Cesium.loadJson(mapUrl + '/scenes.json').then(function (scenes: any) {
      // console.log('%c[🚀🚀🚀 scenes - line 580]', 'color: red;font-size:x-large', 'scenes', scenes)
      const sname = scenes[0].name
      Cesium.loadJson(mapUrl + '/scenes/' + sname + '.json').then(
        function (jsonData: any) {
          Cesium.when(
            promise,
            function (layer: any) {
              // console.log('%c[🚀🚀🚀  - line 586]addShuiXiaLayer', 'color: red;font-size:x-large', 'layer', layer)
              const layer0 = layer[0]
              setHypsometric(layer0)
              if (mapParams) {
                const mapParamsJson = JSON.parse(mapParams || '{}')
                const keysList = Object.keys(mapParamsJson)
                keysList.forEach((item) => {
                  const keyValue = mapParamsJson[item]
                  if (keyValue instanceof Object) {
                    const childKeys = Object.keys(keyValue)
                    childKeys.forEach((child) => {
                      layer0[item][child] = keyValue[child]
                    })
                  }else{
                  layer0[item] = keyValue
                  }
                  
                })
              }
              if (!scene.pickPositionSupported) {
                alert('不支持深度纹理,无法拾取位置!')
              }
            },
            function (e: any) {

            },
          )
        },
      )
    })
  }
  if (item.parentId === '4') {
    const zslayer = new Cesium.SuperMapImageryProvider({
      name: item.mapId,
      url: item.mapUrl,
    })
    leftLayer = viewer.scene.imageryLayers.addImageryProvider(zslayer)
  }
}

// 设置分层设色
function setHypsometric (layer: any) {
  const hyp = new Cesium.HypsometricSetting()
  const minValue = layer.dataMinValue
  const maxValue = layer.dataMaxValue

  hyp.DisplayMode = Cesium.HypsometricSettingEnum.DisplayMode.FACE
  hyp.LineColor = new Cesium.Color(1.0, 0.0, 0.0, 1.0)
  hyp.LineInterval = 100.0
  hyp.MaxVisibleValue = layer.dataMaxValue
  hyp.MinVisibleValue = layer.dataMinValue
  hyp.ColorTableMinKey = minValue
  hyp.ColorTableMaxKey = maxValue

  const colorTable = new Cesium.ColorTable()
  colorTable.insert(
    minValue + (8 * (maxValue - minValue)) / 8,
    new Cesium.Color(201 / 255, 23 / 255, 30 / 255),
  )
  colorTable.insert(
    minValue + (7 * (maxValue - minValue)) / 8,
    new Cesium.Color(231 / 255, 50 / 255, 15 / 255),
  )
  colorTable.insert(
    minValue + (6 * (maxValue - minValue)) / 8,
    new Cesium.Color(238 / 255, 118 / 255, 0 / 255),
  )
  colorTable.insert(
    minValue + (5 * (maxValue - minValue)) / 8,
    new Cesium.Color(255 / 255, 214 / 255, 0 / 255),
  )
  colorTable.insert(
    minValue + (4 * (maxValue - minValue)) / 8,
    new Cesium.Color(246 / 255, 236 / 255, 0 / 255),
  )
  colorTable.insert(
    minValue + (3 * (maxValue - minValue)) / 8,
    new Cesium.Color(157 / 255, 200 / 255, 22 / 255),
  )
  colorTable.insert(
    minValue + (2 * (maxValue - minValue)) / 8,
    new Cesium.Color(104 / 255, 185 / 255, 61 / 255),
  )
  colorTable.insert(
    minValue + (1 * (maxValue - minValue)) / 8,
    new Cesium.Color(18 / 255, 110 / 255, 183 / 255),
  )
  colorTable.insert(
    minValue + (0 * (maxValue - minValue)) / 8,
    new Cesium.Color(0 / 255, 64 / 255, 152 / 255),
  )

  hyp.ColorTable = colorTable
  layer.hypsometricSetting = {
    hypsometricSetting: hyp,
    analysisMode: Cesium.HypsometricSettingEnum.AnalysisRegionMode.ARM_ALL,
  }
}
</script>

<style lang="scss" scoped>
#cesiumContainer {
  width: 100%;
  height: 600px;
  position: relative;
  top: 0;
  left: 0;
  z-index: 1;
}
#cesiumContainer2 {
  width: 100%;
  height: 600px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
}

#slider {
  position: absolute;
  left: 50%;
  top: 0px;
  background-color: #d3d3d3;
  width: 3px;
  height: 100%;
  z-index: 9999;
}

#slider:hover {
  cursor: e-resize;
}

.home-icon {
  position: absolute;
  left: 0;
  top: 0;
  background: #fff;
  cursor: pointer;
}

.swipeBtn {
  position: absolute;
  top: 10px;
  right: 10px;
}
</style>

<style lang="scss">
#cesiumContainer {
  .cesium-viewer-navigationContainer {
    display: none !important;
  }
}
</style>