🦁

Mapbox Newsletter WEEKLY TIPSの解説 -「フィーチャをリアルタイムで更新」

2023/08/16に公開

はじめに

この記事は、先日配信されたMapbox NewsletterのWEEKLY TIPSで紹介されていた「フィーチャをリアルタイムで更新」についての解説です。このサンプルではGeoJSONのデータを動的に変更し表示する方法を例示しています。また、Newsletterの購読はこちらからお申し込みいただけます。

コードを確認

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

日本語サイト

英語サイト

タイトルが日本語訳されていること、Mapbox GL JSのバージョンが異なること以外は同じコードです。

HTML/CSS

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

以下は地図を表示するエレメントです。

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

Mapの作成

次にJavaScriptのコードを見ていきます。以下のコードはいつも通り、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-v9',
  zoom: 0
});

残りのコードはloadイベントのコールバック(map.on('load', async ()=>{}))として実行されます。途中でGeoJSONのデータをfetchで取得するためこのコールバックはasyncとして宣言されています。

さて、通常GeoJSONをソースとして使用する場合はMap#addSourceの引数にURLとして直接指定することが多いです。それに対し、このサンプルではGeoJSONを一度fetchで取得します。これは動的にデータを更新するというデモをする関係上、まず全データのGeoJSONを取得し、そのあと少しずつソースに追加していくためです。

const response = await fetch(
  'https://docs.mapbox.com/mapbox-gl-js/assets/hike.geojson'
);
const data = await response.json();

GeoJSONの中身を確認します。LineStringが一つだけ入っています。
GeoJSON

そしてcoordinatesにLineStringの座標を代入しています。データとしては[経度,緯度]が配列に入ったものです。正確には参照が代入されます。

// save full coordinate list for later
const coordinates = data.features[0].geometry.coordinates;

dataをソース用のデータとして代用すべく、1つ目の座標だけを含む新しい配列を作成してその参照がcoordinatesに代入されます。

// start by showing just the first coordinate
data.features[0].geometry.coordinates = [coordinates[0]];

そして、その1つ目の座標だけを含むGeoJSON(data)をソースとして登録(addSource)し、Lineレイヤーを作成します。

// add it to the map
map.addSource('trace', { type: 'geojson', data: data });
map.addLayer({
  'id': 'trace',
  'type': 'line',
  'source': 'trace',
  'paint': {
    'line-color': 'yellow',
    'line-opacity': 0.75,
    'line-width': 5
  }
});

カメラの中心を1つ目の座標に移動させ、ズームを14、ピッチを30に設定します。

// setup the viewport
map.jumpTo({ 'center': coordinates[0], 'zoom': 14 });
map.setPitch(30);

アニメーションさせるためにsetIntervalで定期的に更新処理を実行します。if (i < coordinates.length)により、元の座標データすべての点が表示されるまで処理が行われます。

data.features[0].geometry.coordinates.push(coordinates[i])i番目の座標をデータの末尾に追加します。map.getSource('trace').setData(data)でソースを更新します。データを更新してもsetDataを呼ばないとソースは更新されないので注意が必要です。そして、map.panTo(coordinates[i])でカメラをi番目の座標に移動させます。

// on a regular basis, add more coordinates from the saved list and update the map
let i = 0;
const timer = setInterval(() => {
  if (i < coordinates.length) {
    data.features[0].geometry.coordinates.push(coordinates[i]);
    map.getSource('trace').setData(data);
    map.panTo(coordinates[i]);
    i++;
  } else {
    window.clearInterval(timer);
  }
}, 10);

まとめ

データが更新されるたびにsetDataで更新するところがポイントでした。移動体の座標データを定期的に取得し、その軌跡を描くといった応用が考えられますね。

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

Discussion