资讯动态

GeoJSON快速入门:从数据结构到Web地图渲染与格式转换

发布时间:2026/9/30 21:21:25 来源:尧图企业网站定制
先聊点实在的。我最早接触GeoJSON是被一个项目逼的后端给了个KML文件要我在网页地图上画出来前端地图库读KML又慢又别扭最后绕了一圈把所有数据统一转成GeoJSON问题一下解决了。从那以后凡是涉及地理数据的传输、展示、交换我第一个想到的就是它。这篇GeoJSON快速入门教程就是把我这几年用这个格式总结下来的要点、工具、坑位一次说清楚。不管你是前端开发、GIS初学者还是手头有一批带坐标的数据想画成地图这篇文章都适用而且我会尽量讲得直白不整太多虚的。1. 先搞懂GeoJSON是干什么的再动手学1.1 它解决的是什么样的“格式沟通”问题很多人第一次听到GeoJSON会以为它是一个软件或者某个库。其实不是它就是一个基于JSON的地理空间数据交换格式2016年8月成了RFC 7946标准。你可以把它理解成地理信息领域的“通用话术”大家语言不同、系统不同、数据库不同但只要都按这个格式说话就能互相听懂。举个例子。你在数据库里存了一堆门店地址每个店有名字、经纬度、营业时间。要想在网页上把这些门店标出来传统方案是把数据导成表格再写代码逐行解析要是数据来源是个旧的GIS系统导出来是Shapefile前端根本没法直接用。GeoJSON的方案是统一包一层把经纬度坐标和业务属性放在同一个JSON文件里前端拿到之后直接解析渲染后端也能直接读写接口传参。它天然继承了JSON的优点纯文本、结构清晰、任何语言都能解析而且体积比Shapefile那种二进制格式更容易在Web场景下传输。所以它核心解决的是多系统之间地理数据的标准化传递问题。你不需要关心数据原本存在Oracle Spatial还是PostGIS也不需要关心对方用的是QGIS还是ArcGIS只要导出成GeoJSON剩下的事就是读取和展示了。1.2 一张图看懂三层核心结构GeoJSON的数据结构看起来有一堆嵌套但拆开看其实只有三个层级想清楚这三个概念后面的内容就顺了。第一层叫Geometry几何对象它只描述“形状在哪”不带任何业务含义。比如一个Point对象里面就一个coordinates数组告诉你某个点的经纬度。它就像一个没有名字、没有任何背景的坐标点。第二层叫Feature要素它把一个几何对象和一个属性表绑在一起。结构上分成两个字段geometry存形状properties存属性。比如一个Feature可以是“西湖边某个公园入口”geometry是那个入口的坐标properties里可以写name、type、open_time等等想带多少字段就带多少。第三层叫FeatureCollection要素集合它就是把一堆Feature打包成一个数组。传输的时候通常用这一层作为最外层一个文件里装几百个点、几千条线都没问题。我用一个生活化类比帮你记Geometry是一块“积木”Feature是“贴了标签的积木”FeatureCollection就是“一盒贴好标签、可以直接交货的积木套装”。前端拿到这盒积木拆开就能拼。{ type: FeatureCollection, features: [ { type: Feature, properties: { name: 示例点 }, geometry: { type: Point, coordinates: [120.1521, 30.2587] } } ] }1.3 六种Geometry类型先知道它们长什么样GeoJSON一共定义了六种几何类型绝大多数使用场景都覆盖了。我先快速列一遍有个印象就行后面实操会反复用到。Point点单个坐标点coordinates是一个二元数组比如[120.15, 30.26]。MultiPoint多点多个点的集合coordinates是点的数组。LineString线一串有序坐标连成的线比如一条骑行路线coordinates是坐标数组。MultiLineString多线多条线的集合。Polygon面由闭合环围成的区域coordinates是“环的数组”每个环又是坐标数组。第一个环是外边界后面的环是“洞”。MultiPolygon多面多个面的集合。还有一个GeometryCollection几何集合允许在同一个geometry里混合多种形状比如一片区域里既有面又有线。实际用得相对少但要知道它存在。这一串类型不需要死记你只需要记住Point、LineString、Polygon是老三样Multi前缀就是“多个”Polygon由闭合环构成。后面写文件的时候你还得注意一个细节——Polygon是数组套数组的结构因为每个多边形可能带洞。这个坑很多人第一次写都会踩我会在第2部分详细说。2. 亲手写一个GeoJSON文件并找到趁手的打开工具2.1 从最简单的点要素开始手写学习这个方法最直接的办法就是打开文本编辑器手写一个文件。不用怕写错JSON格式本来就是给人看的写错了马上就能看出来。打开任意编辑器新建一个文件保存为first.geojson。注意两个点第一文件编码必须是UTF-8否则中文属性名会乱码第二GeoJSON本身就是JSON所以不允许写注释。写一个点要素{ type: Feature, properties: { name: 示例公园入口, category: park }, geometry: { type: Point, coordinates: [120.1521, 30.2587] } }这个文件就表达了一个意思有一个公园入口位置在经度120.1521、纬度30.2587。这里我要特意强调一个非常关键的细节GeoJSON的坐标顺序是“经度在前纬度在后”也就是[longitude, latitude]不是我们口语中常说的“纬度经度”。为什么要这样定因为地理学上习惯用(x, y)表达平面位置x对应经度y对应纬度和数学坐标系保持一致。这个顺序是RFC 7946标准里明确定死的。我第一次写的时候就习惯性写成了[30.2587, 120.1521]结果点位直接跑到了非洲附近排查了半天才发现是坐标顺序反了。写完这个文件之后你可以在浏览器地址栏里输入file:///你的路径/first.geojson但浏览器大概率会直接把它当文本显示因为浏览器不内置GeoJSON渲染器。想要看到实际效果得靠下面的工具。2.2 线和面怎么写闭合环与内洞搞定点之后再写一个线要素和面要素这一节的难点集中在Polygon上。线要素就是LineStringcoordinates是坐标点的数组每个点按顺序连接成一条线{ type: Feature, properties: { name: 示例骑行路线 }, geometry: { type: LineString, coordinates: [ [120.1485, 30.2550], [120.1560, 30.2585], [120.1680, 30.2610] ] } }面要素就要多啰嗦两句。Polygon的coordinates是一个三维数组第一层是一个数组里面放了若干个环每个环又是一个坐标数组。第一个环是外边界后面的环是内环也就是“洞”。而且每个环都必须闭合——首尾两个坐标必须完全相等这样才形成一个封闭区域。一个简单矩形面{ type: Feature, properties: { name: 示例绿地 }, geometry: { type: Polygon, coordinates: [ [ [120.1200, 30.2700], [120.1300, 30.2700], [120.1300, 30.2800], [120.1200, 30.2800], [120.1200, 30.2700] ] ] } }看到最后一个点和第一个点一样了吗这个闭合是硬性要求。如果你画了一个不闭合的Polygon严格来说它不符合规范很多渲染引擎会画出奇怪的形状或直接不渲染。如果要带一个“洞”就在外环后面再塞一个环coordinates: [ [ [120.1200, 30.2700], [120.1300, 30.2700], [120.1300, 30.2800], [120.1200, 30.2800], [120.1200, 30.2700] ], [ [120.1230, 30.2730], [120.1230, 30.2750], [120.1250, 30.2750], [120.1250, 30.2730], [120.1230, 30.2730] ] ]这个结构相当于一个绿地里挖了一个小池塘。注意“洞”的环也必须闭合而且“洞”必须完全落在“外环”内部否则就是一个非法多边形。关于环的方向顺时针还是逆时针RFC 7946里建议外环逆时针、内环顺时针但很多渲染工具并不严格校验。不过为了兼容性建议你按规范来写避免在某些严格的引擎上出错。2.3 用在线工具画图、校验一条龙手写文件适合理解结构但真正干活的时候没人愿意手动敲几千个坐标。这里推荐两个在线工具是我每次调试GeoJSON都会用的第一个是geojson.io。这个网站相当于一个小型在线地图编辑器左边是地图右边是GeoJSON源码。你可以在左边的地图上直接点一下画一个点点几下画一条线或者用绘图工具拉一个面。每次操作右边的代码会实时更新反过来你在右边粘贴一段GeoJSON左边也会立刻显示图形。它还支持直接拖入本地文件打开编辑完可以导出成GeoJSON或CSV。做数据调试、快速预览用它最省事。第二个是geojsonlint.com。这个网站专门做格式校验。你把GeoJSON贴进去它会告诉你格式对不对、哪里不符合RFC标准。很多时候你看代码半天看不出问题往这上面一贴错误行号直接标出来。我常用的工作流是先在geojson.io里手工画草稿导出文件再在geojsonlint里检查一遍没问题之后再丢给前端或后端使用。这个流程基本能过滤掉90%的低级格式错误。2.4 GeoJSON用什么软件打开工具清单“geojson用什么软件打开”是我经常被问到的问题。GeoJSON是纯文本格式理论上记事本就能“打开”但你大概率想看的是图形化展示。我把常用的几类工具整理成一张表工具/平台类型适合场景操作说明geojson.io在线工具快速预览、临摹画图打开网页拖入.geojson文件即可显示QGIS桌面GIS软件复杂地理分析、图层叠加菜单Layer - Add Layer - Add Vector Layer选择GeoJSON文件Kepler.gl在线可视化工具大规模数据点、轨迹可视化打开官网Upload Data选择文件支持上千个点流畅渲染Mapshaper在线工具数据简化、格式转换直接把文件拖进浏览器可以查看和简化坐标Leaflet 自定义JS前端开发嵌入自己网页的地图用L.geoJSON()方法加载后面第3部分细讲Tableau / Power BI商业智能工具业务分析场景结合地图连接数据时选择GeoJSON或把坐标字段放入地图维度如果你只是想“看一眼文件长什么样”直接双击用默认文本编辑器打开也行代码会以纯文本形式展示。但想看到地图效果、叠加底图我还是推荐geojson.io因为它不需要安装任何东西浏览器一开就能用而且对新手最友好。3. 把GeoJSON用起来前端渲染、格式转换与数据入库3.1 用Leaflet 10行代码把数据画上地图GeoJSON最大的优势在于Web端——JSON是JavaScript的原生格式前端拿到数据几乎不需要二次转换。这里我用Leaflet做demo因为它体积小、上手快全世界的开发者在网上留下过大量示例。先搭一个最简页面引入Leaflet的CSS和JS!DOCTYPE html html head meta charsetutf-8 / link relstylesheet hrefhttps://unpkg.com/leaflet1.9.4/dist/leaflet.css / script srchttps://unpkg.com/leaflet1.9.4/dist/leaflet.js/script /head body div idmap styleheight: 600px;/div /body /html然后写JavaScript创建地图并加载GeoJSONconst map L.map(map).setView([30.25, 120.15], 12); L.tileLayer(https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png, { attribution: © OpenStreetMap contributors }).addTo(map); fetch(first.geojson) .then(response response.json()) .then(data { L.geoJSON(data).addTo(map); });这段代码干了几件事创建地图实例加载一份OpenStreetMap的瓦片底图然后通过网络请求读取GeoJSON文件最后用L.geoJSON(data)把文件里所有要素画到地图上。整个过程不需要写任何循环因为Leaflet已经处理了FeatureCollection的遍历和渲染。如果你不想折腾本地服务器也可以直接把GeoJSON变量写在页面里const geoJsonData { type: Feature, properties: { name: 示例点 }, geometry: { type: Point, coordinates: [120.1521, 30.2587] } }; L.geoJSON(geoJsonData).addTo(map);3.2 按属性渲染样式让地图会说话把点画上地图只是第一步实际项目中你常常希望“不同属性的点显示不同颜色”。比如公园显示绿色、学校显示蓝色或者按人流量从高到低用红黄绿渐变区分。Leaflet的L.geoJSON()支持传入一个options对象在style函数里针对每个Feature动态返回样式在onEachFeature里给每个要素绑定事件或弹窗L.geoJSON(data, { pointToLayer: function (feature, latlng) { return L.circleMarker(latlng, { radius: 8, fillOpacity: 0.8 }); }, style: function (feature) { const category feature.properties.category; return { color: category park ? #2ecc71 : #3498db, fillColor: category park ? #2ecc71 : #3498db, weight: 1 }; }, onEachFeature: function (feature, layer) { layer.bindPopup( 名称 feature.properties.name br类别 feature.properties.category ); } }).addTo(map);这段代码的pointToLayer把点要素渲染成圆点而不是默认的图标style根据properties里的category字段切换颜色onEachFeature给每个要素绑定了点击弹窗。这里的关键思路是GeoJSON里的properties就是你的业务数据它的自由度决定了地图图层能表达多丰富的信息。所以你在设计GeoJSON文件时不要吝啬属性字段尽量把展示需要用到的信息都放到properties里。需要提醒一个细节不同渲染引擎对样式的字段名要求不同。Leaflet用的是color、weight、fillColor这一套Mapbox GL则用line-color、line-width、fill-color。如果你在Mapbox里用了Leaflet的字段名样式会不生效。通用做法是——先查对应引擎的文档或者用feature-state这类机制动态设置。3.3 从Shapefile转GeoJSONogr2ogr与Docker环境现实工作里很多坐标数据不是在GeoJSON里而是在Shapefile、KML、GPX甚至CSV里。转换最常用的工具是GDAL全家桶里的ogr2ogr命令行它是社区公认的地理数据格式转换瑞士军刀。基本转换命令非常简单ogr2ogr -f GeoJSON output.geojson input.shp这条命令会把input.shp转成output.geojson。如果你有一个CSV文件里面有经度、纬度两列也可以这样操作ogr2ogr -f GeoJSON output.geojson input.csv -oo X_POSSIBLE_NAMESlng -oo Y_POSSIBLE_NAMESlat-oo X_POSSIBLE_NAMES和-oo Y_POSSIBLE_NAMES指定CSV哪一列是经度、哪一列是纬度。不过GDAL的安装有时比较折腾不同系统依赖不同。这里有个偷懒方案用Docker拉一个gdal镜像直接跑容器命令本地连安装都省了。docker pull ghcr.io/osgeo/gdal:latest docker run --rm -v $(pwd):/data ghcr.io/osgeo/gdal:latest ogr2ogr -f GeoJSON /data/output.geojson /data/input.shp-v $(pwd):/data把当前目录挂载进容器这样容器里就能访问到本地的input.shp了。这个方法对Windows、macOS、Linux通用而且环境始终保持一致不会出现“我电脑上能跑你电脑上报错”的问题。还有一个更轻量的替代方案QGIS桌面软件自带“导出图层为GeoJSON”的功能如果你习惯了图形界面鼠标点几下就能完成转换不需要碰命令行。我一般是这样分工的批量转换、自动化脚本用ogr2ogr临时单文件转换就直接在QGIS里导出。3.4 用DuckDB和Python读GeoJSON做分析GeoJSON不仅是拿来“看”的也可以拿来“算”。当你的GeoJSON文件有成百上千个要素时用代码做统计、按属性筛选、算范围覆盖之类的操作就变得很有必要。先说说最近热度很高的DuckDB。它本身是一个轻量级分析型数据库安装简单单文件运行而且官方提供了spatial扩展可以直接读取GeoJSON文件把它当普通表查询。这也是DuckDB入门教程里常常出现GeoJSON的原因——数据分析师终于不用先把坐标数据导入PostGIS再跑SQL了。INSTALL spatial; LOAD spatial; SELECT properties.name, ST_NPoints(geometry) AS point_count FROM ST_Read(first.geojson);这段SQL里ST_Read函数直接读取GeoJSON文件返回一个关系表properties.name可以直接作为列名访问ST_NPoints是计算一个几何对象包含多少个点的空间函数。你还可以在SQL里写WHERE properties.category park筛选公园或者用ST_Area计算面积。DuckDB这类分析数据库的好处是你不用写复杂的解析代码SQL就能把文件里的各种信息榨出来对数据分析场景特别友好。如果你更习惯Python生态直接用GeoPandas读文件然后就是一个DataFrame后续处理怎么顺手怎么来import geopandas as gpd gdf gpd.read_file(first.geojson) print(gdf.head()) print(gdf.crs)GeoPandas会返回一个GeoDataFrame每一行是一个Featuregeometry列存的是几何对象其他列是properties里的属性。你可以用gdf[gdf[category] park]做筛选也可以调用gdf.plot()直接出一个静态地图图。实测下来几千个点的GeoJSON文件在Python里做分析基本无压力计算和筛选都是毫秒级。顺带一提在阿里DataV这类可视化平台做数据接入时GeoJSON也是前端传递地理数据的常用格式它会配合组件读取GeoJSON里的properties和coordinates来渲染地图图层。本质上和前端Leaflet的思路一致数据结构约定好了剩下的就是各取所需。4. 避坑手册我踩过的GeoJSON常见问题4.1 坐标顺序反了点位跑到海里这是新手最高频的问题也是我自己摔得最惨的一次。现象是明明数据看起来没问题画到地图上点位却跑到了完全不对的地方比如一个北京的坐标画出来跑到了非洲西海岸。根因就是经纬度顺序写反了。GeoJSON要求[经度, 纬度]但很多数据源、接口、表格里存储的顺序可能是[纬度, 经度]。尤其某些从国内数据源拿到的数据习惯用“纬度,经度”记录你没留意就直接丢进GeoJSON结果自然全乱。排查方法很简单看坐标数值区间。经度有效范围是-180到180纬度是-90到90。如果看到一个坐标是[39.9, 116.4]那基本可以断定是反的因为39.9明显是北京的纬度116.4是经度。写成[116.4, 39.9]才对。如果你用Python处理这类数据可以写个判断自动纠正def fix_lng_lat(coord): lng, lat coord if -90 lng 90 and -180 lat 180: return [lat, lng] return [lng, lat]4.2 坐标系不统一偏移几百米另一个频繁踩坑的问题是“偏移”。你拿到的坐标明明很准确画到网页地图上却偏了几百米。大多数情况下是坐标系基准不一致导致的。制图过程中常见的坐标系包括WGS84以及用于国内地图服务商加密坐标体系等。不同体系的坐标差异在小范围看是几百米的平移偏差视觉上非常明显。底层原因我并不展开讲你只需要记住一个实操经验先确认你的数据源和底图到底属于哪个坐标系。比如你在数据文件里标注的是WGS84经纬度但底图用的是加密坐标点位就会偏移。反过来也一样。处理方法有两个一种是在数据源头转换坐标系输出统一基准的坐标另一种是数据文件不动在渲染代码里调用坐标纠偏工具把坐标转换后再画到地图上。这类工具在Python生态里很好找前端也有现成实现。但有个原则同一份GeoJSON文件里所有坐标的坐标系必须一致绝不混用否则你画出来的图一定乱成一团。4.3 多边形画出来一团乱多边形渲染出现乱象一般是下面几个原因第一环没有闭合。前面说过外环和内环都要首尾坐标相同。如果漏了最后一个重复点不同渲染引擎的处理方式不一样有的会帮你补上有的会画一条隐形的边看起来形状就怪了。第二多个多边形的首尾顺序错了。Polygon的coordinates第一层是多边形列表如果你需要表示两个不相邻的独立区域应该用MultiPolygon而不是一个Polygon里塞两个外环。一个Polygon里如果有两个外环引擎会默认后一个环是“洞”结果就是你本来要画两块地显示出来变成一块地上挖了块洞。第三环自相交。自相交在多边形里非常隐蔽坐标看着没问题但两条边交叉了填充区域会出现不规则的“蝴蝶结”形状。修正常用工具是Mapshaper把GeoJSON拖进去以后控制台执行fix相关命令可以自动修复部分拓扑错误。最关键的还是验证先把多边形贴到geojsonlint这类工具里检查再渲染。不要等到前端画出来才发现问题那个排查成本就高了。4.4 文件太大加载卡成PPTGeoJSON是纯文本坐标一多体积就膨胀。一个包含几万个点的FeatureCollection文件动辄几十MB前端加载后地图拖拽会明显卡顿。解决办法有三个方向。第一是简化坐标。对于线面数据用Douglas-Peucker这类算法抽稀减少坐标点数量肉眼几乎看不出差别。Mapshaper里simplify功能就是干这个的拖进去调一下百分比就能导出精简版。第二是换格式。如果数据量确实大可以把GeoJSON转成TopoJSON后者利用弧线共享可以大幅压缩体积尤其是大量相邻多边形的情况体积能缩小一半以上。第三是分块加载。不要一次性把整个文件丢给前端而是按瓦片或按区域动态请求配合后端做裁剪。实际项目中我会先用规则判断数据量少于1万个点用完整GeoJSON10万以上点就必须考虑服务端分片或改用矢量瓦片方案。4.5 常见问题速查表问题现象可能原因快速解决办法点位置偏到另一个大洲经纬度顺序写反检查数值范围确保经度在前点位整体偏移几百米坐标系基准不一致统一数据与底图的坐标系必要时做坐标转换多边形显示成有洞或乱块环未闭合、自相交、独立区域错误放入同一Polygon用geojsonlint/Mapshaper校验修复独立区域改用MultiPolygon文件大、加载卡坐标点过多、无简化用Mapshaper简化或转TopoJSON或做分片加载中文属性乱码文件编码不是UTF-8保存时指定UTF-8可用geojson.io重新保存前端样式不生效使用了错误的样式字段名查询对应渲染引擎的样式规范按字段名填写我个人在实际操作中的体会是GeoJSON这个格式最大的价值不是某个工具而是把地理数据拉到了一个“任何开发者都能轻松操作”的层面。你不需要成为GIS专家也能在网页上做出一张还不错的交互地图。学习路线其实很简单先从手写一个点开始然后用geojson.io画图再跑通Leaflet渲染最后掌握ogr2ogr做转换四步走完基本就入门了。最后再分享一个小技巧开发调试阶段尽量用本地小文件不要一上来就接全量数据把数据简化到能复现问题的程度排查会快很多。等你把整个链路跑顺了再上全量数据也不迟。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑