OutSystems+Google Maps API(3) Entityの一覧画面でも地図を表示する

前回までで、OutSystemsからスキャフォールディングで作った詳細画面に地図を配置し、Entityのデータと連動するようになりました。

OutSystemsでスキャフォールディングするときに、詳細画面のみということはまずなくて、一覧画面も必要になるでしょう。

今回は前回作った詳細画面で登録した長方形をあるだけ、一覧画面の地図上に表示するようにします。

シリーズ一覧

前提条件

前回分の修正を施したモジュールが手元にあるのが前提。

「OutSystems+Google Maps API(1) 地図を埋め込む」「OutSystems+Google Maps API(2) OutSystensのEntityと地図上の長方形を紐づけ」を参照してください。

仕様

Entityの定義は前回と同じです。

MainFlow。Web Block(HouseSoftMap)を作って、BranchesとBranchDetail Web Screenに配置しています。

BrancDetailは前回作った詳細画面です。1レコードずつフォームで表示すると同時に地図に長方形を描画します。

Branches(一覧画面)を今回作っていきます。

MainFlow

まず、どのようにしてOutSystemsで取得したEntity一覧をWeb Blockに渡すか検討します。

OutSystemsのEntity一覧取得は一覧画面のPreparation Actionでサーバサイドで行われます。

それに対して、Google Mapsの地図はJavaScript APIを用いてクライアントサイドで行われます。

そこでPreparationを修正し、EntityのリストをJavaScriptのオブジェクト配列を表す文字列に変換しておきます。

この文字列をWeb BlockのExpressionのJavaScript呼び出しに渡してWeb Block内に定義した関数に描画させましょう。

まとめると、Entityリストは

Branches(一覧画面)のPreparation Action

→Branchesに配置されたHouseSoftMap(Web Block)のパラメータに渡す

→HouseSoftMapのExpression内のJavaScriptで、配列としてWeb BlockのJavaScript関数に渡す

→Web BlockのJavaScript関数(setInitialRectangles)でGoogle Mapsに描画

という流れで作っていきます。

実装:BranchesのPreparation Action

Preprationを変更します。

GetBranchesで取得したOutSystemsのBranch Listデータを、JavaScriptのオブジェクト配列の文字列に変換します。

変換した結果は、Text形式のローカル変数(Branches(一覧画面)を右クリックして、Add Local Valueで作成)に保存していきます。

[
{‘title’ : ‘sydney, ‘north’ : -34.08906132, ‘south’ : -34.55633549, ‘east’ : 151.31195068, ‘west’ : 150.44952393},
{‘title’ : ‘図形2, ‘north’ : -33.88409738, ‘south’ : -34.43862841, ‘east’ : 151.22955322, ‘west’ : 150.89447021}
]

GetBranches以外が追加部分。
Preparation

1つ1つのオブジェクトは「1レコードをJSオブジェクト文字列に変換」で以下のように設定しています。

If~の部分は2行目以降のデータは前に「,」(配列の区切り文字)を追加する記述。

JavaScriptオブジェクトへ変換

配列の開始文字は「[」、終了文字は「]」を固定で渡しています。

実装:Web Screenに配置したWeb Blockのパラメータを設定

一覧画面用にこれから2つのパラメータを追加します。

順番が逆になりますが、以下のように設定します。Web Blockのパラメータはこの次の節で追加します。

  • MaxRectangleCount : -1(地図上に表示する長方形の数の上限。負だと無限に表示する。多すぎると邪魔なので制限したいときは適当な数を設定)
  • RectangleJSString : 長方形のオブジェクト配列をあらわすJavaScriptの文字列表現

実装:Web Blockへの追加パラメータ

以下のパラメータを追加(HouseSoftMapを右クリックして、Add Input Parameterから)

  • MaxRectangleCount : Integer型。Is Mandatory=No。Default Value=1(詳細画面に変更を加えなくて済むように未設定だと1つだけ表示する)
  • RectangleJSString : Text型。。Is Mandatory=No。Default Value=””(空文字列。詳細画面に変更を加えなくて済むように未設定だとここで設定する処理はスキップする。前回の修正により、詳細画面ではこれから追加するのとは別のロジックで長方形を1件描画している)

WebBlockパラメータ定義

追加したパラメータは、Web Block内のExpressionによって以下のようにJavaScriptプロパティで定義した関数を呼び出している。

3行目、5行目が追加部分。

"<script type='text/javascript'>
  function initMap() {
    houseSoftMap.createMap('" + Map.Id + "', " + MaxMarkerCount + ", " + MaxRectangleCount + ", '" 
        + NorthInputId + "', '" + SourthInputId + "', '" + EastInputId + "', '" + WestInputId + "');" +
If (RectangleJSString = "", "", "houseSoftMap.setInitialRectangles(" + RectangleJSString + ");") +
  "}" +
"</script>
<script src='https://maps.googleapis.com/maps/api/js?key=" + Site.APIKey + "&callback=initMap' async defer></script>
"

実装:Web Blockで配列を受け取って長方形を地図に描画

まずはcreateMap(地図のインスタンス化処理)の修正点。地図上に表示する長方形の数を受け取れるようにしました。

  createMap : function (divId, maxMarkerCount, maxRectangleCount, northInputId,
                        southInputId, eastInputId, westInputId) {
    this.mapObj = new google.maps.Map(document.getElementById(divId), {
      center: {lat: -34.397, lng: 150.644},
      zoom: 8
    });
    this.maxMarkerCount = maxMarkerCount;
    this.maxRectangleCount = maxRectangleCount;
    this.setRectangleInputIds(northInputId, southInputId, eastInputId, westInputId);
    this.mapObj.addListener("click", function(mouseEvent) {
      if (houseSoftMap.maxMarkerCount <= 0) return; 
      
      // クリックした位置にマーカーを立てる
      var marker = new google.maps.Marker({
          position: mouseEvent.latLng,
          map: houseSoftMap.mapObj
      });
      houseSoftMap.addMarker(marker);
    });
  },

次に初期表示時点で長方形をまとめて描画する処理。

最初のハイライト部分:上で設定した上限以上の長方形があったら古い方から削除

2番目のハイライト部分:長方形クリック時にtitle属性を情報ウィンドウ(吹き出し)に出している

3番目のハイライト部分:一覧画面で呼び出される長方形一括描画の関数

  addRectangle : function(rectangle, title) {
    if (this.maxRectangleCount === 0) return; // 0のときは長方形を表示しないので処理を終了する
    // 設定値以上に追加されている長方形はクリアする
    if (this.maxRectangleCount > 0) {    // 負の値は長方形を無制限に指定できることにしたので負の値ならクリアしない
      while (this.rectangles.length > this.maxRectangleCount) {
        var temp = this.rectangles.shift();
        temp.setMap(null);
      }
    }
    var rectangle = new google.maps.Rectangle({
      strokeColor: '#FF0000',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: '#FF0000',
      fillOpacity: 0.35,
      map: this.mapObj,
      bounds: rectangle,
      title: title
    });
    if (title) { // title属性が指定されているとき、長方形クリックで情報ウィンドウを出す
      var infoWindow = new google.maps.InfoWindow({
        content: title,
        position: rectangle.getBounds().getCenter()
      });

      rectangle.addListener('click', function() {
        infoWindow.open(rectangle.map);
      });
    }
    this.rectangles.push(rectangle);
  },
  setInitialRectangles : function(rectangleArray) {
      for (var i = 0; i < rectangleArray.length; i++)
        this.addRectangle({
            north: rectangleArray[i].north,
            south: rectangleArray[i].south,
            east: rectangleArray[i].east,
            west: rectangleArray[i].west
        }, rectangleArray[i].title);
  }

さすがに長くなりすぎたので、Web BlockのJavaScriptプロパティに設定する内容は別のファイルにしました。
OutSystems+Google Maps API(3)code