この記事は「ArcGIS で始める Web マップ アプリ開発」のシリーズ記事として、はじめてマップ アプリ開発を行う方に向けて、ArcGIS Maps SDK for JavaScript を使用した Web マップ アプリ開発の流れをシリーズで連載しています。
第 6 回は、クエリー機能を紹介します。 前回の記事と同様にソースコードは ESRIジャパンの GitHub で公開していますので、ぜひご覧ください。
Web アプリ開発の実行環境をお持ちでない方は、CodePen を使用して、Web ブラウザー上でコードの入力・編集、アプリの実行を試すこともできます。
GIS では、属性検索と空間検索と呼ばれる検索方法を用いて、地図に可視化された位置情報から目的の情報を取得します。
属性検索は、データの属性情報に対して検索を行います。一方、空間検索は、データ間の空間的な関連性(指定した範囲内にあるフィーチャなど)に対する検索を行います。
クエリー機能を使用することで、指定した条件に当てはまるフィーチャを簡単に取得することができます。
これまでの連載で、地価公示レイヤー、市区町村レイヤー、地理院のタイル レイヤーを表示した地図を作成しました。 今回は、市区町村レイヤーを使用して、レイヤーに含まれるフィーチャのうち、指定した市区町村名と一致するフィーチャを探してみます。
市区町村レイヤーの [SIKUCHOSON] フィールドには、市区町村名が含まれています。 この値を利用してクエリーを実行します。
これまでの記事を参考に地図を作成します。
今回は、第 2 回の記事で扱った地価公示レイヤー、市区町村レイヤー、地理院のタイル レイヤーを含んだ Web マップを事前に作成しておきましたので、マップの表示は ID ( fb272eacd46046ed9b4e2371608ef32d )を利用して行います。
<body>
<arcgis-map item-id="fb272eacd46046ed9b4e2371608ef32d">
</arcgis-map>
</body>さて、Web マップを利用する場合は、Web マップに含まれるレイヤーからクエリーを実行するレイヤーをあらかじめ取得しておきます。
Web マップに追加されたレイヤーには一意の ID が付与されるので、ID が一致するレイヤーを変数に代入します。
let cityareaLyr;
webmap.when(() => {
webmap.layers.forEach(layer => {
// レイヤー ID をもとに市区町村レイヤーを取得
if (layer.id === "<レイヤー ID>") {
cityareaLyr = layer;
}
});
});ヒント
レイヤー ID は、Web マップの JSON で確認することができます。 以下の URL から JSON を取得できます。
https://<ポータルドメイン>/sharing/rest/content/items/<アイテムID>/data?f=json
また、ArcGIS Online Assistant では、アイテムの管理や利用に役立つツールがいくつか提供されており、Web マップの JSON を確認することもできます。
クエリーの条件を指定するパラメーターを作成します。 フィーチャ レイヤーに対してクエリーを作成する場合は、FeatureLayer.createQuery() を使用します。
パラメーターとして設定できる条件はいくつかあります。
今回は、属性をもとにクエリーを実行するので、作成したパラメーターに対して、SQL の where 句を利用して、where パラメーターに条件を指定します。
さらに、地図に結果を表示するので、検索結果として返ってくるフィーチャにジオメトリーが含まれるよう returnGeometry を true に設定します。
※ where パラメーターを設定する際はクォーテーションの位置にご注意ください。 where 句に文字列を指定する場合はシングルクォートを使用します。
function doQuery() {
// クエリー パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "SHIKUCHOSON = '" + str + "'";
queryParams.returnGeometry = true;
}
では、クエリーを実行しましょう。
FeatureLayer.queryFeatures() に手順 2 で作成したパラメーターを渡します。
このメソッドは Promise を返すので、then() にクエリーが成功した場合に実行する関数、catch() に失敗したときに実行する関数を指定します。
function doQuery() {
// クエリー パラメーターの作成
// ...
// クエリーの実行
cityareaLyr.queryFeatures(queryParams)
.then(showResult)
.catch(showErr);
}
クエリーを実行すると、結果として、FeatureSet オブジェクトが返ります。
FeatureSet には、フィーチャが配列として含まれます。 フィーチャをもとにグラフィックを作成して地図に結果を描画してみましょう。
function doQuery() {
function showResult(results) {
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(feature => {
feature.symbol = {
type: "simple-marker",
style: "none",
outline: {
color: "#00ffff",
width: "5px"
}
};
return feature;
});
// グラフィックを表示
mapElement.graphics.addMany(graphics);
// グラフィックへズーム
mapElement.goTo(graphics);
}
}ヒント
API リファレンスには、各クラスのページが用意されており、クラスの概要や提供されているメソッド、プロパティ、イベントなどの詳細な情報を知ることができます。
クエリーを実行する FeatureLayer.queryFeatures() を見てみましょう。 メソッドの概要のほかに引数や戻り値がどのような形式なのかを確認することができます。 このメソッドは、引数に Query オブジェクトを指定し、戻り値として FeatureSet オブジェクトが返ることがわかります。
最後に、市区町村名を入力するテキスト ボックスとクエリーを実行するボタンを作成して、UI の操作でクエリーを実行できるようにします。
まず、HTML の body タグにテキスト ボックスとボタンを追加し、各要素を以下のように更新します。
<div id="controls">
<div id="queryToggle">
<input type="text" value="" placeholder="八王子市" id="attrTxt"/>
<input type="button" value="検索" id="queryButton"/>
</div>
</div>次に、ボタンのクリックでクエリーを実行するようにイベント ハンドラーを作成します。
さらに、手順2で作成したパラメーターをテキスト ボックスから取得した値を使用するように変更します。
// 検索ボタンのイベント ハンドラー
document.getElementById("queryButton").addEventListener("click", doQuery);
// クエリーの実行
function doQuery() {
// 前回のクエリー結果を削除
mapElement.graphics.removeAll();
// input 要素に入力された文字列を取得
const str = document.getElementById("attrTxt").value;
// クエリー パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "CITY = '" + str + "'";
queryParams.returnGeometry = true;
// クエリーの実行
//...
}コードを実行してみましょう。
検索ボタンをクリックすると、テキスト ボックスに入力した市区町村名と一致するフィーチャを取得して地図上でハイライト表示します。
ここでは、ステップアップとして、これまでの手順で取得した市区町村のフィーチャを利用して空間検索を行ってみましょう。
地価公示レイヤーから、取得した市区町村のフィーチャに含まれるフィーチャを表示します。 このように、『あるフィーチャに「含まれる」フィーチャ』、というような空間的な関連性を求めるためのクエリーは空間検索と呼ばれます。
手順1を参考に、地価公示レイヤーを取得します。
mapElement.map.allLayers.forEach((layer) => {
// レイヤー ID をもとにレイヤーを取得
if (layer.id === "1999e774d4c-layer-6") {
// 市区町村界レイヤー
cityareaLyr = layer;
} else if (layer.id === "1999e73db2f-layer-5") {
// 地価公示価格レイヤー
chikakojiLyr = layer;
}
});
空間検索では、検索に使用するジオメトリーを指定する geometry オプションと、指定したジオメトリーと検索対象のフィーチャとの空間的な関連性を定義する spatialRelationship オプションをパラメーターに設定します。
今回は、地価公示レイヤーのうち、市区町村フィーチャに『含まれる』フィーチャを取得したいので、geometry オプションに、ステップ 4 で取得した市区町村フィーチャを設定し、spatialRelationship オプションに contains を指定します。
// クエリーの実行
function doQuery() {
//...
// クエリーの実行
cityareaLyr.queryFeatures(queryParams)
.then(showCityArea)
.then(queryChikakoji)
.then(showChikakoji)
.catch(showErr);
}
// 市区町村の表示
function showCityArea(results) {
// 結果フィーチャ数が 0 よりおおきいとき
if (results.features.length > 0) {
//...
// 空間検索で使用するためのフィーチャを返す
return results.features;
}
};
// 地価公示の取得
function queryChikakoji(features) {
// クエリー パラメーターの作成
const queryParams = chikakojiLyr.createQuery();
queryParams.geometry = features[0].geometry;
queryParams.spatialRelationship = "contains";
queryParams.where = "1 = 1";
queryParams.returnGeometry = true;
// クエリーの実行
return chikakojiLyr.queryFeatures(queryParams);
};
手順 4 を参考に、クエリーの結果からグラフィックを作成して地図に描画します。
さらに、今回は、取得したフィーチャの数を表示します。
// クエリーの結果を表示
function showChikakoji(results) {
// 結果フィーチャ数が 0 より大きいとき
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(feature => {
feature.symbol = {
type: "simple-marker",
color: "#00ff80",
size: "12px"
};
return feature;
});
// グラフィックを表示
mapElement.graphics.addMany(graphics);
// グラフィックへズーム
mapElement.goTo(graphics);
// フィーチャ数を表示
const count = results.features.length;
document.getElementById("resultText").innerHTML = "地価公示地点:" + count + " 箇所";
}
};HTML にフィーチャ数を表示する要素を追加します。
<div id="controls">
<!-- 省略 -->
<div id="resultText"></div>
</div>では、サンプルを開いてみましょう。
テキスト ボックスに入力した市区町村にある地価公示フィーチャが表示されましたか?
クリアボタンを作成して、UI の操作で追加したグラフィックを削除できるようにします。
まず、HTML の body タグにボタンを追加し、各要素を以下のように更新します。
<div id="controls">
<div id="layerToggle"></div>
<div id="queryToggle">
<input type="text" value="" placeholder="八王子" id="attrTxt" />
<input type="button" value="検索" id="queryButton" />
<input type="button" value="クリア" id="clearButton" />
</div>
<div id="resultText"></div>
</div>次に、ボタンのクリックで初期化 処理を実行するようにイベント ハンドラーと処理を追加します。
// 初期化処理
document.getElementById("clearButton").onclick = () => {
// 入力値、クエリー結果を削除
view.graphics.removeAll();
document.getElementById("resultText").innerHTML = "";
document.getElementById("attrTxt").value = "";
}今回作成したサンプルは以下で動作を確認することも可能です。
本記事では、クエリー機能の基本をご紹介しました。属性検索や空間検索は、ユーザーが地図上の情報を効率的に取得・活用するうえで不可欠です。ぜひ本記事の内容を参考に、実践的なアプリ開発にお役立てください。
・ArcGIS Maps SDK for JavaScript ESRIジャパン Web サイト
・ArcGIS Maps SDK for JavaScript 米国Esri社 Web サイト
・ArcGIS Maps SDK for JavaScript - Components