Mapbox Search JS を触ってみる (SearchBox/Core + Minimap編)
はじめに
この記事はMapbox Search JS を触ってみる (SearchBox/React編)の続きで、Search JSのSearchBox/Coreの使い方を見ていきます。Search Box - Search SessionのSearchSessionのExampleを参考にしつつ、使い方を見ていきます。
以下が本サンプルのデモです。テキストボックスに地名や住所を入れてSuggestボタンをクリックします。次にSelectメニューに追加された候補から一つ選択することで地図が表示され、その場所がマーカーで示されます。
Search Box Core と Minimap
Search Box Coreとは
Web/Reactとは異なり、Search JS CoreはUIを持たないSDKです。Search Boxとしてはsuggestやretrieveへのアクセスを簡単にする機能が提供されています。
Search Box APIについては以下の記事もご参照ください。
Minimapとは
MinimapはAddress AutofillやSearch Boxによる検索結果を表示するための地図機能です。MinimapはMapbox GL JSを使用せずに地図を表示する点が重要です。具体的には、検索結果を受け取るとStatic Images APIで検索結果周辺の地図を取得します。画像を一枚表示するだけなので、軽量です。ただし、Mapbox GL JSのようなインタラクティブな地図は作成できません。
コードの記述
それではサンプルを見ていきます。コードは以下のとおりです。
コード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Search Box/Core + Minimap</title>
<script id="search-js" src="https://api.mapbox.com/search-js/v1.0.0-beta.21/core.js"></script>
<script id="search-js" src="https://api.mapbox.com/search-js/v1.0.0-beta.21/web.js"></script>
</head>
<body>
<form id="form-suggest">
<input type="text" id="text-suggest"></input>
<input type="submit" value="Suggest"></input>
</form>
<select></select>
<div style="height: 360px; width: 100%;">
<mapbox-address-minimap></mapbox-address-minimap>
</div>
<script>
const ACCESS_TOKEN = 'YOUR_MAPBOX_ACCESS_TOKEN';
//
// minimap
//
const minimap = document.querySelector('mapbox-address-minimap');
minimap.accessToken = ACCESS_TOKEN;
minimap.defaultMapStyle = ['mapbox', 'outdoors-v11'];
minimap.theme = {
variables: { border: '13px solid #bbb', borderRadius: '18px', boxShadow: '0 2px 8px #000' }
}
//
// Seaerch
//
const search = new mapboxsearchcore.SearchBoxCore({accessToken: ACCESS_TOKEN,language: 'ja', country: 'JP'});
const session = new mapboxsearchcore.SearchSession(search);
let suggestions = [];
session.addEventListener('suggest', (res) => {
console.log('suggest');
console.log(res.suggestions);
suggestions = res.suggestions;
select.replaceChildren();
const addOption = (value, text) => {
const option = document.createElement('option');
option.value = value;
option.text = text;
select.appendChild(option);
};
addOption('', 'Select');
suggestions.forEach((suggestion, index) => {
addOption(index, suggestion.name);
});
});
session.addEventListener('retrieve', (res) => {
console.log('retrieve');
console.log(res);
minimap.feature = res.features[0];
});
document.getElementById('form-suggest').addEventListener('submit', (e) => {
e.preventDefault();
const text = document.getElementById('text-suggest');
session.suggest(text.value);
});
const select = document.querySelector('select');
select.addEventListener('change', (e) => {
if (suggestions.length <= e.target.value) {
return;
}
select.children[0].disabled = true;
session.retrieve(suggestions[e.target.value]);
});
</script>
</body>
</html>
HTML/CSS
ライブラリの読み込み
以下ではライブラリを読み込んでいます。core.js
はSearch Box/Core、web.js
はMinimapで使用します。
<script id="search-js" src="https://api.mapbox.com/search-js/v1.0.0-beta.21/core.js"></script>
<script id="search-js" src="https://api.mapbox.com/search-js/v1.0.0-beta.21/web.js"></script>
検索用のUI
以下では検索ワードを入力するテキストボックスと、検索を開始するSubmitボタンを配置しています。
<form id="form-suggest">
<input type="text" id="text-suggest"></input>
<input type="submit" value="Suggest"></input>
</form>
候補表示のUI
Submitボタンをクリックすると、suggest
を使用して候補を複数取得します。それらの候補を<select>
の中に<option>
として追加します。それらの中から一つ選択すると、retrieve
を用いて詳細データを取得します。
<select></select>
Minimap
Minimapを表示する場所を定義します。
<div style="height: 360px; width: 100%;">
<mapbox-address-minimap></mapbox-address-minimap>
</div>
JavaScript
Minimap
まず最初にMinimapについて記述します。MinimapはMapboxAddressMinimap
というHTMLElement
を継承したクラスで実装されており、mapbox-address-minimap
というCustom Elementで定義されています。このコードではHTML内で記述した<mapbox-address-minimap>
タグに対して設定を行っています。
//
// minimap
//
const minimap = document.querySelector('mapbox-address-minimap');
minimap.accessToken = ACCESS_TOKEN;
minimap.defaultMapStyle = ['mapbox', 'outdoors-v11'];
minimap.theme = {
variables: { border: '13px solid #bbb', borderRadius: '18px', boxShadow: '0 2px 8px #000' }
}
動的にカスタマイズしないのであれば、以下のように<mapbox-address-minimap>
タグ内に直接アクセストークンを記載する方法もあります。
<mapbox-address-minimap access-token="YOUR_MAPBOX_ACCESS_TOKEN"></mapbox-address-minimap>
また、コンテナだけを用意し、タグを使用せずにMapboxAddressMinimap
を動的に作成してもOKです。
const minimapContainer = document.getElementById('minimap-container');
const minimap = new MapboxAddressMinimap();
minimapContainer.appendChild(minimap);
minimap.accessToken = ACCESS_TOKEN;
minimap.defaultMapStyle = ['mapbox', 'outdoors-v11'];
minimap.theme = {
variables: { border: '13px solid #bbb', borderRadius: '18px', boxShadow: '0 2px 8px #000' }
}
MinimapはMinimap#feature
に値が格納されるまで表示されません。また、格納される値はGeoJSONのPointです。
Search Box/Core
次にSearch Boxについて記述します。SearchBoxCore
クラスがsuggest
とretrieve
を実装しているクラスです。また、複数回のsuggest
とretrieve
は一つのセッションとして扱うことができますが、それを簡単に実現するためのSearchSession
クラスでSearchBoxCore
をラップします。
//
// Seaerch
//
const search = new mapboxsearchcore.SearchBoxCore({accessToken: ACCESS_TOKEN,language: 'ja', country: 'JP'});
const session = new mapboxsearchcore.SearchSession(search);
最初にsuggest
の結果を保存しておく配列を作成しておきます。
let suggestions = [];
次に、suggest
を扱う処理です。フォームのSubmitボタンをクリックした際にSearchSession#suggest
を呼び出します。
document.getElementById('form-suggest').addEventListener('submit', (e) => {
e.preventDefault();
const text = document.getElementById('text-suggest');
session.suggest(text.value);
});
SearchSession#suggest
は結果を取得後、suggest
というイベントを発火させます。そこで、そのイベントを監視する処理を記述します。ここでは結果をsuggestions
に格納しつつ、<select>
タグの中に候補を追加します。
session.addEventListener('suggest', (res) => {
console.log('suggest');
console.log(res.suggestions);
suggestions = res.suggestions;
const select = document.querySelector('select');
select.replaceChildren();
const addOption = (value, text) => {
const option = document.createElement('option');
option.value = value;
option.text = text;
select.appendChild(option);
};
addOption('', 'Select');
suggestions.forEach((suggestion, index) => {
addOption(index, suggestion.name);
});
});
最後にretrieve
を扱う処理です。<select>
タグの要素が一つ選択されると、そこからsugessionts
のインデックスを指定してSearchSession#retrieve
に引数として渡します。
const select = document.querySelector('select');
select.addEventListener('change', (e) => {
if (suggestions.length <= e.target.value) {
return;
}
select.children[0].disabled = true;
session.retrieve(suggestions[e.target.value]);
});
SearchSession#retrieve
は結果を取得後、retrieve
というイベントを発火させます。そこで、そのイベントを監視する処理を記述します。ここでは結果をMinimapのfeature
にそのまま代入しています。このタイミングで始めてMinimapが表示されます。
session.addEventListener('retrieve', (res) => {
console.log('retrieve');
console.log(res);
minimap.feature = res.features[0];
});
Minimapのカスタマイズ
Minimap自体はStatic Images APIで取得した画像ですが、マーカーはHTMLElement
として地図の上に重ねて描画されています。そのため、マーカーのアイコンも変更できます。
まずスタイルを作成します。
<style>
.marker {
background-image: url('https://docs.mapbox.com/mapbox-gl-js/assets/pin.svg');
background-size: cover;
cursor: pointer;
width: 100px;
height: 100px;
}
</style>
そして、theme
で設定します。
minimap.theme = {
variables: { border: '13px solid #bbb', borderRadius: '18px', boxShadow: '0 2px 8px #000' },
icons: {marker: '<div class="marker"></div>'}
}
他にも、satelliteToggle
を設定すると、衛星画像へ切り替えるボタンが表示されます。
minimap.satelliteToggle = true;
結果は以下のとおりです。
React版Minimap
MinimapはReactの実装もあります。簡単な使い方は以下のデモをご参照ください。SafariやFirefoxを使用されている方はデモが実行されない可能性があります。Chromeで表示するか、 https://stackblitz.com/edit/vitejs-vite-y4jt2k を直接ご参照ください。
まとめ
Search JS Coreを用いることで、直接APIを操作するよりも簡単に結果を得ることができました。また、Minimapは検索結果を表示するのに便利な軽量の地図であることわがわかりました。
Discussion