ArcGIS Platform は、ロケーションサービスを Platform as a Service (PaaS) として提供します。高品質・高機能なロケーションサービスを使用して、位置情報をアプリやビジネスシステムに統合することができます。ロケーションサービスは、ArcGIS の API/SDK、ローコードツールはもちろん Leaflet や Mapbox GL JS、OpenLayers などの OSS でも使用できます。
今回は、以前開催した「ArcGIS Platform 活用ウェビナー ~オープンソースのライブラリを使用した地図アプリ開発ハンズオン~」でご紹介した OSS の Leaflet と Esri が提供するロケーションサービスを使用したルート検索アプリの作成についてご紹介していきます。
完成版のソースコードは GitHub で公開していますので、そちらも参考にしてください。
今回のアプリ作成に使用している3つのライブラリについてご紹介します。
Leaflet は、メジャーで軽量なオープンソースのマッピング JavaScript ライブラリです。Leaflet は主に地図の表示や地図内に表示されるレイヤーの処理などを得意としています。 Esri Leaflet は、Esri 開発者アカウントの API キーを使用して、ロケーションサービスにアクセスする Leaflet のプラグインです。今回作成するアプリでは Esri Leaflet を背景地図の表示と地名検索の機能を実装するために使用しています。
ArcGIS REST JS は、ArcGIS REST API の JavaScript ベースのラッパーです。今回は、こちらを使用することでルート検索を実装していきます。
上記3つのライブラリを使用して、ルート検索アプリを作成していきます。
始めに地図の表示から実装していきます。
Esri Leaflet にはいくつかプラグインがあり、その1つに Esri の提供するベクタータイル ベースマップを背景地図として利用できる Esri leaflet vector があります。今回はこちらを参照します。
<!-- CDN から Leaflet の css と js を参照 -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<!-- CDN から esri-leaflet の js を参照 -->
<script src="https://unpkg.com/esri-leaflet@3.0.3/dist/esri-leaflet.js"></script>
<!--Esri のベクタータイルを使用するため CDN から esri-leaflet-vector の js を参照 -->
<script src="https://unpkg.com/esri-leaflet-vector@3.1.0/dist/esri-leaflet-vector.js"></script>
次に地図を表示する場所の指定と API キーの設定を行います。また、 L.esri.Vector.vectorBasemapLayer メソッドを使用し、Esri のベクタータイル ベースマップを指定します。
// API キーを入力
const apiKey="YOUR_API_KEY";
const basemap = "OSM:Streets";
// マップを描画する場所を東京駅上空に指定
const map = L.map('map', {
minZoom: 2
}).setView([35.68109305881504, 139.76717512821057], 14);
// Esri のベクタータイルをベースマップに設定
L.esri.Vector.vectorBasemapLayer(basemap, {
apiKey: apiKey
}).addTo(map);
ここまでできていれば、以下のように東京駅を中心とした地図が表示されます。
上記の画像で示した背景地図だけではなく、他にも多くのベクタータイル ベースマップを提供しています。それらに関しては、ベクタータイル ベースマップを選択するサンプルが用意されているので、そちらをご参考にしてください。
今回のルート検索アプリでは、地名や住所からもルート検索を行いたいと考えています。そこで、今回は Esri Leaflet のプラグイン Esri leaflet geocoder を参照して、地名検索の機能を導入します。
<!-- CDN から esri-Leaflet-geocoder の css と js を参照 -->
<link rel="stylesheet" href="https://unpkg.com/esri-leaflet-geocoder@3.1.1/dist/esri-leaflet-geocoder.css"
integrity="sha512-IM3Hs+feyi40yZhDH6kV8vQMg4Fh20s9OzInIIAc4nx7aMYMfo+IenRUekoYsHZqGkREUgx0VvlEsgm7nCDW9g==" crossorigin="">
<script src="https://unpkg.com/esri-leaflet-geocoder@3.1.1/dist/esri-leaflet-geocoder.js"integrity="sha512-enHceDibjfw6LYtgWU03hke20nVTm+X5CRi9ity06lGQNtC9GkBNl/6LoER6XzSudGiXy++avi1EbIg9Ip4L1w==" crossorigin=""></script>
L.esri.Geocoding.geosearch を使用して、地名検索を行うボタンを地図上に表示し、地名検索の機能を導入しています。ここでは、地名検索を実行した後、その位置にマーカーを立てるまでの機能を実装します。
const searchControl = L.esri.Geocoding.geosearch({
position: 'topleft', // 検索窓をどこに配置するかを指定
placeholder: '住所または場所の名前を入力',
useMapBounds: false, // 全世界を対象に検索
providers: [L.esri.Geocoding.arcgisOnlineProvider({
apikey: apiKey
})]
}).addTo(map);
let searchlayers=L.layerGroup().addTo(map);
searchControl.on('results', function (data) {
if(data.results){
coordinates = data.results[0].latlng;
searchlayers.clearLayers(); //前回の結果を削除
L.marker(coordinates).addTo(searchlayers);
}
});
これらを実装することで、以下の動画のように地名検索を行うことができます。
ArcGIS REST JS を使用して、ルート検索を導入していきます。以下では、ArcGIS REST JS で使用するライブラリの参照を追加します。
<!-- CDN から ArcGIS REST JS の js を参照 -->
<script src="https://unpkg.com/@esri/
arcgis-rest-request@3.0.0/dist/umd/request.umd.js"></script>
<script src="https://unpkg.com/@esri/
arcgis-rest-routing@3.0.0/dist/umd/routing.umd.js"></script>
<script src="https://unpkg.com/@esri/
arcgis-rest-auth@3.0.0/dist/umd/auth.umd.js"></script>
ルート検索を行うには、始点と終点となる地点を含む2点以上の位置情報が必要になります。今回は、始点と終点の2点が用意された時に実行するようなイベントを実装しています。
const directions=document.getElementById("directions");
const startLayerGroup = L.layerGroup().addTo(map);
const endLayerGroup = L.layerGroup().addTo(map);
const routeLines = L.layerGroup().addTo(map);
let currentStep = "start";
let startCoords, endCoords;
// ルート検索をしたい始点終点を決めるための関数
function addstoppoint(){
if (currentStep === "start") {
startLayerGroup.clearLayers();
endLayerGroup.clearLayers();
routeLines.clearLayers();
L.marker(coordinates).addTo(startLayerGroup); // 始点にマーカーを作成
startCoords = [coordinates.lng,coordinates.lat];
currentStep = "end";
} else {
L.marker(coordinates).addTo(endLayerGroup); // 終点にマーカーを作成
endCoords = [coordinates.lng,coordinates.lat];
currentStep = "start";
}
if (startCoords && endCoords) {
searchRoute(); // 始点と終点ができたらルート検索を実行
}
}
// ルート検索を実行する関数
function searchRoute() {
// arcgis-rest-js を利用するための認証用の変数を用意。
const authentication = new arcgisRest.ApiKey({
key: apiKey
});
arcgisRest.solveRoute({
stops: [startCoords, endCoords],
endpoint: "https://route-api.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World/solve",
authentication,
params:{directionsLanguage:"ja"} // 使用言語を日本語に変更
})
.then((response) => {
L.geoJSON(response.routes.geoJson).addTo(routeLines);
const directionsHTML = response.directions[0].features.map((f) => f.attributes.text).join("<br/>");
directions.innerHTML = directionsHTML;
startCoords = null; // 最後に始点、終点の位置情報をリセット
endCoords = null;
})
.catch((error) => {
console.error(error);
alert("ルート検索に失敗しました<br>始点と終点の情報をリセットします");
startCoords = null; // エラー時にも始点、終点の位置情報をリセット
endCoords = null;
});
}
map.on("click", (e) => {
coordinates = e.latlng;
addstoppoint();
});
上記のように実装することで、以下の動画のように地図上をクリックした二点の位置情報を用いたルート検索の機能を実装することができました。
最後に地名検索をした場所をルート検索に使用するために地名検索を実装した際に追加していた `searchControl.on` を書き換えていきます。
searchControl.on('results', function (data) {
if(data.results){
coordinates = data.results[0].latlng;
addstoppoint();
}
});
このように書き換えることで以下のようにクリックと地名検索でルート検索を行う Web アプリを作成することができました。
今回は、オープンソースのライブラリを使用してルート検索アプリを作成しました。今回使用したサービスだけではなく、様々なロケーションサービスを Esri Leaflet や ArcGIS REST JS から簡単に使用できるので、ぜひ試してみてください。今回作成したルート検索アプリについては、GitHub にて詳細な解説とソースコードを公開しているのでそちらも参考にしてください。また、このルート検索アプリの発展形として Esri のデザインフレームワークを Web Components にした Calcite Design System を用いたサンプルも公開しているので参考にしてください。