如何实现cesium 分屏的功能(vue3+cesium)

实现的效果如下

第一步来定义我们的地图样式
  <div class="split-screen-map">

        <div class="screen-map-container">

        layerValue 表示要分成几个屏

            <div v-for="(item, index) in layerValue" :key="index" :id="'screenCesiumContainer' + index" @mouseenter="handleMouseEnter(item, index)"
                class="scereen-map-content">

                经纬度表示我们划过屏幕可以显示我们当前屏幕的经纬度信息
                <!-- 经纬度 -->
                <div class="infoText">
                    <span>{{ item.longitude }}, </span>
                    <span>{{ item.latitude }}</span>
                </div>
            </div>
        </div>
    </div>
<style>
.split-screen-map {
    width: 100vw;
    height: 100vh;
    position: fixed;
    z-index: 1999;
    padding: 10px;
    top: 0;
    left: 0;
    background: rgba(255, 255, 255, 0.8);
}
.screen-map-container {
    height: calc(100vh - 60px);
    width: 100%;
    display: grid;
    grid-template-columns: 50% 50%;
    justify-content: center;
}
.scereen-map-content {
    border: 1px solid #8d99ff;
    height: 100%;
    overflow: hidden;
    display: grid;
    grid-template-rows: repeat(2, 100%);
    grid-template-columns: repeat(2, 100%);
    position: relative;
}
.infoText {
    padding-left: 10px;
    text-align: left;
    line-height: 26px;
    position: absolute;
    width: 100%;
    height: 26px;
    color: #f00;
    bottom: 60px;
    z-index: 1000;
}

</style>
第二步来初始化地图实现地图的展示、记录鼠标移入地图
let radioValue=4;表示我们要将生成几张地图

function initMap() {

    for (let i = 0; i < radioValue; i++) {

        let viewerScreen = new Cesium.Viewer('screenCesiumContainer' + i, {
            animation: false, //动画
            homeButton: false, //home键
            geocoder: false, //地址编码
            baseLayerPicker: false, //图层选择控件
            timeline: false, //时间轴
            fullscreenButton: false, //全屏显示
            infoBox: false, //点击要素之后浮窗
            sceneModePicker: false, //投影方式  三维/二维
            sceneMode: Cesium.SceneMode.SCENE2D, //初始场景模式 为二维
            navigationInstructionsInitiallyVisible: false, //导航指令
            navigationHelpButton: false, //帮助信息
            selectionIndicator: false, // 选择
            orderIndependentTranslucency: false, // orderIndependentTranslucency需要设置为true,才能去掉地球表面的大气效果的黑圈问题
            contextOptions: {
                webgl: {
                    alpha: true,
                },
            },
        })

        viewerScreen._cesiumWidget._creditContainer.style.display = 'none' // 隐藏cesium ion
        viewerScreen.scene.morphTo2D(0)

        将地图定位到地图的位置和高度
        viewerScreen.camera.setView({
            destination: Cesium.Cartesian3.fromDegrees(111.73, 27.8, radioValue == 2 ? 1200000 : 1700000),
        })

        viewerScreen.scene.skyBox.show = false
        viewerScreen.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0)
        //设置球体背景色
        viewerScreen.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 0)
        // 先把所有的影像图层的透明度设置为0
        // viewerScreen.imageryLayers._layers.forEach((layer) => {
        //     // layer.alpha = 0.0;
        //     viewerScreen.imageryLayers.remove(layer)
        // })
        // 保存云瑶的图层indexs
        // layerValue.value[i].YyImgList.push(addYyImgEvery(viewerScreen, layerValue.value[i].YyImg), 0)

             
          用来保存地图的值
        layerValue.value[i].viewerScreen = viewerScreen
            

      
    }
}

 

第三步实现鼠标划过记录当前的地图的经纬度信息
  1. 给地图添加 handleMouseEnter 方法 记录当前鼠标进入了哪个地图
  2. 计算当前鼠标的经纬度信息并更新
给地图添加 handleMouseEnter 方法 记录当前鼠标进入了哪个地图


<div v-for="(item, index) in layerValue" :key="index" :id="'screenCesiumContainer' + index"
                class="scereen-map-content" @mouseenter="handleMouseEnter(item, index)">
                <div class="layer-select-class">
                    <!-- <el-select style="min-width: 230px" v-model="item.layerUrlList" @change="handleSelect(item, index)"
                        collapse-tags-tooltip collapse-tags multiple filterable placeholder="请选择">
                        <el-option v-for="val in layerOptions" :key="val.value" :label="val.name" :value="val.value">
                        </el-option>
                    </el-select> -->
                </div>
</div>

这个方法在初始化中存放
moveLonLatFn(viewerScreen, i)

//计算并保存经纬度信息
function moveLonLatFn(viewerScreen, i) {
    new Cesium.ScreenSpaceEventHandler(viewerScreen.scene.canvas).setInputAction(function (movement) {
        const res = getLatLon(movement)
        layerValue.value[i].longitude = res.longitude
        layerValue.value[i].latitude = res.latitude
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}



let currentView = null
let currentIndex = undefined
// 鼠标移入
function handleMouseEnter(item, index) {
    currentView = item.viewerScreen
    currentIndex = index
}

 

 

第四步实现随便一个地图拖拽另外3个地图跟随移动
   给地图添加事件
   viewerScreen.camera.changed.addEventListener(handleMapChange)
   viewerScreen.scene.preRender.addEventListener(handleMapChange)

// 监听地图变化 跟随移动的方法
function handleMapChange() {
    if (!currentView) return
    const destination = Cesium.Cartographic.toCartesian(currentView.camera.positionCartographic)
    layerValue.value.forEach((item, index) => {
        if (index != currentIndex) {
            item.viewerScreen.camera.setView({
                destination: new Cesium.Cartesian3(destination.x, destination.y, destination.z),
                orientation: {
                    direction: currentView.scene.camera._direction,
                    up: currentView.scene.camera.up,
                    heading: currentView.scene.camera.heading,
                    pitch: currentView.scene.camera.pitch,
                    roll: currentView.scene.camera.roll,
                },
            })
        }
    })
}

全部代码
<template>
    <div class="split-screen-map">

        <div class="screen-map-container">
            <div v-for="(item, index) in layerValue" :key="index" :id="'screenCesiumContainer' + index"
                class="scereen-map-content" @mouseenter="handleMouseEnter(item, index)">
                <div class="layer-select-class">
                </div>
                <!-- 经纬度 -->
                <div class="infoText">
                    <span>{{ item.longitude }}, </span>
                    <span>{{ item.latitude }}</span>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import * as Cesium from 'cesium'
let props = defineProps({
    isShowSplitScreen: {
        type: Boolean,
        default: false,
    },
    radioValue: {
        type: Number,
        default: 2,
    },
})
let emit = defineEmits(['update:isShowSplitScreen', 'isShowSplitScreenFn'])
let layerValue = ref([])
watch(
    () => props.radioValue,
    () => {
        layerValue.value = []
        let defaultUrl = layerOptions.map((item) => item.value)[0]
        for (let i = 0; i < props.radioValue; i++) {
            // let indexs = layerMapOptions[0].children[0].children.length - 1
            // console.log(indexs, 'indexs')
            layerValue.value.push({
                layerUrlList: [],
                layerList: [],
                longitude: 112.59,
                latitude: 28.12,
                viewerScreen: null,
                viewEvent: null,
                stairModel: 1123,
                omenModel: 11232,
                // children: layerMapOptions[0].children, //时间轴二级1m列表
                // indexs: indexs, //记录云瑶的最大下标
                YyImg: {}, //云瑶地址信息
                YyImgList: [], //云瑶加过的服务
            })
        }
        nextTick(() => {
            initMap()
        })
    },
    {
        deep: true,
        immediate: true,
    }
)

function initMap() {
    for (let i = 0; i < props.radioValue; i++) {
        let viewerScreen = new Cesium.Viewer('screenCesiumContainer' + i, {
            animation: false, //动画
            homeButton: false, //home键
            geocoder: false, //地址编码
            baseLayerPicker: false, //图层选择控件
            timeline: false, //时间轴
            fullscreenButton: false, //全屏显示
            infoBox: false, //点击要素之后浮窗
            sceneModePicker: false, //投影方式  三维/二维
            sceneMode: Cesium.SceneMode.SCENE2D, //初始场景模式 为二维
            navigationInstructionsInitiallyVisible: false, //导航指令
            navigationHelpButton: false, //帮助信息
            selectionIndicator: false, // 选择
            orderIndependentTranslucency: false, // orderIndependentTranslucency需要设置为true,才能去掉地球表面的大气效果的黑圈问题
            contextOptions: {
                webgl: {
                    alpha: true,
                },
            },
        })
        viewerScreen._cesiumWidget._creditContainer.style.display = 'none' // 隐藏cesium ion
        viewerScreen.scene.morphTo2D(0)
        viewerScreen.camera.setView({
            destination: Cesium.Cartesian3.fromDegrees(111.73, 27.8, props.radioValue == 2 ? 1200000 : 1700000),
        })

        viewerScreen.scene.skyBox.show = false
        viewerScreen.scene.backgroundColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0)
        //设置球体背景色
        viewerScreen.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 0)
        layerValue.value[i].viewerScreen = viewerScreen
        //camera监听函数
        viewerScreen.camera.changed.addEventListener(handleMapChange)
        viewerScreen.scene.preRender.addEventListener(handleMapChange)
        //设置触发监听函数的时间
        viewerScreen.camera.percentageChanged = 0.01
        moveLonLatFn(viewerScreen, i)
    }
}
let currentView = null
let currentIndex = undefined
// 鼠标移入
function handleMouseEnter(item, index) {
    currentView = item.viewerScreen
    currentIndex = index
}
// 监听地图变化
function handleMapChange() {
    if (!currentView) return
    const destination = Cesium.Cartographic.toCartesian(currentView.camera.positionCartographic)
    layerValue.value.forEach((item, index) => {
        if (index != currentIndex) {
            item.viewerScreen.camera.setView({
                destination: new Cesium.Cartesian3(destination.x, destination.y, destination.z),
                orientation: {
                    direction: currentView.scene.camera._direction,
                    up: currentView.scene.camera.up,
                    heading: currentView.scene.camera.heading,
                    pitch: currentView.scene.camera.pitch,
                    roll: currentView.scene.camera.roll,
                },
            })
        }
    })
}

}
//滑动获取点经纬度
function moveLonLatFn(viewerScreen, i) {
    new Cesium.ScreenSpaceEventHandler(viewerScreen.scene.canvas).setInputAction(function (movement) {
        const res = getLatLon(movement)
        layerValue.value[i].longitude = res.longitude
        layerValue.value[i].latitude = res.latitude
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
// 组件卸载之前销毁地图
onUnmounted(() => {
    if (layerValue.value && layerValue.value.length) {
        layerValue.value.forEach((item) => {
            if (item.viewerScreen) {
                item.viewerScreen.destroy()
                item.viewerScreen = null
            }
        })
    }
})

</script>

<style scoped lang="scss">
.split-screen-map {
    width: 100vw;
    height: 100vh;
    position: fixed;
    z-index: 1999;
    padding: 10px;
    top: 0;
    left: 0;
    background: rgba(255, 255, 255, 0.8);
}

.switch_time_line {
    position: absolute;
    right: 85px;
    top: 9px;
    display: flex;
    align-items: center;
    font-size: 12px;
}

.close-btn {
    width: 100%;
    text-align: right;
    cursor: pointer;
}

.screen-map-container {
    height: calc(100vh - 60px);
    width: 100%;
    display: grid;
    grid-template-columns: 50% 50%;
    justify-content: center;
}

.scereen-map-content {
    border: 1px solid #8d99ff;
    height: 100%;
    overflow: hidden;
    display: grid;
    grid-template-rows: repeat(2, 100%);
    grid-template-columns: repeat(2, 100%);
    position: relative;
}

.infoText {
    padding-left: 10px;
    text-align: left;
    line-height: 26px;
    position: absolute;
    width: 100%;
    height: 26px;
    color: #f00;
    bottom: 60px;
    z-index: 1000;
}

.scereen-map-content:nth-child(2) {
    margin-left: 5px;
}

.scereen-map-content:nth-child(3) {
    margin-top: 5px;
}

.scereen-map-content:nth-child(4) {
    margin-left: 5px;
    margin-top: 5px;
}

.layer-select-class {
    position: absolute;
    top: 0;
    left: 0;
    display: flex;
    width: 100%;
    padding-top: 5px;
    justify-content: space-around;
    align-items: center;
    z-index: 10;
}

.time_line_sceren {
    position: absolute;
    bottom: 1px;
}

// #timeAxisLeft {
//     position: absolute;
//     bottom: 0px;
//     width: 100%;
//     left: 0;
// }
// .timer_shaft {
//     // width: 840px;
//     /* position: absolute; */
//     display: flex;
//     align-items: center;
//     position: relative;
//     bottom: 1px;
//     z-index: 999;
//     height: 66px;
//     background: #eee;
//     border-radius: 5px;
//     opacity: 0.9;
//     .select-type {
//         // position: absolute;
//         // top: 20px;
//         // left: 15px;
//         display: flex;
//     }
//     .time_inner {
//         width: calc(100% - 250px);
//         // position: absolute;
//         position: relative;
//         display: flex;
//         margin-left: 3%;
//         margin-bottom: 20px;
//         .time_inner_left {
//             position: absolute;
//             left: -15px;
//             top: -2px;
//             font-size: 24px;
//             cursor: pointer;
//         }
//         .time_inner_right {
//             position: absolute;
//             right: -33px;
//             top: -2px;
//             font-size: 24px;
//             cursor: pointer;
//         }
//         .time_inner_center {
//             height: 20px;
//             margin-left: 10px;
//             display: flex;
//             position: absolute;
//             top: 0;
//             left: 0;
//             justify-content: space-evenly;
//             border-radius: 8px;
//             background: linear-gradient(180deg, #2f97fe, #0262c1);
//             .long_css {
//                 width: calc(100% / 4);
//                 // width: 4px;
//                 // border-right: 4px;
//                 // border-color: black;
//                 // border-width:;
//                 border-right: 1px solid black;
//                 background-color: red;
//                 height: 100%;

//                 // height: 100%;
//                 // background-color: black;
//                 // margin-right: calc(100% / 5);
//                 // margin-left: calc((100% - 14px) / 5);
//             }
//             // .long_css:nth   ::after {
//             //     content: '';
//             //     width: calc(100% / 4);
//             //     // width: 4px;
//             //     // border-right: 4px;
//             //     // border-color: black;
//             //     // border-width:;
//             //     border-right: 1px solid black;
//             //     background-color: red;
//             //     height: 100%;
//             // }
//         }
//     }
// }
</style>

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
回答: 要在Vue3中使用Cesium实现自定义框,你可以按照以下步骤进行操作。首先,在vite.config.js中配置vite-plugin-cesium插件,引入Cesium和vite-plugin-cesium,并将其添加到plugins中。\[1\]然后,安装Cesium和vite-plugin-cesium插件,可以使用npm命令进行安装。\[2\]接下来,创建一个子组件,使用template标签定义组件的模板,其中包含自定义框的HTML结构和样式。\[3\]在script setup标签中,使用defineProps定义props属性,用于接收父组件传递的数据。最后,在style标签中定义组件的样式。这样就可以实现自定义框了。 #### 引用[.reference_title] - *1* *2* [使用vue3+vite+cesium,在地图上显示图标,并且点击实体弹出消息框](https://blog.csdn.net/weixin_46212682/article/details/127348864)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Vue3+cesium添加自定义弹窗并设置随地图移动位置移动](https://blog.csdn.net/qq_43474235/article/details/129230006)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值