mapboxgl绘制3D线

使用MapboxGL绘制立体行政区划图层时,针对区县边界显示问题,通过不同颜色区分各区县并利用缓冲技术模拟3D边界,解决线无法拔高的限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近遇到个需求,使用mapboxgl绘制行政区划图层,要求把行政区划拔高做出立体效果,以便突出显示。

拿到这个需求后,感觉很简单呀,只需要用fill-extrusion方式绘制就可以啦,实现出来是这个样子的

image-20210628224229898

效果有点丑,并且这里有个问题就是我的数据是区县数据,而绘制出的效果却没有区分出各个区县的边界
于是从下面两个方向做优化处理:

  1. 各区县按不同颜色区分
  2. 添加区县边界

首先尝试不同区县按颜色区分。这个简单,只需要设置fill-extrusion-color即可

image-20210630230042058

设置完效果如下

image-20210628224442854

效果好多了。

接下来继续尝试添加区县边界,之前也看到过类似效果,感觉应该也好实现

然鹅。。。

经过一番查找,发现发现mapboxgl可以对面进行拔高处理,但没有对线做拔高处理的方法,也就是说不支持绘制3D线。这可如何是好

既然线数据不能做拔高处理,那么把线处理成面总可以吧

于是从这个思路出发,按下面两步来操作

  1. 对行政区划边界进行缓冲,这里需要用到turf.js的缓冲方法
  2. 获取到缓冲后的边界面数据,再用fill-extrusion方式绘制

image-20210628224546947

嗯,效果还不错

在绘制边线缓冲面时,需要注意下面两点:

  1. fill-extrusion-height设置的值需要比面数据的稍微高出一些,否则显示时会有遮盖问题
  2. fill-extrusion-base(底部高度)参数可以设置为与前面绘制面的fill-extrusion-height参数一致,如果也采用默认0的话,边线就像一面墙,会感觉很丑

其实,这里还有个问题,由于这里的边界是按缓冲面的方式绘制,所以在地图缩放的时候边界的宽度不会像线那样按固定像素宽度显示,会出现放大地图的时候边线越来越宽,缩小地图的时候边线变越来越窄的问题

image-20210628224822294

解决思路:按各层级分辨率分别对行政区划边界做缓冲计算,然后再分别对应显示在各个层级

各层级的resolutions,也就是各比例尺下地图分辨率,也就是一个像素代表的地图单位,这里要按米为单位进行缓冲,用的是EPSG:900913的分辨率,也就是各比例尺下一个像素代表多少米

核心代码如下

image-20210701134504815

由于拿到数据的只有行政区划的geojson格式面数据,而缓冲时需要用的是线数据,因此需要做面转线处理。

image-20210701135130168

最终效果如下

3DLine

总结

  1. 当对行政区划面数据做立体展示时,仅用fill-extrusion方式绘制,效果不好,无法显示边线
  2. mapboxgl可以对面进行拔高处理,但没有对线做拔高处理的方法,也就是说不支持绘制3D线
  3. 通过对边线数据缓冲,获取缓冲后面数据,当做边线使用
  4. 由于单次缓冲半径固定,从而得到的缓冲面对大小固定,会出现地图缩放边线宽度也随着缩放的问题
  5. 通过resolutions,逐级对边线处理,按层级显示,可以得到较好的显示效果

在线示例

在线示例:http://gisarmory.xyz/blog/index.html?demo=MapboxGL3DLine

代码地址:http://gisarmory.xyz/blog/index.html?source=MapboxGL3DLine


原文地址:http://gisarmory.xyz/blog/index.html?blog=MapboxGL3DLine

关注《GIS兵器库》, 只给你网上搜不到的GIS知识技能

本文章采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名《GIS兵器库》(包含链接: http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

器库》(包含链接: http://gisarmory.xyz/blog/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

### 使用 Three.js 创建 3D 地图行政区划 为了创建基于 Three.js 的 3D 地图并展示行政区划,通常会涉及到几个核心组件:场景(Scene),摄像机(Camera),以及渲染器(Renderer)。此外,还需要加载地理数据来表示不同的行政区域。 对于具体的实现方式,在初始化阶段需先设置好基础环境[^2]: ```javascript // 获取容器元素 const threeDemo = document.getElementById("three"); // 初始化WebGL渲染器,并开启抗锯齿选项 const renderer = new THREE.WebGLRenderer({ canvas: threeDemo, antialias: true }); ``` 接着要构建三维空间内的坐标系与视角效果,这一步骤中将定义一个透视投影类型的摄像机[^5]: ```javascript // 定义宽高比例、近裁剪面距离、远裁剪面距离等参数 const camera = new THREE.PerspectiveCamera( 45, // 视场角度 window.innerWidth / window.innerHeight, // 宽高比 1, // 近平面 1000 // 远平面 ); camera.position.set(200, 200, 200); ``` 当基本框架搭建完毕之后,则可着手处理实际的地图几何形状。这里假设已经获取到了描述各个省份轮廓的数据集(例如GeoJSON格式),那么就可以遍历这些多边形或多部多边形结构,将其转换成适合Three.js使用的BufferGeometry对象[^3]: ```javascript province.geometry.coordinates.forEach(multipolygon => { multipolygon.forEach(polygon => { let shape = new THREE.Shape(); // 构建外环路径 for(let i=0;i<polygon.length-1;i++){ if(i===0){ shape.moveTo(...polygon[i]); }else{ shape.lineTo(...polygon[i]); } } // 添加到场景中的网格模型 const geometry = new THREE.ExtrudeGeometry(shape,{amount:1}); const material = new THREE.MeshBasicMaterial({color:'red'}); const mesh = new THREE.Mesh(geometry,material); scene.add(mesh); }); }); ``` 上述代码片段展示了如何根据给定的经纬度坐标序列构造闭合图形,并赋予一定的厚度形成立体感;同时设置了简单的材质属性以便于观察最终的效果。 最后不要忘记启动动画循环以保持画面更新,确保交互操作能够正常响应: ```javascript function animate() { requestAnimationFrame(animate); controls.update(); // 如果有 OrbitControls 控制 renderer.render(scene,camera); } animate(); ``` 以上就是利用 Three.js 实现带有行政区划分割特性的 3D 地图的大致流程概述。当然这只是最简化版本,真实应用场景下可能还会涉及更多细节优化工作,比如性能调优、视觉特效添加等方面的内容。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值