从一个点到一张图:Leaflet 加载水利对象 GeoJSON 实战
TL;DR :几十上百个水库、堤防、水闸怎么批量上图?一份 GeoJSON(点线面 + properties)+
L.geoJSON三个回调搞定,还能按类型自动换样式、做图层开关。
水利对象在 GeoJSON 里长什么样
水利一张图管的对象正好对应 GeoJSON 三种几何:点 (水库、水闸、测站)、线 (河流、堤防)、面 (蓄滞洪区、管理范围)。业务档案放在 properties 里:
water-features.geojson
json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [114.148, 22.584] },
"properties": { "name": "深圳水库", "type": "reservoir", "capacity": 46 }
},
{
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [[114.045, 22.528], [114.062, 22.522], [114.078, 22.515]]
},
"properties": { "name": "深圳河", "type": "river" }
}
]
}
⚠️ 坐标顺序 :GeoJSON 标准规定坐标是
[经度, 纬度],而 Leaflet 全用[纬度, 经度]。这个方向问题最容易踩。
三行渲染:按类型自动换样式
把数据交给 L.geoJSON,三个回调解决三件事:style 决定怎么画线面,pointToLayer 决定点怎么画,onEachFeature 决定弹什么:
javascript
L.geoJSON(waterFeatures, {
// 线/面:按对象类型上色
style: (f) => {
if (f.properties.type === 'river')
return { color: '#1976d2', weight: 3 }
if (f.properties.type === 'embank')
return { color: '#b45309', weight: 2, dashArray: '4' }
},
// 点:水库/水闸画成蓝色圆点
pointToLayer: (f, latlng) => L.circleMarker(latlng, {
radius: 6, color: '#1976d2',
fillColor: '#42a5f5', fillOpacity: 0.8
}),
// 每个对象挂业务弹窗
onEachFeature: (f, layer) => {
const p = f.properties
layer.bindPopup(`<b>${p.name}</b><br>类型:${p.type}`)
}
}).addTo(map)
真实项目里数据是接口吐的,前面加个 fetch 就是完整流程:数据底板服务返回 GeoJSON → 前端渲染 → 业务弹窗。
一张图标配:对象分组、图层开关
业务人员经常要「只看水库、藏掉河流」。把不同类型丢进不同图层组,交给右上角图层面板:
javascript
// 按类型建两个图层组
const reservoirLayer = L.layerGroup()
const riverLayer = L.layerGroup().addTo(map)
// filter 按 properties.type 分流
L.geoJSON(waterFeatures, {
filter: (f) => f.properties.type === 'reservoir'
}).addTo(reservoirLayer)
// 右上角图层面板
L.control.layers(null, {
'水库 / 水闸': reservoirLayer,
'河流 / 堤防': riverLayer
}).addTo(map)

⚠️ 三个坑
1. GeoJSON 坐标是 经度, 纬度,Leaflet 要 纬度, 经度。 标准规定,不是 Leaflet 的锅。前端自己拼 GeoJSON 时最容易写反。
2. properties 里别塞监测时序数据。 GeoJSON 只放对象档案(名称、类型、库容);实时水位、雨量这种高频变化数据,点弹窗时再单独请求接口,否则一个 GeoJSON 文件几十 MB,首屏卡死。
3. Polygon 首尾坐标要闭合。 蓄滞洪区这类面状要素,最后一个点要和第一个点相同。Leaflet 会帮你补,但其他服务端工具不一定。
小结
| 回调 | 作用 |
|---|---|
style |
线/面按类型上色 |
pointToLayer |
点用 circleMarker 而非默认图钉 |
onEachFeature |
挂业务弹窗 |
filter |
分流到不同图层组 |
L.control.layers |
右上角开关面板 |
📦 本文是《智慧水利 GIS 实战》系列第 3 篇,完整代码见仓库
leafletjs-demo/。