概述
本文分享如何通过mapboxGL实现三维的室内地图的展示。
效果
全部楼层 单楼层 高亮选中实现
1. 数据
精确的数需要通过CAD转换,本文为简单演示,是通过qgis中绘制的,数据主要包括如下字段:
{ "id": 1, "name": "type1","floor": 1, "type": "1" }
其中:
-
floor
为楼层数据,建议为数字,方便排序; -
type
为类型,为商户的类型,通过type渲染不同的颜色;文中为了展示楼层地面,加了一个特殊的类型999,;
示例中用的完整数据如下:
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "id": 1, "name": "type1","floor": 1, "type": "1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.88576766738845, 22.55132808900947 ], [ 113.88689629860265, 22.55132808900947 ], [ 113.888041775058838, 22.550081541101257 ], [ 113.887629066629771, 22.549550915978166 ], [ 113.887283739168709, 22.549525648115164 ], [ 113.886070881744502, 22.549727791019198 ], [ 113.885708709041452, 22.550089963722261 ], [ 113.88576766738845, 22.55132808900947 ] ] ] } },
{ "type": "Feature", "properties": { "id": 2, "name": "type3","floor": 1, "type": "3" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.888269185825877, 22.550536362635334 ], [ 113.888134423889866, 22.550511094772332 ], [ 113.887805941670806, 22.550789041265379 ], [ 113.887014215296674, 22.55160603550252 ], [ 113.886129840091513, 22.551597612881515 ], [ 113.885936119808491, 22.551841868890559 ], [ 113.885986655534495, 22.552692553611703 ], [ 113.886331982995557, 22.552540946433677 ], [ 113.887090018885687, 22.552321958287639 ], [ 113.887511149935747, 22.551892404616567 ], [ 113.887991239332834, 22.551437583082489 ], [ 113.888505019213923, 22.550949071064405 ], [ 113.888715584738961, 22.550957493685406 ], [ 113.888724007359954, 22.55067954719236 ], [ 113.8883871025199, 22.550452136425321 ], [ 113.888269185825877, 22.550536362635334 ] ] ] } },
{ "type": "Feature", "properties": { "id": 3, "name": "type2","floor": 1, "type": "2" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.886171953196524, 22.55290311913674 ], [ 113.887014215296674, 22.553736958615882 ], [ 113.887300584410724, 22.553602196679858 ], [ 113.887595376145768, 22.55366115502687 ], [ 113.889541001597095, 22.551791333164548 ], [ 113.889322013451064, 22.551504964050501 ], [ 113.88943150752408, 22.551353356872475 ], [ 113.889119870547034, 22.551142791347438 ], [ 113.888841924053978, 22.551125946105437 ], [ 113.887704870218784, 22.552246154698626 ], [ 113.887755405944802, 22.552473565465665 ], [ 113.887477459451745, 22.552642017885695 ], [ 113.886972102191663, 22.552515678570675 ], [ 113.886281447269539, 22.552768357200716 ], [ 113.886171953196524, 22.55290311913674 ] ] ] } },
{ "type": "Feature", "properties": { "id": 4, "name": "type3","floor": 2, "type": "3"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.88576766738845, 22.55132808900947 ], [ 113.88689629860265, 22.55132808900947 ], [ 113.888041775058838, 22.550081541101257 ], [ 113.887629066629771, 22.549550915978166 ], [ 113.887283739168709, 22.549525648115164 ], [ 113.886070881744502, 22.549727791019198 ], [ 113.885708709041452, 22.550089963722261 ], [ 113.88576766738845, 22.55132808900947 ] ] ] } },
{ "type": "Feature", "properties": { "id": 5, "name": "type2","floor": 2, "type": "2"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.888269185825877, 22.550536362635334 ], [ 113.888134423889866, 22.550511094772332 ], [ 113.887805941670806, 22.550789041265379 ], [ 113.887014215296674, 22.55160603550252 ], [ 113.886129840091513, 22.551597612881515 ], [ 113.885936119808491, 22.551841868890559 ], [ 113.885986655534495, 22.552692553611703 ], [ 113.886331982995557, 22.552540946433677 ], [ 113.887090018885687, 22.552321958287639 ], [ 113.887511149935747, 22.551892404616567 ], [ 113.887991239332834, 22.551437583082489 ], [ 113.888505019213923, 22.550949071064405 ], [ 113.888715584738961, 22.550957493685406 ], [ 113.888724007359954, 22.55067954719236 ], [ 113.8883871025199, 22.550452136425321 ], [ 113.888269185825877, 22.550536362635334 ] ] ] } },
{ "type": "Feature", "properties": { "id": 6, "name": "type1","floor": 2, "type": "1"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.886171953196524, 22.55290311913674 ], [ 113.887014215296674, 22.553736958615882 ], [ 113.887300584410724, 22.553602196679858 ], [ 113.887595376145768, 22.55366115502687 ], [ 113.889541001597095, 22.551791333164548 ], [ 113.889322013451064, 22.551504964050501 ], [ 113.88943150752408, 22.551353356872475 ], [ 113.889119870547034, 22.551142791347438 ], [ 113.888841924053978, 22.551125946105437 ], [ 113.887704870218784, 22.552246154698626 ], [ 113.887755405944802, 22.552473565465665 ], [ 113.887477459451745, 22.552642017885695 ], [ 113.886972102191663, 22.552515678570675 ], [ 113.886281447269539, 22.552768357200716 ], [ 113.886171953196524, 22.55290311913674 ] ] ] } },
{ "type": "Feature", "properties": { "id": 7, "name": "type2","floor": 3, "type": "2"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.88576766738845, 22.55132808900947 ], [ 113.88689629860265, 22.55132808900947 ], [ 113.888041775058838, 22.550081541101257 ], [ 113.887629066629771, 22.549550915978166 ], [ 113.887283739168709, 22.549525648115164 ], [ 113.886070881744502, 22.549727791019198 ], [ 113.885708709041452, 22.550089963722261 ], [ 113.88576766738845, 22.55132808900947 ] ] ] } },
{ "type": "Feature", "properties": { "id": 8, "name": "type3","floor": 3, "type": "3"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.888269185825877, 22.550536362635334 ], [ 113.888134423889866, 22.550511094772332 ], [ 113.887805941670806, 22.550789041265379 ], [ 113.887014215296674, 22.55160603550252 ], [ 113.886129840091513, 22.551597612881515 ], [ 113.885936119808491, 22.551841868890559 ], [ 113.885986655534495, 22.552692553611703 ], [ 113.886331982995557, 22.552540946433677 ], [ 113.887090018885687, 22.552321958287639 ], [ 113.887511149935747, 22.551892404616567 ], [ 113.887991239332834, 22.551437583082489 ], [ 113.888505019213923, 22.550949071064405 ], [ 113.888715584738961, 22.550957493685406 ], [ 113.888724007359954, 22.55067954719236 ], [ 113.8883871025199, 22.550452136425321 ], [ 113.888269185825877, 22.550536362635334 ] ] ] } },
{ "type": "Feature", "properties": { "id": 9, "name": "type1","floor": 3, "type": "1"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.886171953196524, 22.55290311913674 ], [ 113.887014215296674, 22.553736958615882 ], [ 113.887300584410724, 22.553602196679858 ], [ 113.887595376145768, 22.55366115502687 ], [ 113.889541001597095, 22.551791333164548 ], [ 113.889322013451064, 22.551504964050501 ], [ 113.88943150752408, 22.551353356872475 ], [ 113.889119870547034, 22.551142791347438 ], [ 113.888841924053978, 22.551125946105437 ], [ 113.887704870218784, 22.552246154698626 ], [ 113.887755405944802, 22.552473565465665 ], [ 113.887477459451745, 22.552642017885695 ], [ 113.886972102191663, 22.552515678570675 ], [ 113.886281447269539, 22.552768357200716 ], [ 113.886171953196524, 22.55290311913674 ] ] ] } },
{ "type": "Feature", "properties": { "id": 10, "name": "","floor": 1, "type": "999"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.885632905452397, 22.552818892926712 ], [ 113.885771878698918, 22.553046303693751 ], [ 113.886302503822009, 22.553484279985827 ], [ 113.887106864127674, 22.554212836702447 ], [ 113.887443768967728, 22.554246527186454 ], [ 113.888075465542826, 22.55364430978485 ], [ 113.888214438789362, 22.553412687707311 ], [ 113.890008457062649, 22.551715529575528 ], [ 113.889991611820648, 22.55150075273999 ], [ 113.88778909642879, 22.549538282046655 ], [ 113.88754484041975, 22.549454055836641 ], [ 113.887182667716687, 22.549407731421134 ], [ 113.886353039548055, 22.54956776122016 ], [ 113.885784512630451, 22.549727791019198 ], [ 113.88556552448442, 22.550098386343258 ], [ 113.885632905452397, 22.552818892926712 ] ] ] } },
{ "type": "Feature", "properties": { "id": 11, "name": "","floor": 2, "type": "999"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.885632905452397, 22.552818892926712 ], [ 113.885771878698918, 22.553046303693751 ], [ 113.886302503822009, 22.553484279985827 ], [ 113.887106864127674, 22.554212836702447 ], [ 113.887443768967728, 22.554246527186454 ], [ 113.888075465542826, 22.55364430978485 ], [ 113.888214438789362, 22.553412687707311 ], [ 113.890008457062649, 22.551715529575528 ], [ 113.889991611820648, 22.55150075273999 ], [ 113.88778909642879, 22.549538282046655 ], [ 113.88754484041975, 22.549454055836641 ], [ 113.887182667716687, 22.549407731421134 ], [ 113.886353039548055, 22.54956776122016 ], [ 113.885784512630451, 22.549727791019198 ], [ 113.88556552448442, 22.550098386343258 ], [ 113.885632905452397, 22.552818892926712 ] ] ] } },
{ "type": "Feature", "properties": { "id": 12, "name": "","floor": 3, "type": "999"}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 113.885632905452397, 22.552818892926712 ], [ 113.885771878698918, 22.553046303693751 ], [ 113.886302503822009, 22.553484279985827 ], [ 113.887106864127674, 22.554212836702447 ], [ 113.887443768967728, 22.554246527186454 ], [ 113.888075465542826, 22.55364430978485 ], [ 113.888214438789362, 22.553412687707311 ], [ 113.890008457062649, 22.551715529575528 ], [ 113.889991611820648, 22.55150075273999 ], [ 113.88778909642879, 22.549538282046655 ], [ 113.88754484041975, 22.549454055836641 ], [ 113.887182667716687, 22.549407731421134 ], [ 113.886353039548055, 22.54956776122016 ], [ 113.885784512630451, 22.549727791019198 ], [ 113.88556552448442, 22.550098386343258 ], [ 113.885632905452397, 22.552818892926712 ] ] ] } }
]
}
对上面的数据加以处理,添加height
和base
字段,用以展示楼层3d效果。
let floors = []
const floorHeight = 55, buildHeight = 7, baseHeight = 1
res.features.forEach(feature => {
const {properties} = feature
const {floor, type} = properties
if(!floors.includes(floor)) floors.push(floor)
let height = (floor - 1) * floorHeight + buildHeight
let base = height - buildHeight
if(type === '999') height = base + baseHeight
properties.height = height
properties.base = base
})
2. 添加图层
通过mapboxGL中的fill-extrusion
图层实现楼层和商户的展示,初始化style
如下:
const style = {
version: 8,
glyphs: "https://lzugis.cn/fonts/{fontstack}/{range}.pbf",
sources: {
'building': {
type: 'geojson',
data: res
}
},
layers: [
{
"id": "sky",
"type": "sky",
"paint": {
"sky-gradient": "rgba(0, 0, 0, 1)",
"sky-opacity": 0.1
}
},
{
'id': 'building',
'source': 'building',
'type': 'fill-extrusion',
'filter': ["==", ['get', 'floor'], 0],
'paint': {
'fill-extrusion-color': [
'match',
['get', 'type'],
'999', '#ccc',
'1', '#FFD273',
'2', '#E86D68',
'#A880FF'
],
'fill-extrusion-base': ['get', 'base'],
'fill-extrusion-height': ['get', 'height'],
'fill-extrusion-opacity': 0.45
}
},
{
'id': 'building-height',
'source': 'building',
'type': 'fill-extrusion',
'filter': ["==", ['get', 'floor'], 0],
'paint': {
'fill-extrusion-color': '#0ff',
'fill-extrusion-base': ['get', 'base'],
'fill-extrusion-height': ['get', 'height'],
'fill-extrusion-opacity': 0.45
}
},
{
'id': 'building-label',
'type': 'symbol',
'source': 'building',
'filter': ["==", ['get', 'floor'], 0],
'layout': {
'text-field': ['get', 'name'],
"text-size": 14
},
paint: {
'text-color': '#999'
}
}
]
}
地图的初始化配置如下:
{
container: 'map',
center: [113.88768248794844, 22.551640034479163],
hash: false,
zoom: 16.6,
style,
pitch: 65,
bearing: 120
}
3. 添加楼层控制UI
此处,单楼层和展示全部楼层的fill-extrusion-base
和fill-extrusion-height
配置有区别。
const ul = document.createElement('ul')
ul.classList.add('floor-control')
const showFloor = (floor = 'All') => {
floor = floor === 'All' ? floor : parseInt(floor)
const lis = ul.children
for (let i = 0; i < lis.length; i++) {
const li = lis[i]
li.classList.remove('active')
if(floors.indexOf(floor) === i) li.classList.add('activ
}
map.setFilter('building', [floor === 'All' ? '!=' : '==',
map.setFilter('building-label', ['==', ['get', 'floor'],
if(floor === 'All') {
map.setPaintProperty('building', 'fill-extrusion-base',
map.setPaintProperty('building', 'fill-extrusion-height
map.setPaintProperty('building-height', 'fill-extrusion
map.setPaintProperty('building-height', 'fill-extrusion
} else {
map.setPaintProperty('building', 'fill-extrusion-base',
map.setPaintProperty('building', 'fill-extrusion-height
'match',
['get', 'type'],
'999', baseHeight,
buildHeight
]);
map.setPaintProperty('building-height', 'fill-extrusion
map.setPaintProperty('building-height', 'fill-extrusion
'match',
['get', 'type'],
'999', baseHeight,
buildHeight
]);
}
}
const addFloorsUI = function () {
floors.splice(0, 0, 'All')
floors.forEach(floor => {
const li = document.createElement('li')
ul.appendChild(li)
li.innerText = floor === 'All' ? floor : floor + 'F'
li.setAttribute('floor', floor)
li.onclick = function () {
const floor = this.getAttribute('floor')
showFloor(floor)
}
})
document.body.appendChild(ul)
showFloor()
}
map.on('load', addFloorsUI)
4. 添加点击交互
注册地图的click
事件,用以取消选中,注册图层的click
事件,用以选中。
map.on('click', e => {
map.setFilter('building-height', ['==', ['get', 'id'], null]);
})
map.on('click', 'building', e => {
const { properties } = e.features[0]
let {id, type} = properties
id = type === '999' ? null : id
map.setFilter('building-height', ['==', ['get', 'id'], id]);
})
网友评论