maplibre-gl-opacityをMapbox GL JSで使ってみる
はじめに
現在、Software Designで連載中の「位置情報エンジニアリングのすすめ」を毎月楽しく拝読しております。第6回「防災マップの作成① 浸水想定区域と避難所を可視化する」ではMapLibre GL JSを用いて地理情報を表示していました。記事にも記載されている通り、MapLibre GL JSはMapbox GL JSからフォークされた地図ライブラリなので、使い方は非常に似通っています。そこで、ここでは紙面で紹介されていたMapLibre GL JS用のプラグインであるmaplibre-gl-opacityをMapbox GL JSで使ってみようと思います。
maplibre-gl-opacityとは
maplibre-gl-opacityはMapLibre GL JS用のプラグインで、スタイル上のレイヤーの表示・非表示設定や不透明度の設定を行うことができます。作者様の解説記事は以下です。
maplibre-gl-opacityの使い方
maplibre-gl-opacityはIControl
として実装されています。そのため、以下のコードのようにOpacityControl
をインスタンス化し、Map#addControl
で地図上に表示します。
const opacity = new OpacityControl({
baseLayers: {
'tokyo-st-green': 'GREEN',
'tokyo-st-blue': 'BLUE',
},
overLayers: {
satellite: 'Satellite',
},
opacityControl: true,
});
map.addControl(opacity, 'top-left');
上記のコードで以下のようなコントロールが表示されます。baseLayers
で指定したレイヤーは択一式のラジオボタン、overLayers
で指定したレイヤーは複数選択可能なチェックボックスとして表示されます。また、opacityControl
をtrue
とすることでoverLayers
の不透明度を設定するためのスライダーが表示されます。
maplibre-gl-opacityのコードを読む
IControl
はMap#addControl
のタイミングでonAdd
関数が実行されます。つまり、Icontrol
のエントリポイントはonAdd
関数なので、ここからコードを読むと良いです。
_opacityControlAdd()
関数が内部で呼ばれているようなので中を見ていきます。
baseLayers
に関する処理
以下でbaseLayers
に関する処理が行われています。baseLayers
はキーがレイヤーIDなので、Object.keys
でレイヤーIDの配列が取得されます。その配列に対してmap
を作用させ、各レイヤーIDを引数として_radioButtonControlAdd
関数を実行しています。
_radioButtonControlAdd
ではラジオボタンを作成します。さらに、1つ目のレイヤーに対してはMap#setLayoutProperty
を使用し、visibility
プロパティをvisible
に、それ以外のレイヤーはnone
に設定しています。
さらに、ラジオボタン選択時に、選択されたレイヤーをvisible
にする処理が記述されています。
また、baseLayers
の値はラベルとして利用されます。
overLayers
に関する処理
以下でoverLayers
に関する処理が行われています。overLayers
もキーがレイヤーIDなので、Object.keys
でレイヤーIDの配列が取得されます。その配列に対してmap
を作用させ、各レイヤーIDを引数として_checkBoxControlAdd
関数を実行しています。
_checkBoxControlAdd
関数ではチェックボックスを作成します。さらに、全てのレイヤーを非表示状態にします。
また、チェックボックス選択時に表示・非表示を切り替える処理が記述されています。
opacityControl
がtrue
のときには_rangeControlAdd
関数も実行されます。
_rangeControlAdd
関数ではスライダーを作成し、スライダー変更時にMap#setPaintProperty
でraster-opacity
を変更しています。
raster-opacity
はラスターレイヤー専用のプロパティなので、opacityControl
を使用する際にoverLayers
に指定できるレイヤーはラスターレイヤーのみとなります。
maplibre-gl-opacityをMapbox GL JSで使う
上記ではmaplibre-gl-opacity内部で使用されるMapLibre GL JSの機能を見てきました。以下の表はMapLibre GL JSとMapbox GL JSの機能を比較です。これらの機能はMapbox GL JS v1.13.0以前に実装されたものなので、基本的に互換性があることが期待されます。
MapLibre GL JS | Mapbox GL JS |
---|---|
IControl |
IControl |
Map#addControl |
Map#addControl |
Map#setLayoutProperty |
Map#setLayoutProperty |
Map#setPaintProperty |
Map#setPaintProperty |
サンプル全体
まず今回作成したサンプルです。
import { Map } from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
// @ts-ignore
import OpacityControl from 'maplibre-gl-opacity';
import 'maplibre-gl-opacity/dist/maplibre-gl-opacity.css'
import tokyoSt from './tokyo_st.json'
const map = new Map({
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [139.768435, 35.681054],
zoom: 15,
});
map.on('style.load', () => {
map.addSource('tokyo-st', {
type: 'geojson',
data: tokyoSt as any,
});
map.addLayer({
'id': 'tokyo-st-green',
'type': 'fill',
'source': 'tokyo-st',
'paint': {
'fill-color': '#00ff00',
}
});
map.addLayer({
'id': 'tokyo-st-blue',
'type': 'fill',
'source': 'tokyo-st',
'paint': {
'fill-color': '#0000ff',
}
});
map.addSource('satellite', {
'type': 'raster',
'url': 'mapbox://mapbox.satellite',
});
map.addLayer({
'id': 'satellite',
'type': 'raster',
'source': 'satellite',
});
const opacity = new OpacityControl({
baseLayers: {
'tokyo-st-green': 'GREEN',
'tokyo-st-blue': 'BLUE',
},
overLayers: {
satellite: 'Satellite',
},
opacityControl: true,
});
map.addControl(opacity, 'top-left');
opacity._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
});
以下で各部分の動作を確認します。
地図の作成
以下ではMapをインスタンス化しています。
const map = new Map({
accessToken: 'YOUR_MAPBOX_ACCESS_TOKEN',
container: 'map',
style: 'mapbox://styles/mapbox/streets-v12',
center: [139.768435, 35.681054],
zoom: 15,
});
ソース・レイヤーの作成
ソース・レイヤーの作成はmap.on('style.load', () => { /* ここ */})
の部分で行います。
以下は東京駅のポリゴンをGeoJSONから読み込んでいます。また、ポリゴンを緑色で塗りつぶしたtokyo-st-green
レイヤーとポリゴンを青色で塗りつぶしたtokyo-st-blue
レイヤーを作成しています。これらのレイヤーはbaseLayers
で使用します。
map.addSource('tokyo-st', {
type: 'geojson',
data: tokyoSt as any,
});
map.addLayer({
'id': 'tokyo-st-green',
'type': 'fill',
'source': 'tokyo-st',
'paint': {
'fill-color': '#00ff00',
}
});
map.addLayer({
'id': 'tokyo-st-blue',
'type': 'fill',
'source': 'tokyo-st',
'paint': {
'fill-color': '#0000ff',
}
});
以下はMapboxのSatellite Tilesetをソースとして使用します。また、このタイルセットはラスターなので、ラスターレイヤーとして追加します。このレイヤーはoverLayers
で使用します。
map.addSource('satellite', {
'type': 'raster',
'url': 'mapbox://mapbox.satellite',
});
map.addLayer({
'id': 'satellite',
'type': 'raster',
'source': 'satellite',
});
maplibre-gl-opacityの作成
maplibre-gl-opacityの使い方で見た通り、OpacityControl
をインスタンス化し、addControl
します。
const opacity = new OpacityControl({
baseLayers: {
'tokyo-st-green': 'GREEN',
'tokyo-st-blue': 'BLUE',
},
overLayers: {
satellite: 'Satellite',
},
opacityControl: true,
});
map.addControl(opacity, 'top-left');
最後にちょっとしたハックです。Mapbox GL JSで使用する際に必要なクラス名の指定を行います。
opacity._container.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
この指定の背景は以下のとおりです。
maplibre-gl-opacityコントロールのHTMLエレメントに対し、maplibregl-ctrl
およびmaplibregl-ctrl-group
というクラスが割り当てられています。
これらのクラスは以下の様にMapLibre GL JSのCSSで定義されています。IControl
で作成するコントロールに対してこのクラスを割り当てることで、いい感じに表示されます。
同様のクラスがMapbox GL JSでは以下のように定義されています。
そこで、Mapbox GL JSで使用する場合にはmaplibregl-ctrl
をmapboxgl-ctrl
に、 maplibregl-ctrl-group
をmapboxgl-ctrl-group
に変更する必要があります。
結果
以下のように表示されます。
デモは以下のサイトで試せます。
まとめ
ちょっとしたハックは必要でしたが、maplibre-gl-opacity(v1.6.0)がMapbox GL JS(v3.0.1)でも使用できることがわかりました。ただし、今後MapLibre GL JSの独自機能を使う変更が加えられたり、MapLibre Gl JSまたはMapbox GL GLの既存機能に破壊的変更があった場合には使用できなくなる可能性もあります。
OpacityControl
の設定に関して、baseLayers
という名称からベースマップとして表示するラスターレイヤーの使用がライブラリとしての期待値かもしれません。しかし、今回のような任意のレイヤーの表示の選択にも利用可能です。
また、紙面ではOpacityControl
を2つ作成していましたが、一つはベースマップの選択用、もう一つは浸水想定区域の選択用として作成していると推察されます。一つのOpacityControl
に対し、後者をoverLayers
として表示する使い方もあるかと思います。
おまけ
紙面で以下のような脚注がありました。
注5) MapLibre GL JSはv3から一部のプラグインが機能しない問題があるため、本連載では最新バージョンではなく動作が安定しているv2.4.0を使います。
https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#potentially-breaking-changes
リンク先を確認するとPotentially breaking changesとして以下の項目があります。
⚠️ Remove deprecated mapboxgl- css classes (use maplibregl- instead) (#1575)
maplibre-gl-opacityはv1.5.0でクラスをmaplibregl-ctrl
、maplibregl-ctrl-group
に変更しているので問題ないですが、Mapbox GL JS用に開発されたプラグインは使えなくなっていると考えられます。
Discussion