Mapbox Newsletter WEEKLY TIPSの解説 -「場所にゆっくり飛ぶ」
はじめに
この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「場所にゆっくり飛ぶ」についての解説です。これはMap#flyToのオプションの使い方のサンプルです。また、Newsletterの購読はこちらからお申し込みいただけます。
以下が本サンプルのデモです。
コードを確認
まずExamplesのコードを見に行きましょう。
日本語サイト
英語サイト
基本的に同じコードですが、英語版はスタイルがMapbox Streets v12にアップグレードされているのでこちらを使用します。Mapbox Streets v11ではデフォルトのプロジェクションがWebメルカトルであるのに対し、Mapbox Streets v12ではGlobe(3D表示された地球)なので、印象がかなり異なります。また、コードの中で3D地形や深いピッチ角を使用することで、より印象的な雰囲気に仕上がっています。
HTML/CSS
まずCSSです。以下は上部中央に表示されているFlyボタンのためのスタイルです。
#fly {
display: block;
position: relative;
margin: 0px auto;
width: 50%;
height: 40px;
padding: 10px;
border: none;
border-radius: 3px;
font-size: 12px;
text-align: center;
color: #fff;
background: #ee8a65;
}
次にHTMLです。以下は地図を表示するエレメントを作成しています。
<div id="map"></div>
以下はFlyボタンです。
<button id="fly">Fly</button>
Mapの作成
次にJavaScriptのコードを見ていきます。
以下はflyToの始点・終点におけるカメラの設定値です。特筆すべきはend.pitchが75に設定されていることです。Mapbox GL JS v2からはピッチが80度まで設定可能になりました(v1は60度)が、ピッチを大きく設定すると水平線と空がカメラに収まるようになります。
const start = {
center: [80, 36],
zoom: 1,
pitch: 0,
bearing: 0
};
const end = {
center: [8.11862, 46.58842],
zoom: 12.5,
bearing: 130,
pitch: 75
};
以下のコードはいつも通り、Mapオブジェクトを作成しています。containerで地図を表示するHTMLエレメントのidを指定します。
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/satellite-streets-v12',
...start
});
...startはオブジェクトリテラルでのスプレッド構文です。以下のように記述したのと同じ効果があります。
const map = new mapboxgl.Map({
container: 'map',
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/satellite-streets-v12',
center: [80, 36],
zoom: 1,
pitch: 0,
bearing: 0
});
スタイルの設定
map.on('style.load', () => {/* ここ */});ではスタイルがロードされたタイミングで行う設定を/* ここ */の部分に記述しています。イベントとしてstyle.loadを使用すると、スタイルのロード直後、描画の直前に実行されるので、ユーザーの目には最初から設定が反映されているように見えます。
Map#setFogはFogの設定を行います。Fogとは空や宇宙の色や、霧っぽさの演出を表現するスタイルです。colorで水平線より下(つまり霧)の色、hight-colorで水平線より上(つまり空)の色を指定します。horizon-blendはこの二色の境界をどれだけぼかすかを指定します。
map.setFog({
'color': 'rgb(220, 159, 159)', // Pink fog / lower atmosphere
'high-color': 'rgb(36, 92, 223)', // Blue sky / upper atmosphere
'horizon-blend': 0.4 // Exaggerate atmosphere (default is .1)
});
試しに'horizon-blend': 0としてみると以下のように二色がくっきりと別れてこれらの設定値の挙動がわかりやすくなります。

続いて3D地形を設定しています。 設定方法はこれ以外ないのでイディオムとして覚えてしまうのが良いかと思います。ソースで読み込んているmapbox.terrain-rgbは標高情報を色情報としてエンコードしたラスタータイルセットです。setTerrainでこのソースを指定することで、内部的にはheight = -10000 + ((R * 256 * 256 + G * 256 + B) * 0.1)という計算で高さを算出し、3D地形を表現します。ちなみに、ソースとしてはmapbox.mapbox-terrain-dem-v1を用いるほうが好ましいです。
map.addSource('mapbox-dem', {
'type': 'raster-dem',
'url': 'mapbox://mapbox.terrain-rgb'
});
map.setTerrain({
'source': 'mapbox-dem',
'exaggeration': 1.5
});
Flyボタンクリック時の挙動
いよいよ本題です。isAtStartは"start -> end"方向なのか"end -> start"方向なのかを管理するためのフラグです。
let isAtStart = true;
Flyボタンがクリックされたときの挙動の定義をコールバックで指定しています。
document.getElementById('fly').addEventListener('click', () => {
//ここ
});
向きによってstart/endどちらが終点になるかを指定し、次回のためにisAtStartをトグルします。
const target = isAtStart ? end : start;
isAtStart = !isAtStart;
いよいよflyToです。説明にもある通り、flyToはCameraOptionsとAnimationOptionsをオプションとして指定可能です。...targetはCameraOptionsに関する設定、durationとessentialはAnimationOptionsに関する設定です。durationは何秒間アニメーションするかです。essentialをtrueにすると、ユーザーがOSの設定でアニメーションを抑制する設定(prefers-reduced-motion)にしていても無視します。
map.flyTo({
...target, // Fly to the selected target
duration: 12000, // Animate over 12 seconds
essential: true // This animation is considered essential with
//respect to prefers-reduced-motion
});
まとめ
いちばん大事なのはflyToのオプションでdurationを指定する部分でした。
Discussion