GeoJSON 在线预览编辑器开源:一个纯前端实现的拆解

背景

日常处理行政区划、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:

欢迎在仓库里提 Issue 和 PR。

相关链接

相关推荐
xiaominlaopodaren2 天前
three.js地图视口瓦片(一):屏幕角点射线
javascript·gis·three.js
GIS阵地3 天前
ERA5‑Land逐小时降水数据下载+QGIS后台QgsTask批量处理完整指南(水文洪涝仿真,河南省案例)
gis·qgis·数据处理
xiaominlaopodaren4 天前
three.js最小地图运行时(十):接入离线逻辑瓦片剖面
javascript·gis·three.js
三维地图技术社区5 天前
一张实景三维地图是怎么来的?从无人机航测到倾斜摄影建模的完整技术链路
gis·实景三维·三维可视化大屏·bim·无人机航测·倾斜摄影建模·空三解算
xiaominlaopodaren5 天前
three.js最小地图运行时(九):TileKey 线框与 cursor 坐标探针
javascript·gis·three.js
xiaominlaopodaren6 天前
three.js最小地图运行时(八): 瓦片调试网格
javascript·gis·three.js
久数君7 天前
2026年GIS入门软件怎么选?ArcGIS、QGIS、GISBox等工具详解
gis·qgis·arcgis pro·超图·gisbox·global mapper·地图数据处理工具
xiaominlaopodaren7 天前
three.js最小地图运行时(七): MapRuntime 与地图交互
javascript·gis·three.js
xiaominlaopodaren9 天前
three.js最小地图运行时(六): 地图运行时
javascript·gis·three.js