背景
日常处理行政区划、POI、轨迹等 GeoJSON 数据时,经常需要先看一眼:边界画得对不对、坐标系是不是 WGS84、字段结构是否符合预期。常见的做法是把文件传到在线工具,或者打开一个完整的桌面 GIS。
前者有数据外泄的顾虑,后者对于一个"看一眼"的需求又太重。我们把 GeoJSONcn 站点里的预览编辑器抽出来,做成了一个不依赖任何后端的纯前端工具,并开源出来。
它解决什么问题
- 本地打开 GeoJSON 即可渲染,数据不上传服务器;
- 支持要素级的查看与编辑;
- 能把同一份数据导出成 GeoJSON / KML / SVG / CSV / PNG,对接不同的下游系统;
- 不需要
npm install,不需要构建,双击index.html就能用。
技术实现
渲染:Leaflet 与坐标系
核心就是用地图库把 GeoJSON 画出来。下面是一段最小可用的加载代码:
javascript
// 初始化地图并加载一份 GeoJSON
// 要素量大时把渲染器从默认 SVG 换成 Canvas,避免 DOM 节点过多卡顿
const map = L.map('map', { renderer: L.canvas() }).setView([39.9, 116.4], 4);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap'
}).addTo(map);
fetch('example.geojson')
.then(r => r.json())
.then(geojson => {
L.geoJSON(geojson, {
style: { color: '#2563eb', weight: 1.5 },
onEachFeature: (feature, layer) => {
const name = feature.properties && feature.properties.name;
if (name) layer.bindPopup(name);
}
}).addTo(map);
});
这里有个容易混淆的点:Leaflet 的地图视图默认使用 Web Mercator(EPSG:3857)投影,但 Feature 的坐标本身仍是 EPSG:4326(WGS84),Leaflet 在加载时会自动完成经纬度到墨卡托的转换,开发者无需手动处理。
需要提醒的是,本项目只处理 WGS84 数据。国内的地图数据常常混用 GCJ-02(火星坐标系)或 BD-09,本项目目前没有内置纠偏逻辑,如果拿到的数据偏移明显,需要先自行纠偏再导入。
计算:Turf.js
要素的几何操作(计算包围盒、合并、切分、面积量算等)交给 Turf.js。本仓库把 Turf 以本地文件形式打包在 turf/ 目录里,页面里直接通过全局 turf 对象调用,无需打包工具:
javascript
// 用 Turf 计算要素包围盒与面积(turf 为仓库内置的全局对象)
const bbox = turf.bbox(geojson); // [minX, minY, maxX, maxY]
const area = turf.area(geojson); // 单位:平方米
console.log('包围盒:', bbox, '面积(㎡):', area);
预览页里"切分选中要素"这类能力,就是从主站编辑器移植过来的,底层依赖 Turf 的几何运算。
导出管线
几种导出格式各自有几个容易踩坑的技术点:
javascript
// KML 坐标顺序是 经度,纬度,海拔;注意和 GeoJSON 的 [lon, lat] 对应,多一个高程
// 多环 / 多维坐标需要递归处理
function coordsToKml(coords) {
if (typeof coords[0][0] === 'number') {
return coords.map(c => `${c[0]},${c[1]},0`).join(' ');
}
return coords.map(coordsToKml).join(' ');
}
// 导出 CSV 时在开头写入 BOM,避免 Excel 打开中文乱码
const csv = 'name,lon,lat\n' + rows.join('\n');
const blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' });
- GeoJSON :最直接,把内存里的 FeatureCollection 序列化即可,注意保留
properties与坐标系声明。 - KML :需要按
<Document><Placemark><Polygon><outerBoundaryIs><LinearRing><coordinates>的结构组织;坐标顺序经度,纬度,海拔,转换时别写反(见上)。 - SVG :把
[经度, 纬度]用等距圆柱投影线性映射到viewBox的像素坐标,输出<path d="M x y L x y Z">。投影本身很简单,难点在视口自适应和描边宽度的处理。 - CSV :每个要素一行,属性平铺成列;字段含中文且要进 Excel 时,文件开头需带 BOM(
EF BB BF),否则中文乱码(见上)。 - PNG :把当前渲染结果绘制到
<canvas>后,用toBlob/toDataURL导出图片。
目录结构
bash
geojson-preview/
├── index.html # 入口页:说明 + 主站入口
├── preview.html # 预览编辑器本体
├── leaflet/ # 地图渲染引擎
├── turf/ # 几何计算
├── vendor/ # 其他第三方依赖
├── LICENSE # MIT
├── NOTICE
└── README.md
整个项目是静态文件,没有打包步骤,依赖都以本地文件形式存在 leaflet/、turf/、vendor/ 目录里。
快速开始
bash
# GitHub
git clone https://github.com/laukuo/geojson-preview.git
# Gitee
git clone https://gitee.com/SmartMailer/geojson-preview.git
克隆后用浏览器直接打开 index.html 即可,无需安装依赖、无需启动服务。
与 GeoJSONcn 主站的关系
这个仓库是 GeoJSONcn(全国行政区划边界矢量数据下载平台)预览功能的独立开源版。主站还提供省、市、区县、乡镇街道四级行政区划边界数据的在线预览与下载,你也可以直接在 在线预览页 体验完整功能;开源版把"轻量预览 + 编辑 + 导出"这一段单独拆了出来,方便在自己的项目里直接集成或做二次开发。
二次开发与集成
几种常见的接入方式:
- 在自己的页面里直接引用本仓库的
leaflet/与turf/,复用渲染与计算逻辑; - 把
preview.html以<iframe>的形式嵌到内部系统里; - 本地加载 GeoJSON 时,优先用
FileReader读取用户选定的文件,而不是fetch本地路径------后者在file://协议下会受到浏览器同源策略限制:
javascript
// file:// 下用 FileReader 读本地文件,避开 fetch 的同源限制
const input = document.getElementById('file');
input.addEventListener('change', () => {
const reader = new FileReader();
reader.onload = e => renderGeoJSON(JSON.parse(e.target.result));
reader.readAsText(input.files[0]);
});
开源地址
代码基于 MIT 协议发布,同时托管在 GitHub 与 Gitee:
- GitHub:github.com/laukuo/geoj...
- Gitee:gitee.com/SmartMailer...
欢迎在仓库里提 Issue 和 PR。
相关链接
- 开源仓库(GitHub):github.com/laukuo/geoj...
- 开源仓库(Gitee):gitee.com/SmartMailer...
- 项目主站:geojsoncn.com/
- 在线预览:geojsoncn.com/preview.htm...