都道府県のポリゴンデータを取得する
<div id="map"></div>
で用意した div タグ内に地図を表示するため、ID である map
を指定し geolonia.Map のインスタンスを生成します。
地図が読み込まれたら、geolonia / prefecture-tiles で公開している prefectures.geojson を取得し、レスポンスの json データを geojson
に格納します。
const map = new geolonia.Map('#map')
map.on('load', async () => {
const resp = await fetch('https://raw.githubusercontent.com/geolonia/prefecture-tiles/master/prefectures.geojson')
const geojson = await resp.json()
//...
都道府県のレイヤーを地図に追加する
続いて、addLayer
で取得した GeoJSON データを地図に追加します。
GeoJSON データは、全都道府県のポリゴンデータがまとめて入った FeatureCollection タイプのデータなのですが、個別に指定して表示/非表示が切り替えられるように、それぞれの都道府県(Featureタイプのデータ)に都道府県コード (すでに properties の一つにセットされている) を Feature IDとして扱う必要がある。こういった場合は、 source を指定する時に promoteId
オプションを使います。 promoteId
オプションは、GeoJSON の Feature の properties から指定した値を Feature ID として利用するようになります。
map.addLayer({
id: 'prefectures',
type: 'fill',
source: {
type: 'geojson',
promoteId: 'code',
data: geojson,
},
layout: {},
paint: {
'fill-color': '#ff0000',
'fill-opacity': [
'case', ['boolean', ['feature-state', 'active'], false], 1, 0
]
}
})
paint プロパティでは、'fill-color': '#ff0000'
で赤色に塗りつぶすように指定し、'fill-opacity'
で透明度を指定しているのですが、その値には
[
'case', ['boolean', ['feature-state', 'active'], false], 1, 0
]
という、MapLibre GL JS の StyleSpecification で定義されている Expressions のひとつである case 文を使っています。
この値は、各都道府県の feature-state
の active
が true のときには1(不透明)が、false のときには0(透明)がセットされるということを意味しています。つまり、active
を true にセットするとその都道府県がハイライトされます。デフォルトは false なので、最初はどの都道府県もハイライトされていない状態になります。
都道府県セレクトボックス(カスタムコントロール)を追加
後述する PrefectureSelectBox クラスに GeoJSON データを引数として渡して初期化したあと、カスタムコントロールとして地図に追加します。
const prefectureSelectBox = new PrefectureSelectBox(prefectures)
map.addControl(prefectureSelectBox)
カスタムコントロール用のクラスを定義
カスタムコントロール用のクラス PrefectureSelectBox
を定義します。
class PrefectureSelectBox {
constructor(prefectures) {
this._prefectures = prefectures
this._selectedPrefectureCode = undefined
}
//...
コンストラクタで、引数と渡ってくる prefectures をインスタンス変数の _prefectures にセットし、選択された都道府県コードを格納するための _selectedPrefectureCode も用意します。
カスタムコントロール用のクラスを作るときは、コントロールが追加されたときに呼ばれる onAdd
関数を定義しなければなりません。ここでは this._prefecture
に格納された都道府県データを利用して、都道府県名を選択できるセレクトボックスを作っています。
onAdd(map) {
this._map = map
// 都道府県を選ぶセレクトボックスを作る
this._container = document.createElement('div')
this._container.className = 'maplibregl-ctrl'
this._container.innerHTML = '<select name="prefecture">'
+ '<option value=""></option>'
+ this._prefectures.map(pref => { return `<option value="${pref.properties.code}">${pref.properties.name}</option>` })
+ '</select>';
//...
都道府県のどれかが選択されたときの処理を、セレクトボックスの change
イベントに割り当てます。
前回選択した都道府県がある場合には、this._selectedPrefectureCode
に格納された都道府県コードを ID とする Feature の feature-state
の active
の値を false に変えています。これによって前述した fill-opacity の値が 0 になって透明に、つまりハイライト表示が無効になります。
次に、セレクトボックスで選択された都道府県にひもづく都道府県コードを this._selectedPrefectureCode
に格納し直し、同じ要領で feature-state
の active
の値を true に変えることで、選ばれた都道府県のハイライト表示を有効にします。
// 都道府県が選択されたときに呼ばれる
this._container.addEventListener("change", (e) => {
// 前回選択した都道府県があれば、ハイライト表示を無効にする
if (this._selectedPrefectureCode) {
this._map.setFeatureState(
{ source: 'prefectures', id: this._selectedPrefectureCode },
{ active: false }
);
}
// 選択した都道府県のハイライト表示を有効にする
this._selectedPrefectureCode = e.target.value
this._map.setFeatureState(
{ source: 'prefectures', id: this._selectedPrefectureCode },
{ active: true }
);
// 選択された都道府県をフォーカスする
const selectedPrefecture = this._prefectures.find(prefecture => prefecture.properties.code === this._selectedPrefectureCode)
const prefectureGeojson = {
type: 'FeatureCollection',
features: [selectedPrefecture]
}
this._map.fitBounds(geojsonExtent(prefectureGeojson))
})
後半では mapbox / geojson-extent というライブラリを使い、選択された都道府県の GeoJSON データからバウンディングボックス情報(その都道府県を囲む最小の四角形のポリゴンの座標の集まり)を抽出し、fitBounds
に渡すことで選択した都道府県にフォーカスするように移動できるようにしています。
onAdd の最後では、このようにして作成した this._container を返り値として返しています。
return this._container
カスタムコントロールが削除されるときに呼ばれる onRemove
も定義します。
onRemove() {
this._container.parentNode.removeChild(this.container)
this._map = undefined
}
コード全体を見るには、以下の CodePen のサンプルコードを参照してください。
See the Pen カスタムコントロールのセレクトボックスで選択した都道府県をハイライト表示する by Geolonia (@geolonia) on CodePen.