昨日の記事で多角形を強調して表示し、その多角形の内外で異なる動作をするプログラムを作りました。
【JavaScirpt】【Leaflet】任意の多角形領域の外側だけ色付けしたレイヤーで覆う方法とその内外判定 – 株式会社シーポイントラボ | 浜松のシステム・RTK-GNSS開発
この多角形ですが、実務上は何かしら意味のある多角形になります。ここでは多角形を GeoJSON で表現される静岡県浜松市、静岡県浜松市中区それぞれの境として取り扱う方法を紹介します。
取り扱う境の情報の大本は国土交通省の行政区域データを用います。これはオープンデータである他に年単位で更新される、日本国としての地図情報の本家本元という点でうれしいデータです。
国土数値情報 | 行政区域データ
データは都道府県単位と全国のそれぞれで用意され、いずれのデータも MB 単位、全国に至っては GB であり、で人間が目で読むものではない規模です。
データの仕様は前述の行政区域データページのトップに載っており、TypeScript 的に型に起こすと次の様になります。
export interface PrefGeoJSON { type: string; crs: CRS; features: Feature[]; } export interface CRS { type: string; properties: CRSProperties; } export interface CRSProperties { name: string; } export interface Feature { type: string; properties: FeatureProperties; geometry: Geometry; } export interface Geometry { type: string; coordinates: [number, number][][];// ここに緯度経度が入ります } export interface FeatureProperties { N03_001: string; N03_002: null | string; N03_003: string; N03_004: string; N03_007: string; }
このデータから目的の地域の緯度経度を抜き出し、多角形とすることで目的の区域のみを強調する Leaflet を使ったプログラムを作れます。
例えば、静岡県浜松市中区は次のデモとソースコードの様に作れます。
浜松市中区を Leaflet 上で強調するデモ
leaflet_and_prefecture_demo/nakaku.html at master · cpt-sugiura/leaflet_and_prefecture_demo
こんな感じで何かしら緯度経度を含む地理データが提供されていれば、それを用いた地図を web 上に描画できます。今回紹介している地理データは市よりも小さい単位のため、そのまま点を並べるだけでは市を完璧に表現することはできません。例えば、次のスクリーンショットの様に無駄な辺により、無視できない面を成すことがあります。外縁部のみを表現する多角形にすべきです。
これをきれいに外縁部のみを表現する多角形にするために使える便利なライブラリに turf というものがあります。
Turf.js | Advanced geospatial analysis
Turfjs/turf: A modular geospatial engine written in JavaScript
turf は地理空間情報を操作するための JavaScript ライブラリで点、線、面の計算や編集を手助けしてくれます。ここで使うのは面の和集合を計算する union です。
Turf.js | Advanced geospatial analysis#union
これを使って先ほどの中区を抜き出した部分を次の様に変えることで浜松市の外縁部を示す多角形を得られます。
const hamamatsu = shizuokaGeoJSON.features .filter(node => node.properties.N03_003 === '浜松市')// 浜松市内の区のみを抽出 .reduce((hamamatsu, ku) => {// reduce で一つずつ和集合を抽出 if(hamamatsu === null){ // 最初の一つはそれのみで完結していため turf に通しておしまい。 return turf.polygon([ku.geometry.coordinates[0]]) } // 二つ目以降は turf で和集合を計算 return turf.union( hamamatsu, turf.polygon([ku.geometry.coordinates[0]]) ) }, null ).geometry.coordinates[0].map(lngLat => [lngLat[1], lngLat[0]])// leaflet に渡せる形式に抜き出し ;
これを使ったデモとソースコードが次です。
浜松市を Leaflet 上で強調するデモ
leaflet_and_prefecture_demo/hamamatsu.html at master · cpt-sugiura/leaflet_and_prefecture_demo
上例ではその場で計算を行いましたが計算に使う規模が都道府県レベルになるとユーザがとても待てないほどに処理が遅くなります。そういった時はあらかじめ Node.js + turf なりなんなりで適切な緯度経度ファイルないしデータを作り、それを読み込めるようにすべきです。