このガイドは ArcGIS Web AppBuilder (Developer Edition) (以下、Web AppBuilder)で使用するカスタム ウィジェットを作成する方法を説明します。
Web AppBuilder のインストール方法に関しては、ArcGIS Web AppBuilder (Developer Edition) インストールガイドをご参照ください。
また Esri Japan GitHub では、Web AppBuilder のカスタム ウィジェット/テーマが共有されています。このガイドで作成するウィジェットの完成版も公開されています。
Web AppBuilder で使われる全てのウィジェットは <Web AppBuilder のインストール ディレクトリ>\client\stemapp\widgets
に格納されていて、ソースコードを確認できます。開発したカスタム ウィジェットも同様にこのディレクトリに配置します。
上記ディレクトリにある samplewidgets
フォルダーには簡易機能のサンプル ウィジェットが用意されています(本ガイドではウィジェット作成の雛形となるコードが記述されたテンプレートである CustomWidgetTemplate
を使用します)。
カスタム ウィジェットを作成する際に使用するファイルは以下です。全ファイルが必須ではなく、ウィジェットの UI を設ける、ウィジェットをローカライズする、設定画面を設ける等の目的に応じてファイルを準備します。
Web AppBuilder のウィジェットは2 種類に分けられます。1 つは「描画」ウィジェットのようなパネルを表示して使用するウィジェットです(Web AppBuilder では In-Panel ウィジェットと呼びます)。もう 1 つは、「現在位置」ウィジェットのように画面上にボタンのみを配置するパネルを表示しないウィジェットです(Off-Panel ウィジェットと呼びます)。
本ガイドでは簡単なバッファー検索を行う In-Panel ウィジェットを開発していきます。ウィジェットを追加するには <Web AppBuilder のインストール ディレクトリ>\client\stemapp\widgets
にウィジェットのフォルダーを配置します。
ウィジェットの名前やバージョンなどのウィジェットの属性を設定するファイルです。properties
属性でカスタム ウィジェットのプロパティを構成できます。inPanel
を false
に設定すると Web AppBuilder のウィジェットの追加画面に表示されなくなります。ウィジェットのプロパティについてはWidget manifestをご参照ください。
define({
root: ({
_widgetLabel: "Buffer"
}),
"ja": 1
});
define({
_widgetLabel: "バッファー検索"
});
カスタム ウィジェットを多言語化する場合に使用します(アクセスするブラウザーのロケールにより該当する言語が表示されます)。_widgetLabel
はウィジェット追加時に表示されるラベルをローカライズするための固有の属性です。
使用例
define({
root: ({
label1: "Hello"
}),
"ja": 1 // 日本語ロケールを使用する場合に 1 と設定
});
define({
label1: "こんにちは"
});
<label>${nls.label1}</label>
カスタム ウィジェットのボタンのアイコンを変更したい場合は、このファイルを置き換えます。
Web AppBuilder でウィジェットの構成を行う画面を作成します。ここでは検索に使用するバッファーの距離単位を設定する画面を作成します。
Buffer
フォルダーに setting
フォルダーを作成します。
setting
フォルダーに Setting.html
ファイルを作成し、以下のコードを入力します。
<div>
<table>
<tbody>
<td>距離単位</td>
<td>
<div>
<select data-dojo-attach-point="selectLengthUnit" data-dojo-type="dijit/form/Select">
<option value="kilometers" selected="selected">キロメートル</option>
<option value="meters">メートル</option>
</select>
</div>
</td>
</tbody>
</table>
</div>
setting
フォルダーに Setting.js
ファイルを作成し、以下のコードを入力します。define([
'dojo/_base/declare',
'dijit/_WidgetsInTemplateMixin',
'jimu/BaseWidgetSetting',
'esri/units',
'dijit/form/Select'
], function(declare, _WidgetsInTemplateMixin, BaseWidgetSetting, esriUnits) {
return declare([BaseWidgetSetting, _WidgetsInTemplateMixin], {
baseClass: 'jimu-widget-buffer-setting',
startup: function() {
this.inherited(arguments);
if (!this.config.measurement) {
this.config.measurement = {};
}
this.setConfig(this.config);
},
setConfig: function(config) {
this.config = config;
if (this.config.measurement.LengthUnit) {
this.selectLengthUnit.set('value', this.config.measurement.LengthUnit);
} else {
// デフォルトで表示される単位をキロメートルに設定
this.selectLengthUnit.set('value', 'kilometers');
this.config.measurement.UnitLabel = 'キロメートル';
}
},
getConfig: function() {
// ユーザーが単位を変更した時に config.json にその値を格納
this.config.measurement.LengthUnit = this.selectLengthUnit.value;
// ウィジェットのパネルに表示する単位ラベルに使用
if (this.config.measurement.LengthUnit === 'kilometers') {
this.config.measurement.UnitLabel = 'キロメートル';
} else {
this.config.measurement.UnitLabel = 'メートル';
}
return this.config;
}
});
});
Buffer
フォルダーの config.json
ファイルを開き、以下のコードを入力します。{
"measurement": {}
}
Buffer\manifest.json
を開き hasSettingLocale
と hasSettingStyle
属性を false
にします。setting
フォルダーに css
や nls
フォルダーを作成することで、構成画面用のスタイル定義、ローカライズが可能ですが、ここでは使用しないため false
にします。Web AppBuilder でウィジェットの設定を行う画面を作成します。
Web AppBuilder でウィジェットの設定を行う際の処理を実装します。jimu/BaseWidgetSetting
の子クラスを作成し、baseClass
に jimu-widget-<ウィジェット名>-setting
を指定します。以下のイベントが用意されています。
config.json
のオブジェクトに格納)JSON 形式のオブジェクト格納ファイルです。Web AppBuilder でウィジェットの設定を行う場合は、config.json
に用意した空のオブジェクトに値を格納して、 Widget.html
や Widget.js
からそのオブジェクトを取得します。
Buffer
フォルダーにある Widget.html
ファイルを開き編集します。バッファーの半径(inputNode)とマップ上にあるレイヤーから検索対象のレイヤーを選択(layerSelectNode)する画面を作成します。
<div>
<table>
<tr>
<td>半径を入力(${config.measurement.UnitLabel})</td>
<td>
<input class="jimu-input" data-dojo-attach-point="inputNode" value="1000"></input>
</td>
</tr>
<tr>
<td>検索レイヤーを選択</td>
<td>
<div data-dojo-attach-point="layerSelectNode"></div>
</td>
</tr>
</table>
</div>
Buffer
フォルダーにある Widget.js
ファイルを開き編集します。
define([
'dojo/_base/declare',
'dojo/_base/lang',
'jimu/BaseWidget',
'jimu/LayerStructure',
'esri/geometry/geometryEngine',
'esri/symbols/SimpleMarkerSymbol',
'esri/symbols/SimpleLineSymbol',
'esri/symbols/SimpleFillSymbol',
'esri/Color',
'esri/graphic',
'esri/tasks/query',
'dijit/form/Select'
], function(declare, lang, BaseWidget, LayerStructure, geometryEngine, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Color, Graphic, Query, Select) {
return declare([BaseWidget], {
baseClass: 'jimu-widget-buffer',
ckickfunction: null,
layerList: null,
layerId: null,
// スタートアップ時に実行されるメソッド
startup: function() {
this.inherited(arguments);
// マップ上のレイヤーを取得し、レイヤー一覧を作成
var options = [];
var layerStructure = LayerStructure.getInstance();
layerStructure.traversal(function(layerNode) {
layerNode.getLayerType()
.then(function(type) {
if (type === 'FeatureLayer') {
var option = {
value: layerNode.id,
label: layerNode.title
};
options.push(option);
}
})
.catch(function(err) {
console.log(err);
});
});
this.layerList = new Select({
options: options
}, this.layerSelectNode);
this.layerList.startup();
// レイヤー一覧を変更したときのイベント
this.layerList.on("change", lang.hitch(this, function(val) {
this.layerId = val;
}));
},
// ウィジェットのパネルを開くときに実行されるメソッド
onOpen: function() {
this.inherited(arguments);
// マップをクリックしたときのイベント ハンドラ
this.ckickfunction = this.map.on("click", lang.hitch(this, this._clickHandler));
},
// ウィジェットのパネルを閉じるときに実行されるメソッド
onClose: function() {
this.inherited(arguments);
// マップに表示されているグラフィックを削除
this.map.graphics.clear();
// マップのクリック イベントを削除
this.ckickfunction.remove();
},
// マップのクリック イベント
_clickHandler: function(evt) {
// マップ コンストラクタを取得
var map = this.map;
// マップに表示されているグラフィックを削除
map.graphics.clear();
// inputNode に入力された半径の値を取得
var distance = this.inputNode.value;
// ウィジェット構成時に設定した半径の単位を config.json から取得
var unit = this.config.measurement.LengthUnit;
// クリック地点から指定した半径のバッファーを作成
var bufferGeometry = geometryEngine.buffer(evt.mapPoint, distance, unit);
// 作成したバッファーをマップに表示
var sfs = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASHDOT, new Color([255, 0, 0]), 2),
new Color([255, 255, 0, 0.25]));
var graphic = new Graphic(bufferGeometry, sfs);
map.graphics.add(graphic);
// バッファー内のフィーチャを検索
var query = new Query();
query.geometry = graphic.geometry;
query.spatialRelationship = Query.SPATIAL_REL_CONTAINS;
// マップからレイヤー ID を指定してフィーチャ レイヤーを取得
var layer = map.getLayer(this.layerId);
// フィーチャ レイヤーに対してクエリを実行
layer.queryFeatures(query)
.then(function(featureSet) {
// ポイント、ライン、ポリゴンごとにシンボルを設定
var highlightSymbol;
if (layer.geometryType == "esriGeometryPoint") {
highlightSymbol = new SimpleMarkerSymbol();
highlightSymbol.setColor(new Color("#f00"));
highlightSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 16,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0]), 1),
new Color([255, 0, 0, 0.5]));
} else if (layer.geometryType == "esriGeometryPolyline") {
highlightSymbol = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0, 0.5]), 6);
} else {
highlightSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0]), 3),
new Color([125, 125, 125, 0.5]));
}
// 結果を表示
featureSet.features.forEach(function(feature) {
var queryGraphic = new Graphic(feature.geometry, highlightSymbol);
map.graphics.add(queryGraphic);
});
});
}
});
});
ウィジェットの画面を作成します。Web AppBuilder には、デフォルトでいくつかの css クラスが含まれており、アプリのデザインを統一させることができます。各クラスの詳細は css ファイル(jimu.js/css/jimu.css)を参照ください。
使用例:
<input class="jimu-input" data-dojo-attach-point="inputNode" value="10000"></input>
Widget.html
のスタイル定義ファイルです。
使用例:
jimu-widget-<ウィジェット名> div:first-child {
color: red;
}
ウィジェットの機能を実装するファイルです。jimu/BaseWidget
の子クラスを作成し、"baseClass"
に jimu-widget-<ウィジェット名>
を指定します。
"baseClass"
は、ウィジェットの css クラスとして適用されるためスタイルの競合を避けることができ、スタイルを定義する際に役立ちます。
Web AppBuilder で表示しているマップには map
プロパティを使用してアクセスします。
使用例:
this.mapIdNode.innerHTML = 'マップのID:' + this.map.id;
<div data-dojo-attach-point="mapIdNode"></div>
その他に利用可能なプロパティは以下です。
"opened"
、"closed"
または "active"
)"normal"
、"minimized"
または "maximized"
)ウィジェットは、読み込みやウィジェットの開閉などのイベントの発生で実行されるメソッドが定義されています(ウィジェット ライフサイクル)。このメソッド内に処理を追加することで、ウィジェットをカスタマイズしていきます。
例えば、ウィジェットが開かれた時に処理を実行するには onOpen
メソッドを使用します。
使用例:
onOpen: function() {
var map = this.map;
// ...
}
その他に利用可能なメソッドは以下です。
Web AppBuilder では Dojo Toolkit が提供しているウィジェット(dijit)を使用することができます。
さらに、Web AppBuilder 独自のウィジェット(jimu.js/dijit)も提供されています。
ヘルプに使用方法は記載されていませんが、Web AppBuilder に含まれている以下のウィジェットも使用できます。
ウィジェットで表示されるメニューを多言語化する場合に使用します。ウィジェット名をローカライズした方法と同様の手順でローカライズできます。
<Web AppBuilder のインストール ディレクトリ>\client\stemapp\widgets
にフォルダーを配置します。ウィジェットの構成用ファイルを更新した場合は、ブラウザーで Web AppBuilder を更新することで、更新内容が Web AppBuilder に反映されます。
※ 更新前に作成したアプリケーションには更新内容は反映されません。新たに設置したカスタム ウィジェットを利用したい場合は、新たにアプリケーションを作成する必要があります。
ダウンロードしたアプリケーションの widgets
フォルダーの直下にカスタム ウィジェットのフォルダーを配置し、アプリケーションのルート フォルダーにある config.json
の widgetOnScreen
(マップ上に表示)または widgetPool
(ツールバー上に表示)セクションの widgets
属性にウィジェットの参照先等を設定します。
widgetPool にウィジェットを追加する例:
{
"name": "<ウィジェット名>",
"label": "<アプリで表示する名前>",
"uri": "widgets/<ウィジェット名>/Widget"
}
Web AppBuilder では新規にアプリケーションを作成するときに、<Web AppBuilder のインストール ディレクトリ>\client\stemapp\widgets
フォルダーに配置されたウィジェットが読み込まれます。作成済みの既存アプリケーションには、ウィジェットの更新内容は反映されないため、ウィジェットを更新する度に新規にアプリケーションを作成する作業が発生してしまい、非常に面倒です。
開発段階でウィジェットの更新や動作確認を行うには、以下の手順が便利です。
<Web AppBuilder のインストール ディレクトリ>\server\apps
フォルダーを開きます。このフォルダーには Web AppBuilder で作成したアプリケーションが配置されています。config.json
ファイルに記載された JSON の title
属性で確認できます。