🗺️

Mapbox Search JS を触ってみる (SearchBox/Core + Minimap編)

2024/06/20に公開

はじめに

この記事は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としてはsuggestretrieveへのアクセスを簡単にする機能が提供されています。

Search Box APIについては以下の記事もご参照ください。

https://zenn.dev/ottylab/articles/cc176f72c29a16#search-box-apiとは

Minimapとは

MinimapはAddress AutofillやSearch Boxによる検索結果を表示するための地図機能です。MinimapはMapbox GL JSを使用せずに地図を表示する点が重要です。具体的には、検索結果を受け取るとStatic Images APIで検索結果周辺の地図を取得します。画像を一枚表示するだけなので、軽量です。ただし、Mapbox GL JSのようなインタラクティブな地図は作成できません。

コードの記述

それではサンプルを見ていきます。コードは以下のとおりです。

コード
index.html
<!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クラスがsuggestretrieveを実装しているクラスです。また、複数回のsuggestretrieveは一つのセッションとして扱うことができますが、それを簡単に実現するための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の実装もあります。簡単な使い方は以下のデモをご参照ください。SafariFirefoxを使用されている方はデモが実行されない可能性があります。Chromeで表示するか、 https://stackblitz.com/edit/vitejs-vite-y4jt2k を直接ご参照ください。

まとめ

Search JS Coreを用いることで、直接APIを操作するよりも簡単に結果を得ることができました。また、Minimapは検索結果を表示するのに便利な軽量の地図であることわがわかりました。

GitHubで編集を提案
マップボックス・ジャパン合同会社

Discussion