坑点在于addS3MTilesLayerByScp
,Cesium.loadJson
加载的图层使用splitDirection
和splitPisotion
无效,普通的图层没问题
仅需要加载普通图层进行对比的就不需要用到本文的方法
絮絮叨叨:
感谢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>