下载的 GeoJSON 怎么离线预览?拖拽上传 + 本地校验三件套
从 geojsoncn.com 这类站点完成 GeoJSON下载之后,很多人第一步不是写代码,而是想先"看一眼"边界长什么样。开 ArcGIS 太重,装 QGIS 要点半天,直接拖进浏览器又经常报错。其实只要用原生的 Web API 加一个轻量地图库,再配合几行校验逻辑,就能凑出一个完全够用的本地 GeoJSON 预览工具,全程零后端、零依赖下载。
一、拖拽文件进来,先拿 File 对象
页面放一个 drop 区,监听 dragover 阻止默认行为,drop 里就能拿到 dataTransfer.files。这一步是零依赖的:
dropZone.addEventListener('dragover', e => e.preventDefault());
dropZone.addEventListener('drop', async e => {
e.preventDefault();
const file = e.dataTransfer.files[0];
if (!file) return;
const text = await file.text();
try {
const geojson = JSON.parse(text);
renderMap(geojson); // 交给 Leaflet 渲染
} catch (err) {
statusEl.textContent = '解析失败:' + err.message;
}
});
.text() 是 File 自带的,几 MB 的内存读没问题;真要碰几百 MB 的大文件,就要换回之前聊过的换行式流式解析,别一股脑 JSON.parse。做完 GeoJSON下载,这份代码贴到 里就能用,比开桌面端省太多事。
二、三个常见的"不是 JSON 的 geojson"
预览报解析错,八成不是文件坏了,而是格式不对。我踩过这三个坑:
| 情况 | 表现 | 处理 |
|---|---|---|
| 文件是 Shapefile 误装成 json | JSON.parse 直接 throw | 先识别扩展名,跳转到转 GeoJSON 工具 |
| JSON 顶层是 Feature(缺 features) | 解析成功但地图空白 | 单选时包一层 {type:'FeatureCollection',features:[geojson]} |
| 坐标是字符串 / 缺 coordinates | 解析成功但画不出面 | 用 schema 校验兜住,给出具体字段定位 |
前两种用 switch (geojson.type) 就能兜住:遇到单个 Feature 或 Geometry,自动包成集合。坐标被转成字符串的情况,最典型的是 Excel 把 CSV 转 json 时数字丢了原始性,这时候靠 turf.cleanCoords 也救不回,得从源头重导。
三、用 bbox 算视野,别让人工缩放
解析通过、图层挂上去之后,还得让视野自动框住整张图。Leaflet 里 map.fitBounds 吃一个 [[西南],[东北]],而 GeoJSON 自带的 bbox 恰好就是这个顺序(注意是两个对角点、不是四组经纬度):
const lyr = L.geoJSON(geojson, { style: { color: '#c0392b', weight: 1 } }).addTo(map);
if (Array.isArray(geojson.bbox) && geojson.bbox.length === 4) {
map.fitBounds([[geojson.bbox[1], geojson.bbox[0]], [geojson.bbox[3], geojson.bbox[2]]]);
}
没带 bbox 的也不用慌,L.geoJSON 对象自带的 getBounds() 会现算包络。唯一要注意的是坐标系——底图默认用 WGS84 经纬度,如果你这份数据是投影坐标(比如 CGCS2000 高斯平面),叠上去必然偏出天际,先回坐标系那套统一到 4326 再说。
四、离线也能用的底图方案
本地预览最尴尬的是底图。内网环境没外网,天地图瓦片拉不动怎么办?两个兜底:
1. 矢量图层画个浅色背景:把 GeoJSON 本身当唯一图层,fillColor:'#eef' 浅蓝底 + 描边,视觉上就是一张自足的地图,不需要任何瓦片。 2. 缓存常用瓦片:在线时把用过的瓦片 fetch 下来写进 Cache Storage,断网时优先命中本地缓存。
对 99% 的"看一眼边境界线"需求,方案 1 就够了,还天生兼容多边形洞与 MultiPolygon,不需要为连不连得上网操心。矢量瓦片那种要多级缩放的场景,再往上走PMTiles 单文件托管。
五、数据集很大时先甩个元素计数
很多 GeoJSON下载回来的 FeatureCollection 有几百上千个面,直接全量画上去不仅慢,还容易让浏览器卡死。预览和正式分析不一样,不需要一次把全部要素都渲染出来,可以先扫一遍统计下规模:
function statFC(geojson) {
if (geojson.type === 'FeatureCollection')
return { count: geojson.features.length };
return { count: 1, single: true };
}
只有几十个面的区县级数据,Leaflet 默认矢量渲染毫无压力;上千个区县面那种,就该按之前聊的前端渲染三条路线切到 Canvas 甚至 WebGL。顺手再给每个 Feature 一个 color 属性做分级预览,就够做 Choropleth 的草图了。
六、三个容易踩的坑
1. FeatureCollection 才是默认形制。 单 Feature / Geometry 虽合法,但很多渲染库和后续空间分析工具只认 FeatureCollection,预览时顺手归一化能省后面一堆兼容问题。
2. bbox 顺序别记反。 GeoJSON 的 bbox 是 [minLon, minLat, maxLon, maxLat],fitBounds 要的正好是西南角在前。前几年我按东北角在前传过一次,整个图直接横过来,排查了半天。
3. "预览免费、导出付费"的边界要写在页面里。 本地预览只是把下载回来的数据在浏览器里画出来,不含任何服务端计算;真需要把区县边界导出成印刷级图纸或按需转换格式,才涉及商业服务。预览工具本身保持零后端,静态页一个 HTML 就能跑,也不该把它伪装成全功能 GIS 客户端。
4. 几何非法的面预览时看不出,分析时才爆。 预览只是把 polygon 的洞和环画出来,自相交、未闭合这类问题肉眼基本看不见,等你拿去算面积或做空间分析时才炸。要提前体检,就把几何校验与修复那套 shapely / turf 流程在预览后顺手跑一遍,比事后排错省心。
这套流程固定下来,就是"下载 → 拖进页面 → 框选视野"三步。更多的格式与下载细节,见主站。