地图框架leaflet和cesium实现二三维联动

本文介绍如何在项目中实现基于Leaflet的二维地图与Cesium的三维地图联动,包括平移和缩放的同步。通过设置标志位避免无限循环,使用坐标转换方法解决联动问题,并探讨了在不同视角下保持地图范围一致性的解决方案。

地图框架leaflet和cesium实现二三维联动

最近做个项目,要实现二三维联动。二维是基于leaflet的地图,三维是基于cesium,webgl的场景。要实现的是,平移、缩放二维地图时,三维跟着平移缩放,反过来也一样。

  一  问题界定

总体看,一共三个问题。

1 要解决二维三维循环联动的问题。就是说,不能拖动二维,三维跟着动,然后二维再跟着三维动,无限循环。

2 二维和三维的平移联动

3 二维和三维的缩放联动

二  问题解决

1 使用flag,鼠标进入二维div时,flag为true,进入三维时为false。使用onmouseover事件

2 这个比较简单,但注意坐标转换,cesium中需要将二维传过来的经纬度转为笛卡尔坐标,使用Cartesian3.fromDegrees接口

3 本文讨论的重点:

问题3的难点在于,leallet中的zoom和cesium中的height,这显然不是一个概念,那么常规的想法就是将zoom和height建立起联系。最简单粗暴的就是多观测几组zoom和height的对应值,然后用最小二乘法等回归算法进行拟合。但对于我这种懒人,这方法实在太麻烦、太“业余”,而且进一步想想,zoom是离散型变量,height是连续型的,即使拟合出了联系,效果也不会很好的,于是这个方案pass掉。

那么就开动脑筋想想其他方案。zoom和height对应是最直观的方式,但是除此之外,在相同视角下,二维地图和三维地图的范围应当一致。无论是二维和三维地图,一定都有extent的概念,就是当前可见范围。于是沿着这个思路寻找,发现leaflet中有fitbounds和getbounds的接口,而cesium中有Rectangle的接口,那就开干吧。

cesium

var rectangle = viewer.camera.computeViewRectangle();

// 弧度转为经纬度

var west =rectangle.west / Math.PI * 180;

var north = rectangle.north / Math.PI * 180;

var east = rectangle.east / Math.PI * 180;

var south = rectangle.south / Math.PI * 180;
使用leaflet的fitbounds接口,西北、东南传入参数即可。

leaflet

使用getbounds接口,获取四至,当然,需要转成度。然后用cesium.Rectanle传入参数即可。

注意,东南西北参数的对应

三 总结

代码写完基本就忘,因为这都不是核心。发现问题、提出问题、界定问题、解决问题的能力,无论是搞技术还是产品,这都是核心竞争力。

Cesium.Rectangle.fromDegrees(x1, y1, x2, y2)

<think>嗯,用户的问题聚焦在Cesium二三一体化开发的具体实现方法上。结合历史引用中的技术细节可视化案例,说明用户大概率是一名有三GIS基础的前端开发者,希望构建融合2D地图与3D地球的应用场景。用户提到的"二三一体化"这个关键词很专业,通常用于描述同时支持平面地图球体的交互系统。从引用[1][4]看,用户已掌握基础环境搭建,因此重点应放在视图切换场景联动这两大核心。引用[5]提到的Mars2D框架集成案例值得参考,不过用户明确要求原生Cesium方案。需要特别注意引用[3]暗示的d3kit工具包——虽然它可能提供封装好的二三组件,但用户需要的是实现原理而非黑盒工具。三转二的核心在于相机投影计算(Cesium.Scene.camera.positionWC转Cartographic)。二转三则相反,引用[4]的GlobalTranslucency示例展示过屏幕坐标转地球位置的方法。同步部分的关键是共享Camera事件监听器,当三视角变化时需重新计算二地图的centerzoom——这里可以引入地图缩放等级与三相机高度的对数关系公式:$$z=k\timeslog_{10}(h)+b$$考虑到性能,二标注在三模式下应转为billboard避免DOM重绘。而三实体在二模式下需要用Cesium.Entity.polyline实现投影,引用[5]提到的Three.js集成方案在这里可能有启发价值。错误边界处理需要特别说明:当三相机切入地下时,二地图应自动切换到平面坐标系;当二地图缩放超过20级时,三场景要禁用地形细节避免性能崩溃。这些细节在官方文档往往被忽略,却是实际项目的关键点。最后生成的示例代码保留扩展接口很重要——比如SceneModeSwitch事件的回调函数,方便用户接入自定义业务逻辑。毕竟用户需求本质上是搭建基础框架,后续肯定要叠加业务数据层。</think> 以下是基于 Cesium二三一体化开发的核心实现方法示例代码,重点解决三地球与二地图联动、视图同步及统一数据加载: --- ### **二三一体化开发核心思路** 1. **视图联动** - 三地球(`Cesium.Viewer`)与二地图(`Leaflet/OpenLayers`)共用一个容器或相邻布局 - 通过事件监听实现镜头同步(如三相机位置变化时自动更新二地图中心点) 2. **统一数据源** - 使用 `GeoJSON` 或 `WMS` 服务同时加载到三球体与二平面 - 实体(Entity)数据双向绑定(如点击二要素高亮三实体) 3. **模式切换** - 通过按钮切换 2D/3D 视图模式,动态调整场景参数 --- ### **示例代码 (关键部分)** ```html <!-- 引入依赖 --> <script src="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Cesium.js"></script> <link rel="stylesheet" href="https://cesium.com/downloads/cesiumjs/releases/1.89/Build/Cesium/Widgets/widgets.css"> <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script> <!-- Leaflet 作为二地图库 --> <div id="map2D" style="width:50%; height:100%; float:left;"></div> <!-- 二容器 --> <div id="cesiumContainer" style="width:50%; height:100%; float:left;"></div> <!-- 三容器 --> <script> // 初始化三地球 const viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, terrainProvider: Cesium.createWorldTerrain() }); // 初始化二地图 const map2D = L.map('map2D').setView([39.9, 116.4], 4); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map2D); // 核心: 视图同步 (三 => 二) viewer.camera.changed.addEventListener(() => { const carto = viewer.camera.positionCartographic; const lon = Cesium.Math.toDegrees(carto.longitude); const lat = Cesium.Math.toDegrees(carto.latitude); map2D.setView([lat, lon], Math.floor(viewer.camera.positionCartographic.height / 100000)); }); // 二 => 三同步 map2D.on('moveend', () => { const center = map2D.getCenter(); viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(center.lng, center.lat, 100000) }); }); // 统一加载 GeoJSON 数据 (示例) const dataSource = Cesium.GeoJsonDataSource.load('data.geojson'); viewer.dataSources.add(dataSource); // 在二地图添加相同数据 (Leaflet) fetch('data.geojson') .then(res => res.json()) .then(data => L.geoJSON(data).addTo(map2D)); </script> ``` --- ### **关键技术点说明** 1. **坐标系转换** - 三坐标 (`Cartesian3`) 与经纬度 (`Cartographic`) 的转换: ```js const carto = Cesium.Cartographic.fromCartesian(position); const lon = Cesium.Math.toDegrees(carto.longitude); const lat = Cesium.Math.toDegrees(carto.latitude); ``` - 二地图直接使用 `[lat, lon]` 格式 2. **性能优化** - 视图同步添加防抖机制(避免频繁触发): ```js Cesium.throttle(() => { /* 同步逻辑 */ }, 500), 'updateView'); ``` - 使用 `Primitive API` 替代 `Entity` 加载海量数据 3. **高级交互实现** - **要素双向选择**: ```js // 点击二要素时高亮三实体 layer2D.on('click', e => { viewer.selectedEntity = dataSource.entities.getById(e.layer.feature.id); }); ``` --- ### **官方推荐资源** 1. [Cesium 官方示例 - 2D/3D 模式切换](https://sandcastle.cesium.com/?src=2D%20and%203D%20Modes.html) - 展示三球体与二平面切换(非同步) 2. [Mars2D 框架集成方案](https://mars2d.cn/) [^5] - 提供开箱即用的二三融合组件(基于 Cesium + Leaflet) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值