🚗

Google Maps PlatformとReactで実現するルート検索機能

に公開

はじめに

こんにちは。第四開発部の富田です。
皆さんは Google Maps を使って普段どんなことをしていますか?
行きたい場所までのルートを調べることが多いのではないでしょうか。

ウェブアプリケーションやモバイルアプリケーションにおいて、ユーザーが出発地から目的地までのルートを検索できる機能は非常に価値が高いものです。Google Maps Platform は、このルート検索機能を実現するための強力なツール群を提供しています。
本記事では、特に React アプリケーションでルート検索機能を実装する方法を解説します。

ルート検索機能の実装

Google Maps Platform を利用してアプリケーションにルート検索機能を組み込むためのステップを見ていきましょう。

作るもののイメージ

完成イメージとしては、以下のような画面となります。
alt

Google Maps Platform 導入方法

導入方法については以下の記事で解説していますので、参考にしてください。

また、上記記事でAPIを有効化する手順がありますが、今回は以下を有効にしてください。

  • Maps JavaScript API
  • Directions API

マップの表示の基本方法(React)

ReactアプリケーションでGoogle Maps JavaScript APIを扱うには、専用のライブラリを使用するのが一般的です。
今回は @vis.gl/react-google-maps ライブラリを用いた方法を解説しています。

Directions ServiceとDirections Rendererの利用

Maps JavaScript APIでは、ルート検索のロジックと表示を分担する主要なオブジェクトとして、Directions ServiceDirections Renderer が提供されています。

実装の流れとしては、

  1. Directions Service を呼び出し、DirectionsResult オブジェクトを取得します
  2. DirectionsResult オブジェクトを Directions Renderer に渡して、マップにルートを描画します

というものになります。

では詳しく見ていきましょう。

1. Directions Service の呼び出し

Directions Service(ルートサービス)は、指定された条件(出発地、目的地、交通手段、経由地など)に基づいてルート計算を行うためのオブジェクトです。
このサービスは、Google Maps API の Directions Service と通信し、その結果として DirectionsResult オブジェクトを返します。

リクエストの際には、route()メソッドにリクエストを渡します。
DirectionsRequest オブジェクトで指定できる主要なパラメータには以下のようなものがあります。

  • origin: 出発地
  • destination: 目的地
  • travelMode: 交通手段 (DRIVING, WALKING, BICYCLING, TRANSITなど)
  • waypoints: 経由地の配列

origin, destination, waypoints には緯度経度情報の他、地名や住所などのテキスト情報を渡すことも可能です。

app/route/page.tsx
const [directionsService, setDirectionsService] = useState<google.maps.DirectionsService | null>(null);
setDirectionsService(new routesLibrary.DirectionsService());

const request: google.maps.DirectionsRequest = {
  origin: props.origin as google.maps.LatLng | google.maps.LatLngLiteral,
  destination: props.destination as
    | google.maps.LatLng
    | google.maps.LatLngLiteral,
  travelMode: google.maps.TravelMode.DRIVING,
};

directionsService
  .route(request)
  .then((response) => {
    // Directions Result を受け取ったあとの処理を記述
  })
  .catch((error) => {
    console.error('Direction service error:', error);
  });

2. Directions Renderer でのルート描画

Directions Renderer は、Directions Service から取得した DirectionsResult オブジェクトを受け取り、その内容を地図上に自動的に描画する役割を担います。
ルート経路をポリラインで表示したり、出発地、目的地、経由地にマーカーを設置したりする処理を開発者が個別に実装する必要がなくなります。
Directions Renderer は、地図オブジェクトに関連付けることで機能します。また、オプションで指定したHTML要素(通常は <div>)に、テキスト形式の経路案内を表示させることも可能です。

Directions Renderer の基本的な使用手順は以下の通りです。

  1. google.maps.DirectionsRenderer のインスタンスを作成します。
  2. setMap() メソッドで、ルートを表示したい地図オブジェクトに関連付けます。
  3. DirectionsService.route() で得られた DirectionsResult を setDirections() メソッドに渡して、ルートを描画します。
app/route/page.tsx
const [directionsRenderer, setDirectionsRenderer] =
  useState<google.maps.DirectionsRenderer>();
const renderer = new routesLibrary.DirectionsRenderer({
  draggable: false,
  map
});
setDirectionsRenderer(renderer);

directionsService
  .route(request)
  .then((response) => {
    // directions Service が受け取ったレスポンスを directions Renderer に渡す
    directionsRenderer.setDirections(response);
    setRoutes(response.routes);
  })
  .catch((error) => {
    console.error('Direction service error:', error);
  });

これらのメソッドは、setDirections() に新しい結果が渡されるたびに地図上の表示を自動的に更新します。これにより、React のような宣言的なUIフレームワークで状態(検索結果)が更新された際に、地図表示もリアクティブに追従させやすくなります。

全体のコード例

app/route/page.tsx
'use client';

import {
  APIProvider,
  Map,
  useMap,
  useMapsLibrary
} from '@vis.gl/react-google-maps';
import { useEffect, useRef, useState } from 'react';

const API_KEY = 'YOUR_API_KEY';

export const MapView = () => (
  <APIProvider apiKey={API_KEY}>
    <div className="h-full">
      <MapContent />
    </div>
  </APIProvider>
);

const MapContent = () => {
  return (
    <>
      <Map
        defaultZoom={8}
        defaultCenter={CENTER_LATLNG}
        gestureHandling={'greedy'}
      >
        <Directions
          origin={ORIGIN_LATLNG}
          destination={DESTINATION_LATLNG}
          waypoint={[]}
        />
      </Map>
			<div>
        <ControlPanel />
      </div>
    </>
  );
};

/*** ルート検索コンポーネント ***/
const Directions = (props: directionsProps) => {
  const map = useMap();
  const routesLibrary = useMapsLibrary('routes');
  const [directionsService, setDirectionsService] =
    useState<google.maps.DirectionsService>();
  const [directionsRenderer, setDirectionsRenderer] =
    useState<google.maps.DirectionsRenderer>();
  const directionsRendererRef = useRef<google.maps.DirectionsRenderer | null>(
    null
  );
  const [routes, setRoutes] = useState<google.maps.DirectionsRoute[]>([]);

  // ルートサービスとレンダラーを初期化
  useEffect(() => {
    if (!routesLibrary || !map) return;
    setDirectionsService(new routesLibrary.DirectionsService());
    const renderer = new routesLibrary.DirectionsRenderer({
      draggable: false,
      map
    });

    setDirectionsRenderer(renderer);
  }, [routesLibrary, map]);

  useEffect(() => {
    if (!directionsRenderer) return;
    directionsRendererRef.current = directionsRenderer;
  }, [directionsRenderer]);

  useEffect(() => {
    if (!directionsService || !directionsRenderer) return;
    if (!props.origin || !props.destination) return;

	// リクエストを作成
    const request: google.maps.DirectionsRequest = {
      origin: props.origin as google.maps.LatLng | google.maps.LatLngLiteral,
      destination: props.destination as
        | google.maps.LatLng
        | google.maps.LatLngLiteral,
      travelMode: google.maps.TravelMode.DRIVING,
      provideRouteAlternatives: true
    };

    // 経由地の指定がある場合追加
    if (props.waypoint) {
      request.waypoints = props.waypoint.map((point) => ({
        location: point,
        stopover: true
      }));
    }

	// リクエストと描画
    directionsService
      .route(request)
      .then((response) => {
        directionsRenderer.setDirections(response);
        setRoutes(response.routes);
      })
      .catch((error) => {
        console.error('Direction service error:', error);
      });
  }, [
    directionsService,
    directionsRenderer,
    props.origin,
    props.destination,
    props.waypoint,
  ]);

  return (
    <div className="directions">
    </div>
  );
}

/*** コントロールパネル(省略) ***/
const ControlPanel = () => {
	return (...)
}

まとめ

今回は、React アプリケーションにルート検索機能を実装する基本的な方法を解説しました。
Directions Service と Directions Renderer を使用することで簡単にルート機能を実装できます。ぜひ試してみてください。

Discussion

OSZAR »