基于原生 CSS 与 Cesium的地图卷帘对比实践

🚀 个人简介:某大型测绘遥感企业资深Webgis开发工程师,软件设计师(中级)、优快云优质创作者
💟 作 者:柳晓黑胡椒❣️
📝 专 栏:gis实践
🌈 若有帮助,还请关注点赞收藏,不行的话我再努努力💪💪💪

本文基于 Cesium 1.132 版本进行演示,其他版本在 API 上可能略有不同。

本文整理了css和cesium 卷帘效果应用,配合示例代码,你可以在实际项目中直接使用或二次封装,提升开发效率。

✨ 欢迎大家在评论区提出建议或交流心得,如果需要完整源码及css资源,可以私聊我获取。

原生 CSS 的卷帘实现

效果

<template>
  <div class="mapClip-wrap" ref="mapClipRef">
    <div class="image-box image-left" :style="{ clip: `rect(0px, ${leftPos}px, 570px, 0px)`}">
      <img src="@/assets/images/ui/sun-left.jpg"/>
      <p>水效:关闭</p>
    </div>
    <div class="image-box image-right">
      <img src="@/assets/images/ui/sun-right.jpg"/>
      <p>水效:打开</p>
    </div>
    <div class="control-handle" :style="{left:leftPos + 'px'}"
         @mousedown="mousedownFn">
      <el-icon size="18">
        <ArrowLeftBold class="icon left"/>
      </el-icon>
      <el-icon size="18">
        <ArrowRightBold class="icon right"/>
      </el-icon>
      <div data-v-64761556="" class="line"></div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import {reactive, ref, toRefs} from "vue";
// Ref
const mapClipRef = ref(null)

const model = reactive({
  draggingType: "",
  leftPos: 100,
})
const {leftPos} = toRefs(model)

const mousedownFn = () => {
  model.draggingType = '1'
  document.addEventListener('mousemove', mousemoveFn)
  document.addEventListener('mouseup', mouseupFn)
}

const mousemoveFn = (e) => {
  if (!model.draggingType) return
  const {left, width} = mapClipRef.value.getBoundingClientRect()
  switch (true) {
    case e.clientX - left < 0:
      model.leftPos = 0
      break
    case e.clientX - left > width :
      model.leftPos = width
      break
    default:
      model.leftPos = e.clientX - left
      break
  }
}

const mouseupFn = () => {
  model.draggingType = ""
  document.removeEventListener('mousemove', mousemoveFn)
  document.removeEventListener('mouseup', mouseupFn)
}

</script>

适用场景

前端页面、二维地图对比、轻量级可视化、移动端页面

实现思路

原生 CSS 的卷帘,本质是在两张叠加的图片之间,通过修改上层图片的 可视区域 来实现左右拖动的对比效果。
CSS 卷帘的核心就是:

  • 将两层地图图片叠放(z-index)
  • 📌上层地图用 clip 控制裁剪宽度
  • 与拖动条同步裁剪区域
  • 通过监听 mousemove 或拖拽条位置动态更新裁剪范围
  • 不依赖任何框架,非常轻量级 ⚡

Cesium 的地图卷帘实现

效果

<template>
  <div class="mapSplit-wrap">
    <div class="slider" ref="sliderRef" @mouseup="moveActive = false">
      <div class="sliderImg" @mousedown="moveActive = true"></div>
    </div>
    <!-- 默认加载天地图-->
    <Tdt_img_d/>
  </div>
</template>

<script lang="ts" setup>
import {usemapStore} from "@/store/modules/cesiumLastMap";
import GUI from "lil-gui";
import {onMounted, onUnmounted, reactive, ref, toRefs} from "vue";
import * as Cesium from "cesium";
// Component
import Tdt_img_d from "@/views/cesiumLast/component/main/controlPanel/layerManagement/basicMap/tdt_img_d.vue"
// Ref
const sliderRef = ref(null)

const mapStore = usemapStore()
const model = reactive({
  moveActive: false
})
const {moveActive} = toRefs(model)
onMounted(async () => {
  initGui()
  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  viewer.scene.splitPosition = sliderRef.value.offsetLeft / viewer.scene.canvas.offsetWidth;
  handler.setInputAction(onMouseMove, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  addSplitDirection()
})

onUnmounted(() => {
  gui.destroy()
})

// 地图逻辑
const viewer = mapStore.getCesiumViewer()
let handler, imageryProviderL, imageryProviderR

const addSplitDirection = async () => {
  imageryProviderL = await viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
    url: 'https://{s}.tianditu.gov.cn/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=' + import.meta.env.VITE_APP_TDT_KEY,
    layer: 'vec_d',
    style: 'default',
    format: 'image/jpeg',
    tileMatrixSetID: 'GoogleMapsCompatible',
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    maximumLevel: 18
  }));
  imageryProviderL.splitDirection = -1

  imageryProviderR = await viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
    url: 'https://{s}.tianditu.gov.cn/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=' + import.meta.env.VITE_APP_TDT_KEY,
    layer: 'img_d',
    style: 'default',
    format: 'image/jpeg',
    tileMatrixSetID: 'GoogleMapsCompatible',
    subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
    maximumLevel: 18
  }));
  imageryProviderR.splitDirection = 1
}

const onMouseMove = (movement) => {
  if (!model.moveActive) return
  const splitPosition = movement.endPosition.x / viewer.scene.canvas.offsetWidth;
  sliderRef.value.style.left = `${100 * splitPosition}%`;
  viewer.scene.splitPosition = splitPosition;
}

// lil-gui逻辑
let gui
const formData = {
}

const initGui = () => {
  gui = new GUI({title: "mapSplit"});
}

</script>

实现思路

Cesium 提供内置的卷帘能力,通过 viewer.scene.splitPosition 控制三维场景中左右图层的切割比例。

  • 添加两个影像图层 A、B
  • 为 A 设置:layer.splitDirection = Cesium.SplitDirection.LEFT
  • 为 B 设置:layer.splitDirection = Cesium.SplitDirection.RIGHT
  • 📌通过 viewer.scene.splitPosition = x 控制切割位置(0 ~ 1)
  • 随着滑块拖动动态调整 splitPosition,实现三维地图卷帘⚡

适用场景

三维水利、遥感对比、地形变化分析、城市规划、倾斜摄影前后对比

Takeaways

地图卷帘(Map Swipe / Split View)是一种常见的时空对比方式,被广泛用于遥感解译、水利监测、规划对比等场景。
🌐 在 CSS 方案中,我们通过 clip 完成轻量卷帘,非常适合网页展示与 UI 控件自定义。
🛰️ 在 Cesium 方案中,我们利用 viewer.scene.splitPosition 实现专业级的三维卷帘能力,可对比影像、地形、倾斜模型等多源数据。

无论你是做 Web 可视化、数字孪生、还是 GIS 系统开发,这两种方案都能在实际项目中带来清晰、高效的数据对比体验。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳晓黑胡椒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值