Esri Leaflet Tips では Leaflet.js と ArcGIS を組み合わせてできることを紹介しています。
前回は Esri Leaflet ※という ArcGIS 連携のための Leaflet プラグインを使って、ArcGIS の住所検索サービスを利用した検索フォームを実装してみました。
さて、今回はもう少し GIS (Geographic Information System:地理情報システム) 的な機能として空間フィルタリングを Leaflet.js で実装してみましょう。
空間フィルタリング (あるいは空間検索) とはその言葉の通り、ある特定のエリア内に存在するデータのみを抽出する作業です。
言葉の定義については、弊社で公開している GIS 基礎解説 (空間検索) に詳しいです。
よく使われる例としては、駅から半径 xx メートル以内の店舗を抽出して最寄りの店舗を地図上に可視化したり、地図に表示されている範囲に含まれる施設情報をテーブル表示したりといった機能が挙げられます。
空間フィルタリングをする際には抽出する対象となるデータが何なのかで実装方法が異なります。
Leaflet を含め、地理情報を記述するデータ フォーマットとしては GeoJSON がポピュラーですが、ArcGIS のクラウドで配信可能な GeoServices API (ArcGIS REST API とも呼ばれます) という形式を利用することで、いわゆるクエリに応じた空間判定の結果を動的に取得することが可能です。
ArcGIS のクラウド上にある GIS サーバー側で空間的な処理を行ってくれるため、複雑なエリアを対象とした空間フィルタリングでも、REST API さえ理解していれば実現できることが大きなメリットです。
また、前回の記事で紹介した住所検索やルート案内などの交通ネットワーク解析もすべて GeoServices API として配信されています。
さて、では本題に入りましょう。
L.esri.Query
今回は Esri Leaflet の L.esri.Query クラスを利用します。
L.esri.Query とは ArcGIS にホストしたデータに対して where 句での属性検索や空間領域に含まれるかどうかといった空間検索を処理するためのリクエストを発行し、検索結果として位置情報 (座標) と属性情報を GeoJSON 形式で取得することができます。
L.esri.Query にはいくつかのメソッドが用意されており、多様な属性/空間検索に対応できます。
以下に代表的なメソッドを紹介します。
メソッド | 説明 |
---|---|
within(<Geometry> geometry) | 引数のジオメトリに含まれるデータの取得 |
contains(<Geometry> geometry) | 引数のジオメトリに完全に含まれるデータの取得 |
intersects(<Geometry> geometry) | 引数のジオメトリと交差するデータの取得 |
nearby(<LatLng> latlng, <Integer> distance) | 引数の中心緯度経度と距離に含まれるデータの取得 |
where(<String> where) | where 句によって引数に指定した属性条件に一致するデータの取得 |
returnGeometry(<Boolean> returnGeometry) | 座標情報の取得の有無 (属性情報のみでよければ false) |
orderBy(<String> fieldName, <String> order) | 引数に指定した属性フィールドをもとに結果 (配列) の順序を指定 |
なお、これらをメソッドチェーンでつなぐことで複数の条件を1つのクエリとして実行することも可能です。
以下の例は、ある範囲内に含まれてかつ施設種別がコンビニで ID を昇順で結果を返すという条件を定義しています。
query.within(bounds).where("type='コンビニエンスストア'").orderBy('id', 'ASC');
空間フィルタリングをやってみる
前置きはここまでで、ここからは実際に空間フィルタリングを実装してみましょう。
わかりやすく冒頭で例として挙げていたように、「駅から半径 xx メートル以内の店舗を抽出して最寄りの施設を地図上に可視化」してみましょう。
実際のデモはこちら。
この機能の実装に必要なフローを整理してみます。
1 は前回紹介した L.esri.Geocoding.Geosearch が使えそうです。
ArcGIS の住所検索サービスは駅名や施設名のような POI にも対応しているので、住所検索フォームから駅名を入力して、検索結果をバッファー生成の中心点として利用します。
検索結果の座標値は results イベントで拾えます。
詳しくは前回の記事をご覧ください。
続いて、2 のバッファーの表示には L.Circle を使います。
// 検索結果用の空レイヤー(住所検索) var results = L.layerGroup().addTo(map); ... // 住所検索結果のバッファー表示 results.addLayer(L.circle(resultLatlng, r));
3 と 4 のクエリ生成と検索結果の表示です。
まずクエリの初期化の際に、施設データ (今回は保育園のオープンデータを使用) の配信 URL を設定します。
今回は L.esri.Query の nearby() メソッドを使います。
このメソッドは中心座標と半径を引数に与えることで、バッファー内に含まれるデータを検索することができます。
query.run() のコールバック関数内で取得できる検索結果 (featureCollection) をあらかじめ用意しておいた L.geoJson のレイヤーに追加して地図に表示をします。
// 検索結果用の空レイヤー(空間検索) var filterResults = L.geoJson(null, { onEachFeature: function (feature, layer) { layer.bindPopup(feature.properties['施設名']); } }).addTo(map); ... // 空間検索用クエリの初期化 var query = L.esri.query({ url: 'https://services.arcgis.com/wlVTGRSYTzAbjjiC/arcgis/rest/services/%E4%BF%9D%E8%82%B2%E5%9C%9223%E5%8...' }); query.nearby(resultLatlng, r); // クエリの実行 query.run(function(error, featureCollection, response){ // クエリ結果の表示 filterResults.addData(featureCollection); });
いかがでしたでしょうか?
クラウドにデータをアップロードして配信するだけで、空間フィルタリングのようなクエリの API を利用できるのは GeoServices API (ArcGIS REST API) の強みです。
DB × サーバー API 実装の組み合わせで一から空間的な機能を作らずとも、ArcGIS にサインアップするだけで開発/運用環境として GeoServices API 配信のための GIS サーバー機能を手に入れることができます。
クエリの API をサポートしたデータ配信の詳細は以下を参考にしてください。
開発あるいは非商用目的での公開 (個人/NPO/NGO/教育機関のみ) は無償でできます。
気軽に GeoServices API の威力をご自身の目で確認してみてください。
これからも、引き続き Esri Leaflet で実現できるおもしろい機能を紹介していきたいと思います。
※ Esri Leaflet は弊社での技術サポートは行っておりませんが、GitHub リポジトリにてバグ・課題の報告やプルリクエストによる改善が可能です
関連リンク