📱

Mapbox Newsletter WEEKLY TIPSの解説 -「ユーザーを探す」

2023/11/11に公開

はじめに

この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「ユーザーを探す」についての解説です。これはGeolocateControlの使い方のサンプルです。また、Newsletterの購読はこちらからお申し込みいただけます。

以下が本サンプルのデモです。

ただし、上記デモはiframeで表示している(かつセキュリテイ設定が変更できない)関係上、動作しません。挙動を確認したい場合は以下のリンクをクリックして別タブで表示して試してください。また、CodePenもiframeを用いてコードを実行している関係上、ポリシーの問題でデバイスの向きを表す三角形の表示が出ません。完全な挙動を確認したい場合はExampleのページをご確認ください。

https://codepen.io/OttyLab/pen/jOdBGPJ

使い方

まず、地図右上のボタンをクリックします。
button

次にアドレスバーにダイアログが表示されるので、「許可する」をクリックします(初回のみです)。
dialog

しばらくすると現在位置にカメラが移動し、現在位置が丸い点で表示されます。
result

コードを確認

まずExamplesのコードを見に行きましょう。

日本語サイト

英語サイト

基本的に同じコードですが、英語版はスタイルがMapbox Streets v12にアップグレードされているのでこちらを使用します。Mapbox Streets v11ではデフォルトのプロジェクションがWebメルカトルであるのに対し、Mapbox Streets v12ではGlobe(3D表示された地球)なので、印象がかなり異なります。

HTML/CSS

まずHTMLを見ていきましょう。

以下は地図を表示するエレメントを作成しています。

<div id="map"></div>

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: [-24, 42], // starting center in [lng, lat]
  zoom: 1 // starting zoom
});

GeolocateControlの追加

GeolocateControlIControlを実装したものなので、Map#addControlでマップに追加します。

map.addControl(
  new mapboxgl.GeolocateControl({
    positionOptions: {
      enableHighAccuracy: true
    },
    // When active the map will receive updates to the device's location as it changes.
    trackUserLocation: true,
    // Draw an arrow next to the location dot to indicate which direction the device is heading.
    showUserHeading: true
  })
);

オプションの内容を確認します。

  • positionOptions: GeolocateControlはGeolocation APIを内部で使用していますが、そのGeolocation APIのgetCurrentPositionのオプションに渡す値を指定します。ここではenableHighAccuracy: trueを設定しているので、可能な場合には詳細な現在位置が返されます。
  • trackUserLocation: trueに設定すると、位置情報の更新に対して地図やポイントの位置を追従させます。デフォルトはfalseです。
  • showUserHeading:デバイスの向いている方向を三角形で表示します。デフォルトはfalseです。ちなみにこの機能、当時マップボックス・ジャパンでテクニカルサポートエンジニアをされていたT Suzukiさんが実装したものです。

Android端末で動きを含めた挙動を確認すると以下のようになります。
demo

まとめ

GeolocateControlを用いてユーザの現在位置を表示する方法を確認しました。IControlとして実装されており、数行のコードで実現できることがわかりました。

おまけ

位置情報取得が成功すると自動的にカメラがコントロールされます。この仕組みについて見ていきます。

位置情報が取得されると、_onSuccessが呼ばれます。この中の以下の部分でカメラのコントロールが行われます。

https://github.com/mapbox/mapbox-gl-js/blob/v2.15.0/src/ui/control/geolocate_control.js#L288-L292

_updateCameraでは以下のような処理が行われています。
https://github.com/mapbox/mapbox-gl-js/blob/v2.15.0/src/ui/control/geolocate_control.js#L308-L317

カメラのコントロールはfitBoundsで行われます。このメソッドはMapクラスの親クラスであるCameraクラスで以下のように定義されています。引数にLngLatBoundsLikeを取ります。これは矩形を[[左下],[右上]]の形式で表現するデータ構造で、主に領域を表現するために使用します。つまりfitBoundsは引数として与えられた領域が表示されるようにカメラの座標やズームを適切にコントロールします。
https://github.com/mapbox/mapbox-gl-js/blob/v2.15.0/src/ui/camera.js#L903-L934

さて、ここでは以下のように、取得した位置情報の中心座標(position.coords.longitude, position.coords.latitude)および精度情報(position.coords.accuracy)からtoBoundsを用いてLngLatBoundsLikeを算出しています。

const center = new LngLat(position.coords.longitude, position.coords.latitude);
const radius = position.coords.accuracy;
...

this._map.fitBounds(center.toBounds(radius), options, {
  ...

ということで、位置情報の座標・精度から適切にカメラがコントロールされているんですね。GeolocateControlのドキュメントの以下の記述内容も、これで納得です。

The zoom level applied depends on the accuracy of the geolocation provided by the device.

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

Discussion