整個處理大致都被 GeoJSON 包裝好了
原本沒碰過 GeoJSON,自己想像要處理區塊框線、互動,以為要折磨很多事;但其實在 Leaflet 裡可以看成載入一個 GeoJSON 資源,再用 addTo(map)
掛上去就結束了。
建立與顯示:
const layer = Leaflet.geoJSON(data as GeoJsonObject, options);
layer.addTo(map);
外觀、互動行為等,可以用 options
去調,以下是一個 options 物件:
{
style: () => ({
fill: false,
}),
onEachFeature: function (feat: Feature, layer: Path) {
layer.on('mouseover', function () {
layer.setStyle({ fill: true });
});
layer.on('mouseout', function () {
layer.setStyle({ fill: false });
});
},
}
要關閉圖層,就 remove 掉:
layer.removeFrom(map);
取得地圖資料
另一個問題是圖資怎麼來,首選當然是內政部的開放資料:
縣市界:鄉鎮市區界線(TWD97經緯度)、村(里)界:村里界圖(TWD97經緯度)。
但要怎麼轉成 GeoJSON 格式?尋找現成整理好的,似乎都失連,或看起來有點年代,幸好裡面原理沒變,參考
jason2506/Taiwan.TopoJSON,它是用 mapshaper 將 .shp 轉為 .geojson。
具體指令例,縣市:
mapshaper raw/COUNTY_MOI_1090820.shp -simplify interval=400 \
-filter 'COUNTYNAME !== "金門縣" && COUNTYNAME !== "連江縣"' \
-rename-fields name=COUNTYNAME -filter-fields name \
-o format=geojson precision=0.0001 \
counties.geojson
村里:
mapshaper raw/VILLAGE_NLSC_1130807.shp -simplify interval=30 \
-rename-fields id=VILLCODE \
-verbose \
-filter 'COUNTYNAME !== "金門縣" && COUNTYNAME !== "連江縣"' \
-each 'name=TOWNNAME + " " + VILLNAME' -filter-fields id,name \
-o format=geojson precision=0.0001 \
villages.geojson
其中 -simplify interval=
和 precision
參數可以控制產出的精細度,也決定了檔案大小。
上面範例出來的結果是 61.35 KB 和 7.21 MB,後者檔案很大,但其實掛在 Cloudflare R2,在 HTTP/2 和壓縮加持下傳輸量只有 1.7 MB,使用上是沒什麼問題的。