前置說明
這篇介紹的在 Awesome GIS 基本上都有,經過我的篩選,在 npmjs.com
上也都能找到,方便融入日益強大的 npm 生態。不過這些庫大部分都保留了全域性庫的形式,在非框架中也能使用。有一部分是瀏覽器 + NodeJS 雙端可用的。
1. 與資料格式轉換解析相關
1.1. 解析和轉換 WKT 幾何資料
如果只是完成 WKT
與 GeoJSON
這兩個格式之間的轉換,那麼下面任意一個都能完成你的任務,選庫體積最小的即可。否則,就按需選擇,就個人體驗而言,@terraformer/wkt
這個庫比較均衡。
下面用表格對比這幾個庫。
wkt | @terraformer/wkt | wkt-parser-helper | @syncpoint/wkx | |
---|---|---|---|---|
ts型別 | 無 | 有,額外安裝 | ts 原始碼 | 有 |
庫大小 | 16.7 KB | 86.8 KB | 15.1 KB | 69.7 KB |
純淨度 | 0 依賴 | 0 依賴 | 1 依賴 | 1 依賴 |
豐富度 | parse + stringify | parse + stringify | parse + stringify | 豐富,還包括 WKB |
API檔案 | 有 | 有,詳盡 | 有,詳盡 | 有 |
更新 | 2019.11 | 2022.8 | 2022.8 | 2021.5 |
@syncpoint/wkx
是 wkx
這個庫的改良版,主要是升級了一些過期的底層 API(適配 NodeJS)。
其實這些庫的更新時間不必太在意,因為 WKT
這種規範已經發布多年,且足夠簡單,能用就行,主要是用得舒服。
庫大小也並不是真正會包含在最終頁面程式之中的大小,因為這些庫有的用到 bundler,庫大小是包含了多個檔案的(例如不同模組風格的庫檔案、源程式檔案等)。
1.2. 前端直接讀取 GeoPackage - @ngageoint/geopackage
GeoPackage
是一種基於 SQLite3 定義來的簡易單檔案地理資料儲存格式,檔案字尾名是 .gpkg
,可以被 QGIS、ArcGIS 讀取,開源免費,支援擴充套件。
與 SpatialLite 均基於 SQLite3 是相似的,但是最大的不同是,SpatialLite 支援資料庫的基本操作,而 GeoPackage 更像一種存粹倉庫,不太像普通資料庫一樣能做查詢。
pnpm add @ngageoint/geopackage
這裡有一個使用這個庫直接在頁面讀取 GeoPackage 檔案中地理資料的網站 GeoPackage Viewer。
此外,這個 @ngageoint
賬戶下還有一堆比較積極維護的庫:
@ngageoint/leaflet-geopackage
- Leaflet.js 的外掛,允許把 gpkg 直接載入到 lf 地圖中
剩下的是一些 NodeJS 才能用的(瀏覽器不能用)格式轉換庫:
@ngageoint/geopackage-geojson-js
- NodeJS 端使用,GeoJSON 和 GeoPackage 互轉@ngageoint/geopackage-xyz-js
- NodeJS 端使用,把 xyz 瓦片的 zip 包轉為 GeoPackage@ngageoint/geopackage-pbf-js
- NodeJS 端使用,把 pbf 資料轉為 GeoPackage@ngageoint/geopackage-mbtiles-js
- NodeJS 端使用,把 mbtiles 資料轉為 GeoPackage@ngageoint/geopackage-csv-js
- NodeJS 端使用,把 csv 資料轉為 GeoPackage@ngageoint/geopackage-shapefile-js
- NodeJS 端使用,把 shapefile zip 檔案轉為 GeoPackage
1.3. 前端直接讀取 Esri Shapefile - ts-shapefile
Shapefile 是 Esri 的傑作,是一種多檔案的資料格式,雖然我在各種場合不遺餘力地推薦大家使用新的資料格式,但是總是有一些人還在問前端能不能解析 Shapefile。這個庫原始碼使用 TypeScript 編寫,打包後支援型別提示(自帶 d.ts
)。
用於瀏覽器的打包庫檔案大約 100+ KB,可以接受。
pnpm add ts-shapefile
這個庫的用法要到 GitHub 倉庫看 README。
注意,Shapefile 規範本體並不含座標系,所以本庫不解析 .prj
檔案中的座標系資訊。座標系的操作庫可以看本文第二節。
Mapbox 團隊有一個用於寫入 Shapefile 並下載為 zip 的庫可供參考(純 js,瀏覽器可用):shp-write
注意,部分 npm 上的 shapefile 庫是 NodeJS 後端庫,瀏覽器不可用,例如shp2json
、shp-write-stream
、shp-stream
等
1.4. 把 GDAL 搬進瀏覽器 - gdal3.js
GIS 開發界 GDAL 可謂是祖師爺級別的庫,它為多種空間資料格式提供了驅動程式(解析器),整合了一些簡單的演演算法實現。
與 npm 上的 gdal 庫不同,gdal
庫是 NodeJS 對 GDAL 的介面繫結,是後端庫,瀏覽器不可用。(p.s,gdal-async 解決了 gdal 庫非非同步的問題,然而瀏覽器還是用不了)。
這個 gdal3.js 使用 emscripten
把 GDAL 轉成了 WebAssembly
,這樣瀏覽器就能使用 GDAL 了,不過與繫結版本效能還是有所差異的。這個庫的原始碼使用 TypeScript 編寫。
pnpm add gdal3.js
由於支援了多種格式,攜帶的 WebAssembly 檔案略多,這個庫的體積也膨脹到了 38.4 MB
,瀏覽器真的想用請謹慎考慮。
檔案很詳盡,因為攜帶了 wasm 等額外檔案,所以在打包環境使用也要注意檔案的複製,很時髦地在檔案中告知了 Webpack、Vite 環境的瀏覽器應用應該怎麼做。
1.5. 格式庫小結
我在很多場合都表明:瀏覽器 + JavaScript 不應用於重度的資料轉換,所以大部分重量級的格式轉換應該由後端程式完成,其它語言(執行時)有更出色的實現,例如 C++、Java、C#.NET、Rustlang、NodeJS、Python 都有。
在瀏覽器端有時候是不得而為之。應付一些簡單的格式轉換還是能勝任的。
2. 操作空間座標系
2.1. 重投影 proj4
著名 C++ 投影庫 PROJ
的 JavaScript 版本,ts 型別需要額外安裝 @types/proj4
。
pnpm add proj4
這個庫僅支援單個座標的轉換,對於複雜的資料格式投影轉換,需要藉助更高層級的封裝庫,見下文。
2.2. 糾“火星”、“百度”加密座標
pnpm add gcoord
國人開發的專門解決 “火星”、“百度” 等加密演演算法的問題。坊間通常稱他們 “火星座標系”、“百度座標系”,實際上只是一些非公開的加密演演算法,這個庫能將加密後的座標透過擬合的方式比較準確地糾正。
其官方檔案指出支援座標陣列和 GeoJSON 的轉換。
2.3. 空間座標系的 WKT 定義 - spatialreference
這個庫並不是拿來做資料座標系轉換的,而是根據 WKID
取座標系的 WKT 定義用的。
它沒有 ts 定義,這是比較可惜的一點。它的預設查詢模式需要聯網,透過 epsg.io
線上 API 請求查詢,所以在大陸環境可能有影響。
pnpm add spatialreference
用法舉例:
import SR from 'spatialreference'
new SR({}).wkidToWkt(4326, (err, wkt) => {
if (!err) console.log(wkt)
})
這個庫還支援在傳入物件中新增資料庫方面的資料,參考它的檔案,允許從資料庫中獲取 WKT。
2.4. 空間座標系的 PROJ 定義 - epsg
如果你沒有線上環境,用不了 2.3 的庫,那麼可以使用 epsg
庫獲得座標系的 PROJ4
定義。這個庫自帶了一個 JSON 字典。
pnpm add epsg
例子:
import epsg from 'epsg'
console.log(epsg['EPSG:3857'])
// +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs
這個庫是 commonjs 模組,需要藉助 bundle 轉換。
2.5. 從座標系定義字串推導 WKID - get-epsg-code
這個與 2.3、2.4 就是相反的操作了。
pnpm add get-epsg-code
例子:
import getEPSGCode from 'get-epsg-code'
const proj4string = `+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs`
const wkid = getEPSGCode(proj4string)
// 3857
它的檔案說支援幾乎所有格式,WKT、proj4、esriproj 均可嘗試:線上測試。
2.6. 對 GeoJSON 的重投影 - reproj-helper
、reproject
前者由 TypeScript 寫成,在其 dist/
下的打包成果檔案中,是將 proj4
打包進去了,所以體積會略大(因為 proj4
本身就有 900+KB),好處是 API、說明檔案較齊全,也有型別提示,不過缺點是對 GeoJSON 沒有使用定義,而是粗暴地設為 any
。
pnpm add reproj-helper
舉例:
import RH from 'reproj-helper'
const pointFeature = {
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
27.896140109578766,
20.219492193232625
],
"type": "Point"
}
}
const rp = new RH.ReProjector()
rp.from('4326')
rp.to('3857')
rp.feature(pointFeature)
const result = await rp.project()
後者就比較輕量化了,釋出到 npmjs.com 上的包不含打包成果,但是在安裝依賴時也會把 proj4
安裝進來,專心於 GeoJSON 物件的轉換,支援校驗 GeoJSON 是否存在座標系定義。這個就沒有 ts 型別提示了:
pnpm add reproject
舉例:
import { reproject } from 'reproject'
const pointFeature = {
"type": "Feature",
"properties": {},
"geometry": {
"coordinates": [
27.896140109578766,
20.219492193232625
],
"type": "Point"
}
}
console.log(reproject(
pointFeature,
'+proj=longlat +datum=WGS84 +no_defs +type=crs',
'+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs'
))
3. 簡易空間分析與幾何運算
3.1. JTS 的移植 - jsts
JTS 有個 C++ 的兒子 GEOS
,然後又有個 JavaScript 的兒子 jsts
。JTS
是 Java 編寫的幾何庫,其地位無需多言。
pnpm add jsts
pnpm add @types/jsts -D
之前寫過一篇如何用它的文章,以緩衝分析為例:
import JSTSWKTReader from 'jsts/org/locationtech/jts/io/WKTReader'
import JSTSGeoJSONWriter from 'jsts/org/locationtech/jts/io/GeoJSONWriter'
import JSTSBufferOp from 'jsts/org/locationtech/jts/operation/buffer/BufferOp'
const wkt = `POINT (0 0)`
const bufferCenter = new JSTSWKTReader().read(wkt)
const bufferResult = JSTSBufferOp.bufferOp(
bufferCenter,
10
) // instanceof Geometry
const bufferResultGeoJSON = new JSTSGeoJSONWriter().write(bufferResult)
如果不熟悉其包結構和 JTS 的用法,我不是很推薦直接上手使用 jsts。
3.2. 給 GeoJSON 設計的簡易版 “turf” - @terraformer/spatial
上文介紹 WKT 庫時這個 @terraformer
賬號有出現。這個庫可以簡易地對 GeoJSON 物件進行簡單的空間分析,可以說是一個簡單版本的 turf:
pnpm add @terraformer/spatial
它的型別庫需要額外安裝 @types/terraformer__spatial -D
。
它具備 applyConverter
(GeoJSON 要素頂點遍歷器)、intersects
、convexHull
、contains
等非常簡單的分析功能,見其 README 檔案。
3.3. 其他一些幾何圖形變換與計算庫
接下來這些幾何庫的 “GIS” 血緣就比較淡了,不過輔助用用也還是可以的。
型別提示 | 庫大小 | 豐富度 | 檔案 | 用途建議 | |
---|---|---|---|---|---|
earcut | 額外安裝 | 95.2 KB | 專一功能 | 齊備 | 離散幾何多邊形的三角化,生成三角網格 |
hextile | 無 | 小於 50KB | 專一功能 | 基本齊全 | 生成漁網(支援若干種內建形狀) |
geometric | 額外安裝 | 107 KB | 中等 | 齊備 | 簡單幾何運算,替代部分 turf 需求 |
@flatten-js/core | ts 原始碼 | 5.68 MB | 豐富 | 完善 | 應對較為複雜幾何圖形的幾何計算 |
geometry-extrude | ts 原始碼 | 288 KB | 專一功能 | 齊備 | 擠出 polygon 成體,並三角化;基於 earcut |
simplepolygon | 無 | 36.6 KB | 專一功能 | 齊備 | 處理 GeoJSON。將複雜的(即自交的)GeoJSON 多邊形,分解為複合的簡單、非自交的單環多邊形。見 README |
3.4. 幾何空間分析庫小結
其實上述這些庫還遠遠不夠,開源社群總能找到寶藏,不過應該也足夠使用了。我為什麼沒有把 turf
列出來呢?是因為 turf 的演演算法準確性、效能實在是拿不出手,群友們都反饋過這個問題,能不用還是儘量不要用了。
而且,複雜的幾何計算我覺得還是交給後臺計算程式比較好,前端能運算的終究有限。
4. 地相簿擴充套件
4.1. 為 ol、mapboxgl、leaflet.js 擴充套件繪圖工具 - terra-draw
這個庫是前端幾個地相簿(支援 OpenLayers V7、Leaflet.js V1.9、MapboxGL V2、Maplibre V2、GoogleMapAPI V3)的外掛,由 TypeScript 寫成,檔案齊全,也有線上例子。
pnpm add terra-draw
在我寫這篇文章時,它還在 alpha 階段,不過可用性已經很不錯了。官方示例指路:TerraDraw
4.2. 為 leaflet.js 擴充套件的繪圖工具
如題。這個繪圖外掛很強大,基本滿足絕大多數 2D 繪製要求,體積也來到了 450 KB+。
pnpm add @geoman-io/leaflet-geoman-free
由 TypeScript 編寫,支援多國語言,具有十分完善的檔案。不過,它自帶的按鈕對於某些場景可能不太合適使用了(想自定義按鈕樣式、UI 邏輯的情況)。總體來說我打 98 分。
5. 雜項
5.1. 中國大陸行政區劃編碼庫
這個像個字典,小型專案(不具備資料庫介面呼叫條件)適合使用。
pnpm add china-region
另有帶型別提示的版本 china-regions-ts
,不過我個人建議在找這類行政編碼庫時,儘量找最新版的。
5.2. 為 GeoJSON 增強型別提示 - @types/geojson
這個可以替代 GeoJSON 各級物件在你 TypeScript 專案中的 any
問題,注意要安裝到開發依賴,這東西只是個型別庫。
pnpm add @types/geojson -D
用法簡單:
import type { Polygon } from 'geojson'
// ...
5.3. 與 WFS 類似的 OGC Feature API 客戶端實現庫 - @ogcapi-js/features
OGC API 是什麼我之前寫過一篇入門介紹,是 OGC 正在開發推進的下一代 GIS 網路規範,涵蓋方方面面。其中,OGC Feature API
就是 WFS
的下一代規範,也即原來打算的 WFS 3.0
。
當滿足 OGC Feature API 的服務啟動後,可以用這個包來呼叫 OGC Feature API
規範定義的功能。
當前 OGC API 仍未完全落定,以最新版為準,可以關注 @ogcapi-js
這個賬戶下的新包。
pnpm add @ogcapi-js/features
用法也很簡單。
import { Service } from `@ogcapi-js/features`;
// 建立一個服務物件
const service = new Service({
baseUrl: 'https://ogcapi.service.com'
});
// 呼叫介面獲取資料集清單
const collections = await services.getCollections();
5.4. 操作 Esri 的投影定義物件
Esri 使用者的小工具,不過也適用於部分需要座標系 WKT 的場景,暴露一個 lookup 函式,傳入 WKID 來查詢座標系物件:
pnpm add @esri/proj-codes
這個包略大,如無必要則不用,查詢座標系的工作應該讓後端資料庫完成。
import codes from '@esri/proj-codes'
const crs = codes.lookup(3857)
crs.name
// 'WGS_1984_Web_Mercator_Auxiliary_Sphere'
crs.wkt
// 'PROJCS["WGS_1984_Web_Mercator_Auxiliary_Sphere",GEOGCS["GCS_WGS_1984"...'
crs.description
// 'WGS 1984 Web Mercator Major Auxiliary Sphere'
crs.authority
// 'EPSG'
crs.deprecated
// 'no'
crs.extent
// { "slat": -85.06, "nlat": 85.06, "llon": -180.0, "rlon": 180.0 }
// this works too
codes.lookup(3857).name
// 'WGS_1984_Web_Mercator_Auxiliary_Sphere'
6. 小結
這篇主要以瀏覽器前端為主,其實有一部分庫在 NodeJS 後端也能用,譬如座標系、格式轉換、幾何空間分析等。單獨給後端 NodeJS 的也有,資料庫、格式轉換、影像演演算法的偏多,不過也逐漸淡去了 GIS 血緣,有機會再介紹吧。