基于 mapbox 开发大屏地图应用中,有时候需要展示一些三维图层立体效果。Mapbox 本身可以支持三维开发,详细介绍请参考文章:用 Mapbox 做 3D 地图,这篇文章快说透了 (技术&案例大盘点)。但要实现一些复杂的三维功能开发,有一定的门槛,包括但不限于掌握以下技术:
- 具备一定的计算机图形学基础,掌握三维计算相关数学知识;
- 深度掌握 Mapbox 相关应用场景及功能使用方式;
- 熟悉WebGL/OpenGL技术;
- 熟悉 Cesium、Three.js、Babylon.js 等三维引擎的使用。 :::warning 在这里,我们介绍使用 mapbox 的 line-translate 绘图属性实现简单的图层拔高立体效果。 :::
一、最终效果对比
图层来源说明:基于杭州市行政边界及下属区县行政边界进行开发。
- 二维平面呈现效果
- 三维立体呈现效果
二、实现步骤
2.1、Mapbox 地图初始化
代码略,详见:Mapbox 使用入门
2.2、添加全国行政区划图层数据源
// map 为 mapbox 地图实例(下同)
map.addSource('region_info', {
type: 'vector',
scheme: 'tms',
tiles: ['https://gis.certifarm.cn/geoserver/gwc/service/tms/1.0.0/wisdomOrchard:region_info@EPSG:900913@pbf/{z}/{x}/{y}.pbf'],
})
2.3、添加杭州市行政边界线图层
- 展示二维平面边界线
// 添加杭州市边界线图层
let lineOption = {
id: `city-line-layer`,
source: `region_info`,
'source-layer': `region_info`,
type: 'line',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
filter: ['match', ['get', 'code'], '330100', true, false],
paint: {
'line-color': '#6AF9F8',
'line-width': 4,
},
}
map.addLayer(lineOption)
效果如下:
- 添加一系列边界线图层,通过 line-translate 进行边界线偏移处理,模拟三维立体效果
// 采用边界偏移的方式,添加杭州区域下沉模糊效果(多个图层,每个图层偏移量递增)
const blurValueList = [0.6, 0.5, 0.5, 0.4, 0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1, 0.1, 0.3, 0.3]
blurValueList.forEach(async (item, index) => {
let tempOption = {
id: `city-line-blur-layer${index}`,
source: `region_info`,
'source-layer': `region_info`,
type: 'line',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
filter: ['match', ['get', 'code'], '330100', true, false],
paint: {
'line-color': `rgba(106, 249, 248, ${item})`,
'line-width': 2,
// 横向:左右无偏移,纵向:每一个图层向下偏移+1px
'line-translate': [0, (index + 1) * 1],
'line-translate-anchor': 'map',
},
}
map.addLayer(tempOption)
})
效果如下:
但在地图放大过程中,出现了奇怪的干扰线(见下图),地图缩小则没有这个问题。目前还没找到引起这个问题的具体原因,大家有空可以一起来调试研究下。
2.4、添加杭州市下属区县行政边界线图层、杭州市区域面图层
:::warning 说明一下,可以将杭州市区域面图层放到边界线偏移图层之上,则可以掩盖掉干扰线。 ::: 最终完整图层处理代码如下:
// 添加杭州市及下属区县行政区划图层
export default function addHZBoundaryLayer(map) {
return new Promise(async (resolve, reject) => {
try {
// 添加杭州市边界线图层
let lineOption = {
id: `city-line-layer`,
source: `region_info`,
'source-layer': `region_info`,
type: 'line',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
filter: ['match', ['get', 'code'], '330100', true, false],
paint: {
'line-color': '#6AF9F8',
'line-width': 4,
},
}
await map.addLayer(lineOption)
// 采用边界偏移的方式,添加杭州区域下沉模糊效果(多个图层,每个图层偏移量递增)
const blurValueList = [0.6, 0.5, 0.5, 0.4, 0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1, 0.1, 0.3, 0.3]
blurValueList.forEach(async (item, index) => {
let tempOption = {
id: `city-line-blur-layer${index}`,
source: `region_info`,
'source-layer': `region_info`,
type: 'line',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
filter: ['match', ['get', 'code'], '330100', true, false],
paint: {
'line-color': `rgba(106, 249, 248, ${item})`,
'line-width': 2,
// 横向:左右无偏移,纵向:每一个图层向下偏移+1px
'line-translate': [0, (index + 1) * 1],
'line-translate-anchor': 'map',
},
}
await map.addLayer(tempOption)
})
// 杭州市范围填充面图层
let options = {
id: `city-area-layer`,
source: `region_info`,
'source-layer': `region_info`,
type: 'fill',
filter: ['match', ['get', 'code'], '330100', true, false],
paint: {
'fill-color': '#1C4B5D',
},
}
await map.addLayer(options)
// 杭州下属各区县边界线图层
let districtLineOption = {
id: `district-line-layer`,
source: `region_info`,
'source-layer': `region_info`,
type: 'line',
layout: {
'line-cap': 'round',
'line-join': 'round',
},
filter: ['match', ['get', 'parent_code'], '330100', true, false],
paint: {
'line-color': '#245D6D',
'line-width': 1,
},
}
await map.addLayer(districtLineOption)
resolve()
} catch (err) {
reject(err)
}
})
}
最终展示效果如下: