この記事は「はじめてのWeb マッピングアプリケーション開発」のシリーズ記事として、はじめて地図アプリ開発を行う開発者の方に向けて、ArcGIS API for JavaScript を使用した Web アプリ開発の流れをシリーズで連載しています。
第7回は、クエリ機能を紹介します。前回の記事と同様にソースコードは ESRIジャパンの GitHub で公開しています(※2022年2月追記:”ファイル名.html” が2018年時のサンプル、”ファイル名_2021.html” が2022年に書き換えしたサンプルです)ので、ぜひご覧ください。
Web アプリ開発の実行環境をお持ちでない方は、JSBin を使用して、Web ブラウザー上でコードの入力・編集、アプリの実行を試すこともできます。
Tips
GIS では、属性検索と空間検索と呼ばれる検索方法を用いて、地図に可視化された位置情報から目的の情報を取得します。
属性検索は、データの属性情報に対して検索を行います。一方、空間検索は、データ間の空間的な関連性(指定した範囲内にあるフィーチャなど)に対する検索を行います。
クエリ機能を使用することで、指定した条件に当てはまるフィーチャを簡単に取得することができます。
クエリの実行
これまでの連載で、地価公示レイヤー、市区町村レイヤー、地理院のタイル レイヤーを表示した地図を作成しました。今回は、市区町村レイヤーを使用して、レイヤーに含まれるフィーチャのうち、指定した市区町村名と一致するフィーチャを探してみます。
市区町村レイヤーの [SIKUCHOSON] フィールドには、市区町村名が含まれています。この値を利用してクエリを実行します。
1. 地図の作成
これまでの記事を参考に地図を作成します。
今回は、第5回「Web マップの作成・表示編」をもとに進めていきます。
さて、Web マップを利用する場合は、Web マップに含まれるレイヤーからクエリを実行するレイヤーをあらかじめ取得しておきます。
Web マップに追加されたレイヤーには一意の ID が付与されるので、ID が一致するレイヤーを変数に代入します。
let cityareaLyr;
webmap.when(function() {
webmap.layers.forEach(function(layer) {
//...
// レイヤー ID をもとに市区町村レイヤーを取得
if (layer.id === "<レイヤー ID>") {
cityareaLyr = layer;
}
});
});
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
let cityareaLyr;
webmap.when(() => {
webmap.layers.forEach(layer => {
//...
// レイヤー ID をもとに市区町村レイヤーを取得
if (layer.id === "<レイヤー ID>") {
cityareaLyr = layer;
}
});
});
Tips
レイヤー ID は、Web マップの JSON で確認することができます。以下の URL から JSON を取得できます。
- https://<portalurl> /sharing/rest/content/items/<webmapid>/data?f=json
また、ArcGIS Online Assistant では、アイテムの管理や利用に役立つツールがいくつか提供されており、Web マップの JSON を確認することもできます。
2. クエリ パラメーターの作成
クエリの条件を指定するパラメーターを作成します。フィーチャ レイヤーに対してクエリを作成する場合は、FeatureLayer.createQuery() を使用します。
パラメーターとして設定できる条件はいくつかあります。
今回は、属性をもとにクエリを実行するので、作成したパラメーターに対して、SQL の where 句を利用して、where パラメーターに条件を指定します。
さらに、地図に結果を表示するので、検索結果として返ってくるフィーチャにジオメトリが含まれるよう returnGeometry を true に設定します。
※ where パラメーターを設定する際はクォーテーションの位置にご注意ください。where 句に文字列を指定する場合はシングルクォートを使用します。
function doQuery() {
// クエリ パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "SIKUCHOSON = '<市区町村名>'";
queryParams.returnGeometry = true;
}
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
function doQuery() {
// クエリ パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "SIKUCHOSON = '<市区町村名>' + str + "' AND JCODE LIKE '23%'";
queryParams.returnGeometry = true;
}
3. クエリの実行
では、クエリを実行しましょう。
FeatureLayer.queryFeatures() に手順2で作成したパラメーターを渡します。
このメソッドは Promise を返すので、then() にクエリが成功した場合に実行する関数、catch() に失敗したときに実行する関数を指定します。
function doQuery() {
// クエリ パラメーターの作成
// ...
// クエリの実行
cityareaLyr.queryFeatures(queryParams)
.then(showResult)
.catch(showErr);
}
4. 結果の描画
クエリを実行すると、結果として、FeatureSet オブジェクトが返ります。
FeatureSet には、フィーチャが配列として含まれます。フィーチャをもとにグラフィックを作成して地図に結果を描画してみましょう。
function showResult(results) {
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(function(feature) {
const graphic = feature.clone();
graphic.symbol = {
type: "simple-marker",
style: "none",
outline: {
color: "#00ffff",
width: "5px"
}
};
return graphic;
});
// グラフィックを表示
view.graphics.addMany(graphics);
// グラフィックへズーム
view.goTo(graphics);
}
}
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
function showResult(results) {
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(feature => {
const graphic = feature.clone();
graphic.symbol = {
type: "simple-marker",
style: "none",
outline: {
color: "#00ffff",
width: "5px"
}
};
return graphic;
});
// グラフィックを表示
view.graphics.addMany(graphics);
// グラフィックへズーム
view.goTo(graphics);
}
}
Tips
API リファレンスには、各クラスのページが用意されており、クラスの概要や提供されているメソッド、プロパティ、イベントなどの詳細な情報を知ることができます。
クエリを実行する FeatureLayer.queryFeatures() を見てみましょう。メソッドの概要のほかに引数や戻り値がどのような形式なのかを確認することができます。このメソッドは、引数に Query オブジェクトを指定し、戻り値として FeatureSet オブジェクトが返ることがわかります。
5. UI の実装
最後に、市区町村名を入力するテキストボックスとクエリを実行するボタンを作成して、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"/>
</div>
</div>
次に、ボタンのクリックでクエリを実行するようにイベント ハンドラを作成します。
さらに、手順2で作成したパラメーターをテキストボックスから取得した値を使用するように変更します。
// 検索ボタンのイベントハンドラ
document.getElementById("queryButton").addEventListener("click", doQuery);
// クエリの実行
function doQuery() {
// 前回のクエリ結果を削除
view.graphics.removeAll();
// input 要素に入力された文字列を取得
const str = document.getElementById("attrTxt").value;
// クエリ パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "SIKUCHOSON = '" + str + "'";
queryParams.returnGeometry = true;
// クエリの実行
//...
}
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
// 検索ボタンのイベントハンドラ
document.getElementById("queryButton").addEventListener("click", doQuery);
// クエリの実行
function doQuery() {
// 前回のクエリ結果を削除
view.graphics.removeAll();
// input 要素に入力された文字列を取得
const str = document.getElementById("attrTxt").value;
// クエリ パラメーターの作成
const queryParams = cityareaLyr.createQuery();
queryParams.where = "SIKUCHOSON = '" + str + "' AND JCODE LIKE '23%'";
queryParams.returnGeometry = true;
// クエリの実行
//...
}
コードを実行してみましょう。
検索ボタンをクリックすると、テキストボックスに入力した市区町村名と一致するフィーチャを取得して地図上でハイライト表示します。
クエリの基本的な利用方法の紹介は以上です。
ステップアップ:空間検索の実行
ここでは、ステップアップとして、これまでの手順で取得した市区町村のフィーチャを利用して空間検索を行ってみましょう。
地価公示レイヤーから、取得した市区町村のフィーチャに含まれるフィーチャを表示します。このように、『あるフィーチャに「含まれる」フィーチャ』、というような空間的な関連性を求めるためのクエリは空間検索と呼ばれます。
6. 地価公示レイヤーの取得
手順1を参考に、地価公示レイヤーを取得します。
webmap.when(function() {
webmap.layers.forEach(function(layer) {
//...
// レイヤー ID をもとにレイヤーを取得
if (layer.id === "all_Japan_shikuchoson_2377") {
cityareaLyr = layer;
} else if (layer.id === "Aichi_ken_Chikakoji_H25_7383") {
chikakojiLyr = layer;
}
});
});
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
webmap.when(() => {
webmap.layers.forEach(layer => {
//...
// レイヤー ID をもとにレイヤーを取得
if (layer.id === "municipalityboundaries2021_5687") {
cityareaLyr = layer;
} else if (layer.id === "LandPrice_4765") {
chikakojiLyr = layer;
}
});
});
7. クエリ パラメーターの作成とクエリの実行
空間検索では、検索に使用するジオメトリを指定する 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);
}
8. 結果の描画
手順 4 を参考に、クエリの結果からグラフィックを作成して地図に描画します。
さらに、今回は、取得したフィーチャの数を表示します。
// クエリの結果を表示
function showChikakoji(results) {
// 結果フィーチャ数が 0 以上のとき
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(function(feature) {
const graphic = feature.clone();
graphic.symbol = {
type: "simple-marker",
color: "#00ff80",
size: "12px"
};
return graphic;
});
// グラフィックを表示
view.graphics.addMany(graphics);
// グラフィックへズーム
view.goTo(graphics);
// フィーチャ数を表示
const count = results.features.length;
document.getElementById("resultText").innerHTML = "地価公示地点:" + count + " 箇所";
}
}
※2022年2月追記:2022年2月以降に試す場合は以下のコードを追加してください。
// クエリの結果を表示
function showChikakoji(results) {
// 結果フィーチャ数が 0 以上のとき
if (results.features.length > 0) {
// 結果フィーチャからグラフィックを作成
const graphics = results.features.map(feature => {
const graphic = feature.clone();
graphic.symbol = {
type: "simple-marker",
color: "#00ff80",
size: "12px"
};
return graphic;
});
// グラフィックを表示
view.graphics.addMany(graphics);
// グラフィックへズーム
view.goTo(graphics);
// フィーチャ数を表示
const count = results.features.length;
document.getElementById("resultText").innerHTML = "地価公示地点:" + count + " 箇所";
}
}
HTML にフィーチャ数を表示する要素を追加します。
<div id="queryToggle">
<!-- 省略 -->
<span id="resultText"></span>
</div>
では、サンプルを開いてみましょう。
テキストボックスに入力した市区町村にある地価公示フィーチャが表示されましたか?
属性検索と空間検索の2つのクエリ方法を紹介しました。
クエリを活用して、目的の情報を効率的に探してみましょう。
※2022年2月追記:クリア処理を追加
追加:クエリ結果のクリア
クリアボタンを作成して、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 = "";
}
今回作成したサンプルは以下で動作を確認することも可能です。
※2022年2月追記:2022年2月以降は、以下で動作を確認できます。
さいごに
「はじめての Web マッピングアプリケーション開発」は本記事で最後となります。
地図の作成やレイヤーの表示、検索方法など基本的な要素を紹介してきましたが、API には、マッピング アプリケーションを開発するための豊富な機能が提供されています。
API の Web ヘルプ(英語)には、トピックごとにまとめられたガイドやクラスの詳細を網羅した API リファレンス、コードと一緒に手軽に試せるサンプルを紹介したサンプル コードなど開発に役立つさまざまな情報が提供されています。
また、専門的な用語が多い GIS をわかりやすく解説した GIS 基礎解説も併せてご参照ください。
ArcGIS 開発者コミュニティでは、今後も開発に役立つ情報を提供していく予定です。ご期待ください!
関連リンク