Lightningコンポーネント開発-地図アプリの開発を試してみました。
開発と言ってもSalesforceが標準で用意しているlightning:mapタグを使って実装できます。地図系の開発にはGoogleMapのAPIの契約が必要だったり、フリーのライブラリ「leaflet」の利用を検討したりが必要になりますが、lightning:mapを利用すれば気軽にGoogleMapの地図表示が可能そうでした。
開発してみてわかったこと
地図上にマーカーを表示にするには二種類の方法があります。
- 住所情報をつかってマーカーを表示する
- 緯度・経度の情報をつかってマーカーを表示する
はじめに利用を検討したのは住所情報をつかった実装です。緯度・経度の登録は住所情報とは別に行う必要があり、自動化を行う場合はGoogleのAPIの利用が必要になると思われるためです。
ところが住所情報をつかったマーカー表示には下記の制限がありました。
住所情報をつかってマーカーを配置できるのは10箇所まで
最終的にマーカー配置に必要なのは緯度・経度の情報で、住所情報をそのまま使うと変換処理が実行される仕組みのためです。10箇所より多く配置しようとすると下記のJSエラーが発生して処理が中断されます。
Google geocoder status is OVER_QUERY_LIMIT
マーカー配置したい場合はさすがに10箇所以内のケースはあまり無いと思います。基本的には緯度経度の情報が必要になることを認識しておくと良さそうでした。
ちなみに緯度・経度のデータは下記のように登録できます。(専用のデータ型があります。)
緯度・経度での管理の場合はマーカーの配置は100個を上限の目安と考えれば良いと開発者ガイドに記載がありました。無限には配置できないため、ある程度絞り込んで表示するケースを想定しておく必要がありそうです。
以下Google翻訳した内容です。(元のサイトのURLがどこだったか失念しました。)
マーカーの配置数を多くした場合ですが、地図の右側に表示できるリストビューが長くなり、それにより地図コンポーネントの高さも伸びてしまうことがわかりました。この挙動により、レイアウト崩れが発生します。
この問題を解決する方法ですが、下記のCSSを組み込むことで、リストビューのスクロールが可能になります。(Windowsでの挙動は未確認ですがmacで問題なく動いたのでたぶん大丈夫。)
また、マーカー情報の変数を格納するmapMarkersですが、値が存在しない場合はエラーが発生してしまうので、 aura:renderIf で表示判定しておくと良いと思います。
おまけとしてshowFooterをtrueにしたときの挙動ですが、地図の下にGoogleマップで表示のボタンが表示される仕組みでした。
以上がLightningコンポーネント開発での地図アプリの開発を試したときの記録です。
動画
サンプルコード (最初に公開した後にちょっと修正)
LightningMap.cmd
<aura:component controller="LighntingMapController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global" > <aura:attribute name="mapMarkers" type="Map[]" /> <aura:attribute name="center" type="Object"/> <aura:attribute name="zoomLevel" type="Integer" /> <aura:handler name="init" value="{! this }" action="{! c.init }"/> <div class="slds-page-header"> <div class="slds-page-header__row"> <div class="slds-page-header__col-title"> <div class="slds-media"> <div class="slds-media__body"> <div class="slds-page-header__name"> <div class="slds-page-header__name-title"> <h1> <span class="slds-page-header__title slds-truncate">県庁</span> </h1> </div> </div> </div> </div> </div> </div> </div> <aura:renderIf isTrue="{! v.mapMarkers.length > 0}"> <lightning:map style="max-height: 1200px;" listView ="auto" mapMarkers="{! v.mapMarkers }" center="{!v.center}" zoomLevel="{!v.zoomLevel}" showFooter="false" /> </aura:renderIf> </aura:component>
LightningMapController.Js
({ init: function (cmp, event, helper) { // センターセット cmp.set('v.center', { location: { State: '東京都', City: '新宿区', Street: '西新宿2-8-1', PostalCode: '163-8001', }, }); // 拡大率セット cmp.set('v.zoomLevel', 7); // Apex実行 var action = cmp.get("c.getPrefecturalOfficeList"); action.setCallback(this, function(data) { // Apex実行結果取得 var results = data.getReturnValue(); // マーカーリスト var mapMarkers = []; // マーカーリスト情報取得 for (var i = 0; i < results.length; i++) { var result = results[i]; // マーカー情報セット var marker = { location: { Latitude: result.AddressLatLng__Latitude__s, Longitude: result.AddressLatLng__Longitude__s, }, title: '■' + result.State__c + '庁' + '(' + result.Name + ')', description: 'TEL:' + result.Phone__c, 'icon': 'standard:account', }; console.log(marker); // マーカー情報 mapMarkers.push( marker ); } // マーカーセット cmp.set( 'v.mapMarkers', mapMarkers ); }); $A.enqueueAction(action); }, })
LightningMap.css
.THIS .slds-coordinates__list { height: 800px; overflow-y: auto; }
Apex: LightningMapController.cls
public with sharing class LighntingMapController { /** * コンストラクタ */ public LighntingMapController() { } /** * 県庁情報取得 */ @AuraEnabled public static List<PrefecturalOffice__c> getPrefecturalOfficeList() { return [ SELECT Id ,Name ,State__c ,Phone__c ,PostalCode__c ,Address__c ,AddressLatLng__Latitude__s ,AddressLatLng__Longitude__s FROM PrefecturalOffice__c WHERE AddressLatLng__Latitude__s != null AND AddressLatLng__Longitude__s != null ORDER BY Name ASC LIMIT 100 ]; } }