OutSystemsにLeafletで地図を表示する

Forgeにある「LeafletJS - Reactive」コンポーネントを使い、OutSystemsアプリケーションに地図を組み込む手順を確認してみます（Reactive Web App利用）。
LeafletはJavaScriptで作られたオープンソースのライブラリで、地図を表示・操作する機能を提供します。

表示対象の地図データは、外部の別サービスを使っているようです

以下、Leaflet公式ページにあった[一番基礎的なチュートリアル](https://leafletjs.com/examples/quick-start/)に従って設定方法を確認していきます。

# サンプル
https://www.outsystems.com/forge/component-overview/7086/housesoftsamplereactive
LeafletQuickStart Screenを参照してください。

# 環境
Personal Environment(Version 11.7.3 (Build 5968))
Service Studio(Version 11.6.32)
[LeafletJS - Reactive](https://www.outsystems.com/forge/component-overview/6907/leafletjs-reactive)(Version 1.2.2)
　1.2.1だとマーカーが表示されない不具合があるので注意

# 地図画像のライセンス
OutSystemsのForgeコンポーネント「LeafletJS - Reactive」がデフォルトで使用するOpenStreetMapのライセンスは以下で確認してください。この記事内に埋め込んだ地図画像はここのものを使っています。
https://www.openstreetmap.org/copyright

なお、これとは別に、Leafletライブラリ自体のライセンスもあります。

# セットアップ
Service StudioのBrowse Forgeのタブで、「LeafletJS」で検索し、LeafletJS - Reactiveをインストールします。
このモジュールは、Reactive Web App用なのでReactive Web Appのモジュールを用意してください。

用意したアプリケーションに参照を追加します。Manage DependenciesダイアログからLeafletJSモジュールの各要素への参照を追加します。
![qLeaflet1_1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/fe0ba6fb-999d-878d-c8af-e17d42e123b2.png)

# 地図を表示してみる
Screenを用意し、Leaflet Blockを配置し、以下のプロパティを設定します。

* MapHeight：ページ内の地図表示領域の高さ（例："300px"）。これだけは必須指定
* StartLatitude, StartLongitude：初期表示時点での中心座標（緯度・経度）
* StartZoom：0以上の整数で初期表示時点でのズームレベルを指定

ズームレベルについて。0だと1枚の画像(縦・横それぞれ256px）で全世界を表示します。レベルの数値が1上がるごとに、縦・横ともに2倍に拡大表示される。
[公式の説明](https://leafletjs.com/examples/zoom-levels/)

表示例（緯度34.6873、経度135.5238、ズームレベル16を指定）：
![qLeaflet1_2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/e72ac8dd-0595-e780-e0aa-f645fcaa65a3.png)

BlockのInput Parameter：TileLayerで明示的に指定しない限り、OpenStreetMapの地図が表示されるようになっています（Leaflet BlockのOnReady Actionの実装により）。

## 別の地図サービスを利用する
何らかの地図サービスを使える場合、Leaflet BlockのTileLayerプロパティを設定することによって表示可能（Leafletで対応できる形式の場合）。
チュートリアルで使われているMapBoxの地図に差し替えてみます。

MapBoxを使う場合、access tokenが必要なのでMapBoxのサイトでアカウントを作り、更にaccess tokenを発行しておいてください。[発行したaccess tokenの一覧](https://account.mapbox.com/access-tokens/)

LeafletJSコンポーネントで定義されているTileLayer Structure型の変数を設定する必要があります。Leaflet Blockを配置したScreenの初期処理を定義します。
ScreenのプロパティのEventドロップダウンリストから「On Initialize」を選択してイベントハンドラを作成します。
![qLeaflet1_3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/57292919-190a-f17f-c4f0-4aebddfbe11a.png)

On Initializeは画面表示が始まる前に発生するイベントで、画面で使う変数の設定に使えます。
![qLeaflet1_4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/2a578abc-3292-37f6-8300-864addb3c9ea.png)
変数はMapBoxTileLayerという名前で作成し、値はLeaflet公式チュートリアルと同じものを設定してみました。

MapBoxTileLayer.URLは、自分で発行したaccess tokenを設定する必要があります。文字列末尾の部分（「=」の後）に設定してください。
Attributionは著作権表示用のHTMLの文字列ですが、文字列内にダブルクォーテーション「"」を含んでいます。OutSystemsの文字列内にダブルクォーテーション「"」を含む場合は「""」のように2重にします。そうしないと、文字列の終端とみなされてしまうため。

# 図形を表示
## マーカー（点）
ある1点を地図上に表示するときはマーカー（Marker）を使用します。
地図を表示する時点でマーカーを表示するには、Leaflet BlockのMarkersプロパティにマーカー情報を設定します。

初期表示用に変数を設定するため、On InitializeイベントのActionを利用します。
![qLeaflet1_5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/a6b11dc8-86ee-988c-388f-c499fbeee80b.png)

Markersプロパティに設定するのは、MapMarkers Structure型の変数です。
MapMarkers.MarkersはMarker List型でここに地図上に表示したいマーカーを表すMarker Structure型の変数（上の例ではTempMarker）をListAppendで登録しておきます。

設定後に表示すると、このようにマーカーが表示されます。

![qLeaflet1_6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/5f6b606c-8aaa-8ba0-6a31-b4d430e0b301.png)

なお、テスト中、画像が表示されないことがありました。
モジュールに含まれる画像を参照し、更に、画面に参照した画像を表示（Image Widgetを使う）した状態で1回Publishすることでマーカーが表示されるようになりました。どうもこうしないと、画像がサーバーに配置されないようでした。
LeafletJSはLibrary Moduleです。Library Moduleの要素は参照する側のコンテキストに配置されるためではないかと思います。

## 円
![qLeaflet1_7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/2917198f-d37d-e503-a7a7-b805d1986c48.png)

設定方法は基本的にマーカーと同じ。
MapCircles Structure変数のCirclesに表示したいMapCircle Structure型変数を設定していく。
例えば、上のスクリーンショットの赤い円なら、
![qLeaflet1_8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/0f8743e5-6b44-700a-2606-a364908c50c8.png)
Point：円の中心座標
CircleOptions.Radius：円の半径
CircleOptions.PathOptions.Color：境界線の色
CircleOptions.PathOptions.FillColor：円内部の塗りつぶし色
CircleOptions.PathOptions.FillOpacity：塗りつぶし色の透明度（恐らく0-1の範囲）

## ポリゴン
これも円とだいたい同じ。この設定で表示されるのは多角形。上のスクリーンショットでは円の右に出ている青い三角形が該当。
Polygon StructureのPointsがLatLng Listになっていて、ここにListAppendで頂点（LatLng Structure）を順に登録していく。三角形なら3つ。

## ポップアップ
ポップアップに関しては、Blockのプロパティに対応する設定がないようです。
そのため、ポップアップ表示用Action BindPopupを明示的に呼び出して設定します。

以下の設定は、「testmarker」という名前で配置したマーカーにポップアップを割り付けています。この設定で、マーカークリック時にポップアップされるようになりました。

Leaflet Blockの初期表示時点で処理を動作させるには、BlockのOnMapRenderイベントを使います。Blockの初期処理完了後に発生するイベントです。
BindPopupには、ComponentNameにポップアップを紐付けるオブジェクト（この場合はマーカー）に設定した名前、Popupに表示したいポップアップ情報（HTMLを使えるContentプロパティにポップアップ内に表示するテキスト）を設定します。
![qLeaflet1_9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/bd541b55-3a87-79b6-f1e1-40d30ffe523e.png)

![qLeaflet1_10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/332987/09d39174-cf69-5db4-52a1-950dc4024e3b.png)