03-从一个点到一张图:Leaflet 加载水利对象 GeoJSON 实战

108 阅读2分钟

从一个点到一张图:Leaflet 加载水利对象 GeoJSON 实战

TL;DR:几十上百个水库、堤防、水闸怎么批量上图?一份 GeoJSON(点线面 + properties)+ L.geoJSON 三个回调搞定,还能按类型自动换样式、做图层开关。


水利对象在 GeoJSON 里长什么样

水利一张图管的对象正好对应 GeoJSON 三种几何:点(水库、水闸、测站)、线(河流、堤防)、面(蓄滞洪区、管理范围)。业务档案放在 properties 里:

water-features.geojson

{
  "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 决定弹什么:

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 → 前端渲染 → 业务弹窗。


一张图标配:对象分组、图层开关

业务人员经常要「只看水库、藏掉河流」。把不同类型丢进不同图层组,交给右上角图层面板:

// 按类型建两个图层组
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)

water-leaflet-03-demo.png


⚠️ 三个坑

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/。