在 Cesium 可视化开发中,卷帘对比是常用功能,可用于 3D Tiles 模型、影像图层的左右分屏对比,支持动态调整分割比例。
本文基于 Cesium 1.41+ 版本的 SplitDirection 特性,从核心原理、到代码实现,带着大家实现一下cesium卷帘对比效果。欢迎大家一起交流学习。
2025cesium进阶教程持续更新中...
前篇回顾:
2025cesium进阶教程|Cesium 天气特效实现:从 ShaderToy 移植下雪效果的完整方案_shadertoy和cesium如何结合-CSDN博客
https://blog.csdn.net/yaogis888/article/details/154843181?spm=1001.2014.3001.5502Cesium进阶教程(2)|基于 Cesium 后处理Post Processing的图形绘制(上)-CSDN博客
https://blog.csdn.net/yaogis888/article/details/154994782?spm=1001.2014.3001.5502Cesium进阶教程(2)|基于 Cesium 后处理Post Processing的图形绘制(下)-CSDN博客
https://blog.csdn.net/yaogis888/article/details/154995091?spm=1001.2014.3001.55022025Cesium进阶教程(3) 发光流动线实例讲解,实现自定义 MaterialProperty(上)_cesium.createpropertydescriptor-CSDN博客
https://blog.csdn.net/yaogis888/article/details/155226305?spm=1001.2014.3001.55012025Cesium进阶教程(3) 发光流动线实例讲解,实现自定义 MaterialProperty(下)_cesium流动线-CSDN博客
https://blog.csdn.net/yaogis888/article/details/155227354?spm=1001.2014.3001.55012025Cesium进阶教程(4)| 动态响应的发光流动线实例讲解-CSDN博客
https://blog.csdn.net/yaogis888/article/details/155483412?spm=1001.2014.3001.55012025Cesium进阶教程(5)| webgis智慧城市开发,大屏可视化行政区高亮-CSDN博客
https://blog.csdn.net/yaogis888/article/details/155575623?spm=1001.2014.3001.5501
一、核心功能与原理概括
1.SplitDirection 核心功能
-
支持 3D Tiles / 影像图层的左右分屏对比,指定目标图层仅在左侧或右侧显示;
-
提供可视化分割线,支持鼠标拖拽交互,动态调整分屏比例;
-
解决拖拽偏移误差,确保分割线移动流畅、位置精准。
2. 实现原理
-
核心依赖 Cesium 两个关键配置:
splitDirection(指定图层显示侧:左 / 右)和splitPosition(控制分割位置,取值 0-1); -
通过创建 DOM 元素作为分割线,绑定鼠标 "按下 - 移动 - 抬起" 事件,动态计算并更新
splitPosition,实现分屏比例的实时调整; -
引入偏移修正逻辑,通过记录鼠标初始点击位置,避免拖拽时分割线突然跳转。
二、效果实现:
1:依赖引入与场景初始化
使用Cesium库创建一个3D地球视图,并配置了基础控件和地形加载功能。同时引入dat.gui库(通常用于调试参数调节),并设置Cesium的Ion访问令牌。
Cesium初始化配置
javascript
import * as Cesium from "cesium";
import * as dat from "dat.gui";
import { token } from "../lib/token";
Cesium.Ion.defaultAccessToken = token;
const viewer = new Cesium.Viewer("container", {
timeline: true, // 显示时间线控件
animation: false, // 隐藏动画控件
baseLayerPicker: false, // 隐藏底图切换控件
infoBox: false, // 隐藏要素点击信息框
selectionIndicator: false, // 隐藏选中元素指示器
homeButton: false, // 隐藏复位按钮
fullscreenButton: false, // 隐藏全屏按钮
geocoder: false, // 隐藏地理编码(搜索)控件
sceneModePicker: false, // 隐藏二三维模式切换控件
shouldAnimate: true, // 启用动画效果(必填)
navigationHelpButton: false, // 隐藏导航帮助按钮
地形加载配置
javascript
terrainProvider: new Cesium.CesiumTerrainProvider({
url: Cesium.IonResource.fromAssetId(1), // 加载地形(可选)
}),
});
关键渲染设置
javascript
viewer.scene.globe.depthTestAgainstTerrain = true; // 开启地形深度测试
2:3D Tiles 加载与卷帘基础配置
使用CesiumJS库加载并控制一个3D Tiles模型,同时实现卷帘对比效果。以下是逐部分解析:
加载3D Tiles模型
javascript
const tileset = new Cesium.Cesium3DTileset({
url: "http://localhost:666/model/AGI_HQ/tileset.json", // 3D Tiles 模型地址
});
viewer.scene.primitives.add(tileset); // 将模型添加到场景
等待模型加载完成
javascript
await tileset.readyPromise;
设置模型位置
javascript
// 定义模型位置(经纬度:114.3°E,30.5°N,高度 30m)
const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(114.3, 30.5, 30.0)
);
tileset._root.transform = modelMatrix; // 应用模型位置变换
视角控制
javascript
viewer.zoomTo(tileset);
卷帘效果实现
javascript
// 核心卷帘参数配置
tileset.splitDirection = Cesium.SplitDirection.LEFT;
viewer.scene.splitPosition = 0.5;
3:可视化分割线创建
于在网页中创建一条3:1比例的可视化分割线,支持自定义颜色和样式。
javascript
const slider = document.createElement("div");
document.querySelector("#container").appendChild(slider);
slider.id = "slider";
// 分割线样式配置
slider.style.display = "block";
slider.style.position = "absolute"; // 绝对定位(相对于 container)
slider.style.top = "0";
slider.style.height = "100%"; // 高度占满容器
slider.style.width = "5px"; // 分割线宽度(便于点击拖拽)
slider.style.backgroundColor = "#fff"; // 白色分割线
slider.style.cursor = "col-resize"; // 鼠标悬浮显示左右拖拽样式
slider.style.zIndex = "1000"; // 确保分割线在最上层
slider.style.left = "50%"; // 初始位置与 splitPosition 一致
4:鼠标拖拽事件绑定(交互逻辑实现)
基于Cesium.js的屏幕分割交互功能,通过鼠标拖拽控制场景分屏比例。核心功能包括:拖拽状态管理、分割位置计算、界面元素同步更新。
变量定义
javascript
const handler = new Cesium.ScreenSpaceEventHandler(slider);
let isDragging = false; // 拖拽状态标记(默认未拖拽)
let startX; // 记录鼠标按下时的初始 X 坐标(修正拖拽偏移)
鼠标按下事件
javascript
// 鼠标左键按下事件(开启拖拽)
handler.setInputAction((movement) => {
isDragging = true;
startX = movement.position.x; // 记录鼠标按下时的初始 X 坐标
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
鼠标移动事件
javascript
// 鼠标移动事件(更新分割位置)
handler.setInputAction((movement) => {
if (!isDragging) return; // 未拖拽时,不执行任何操作
const endPosition = movement.endPosition; // 鼠标当前位置
// 计算新的分割位置(0-1 范围)
const splitPosition = (slider.offsetLeft + endPosition.x - startX) / slider.parentElement.offsetWidth;
// 限制 splitPosition 范围在 0-1 之间,避免超出屏幕
const clampedSplitPosition = Cesium.Math.clamp(splitPosition, 0, 1);
// 更新场景分屏位置和分割线样式
viewer.scene.splitPosition = clampedSplitPosition;
slider.style.left = `${clampedSplitPosition * 100}%`;
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
鼠标释放事件
javascript
// 鼠标左键抬起事件(结束拖拽)
handler.setInputAction(() => {
isDragging = false;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
看不明白没关系,点这里可以查看视频解析👇