Mapbox Newsletter WEEKLY TIPSの解説 -「ズーム・レベルに応じて建物の色を変更」
はじめに
この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「ズーム・レベルに応じて建物の色を変更」についての解説です。このサンプルではMap#setPaintProperty
とExpressionsの使い方について例示しています。また、Newsletterの購読はこちらからお申し込みいただけます。
以下が本サンプルのデモです。
コードを確認
まずExamplesのコードを見に行きましょう。
日本語サイト
英語サイト
基本的に同じコードですが、英語版はスタイルがMapbox Streets v12にアップグレードされているのでこちらを使用します。Mapbox Streets v11ではデフォルトのプロジェクションがWebメルカトルであるのに対し、Mapbox Streets v12ではGlobe(3D表示された地球)なので、印象がかなり異なります。また、英語版はMapbox GL JS v3が使用されています。
HTML/CSS
まずHTMLを見ていきましょう。
以下は地図を表示するエレメントです。
<div id="map"></div>
以下は地図上部にある「Zoom to buildings」ボタンです。
<button id="zoom">Zoom to buildings</button>
また、このボタンのスタイルが以下のように定義されています。
#zoom {
display: block;
position: relative;
margin: 20px auto;
width: 50%;
height: 40px;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #fff;
background: #ee8a65;
}
Mapの作成
次にJavaScriptのコードを見ていきます。以下のコードはいつも通り、Mapオブジェクトを作成しています。container
で地図を表示するHTMLエレメントのidを指定します。
const map = new mapboxgl.Map({
container: 'map', // container ID
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/streets-v12', // style URL
center: [-90.73414, 14.55524], // starting position [lng, lat]
zoom: 15 // starting zoom
});
プロパティの設定
建物の色を変えるために、Streets v12スタイルのbuilding
レイヤーのプロパティを設定します。これはスタイルが読み込まれた後に設定する必要があるため、map.on('load', () => { /* ここ */})
の部分に処理を書きます。
プロパティの値の設定にはMap#setPaintProperty
を使用します。第1引数がレイヤーID、第2引数がプロパティ名、第3引数が設定する値になります。値の部分はExpressionsが記述できます。
まず、このサンプルで使用されているExpressionsであるinterpolate
について説明します。このExpressionsは補間の方法を指定します。例えばzoom 16で赤色、zoom 20で青色とした場合、途中のズームレベルではこの2点の間の色になるように適切に補間させることができます (線形補間のとき、zoom 18で紫色)。第1引数は補間の種類をlinear
、exponential
、cubic-bezier
から選択します。第2引数はinputとして使用するプロパティ等(先程の例ではズームレベル)を指定します。これ以降の引数は「inputの値とその時の出力値」の順番で並べていきます。
それではコードを確認します。まず1つ目のプロパティはfill-color
です。これはfillレイヤー(ポリゴン)の色を設定するプロパティです。補間方法はexponential
を指定しているので、指数関数的な変化となります。底として0.5を指定しています。inputはzoom、色はzoom 15のときベージュ、zoom 18で黄色になります。
map.setPaintProperty('building', 'fill-color', [
'interpolate',
// Set the exponential rate of change to 0.5
['exponential', 0.5],
['zoom'],
// When zoom is 15, buildings will be beige.
15,
'#D9D3C9',
// When zoom is 18 or higher, buildings will be yellow.
18,
'#ffd700'
]);
2つ目のプロパティはfill-opacity
です。これはfillレイヤー (ポリゴン) の不透明度を設定するプロパティです。補間方法はexponential
を指定しているので、指数関数的な変化となります。inputはzoom、不透明度はzoom 10のとき0.5、zoom 18で1になります。
map.setPaintProperty('building', 'fill-opacity', [
'interpolate',
// Set the exponential rate of change to 0.5
['exponential', 0.5],
['zoom'],
// When zoom is 10, buildings will be 100% transparent.
10,
0.5,
// When zoom is 18 or higher, buildings will be 100% opaque.
18,
1
]);
ボタンの処理
ボタンクリック時の処理です。具体的にはMap#zoomTo
でズームレベルを18にしています。また、オプションとして9秒かけてズームする設定になっています。
document.getElementById('zoom').addEventListener('click', () => {
map.zoomTo(18, { duration: 9000 });
});
まとめ
setPaintProperty
とExpressionsを使用することで、動的に見た目を変更できることがわかりました。
おまけ - Exponential
interpolate
の第1引数をexponential
とすると、指数関数的な補間が行われます。ここでは実際にどのような曲線が描かれるのか、また底の値でどのような違いが生じるのかを見てみます。
まず、exponental
選択時に行われる内部での計算ロジックについてはMapbox GL JSのソースコード内にコメントがあります。
exponential
の曲線の概念を表現しているのは以下の式です。
具体的に見てみます。
単調増加
xが増加したときにyも増加するケース。底は0.5, 0.75, 1, 1.25, 1.5。底によって曲線の膨らみ具合が変化していく様子がわかります。
単調減少
xが増加したときにyが減少するケース。底は0.5, 0.75, 1, 1.25, 1.5。このケースでは
Discussion