用Cesium做个地图标记功能?手把手教你实现点击获取经纬度的完整流程
用Cesium实现地图标记功能从点击事件到经纬度坐标的完整指南第一次接触Cesium的三维地球开发时最让我兴奋的就是能够像主流地图应用那样通过点击获取任意位置的经纬度信息。这个看似简单的功能背后其实隐藏着屏幕像素、三维空间和地理坐标三个不同维度的坐标系转换。本文将带你用不到100行代码实现一个完整的坐标拾取工具。1. 环境搭建与基础准备在开始编写交互代码前我们需要准备一个基础的Cesium开发环境。这里推荐使用CDN方式快速引入Cesium库避免复杂的构建配置!DOCTYPE html html head meta charsetUTF-8 titleCesium坐标拾取示例/title script srchttps://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Cesium.js/script link hrefhttps://cesium.com/downloads/cesiumjs/releases/1.95/Build/Cesium/Widgets/widgets.css relstylesheet style html, body, #cesiumContainer { width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden; } /style /head body div idcesiumContainer/div script // 初始化Viewer const viewer new Cesium.Viewer(cesiumContainer, { terrainProvider: Cesium.createWorldTerrain(), timeline: false, animation: false }); /script /body /html提示使用createWorldTerrain()需要Cesium ion账号和token如需离线开发可改用new Cesium.EllipsoidTerrainProvider()基础场景中几个关键对象需要提前了解Viewer整个三维场景的容器和控制器Scene包含所有图形对象的场景树Camera控制观察视角和投影方式Globe代表地球表面的地形和影像层2. 坐标系系统深度解析Cesium开发涉及三种核心坐标系理解它们的区别和转换关系至关重要坐标系类型描述典型用途代表类屏幕坐标二维像素坐标原点在左上角鼠标点击位置Cartesian2世界坐标三维直角坐标系原点在地球中心空间位置计算Cartesian3地理坐标经纬度高程表示的椭球面坐标地理信息存储Cartographic转换流程遵循这样的链条屏幕坐标 → 世界坐标 → 地理坐标这个转换过程需要考虑地球曲率和地形高程。在平坦的地球模型下转换相对简单但真实场景中必须通过Globe.pick()方法考虑地形因素。3. 实现点击拾取功能现在我们来编写核心的点击事件处理代码。完整的实现包含三个关键步骤// 在Viewer初始化后添加以下代码 viewer.screenSpaceEventHandler.setInputAction((click) { // 步骤1获取屏幕坐标 const screenPosition click.position; // 步骤2屏幕坐标转世界坐标 const ray viewer.camera.getPickRay(screenPosition); if (!ray) return; const worldPosition viewer.scene.globe.pick(ray, viewer.scene); if (!worldPosition) return; // 步骤3世界坐标转地理坐标 const cartographic Cesium.Cartographic.fromCartesian(worldPosition); const longitude Cesium.Math.toDegrees(cartographic.longitude); const latitude Cesium.Math.toDegrees(cartographic.latitude); const height cartographic.height; console.log(经度: ${longitude.toFixed(6)}°, 纬度: ${latitude.toFixed(6)}°, 高程: ${height.toFixed(2)}米); // 添加标记点 viewer.entities.add({ position: worldPosition, point: { pixelSize: 10, color: Cesium.Color.RED, outlineColor: Cesium.Color.WHITE, outlineWidth: 2 }, label: { text: ${longitude.toFixed(4)}°, ${latitude.toFixed(4)}°, font: 14px sans-serif, style: Cesium.LabelStyle.FILL_AND_OUTLINE, outlineWidth: 2, verticalOrigin: Cesium.VerticalOrigin.TOP, pixelOffset: new Cesium.Cartesian2(0, -15) } }); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);这段代码实现了完整的交互流程通过screenSpaceEventHandler监听左键点击事件将点击位置的屏幕坐标转换为三维射线通过globe.pick()获取射线与地表的交点将世界坐标转换为人类可读的经纬度高程在点击位置添加可视化标记4. 高级功能扩展基础功能实现后我们可以进一步优化用户体验和功能完整性4.1 添加坐标显示面板在HTML中添加一个显示面板div idcoordinatePanel styleposition:absolute; top:10px; left:10px; background:white; padding:10px; border-radius:5px; 点击地图获取坐标 /div更新点击事件处理代码// 替换原来的console.log输出 const coordText 经度: ${longitude.toFixed(6)}°br纬度: ${latitude.toFixed(6)}°br高程: ${height.toFixed(2)}米; document.getElementById(coordinatePanel).innerHTML coordText;4.2 支持多点标记与清除添加控制按钮button idclearPoints styleposition:absolute; top:60px; left:10px;清除所有标记/button对应JavaScript代码document.getElementById(clearPoints).addEventListener(click, () { viewer.entities.removeAll(); document.getElementById(coordinatePanel).innerHTML 点击地图获取坐标; });4.3 地形精确度优化在山区或复杂地形区域可以开启更精确的地形采样viewer.terrainProvider Cesium.createWorldTerrain({ requestWaterMask: true, requestVertexNormals: true }); // 在pick调用时指定详细级别 const worldPosition viewer.scene.globe.pick(ray, viewer.scene, 9); // 9表示最高精度5. 常见问题与调试技巧在实际开发中你可能会遇到以下典型问题问题1点击海洋或空白区域返回null原因射线没有与地表相交解决添加有效性检查if (!worldPosition) { console.warn(未点击到有效地形); return; }问题2坐标精度不足原因默认地形采样率有限解决提高采样级别或使用本地高精度地形数据问题3标记点被地形遮挡解决调整点实体的高度参考模式viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height 2), // 抬高2米 // ...其他属性 heightReference: Cesium.HeightReference.CLAMP_TO_GROUND });调试时可以利用Cesium的内置工具// 开启调试模式 viewer.scene.debugShowFramesPerSecond true; viewer.scene.globe.show true; viewer.scene.globe.showGroundAtmosphere true;6. 性能优化建议当需要处理大量标记点时考虑以下优化策略使用EntityCluster聚合显示密集点viewer.dataSources.add(Cesium.EntityCluster.new());对于静态标记改用Primitive API替代Entity APIviewer.scene.primitives.add(new Cesium.PointPrimitiveCollection({ modelMatrix: Cesium.Matrix4.IDENTITY, debugShowBoundingVolume: false }));按视距分级加载标记viewer.scene.postRender.addEventListener(() { const cameraHeight viewer.camera.positionCartographic.height; // 根据相机高度调整标记显示细节 });在最近的一个气象站项目中我们使用类似的坐标拾取功能让用户可以标记异常天气位置。最初直接使用Entity API导致在移动端出现卡顿后来改用Primitive结合视距检测性能提升了3倍以上。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2523104.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!