WebGIS开发入门教程四: GeoJSON咋读?数据怎么解析?

GIS基础理论
Dr.GIS
wowwwai GIS研习社 · 工具流程与项目排障

WebGIS开发入门教程四: GeoJSON咋读?数据怎么解析?这篇文章里,我们专门解决一个入门阶段最常见的问题:拿到一个 GeoJSON 文件以后,前端到底应该怎么读、怎么解析、怎么把里面的点线面数据变成地图上的要素。

引言:为什么 WebGIS 新手一定要先看懂 GeoJSON

很多同学学习 WebGIS 时,会先接触 Leaflet、OpenLayers 或 Mapbox GL JS。地图底图能加载出来以后,下一步通常就是加载自己的业务数据,比如门店点位、行政区边界、河流线、巡检轨迹等。

这些数据最常见的交换格式之一就是 GeoJSON。它本质上是 JSON,但按照 GIS 的规则组织了空间几何和属性信息。只要你能读懂 GeoJSON,就能理解 WebGIS 中“数据从哪里来、坐标在哪里、属性怎么取、地图怎么画”的基本链路。

本文会围绕 WebGIS GeoJSON解析 这个具体任务,讲清楚 GeoJSON 的结构、点线面数据的读取方法、前端解析流程,以及常见错误的排查方式。

WebGIS GeoJSON解析与GeoJSON数据读取流程示意图
GeoJSON 在 WebGIS 中通常经历“读取文件、解析 JSON、识别几何、读取属性、渲染图层”几个步骤。

背景:GeoJSON 在 WebGIS 里到底负责什么

在 WebGIS 项目中,地图通常由两类内容组成:

  • 底图:例如天地图、OpenStreetMap、ArcGIS Online、Mapbox、XYZ 瓦片等。
  • 业务图层:例如地块边界、监测点、道路中心线、行政区、网格单元等。

GeoJSON 主要用来承载业务图层。它既能保存空间位置,也能保存属性字段。例如一个监测站点,不仅有经纬度坐标,还可以有站点名称、编号、监测类型、所属区域等属性。

一个典型的 GeoJSON 数据通常长这样:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [116.391, 39.907]
      },
      "properties": {
        "name": "示例点位",
        "type": "监测站"
      }
    }
  ]
}

对 WebGIS 开发来说,你最需要关注三个关键词:

  • FeatureCollection:要素集合,表示一组空间要素。
  • geometry:几何对象,保存点、线、面的坐标。
  • properties:属性对象,保存业务字段。

原理:GeoJSON 的核心结构怎么读

理解 GeoJSON数据读取,不要一上来就背规范。先记住一句话:GeoJSON 是用 JSON 表达 GIS 要素的数据格式。

1. type 字段说明当前对象是什么

GeoJSON 中大量使用 type 字段。不同位置的 type 含义不同:

位置 常见值 含义
根对象 FeatureCollection 一组要素集合
单个要素 Feature 一个带几何和属性的 GIS 要素
geometry Point、LineString、Polygon 具体几何类型

2. geometry 保存空间坐标

geometry 是 GeoJSON 中最关键的空间部分。不同几何类型的 coordinates 层级不一样:

几何类型 coordinates 示例 说明
Point [116.391, 39.907] 一个点,通常为 [经度, 纬度]
LineString [[116.1,39.1],[116.2,39.2]] 一串坐标组成一条线
Polygon [[[116.1,39.1],[116.2,39.1],[116.2,39.2],[116.1,39.1]]] 一个或多个闭合环组成面

这里有一个非常重要的细节:GeoJSON 标准坐标顺序通常是 [longitude, latitude],也就是 [经度, 纬度],不是很多地图 API 中常见的 [纬度, 经度]

3. properties 保存业务属性

properties 中的内容不参与几何绘制,但它决定了你在弹窗、样式分类、筛选查询中能使用哪些字段。

{
  "properties": {
    "name": "朝阳区",
    "adcode": "110105",
    "level": "district"
  }
}

例如你可以根据 level 字段设置不同颜色,也可以把 name 字段显示到点击弹窗里。

步骤:前端如何读取并解析 GeoJSON 数据

下面用一个最常见的前端流程说明 WebGIS GeoJSON解析 的基本做法。这里先不绑定具体框架,重点看数据读取逻辑。

步骤一:准备一个 GeoJSON 文件

假设项目中有一个文件:

/data/stations.geojson

文件内容如下:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [116.391, 39.907]
      },
      "properties": {
        "name": "北京示例站",
        "status": "正常"
      }
    }
  ]
}

步骤二:用 fetch 读取 GeoJSON

在浏览器端,可以用 fetch 读取本地或服务器上的 GeoJSON 文件:

fetch('/data/stations.geojson')
  .then(response => response.json())
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('GeoJSON 读取失败:', error);
  });

这一步做了两件事:

  • 通过 URL 请求 GeoJSON 文件。
  • 使用 response.json() 把文本解析成 JavaScript 对象。

步骤三:遍历 features 数组

多数业务 GeoJSON 都是 FeatureCollection,真正的数据在 features 数组里:

fetch('/data/stations.geojson')
  .then(response => response.json())
  .then(data => {
    data.features.forEach(feature => {
      const geometry = feature.geometry;
      const properties = feature.properties;

      console.log('几何类型:', geometry.type);
      console.log('坐标:', geometry.coordinates);
      console.log('名称:', properties.name);
    });
  });

这就是最基础的 GeoJSON数据读取:先拿到要素集合,再逐个读取 geometry 和 properties。

步骤四:判断点线面类型

实际项目中,一个 GeoJSON 可能包含不同类型的数据。你需要根据 geometry.type 做不同处理:

function parseFeature(feature) {
  const geometry = feature.geometry;
  const properties = feature.properties || {};

  if (!geometry) {
    console.warn('缺少 geometry:', feature);
    return;
  }

  switch (geometry.type) {
    case 'Point':
      parsePoint(geometry.coordinates, properties);
      break;

    case 'LineString':
      parseLineString(geometry.coordinates, properties);
      break;

    case 'Polygon':
      parsePolygon(geometry.coordinates, properties);
      break;

    default:
      console.warn('暂未处理的几何类型:', geometry.type);
  }
}

步骤五:解析 Point 点数据

点数据的坐标最简单,通常是一个二维数组:

function parsePoint(coordinates, properties) {
  const lng = coordinates[0];
  const lat = coordinates[1];

  console.log('点位经度:', lng);
  console.log('点位纬度:', lat);
  console.log('点位名称:', properties.name);
}

如果你用 Leaflet,要注意 Leaflet 的 L.marker 接收的是 [lat, lng],所以需要调换顺序:

const lng = coordinates[0];
const lat = coordinates[1];

L.marker([lat, lng]).addTo(map);

这也是很多 GeoJSON坐标顺序 错误的来源。

步骤六:解析 LineString 线数据

线数据是一组点坐标:

function parseLineString(coordinates, properties) {
  const path = coordinates.map(coord => {
    const lng = coord[0];
    const lat = coord[1];
    return [lat, lng];
  });

  console.log('线名称:', properties.name);
  console.log('Leaflet 可用路径:', path);
}

如果用 Leaflet 绘制:

L.polyline(path, {
  color: 'blue',
  weight: 3
}).addTo(map);

如果用 OpenLayers,一般不需要你手动把坐标改成 [lat, lng],而是要关注数据投影和视图投影是否一致。

步骤七:解析 Polygon 面数据

面数据比点线更容易出错,因为它的坐标多了一层数组。一个 Polygon 通常由一个外环和若干内环组成:

function parsePolygon(coordinates, properties) {
  const rings = coordinates.map(ring => {
    return ring.map(coord => {
      const lng = coord[0];
      const lat = coord[1];
      return [lat, lng];
    });
  });

  console.log('面名称:', properties.name);
  console.log('面环坐标:', rings);
}

在 Leaflet 中绘制面:

L.polygon(rings, {
  color: 'red',
  weight: 2,
  fillColor: '#ff7800',
  fillOpacity: 0.4
}).addTo(map);

注意:Polygon 的第一个环通常是外边界,后面的环可能表示洞。如果面显示不正常,要检查坐标环是否闭合、坐标顺序是否正确、数据是否存在自相交。

步骤八:直接用 Leaflet 加载 GeoJSON

在入门项目中,最简单的方式是直接交给 Leaflet 的 L.geoJSON 处理:

fetch('/data/stations.geojson')
  .then(response => response.json())
  .then(data => {
    L.geoJSON(data, {
      onEachFeature: function(feature, layer) {
        const name = feature.properties.name || '未命名';
        layer.bindPopup(name);
      },
      pointToLayer: function(feature, latlng) {
        return L.circleMarker(latlng, {
          radius: 6,
          color: '#0066cc',
          fillColor: '#3399ff',
          fillOpacity: 0.8
        });
      }
    }).addTo(map);
  });

Leaflet 会自动理解 GeoJSON 的 [lng, lat] 坐标顺序,并转换成它内部需要的点位对象。因此,如果使用 L.geoJSON,通常不需要你手动调换坐标。

步骤九:用 OpenLayers 加载 GeoJSON

OpenLayers 中常用 ol/format/GeoJSON 读取 GeoJSON。关键是设置正确的数据投影和地图投影。

import GeoJSON from 'ol/format/GeoJSON';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';

const vectorSource = new VectorSource({
  url: '/data/stations.geojson',
  format: new GeoJSON({
    dataProjection: 'EPSG:4326',
    featureProjection: 'EPSG:3857'
  })
});

const vectorLayer = new VectorLayer({
  source: vectorSource
});

map.addLayer(vectorLayer);

这里的含义是:

  • dataProjection: 'EPSG:4326':GeoJSON 原始数据是经纬度坐标。
  • featureProjection: 'EPSG:3857':地图视图使用 Web Mercator 投影。

如果这两个参数写错,常见结果就是图层不显示、位置偏到海里、或者比例尺看起来异常。

常见坑:GeoJSON 解析为什么经常不显示

1. 把经纬度顺序写反

GeoJSON 标准坐标顺序是 [经度, 纬度]。例如北京附近应类似:

[116.391, 39.907]

如果写成:

[39.907, 116.391]

数据会跑到错误位置。做 GeoJSON坐标顺序 排查时,可以先看坐标范围:中国大陆经度大约在 73 到 135 之间,纬度大约在 18 到 54 之间。

2. 文件不是合法 JSON

GeoJSON 首先必须是合法 JSON。常见错误包括:

  • 属性名没有使用双引号。
  • 数组或对象最后多了逗号。
  • 字符串用了中文引号。
  • 复制数据时漏掉了括号。

浏览器控制台如果出现 Unexpected token,通常就是 JSON 语法问题。

3. FeatureCollection 拼写错误

GeoJSON 对字段值大小写敏感。下面这些写法都可能导致库无法识别:

  • featurecollection
  • Featurecollection
  • Feature Collection

正确写法是:

"type": "FeatureCollection"

4. Polygon 面没有闭合

Polygon 的线环一般要求首尾坐标一致:

[
  [116.1, 39.1],
  [116.2, 39.1],
  [116.2, 39.2],
  [116.1, 39.1]
]

如果首尾不闭合,部分工具可能会自动补齐,但也可能导致渲染异常或空间分析结果不可靠。

5. 坐标系和地图投影不一致

GeoJSON 常见坐标系是 WGS84,经纬度坐标,对应 EPSG:4326。而很多 Web 地图底图使用 Web Mercator,对应 EPSG:3857

如果使用 OpenLayers,需要明确告诉它原始数据投影和地图显示投影。如果使用 Leaflet 的 L.geoJSON,一般会按经纬度数据处理,但你的数据本身仍然要保证是正确的经纬度。

6. 本地文件直接打开导致请求失败

如果你直接双击打开 HTML 文件,浏览器地址可能是 file://。这时用 fetch('/data/test.geojson') 读取文件很容易失败。

更推荐的方式是启动一个本地开发服务,例如:

python -m http.server 8000

然后访问:

http://localhost:8000

方法比较:手动解析、Leaflet、OpenLayers 怎么选

方法 适合场景 优点 注意点
手动解析 GeoJSON 学习数据结构、做自定义处理 能真正理解 geometry 和 properties 需要自己处理点线面坐标层级
Leaflet L.geoJSON 轻量级 WebGIS 入门、点线面展示 代码少,上手快,适合教学和小项目 复杂投影和大数据量支持有限
OpenLayers GeoJSON 专业 WebGIS、投影转换、多图层管理 投影、样式、交互能力更强 API 学习成本比 Leaflet 高
后端预处理后再加载 大文件、复杂属性、需要过滤查询 前端压力小,性能更稳定 需要配合 PostGIS、GeoServer 或接口服务

如果你是 WebGIS 初学者,建议顺序是:先手动读懂 GeoJSON 结构,再用 Leaflet 快速展示,最后在需要复杂投影、编辑、空间交互时学习 OpenLayers。

检查清单:GeoJSON 数据解析前后应该检查什么

  • 确认根对象 type 是否为 FeatureCollection
  • 确认 features 是否是数组,并且数组不为空。
  • 确认每个要素是否包含 geometryproperties
  • 确认 geometry.type 是否为标准值,例如 Point、LineString、Polygon。
  • 确认坐标顺序是否为 [经度, 纬度]
  • 确认坐标范围是否符合数据所在地区。
  • 确认 Polygon 外环是否闭合。
  • 确认 GeoJSON 文件是否能被浏览器正常请求。
  • 确认控制台是否有 JSON 语法错误或跨域错误。
  • 确认地图视图范围是否移动到了数据所在区域。
  • 确认 OpenLayers 中 dataProjectionfeatureProjection 是否设置正确。
  • 确认属性字段名称是否和代码中读取的字段一致。

FAQ:GeoJSON 读取和解析常见问题

1. GeoJSON 和普通 JSON 有什么区别?

GeoJSON 是一种有空间数据规范的 JSON。普通 JSON 可以随意组织字段,而 GeoJSON 规定了 FeatureCollectionFeaturegeometrypropertiescoordinates 等结构,用来表达 GIS 点线面数据。

2. GeoJSON 坐标顺序到底是经纬度还是纬经度?

GeoJSON 标准通常使用 [经度, 纬度],也就是 [lng, lat]。但部分地图 API 的函数参数可能使用 [lat, lng]。所以做 WebGIS GeoJSON解析 时,要区分“GeoJSON 原始坐标顺序”和“地图 API 接收参数顺序”。

3. 为什么我的 GeoJSON 图层加载后地图上看不到?

常见原因有五类:文件请求失败、JSON 格式错误、坐标顺序写反、坐标系不匹配、地图没有缩放到数据范围。建议先打开浏览器控制台,看网络请求是否成功,再打印 GeoJSON 数据和坐标范围。

4. Leaflet 加载 GeoJSON 需要手动转换坐标吗?

如果使用 L.geoJSON(data),Leaflet 会按 GeoJSON 的 [lng, lat] 规则读取,一般不需要手动转换。只有当你自己用 L.markerL.polylineL.polygon 手动创建图层时,才需要注意 Leaflet 常用的 [lat, lng] 参数顺序。

5. OpenLayers 加载 GeoJSON 为什么经常位置不对?

OpenLayers 对投影更严格。很多 GeoJSON 是 EPSG:4326,而 Web 地图视图常用 EPSG:3857。如果没有正确设置 dataProjectionfeatureProjection,就可能出现位置偏移或图层不可见。

6. GeoJSON 适合加载很大的行政区边界数据吗?

小规模数据可以直接加载。若 GeoJSON 文件达到几十 MB,前端解析和渲染会明显变慢。此时建议做简化、切片、按范围请求,或者使用矢量瓦片、PostGIS 接口、GeoServer 服务等方案。

结论:读懂 GeoJSON,就是读懂 WebGIS 数据入口

GeoJSON 是 WebGIS 入门阶段最值得认真掌握的数据格式。它把空间几何放在 geometry 中,把业务信息放在 properties 中,再通过 FeatureCollection 组织成一组可渲染、可查询、可交互的地图要素。

实际开发时,不要只会复制 L.geoJSON 或 OpenLayers 示例代码。你至少要能判断点线面类型、看懂坐标数组层级、区分经纬度顺序、检查坐标系和投影问题。这样遇到 GeoJSON 不显示、位置错误、属性读不到时,才能快速定位原因。

对 WebGIS 初学者来说,推荐的练习路径是:先手动解析一个点 GeoJSON,再解析线和面,最后分别用 Leaflet 和 OpenLayers 加载同一份数据。完成这一步以后,你对 GeoJSON数据读取 和 WebGIS 图层渲染的理解会扎实很多。