实现楼层效果
准备数据
楼层数据
楼层的数据和楼的数还是有区别的:
- 楼的数据只要有高度即可
- 楼层的数据不仅要有高度的数据,还有有离地的高度,比如1楼离地0米,高度4M,二楼离地4M高度8米,其他楼层以此类推
TIP
注意这里的离地高度指的的楼的地面相对于地面的高度,高度指的是楼顶相对于地面的高度,一般一层楼4M左右,所以楼层的高度和离地高度差值一般在4
- 楼层的数据相对于楼的数据量比较大,假设一个楼有10层,那么楼层数据就要对应的有10条,这10条数据他们的经纬度数据 都是相同的,仅有业务的属性(离地高度和高度)不同而已
json
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
120.6025242805481,
31.26763860051824
],
[
120.60255110263824,
31.26762943002237
],
[
120.60255110263824,
31.26752396925585
],
[
120.6025242805481,
31.26751479874885
],
[
120.6022185087204,
31.26751479874885
],
[
120.60220777988434,
31.267537725014687
],
[
120.60220777988434,
31.26761108902796
],
[
120.6022185087204,
31.267634015270414
],
[
120.60223460197449,
31.267634015270414
],
[
120.6025242805481,
31.26763860051824
]
]
]
},
"properties": {
"height": 16,
"id": "2A5B2B17-6EF7-4343-A62F-894CFA9A1CDA",
"floor": 4,
"bottomHeight": 12
}
}
楼层标注数据
注意标注数据应该携带海拔值,海拔值一般是楼层的高度数据(即楼层顶部相对于地面的高度值)
json
{
"type": "Features",
"properties": {
"height": 16,
"id": "2A5B2B17-6EF7-4343-A62F-894CFA9A1CDA",
"floor": 4,
"bottomHeight": 12
},
"geometry": {
"type": "Point",
"coordinates": [
120.6025242805481,
31.26763860051824,
16
]
}
}
合并数据
为了更好的性能表现,我们把楼层数据和楼层标注数据合并到一个文件,尽可能的去减少图层数量
使用maptalks的矢量切片图层加载
准备样式
需要用到两个渲染插件
lit
渲染楼层text
渲染楼层文字标注
js
const style = [
{
name: 'building-floors',
filter: ["all",
["==", "$type", "Polygon"]
],
renderPlugin: {
type: "lit",
dataConfig: {
type: "3d-extrusion",
//楼层高度
altitudeProperty: "height",
//楼层离地高度
minHeightProperty: "bottomHeight",
altitudeScale: 1,
defaultAltitude: 10,
topThickness: 1,
// top: true,
side: true
},
sceneConfig: {}
},
symbol: {
polygonFill: {
property: 'floor',
type: 'interval',
stops: (function () {
let floor = 1;
const result = [];
while (floor < 100) {
if (floor % 2 === 0) {
result.push([floor, 'white']);
} else {
result.push([floor, '#0579D6'])
}
floor++;
}
return result;
})(),
default: '#fff'
},
polygonOpacity: 0.7,
material: {
baseColorFactor: [1, 1, 1, 1],
roughnessFactor: 1,
metallicFactor: 1
}
}
},
{
name: 'building-floors-label',
filter: [
"all",
["==", "$type", "Point"],
],
renderPlugin: {
dataConfig: {
type: "point",
},
sceneConfig: {
//开启碰撞检测
collision: true,
fading: true,
depthFunc: 'always'
},
type: "text",
},
symbol: {
textFaceName: "Microsoft YaHei,sans-serif",
textFill: [0, 0, 0, 1],
textHaloFill: [1, 1, 1, 1],
textHaloOpacity: 1,
textHaloRadius: 1,
textName: "{floor}楼",
textSize: 12,
textDy: -10
},
}
];
TIP
每个样式的item请给它起个名字,方便后续样式的更新,比如上面的
js
name: 'building-floors',
...
name: 'building-floors-label',
每个样式的名字要做到唯一性,不可重复
- 关于这两个插件的详细文档请参阅 样式手册
- 关于楼层配色我使用了function-type,只是简单的根据楼层的奇偶做了简单的配色,自己的业务里请根据自己的需要配色
js
polygonFill: {
property: 'floor',
type: 'interval',
stops: (function () {
let floor = 1;
const result = [];
while (floor < 100) {
if (floor % 2 === 0) {
result.push([floor, 'white']);
} else {
result.push([floor, '#0579D6'])
}
floor++;
}
return result;
})(),
default: '#fff'
},
创建图层加载数据
因为我这里只是简单的用GeoJSON
数据来测试的,所以使用了GeoJSONVectorTileLayer
图层,如果你的数据是切片服务(静态服务,GeoServer服务,PostGIS服务等)请使用VectorTileLayer
图层
js
const layer = new maptalks.GeoJSONVectorTileLayer("geo", {
data: "./../assets/data/floors.geojson",
style,
});
// GroupGLLayer能实现抗锯齿等后处理,也能加入其他三维图层,让子图层都融合到同一个三维空间中
const sceneConfig = {
postProcess: {
enable: true,
antialias: { enable: true }
}
};
const groupLayer = new maptalks.GroupGLLayer('group', [layer], { sceneConfig });
groupLayer.addTo(map);
- GeoJSONVectorTileLayer是 VectorTileLaye 子类,他们的用户几乎一样,只是GeoJSONVectorTileLayer的数据源是
GeoJSON
,而VectorTileLaye的数据源是 切片服务
注意事项
- GeoJSONVectorTileLayer是在前端对GeoJSON文件进行自动切片,所以不适合数据体积比较大的GeoJSON
- GeoJSON比较大时解决方法:
- 应该将GeoJSON切成静态的MVT数据放到服务端
- 或者把GeoJSON文件导入数据库有数据库提供MVT服务
- 或者利用GeoServer等GIS容器发布成MVT服务
然后用VectorTileLayer去加载服务
- GeoJSONVectorTileLayer图层不宜过多,即使每个GeoJSON文件不大,当GeoJSONVectorTileLayer过多时:
- 因为图层太多,导致浏览器有大面积的切片服务,即使放到worker里也会导致大面积的worker数据通信,因此性能极差
可以把多个GeoJSON文件合并成一个文件,然后再GeoJSONVectorTileLayer的样式系统里用filter
进行数据分类和进行分类配置样式
- 关于合并GeoJSON
- 可以在前端请求这些GeoJSON文件,然后将他们合并成一个
- 或者用工具或者自己写个脚本将其合并成一个文件放到前端的项目里的静态目录
- 具体的可以参考这个geojson 合并的例子