今回の記事は、Onsen UI blogで2月に公開した"Creating Google Maps Sample App with AngularJS and Onsen UI"の翻訳記事です。
![]()
以下のツールを使用して、このサンプルを構築します。
Onsen UI ( HTML5 を使用したハイブリッドアプリを作成するためのフレームワーク )
AngularJS ( Google 社が開発した JavaScript のフレームワーク )
Google Maps JavaScript API v3
ここでは、Monacaを使用して、アプリを開発します。Monaca は、クロウド型のアプリ開発環境です。このツールを使用すれば、マルチプラットフォーム ( iOS/Android/Windows8 ) に対応するハイブリッドアプリを開発できます。Monaca には、Onsen UI のフルサポート、テンプレートの提供など、開発を容易にしてくれる作り込みが多数してあります。これらの点が、今回、Monaca を使用して、開発を行う理由です。
このサンプルアプリに実装している機能は、上記ツールの解説に必要となる、最低限に抑えてあります。また、ここでは、複雑・大規模アプリの構築ではなく、拡張可能な、ひな形となるアプリの構築に焦点を当てています。よって、アプリ内の機能のいくつかは、表示されているだけで、機能しません。開発者側で自由に書き換えれるように、枠組みだけ、提供しています。
実装している機能を、以下に記します。
を使用して、メインのインターフェイス ( ページ選択の画面 ) を配置し、その上に、map.html と settings.html へのリンクを置いています。map.html には、map 関連の要素と Onsen UI の要素 ( など ) を記述しています。スライティングメニュー上から、map 画面または settings 画面へ遷移できます。
上のサンプルアプリは、実際に操作できます。または、こちらのリンクからブラウザー表示も行えます。GitHub上にも、コードを置いていますので、開発者の環境で検証もできます。
また、上述の HTML コンテンツの他にも、controller.js と style.css の 2 つの重要な部品から、このアプリは構成されています。
コントローラー
コントローラーには、アプリのロジックを記述しています。このアプリには、2 つのコントローラーを使用しています。1 つは、ons-sliding-menu の制御用で、もう 1 つは、地図の制御用です。どちらのコントローラーも、controller.js 内に記述されています。
SlidingMenuController
ons-sliding-menu 要素と Google Maps 関連の要素を、同時に使用する際の問題点として、スクロール処理のイベントに、どちらも影響されることが挙げられます ( ここでは、水平方向のスワイプ )。よって、スライディングメニューのスワイプ時の挙動を、コントローラー側で制御する必要があります。
ここでは、この問題を解消するために、 'postopen' または 'postclose' イベントの制御を行う要素に、リスナーを登録します。スライディングメニューのスワイプは、デフォルトでは、無効化されていますが、ons-toolbar-button をクリックして、メニューを開くと有効化され、メニューが閉じるまで ( スワイプまたは ons-toolbar-button の再実行 )、そのまま有効化されています。このリスナーは、スライディングメニューを初回に開いた後に、設定されます。
MapController
このコントローラーには、map オブジェクト関連のロジックと Onsen UI 関連のロジック ( Google Maps と Onsen UI との連携部分 ) を記述しています。最初の処理は、maker 用の配列の作成 ( 後から使用 ) と map 要素の作成です。ここでは、地図
の初期化時に、AngularJS の $timeout を使用して、地図の読み込みを、100ms ほど、遅延させます。DOM を読み込む前に、AngularJS のコントローラーの初期化が行われるため、この処理が必要となります。
地図の読み込み後、タップイベント ( マーカーの表示 ) に対して、リスナーを設定します。ここでは、Hammer.JS ライブラリーを使用します。Hammer.JS は、Onsen UI に、初めから組み込まれています。
地図の初期化後、上述した機能が使用できます。上述の機能には、それぞれ、対応するメソッドがあります ( $scope.addOnClick()、$scope.deleteAllMarkers()、$scope.calculateDistance() )。
$scope.addOnClick() は、上述したリスナーと紐付けされています。画面のクリック/タップ位置 ( X値、Y値 ) を取得して、経緯・緯度の座標に変換します。Google Maps では、このような形式でエンコード化が行われているため、この変換処理が必要となります。この処理には、以下のような関数を使用します。
地図を入れる div の左上の地点に、座標の原点があります ( 端末の画面の左上ではありません )。これが、Y 座標の取得時に、(-) 44px 分だけ、差し引く理由です ( 44px は、画面上部に置かれた 要素の高さです )。座標の変換後、地図上に、マーカーを表示できます ( マーカー用の配列を使用 )。
次に、マーカーに対するクリック/タップに備えて、リスナーを設定します。マーカーが押された場合、ons.notification.confirm 要素を使用して、マーカーを削除するか否か、ユーザー側に確認します。次に、ユーザーの選択肢に応じて、ons.notification.alert 要素を表示します。
$scope.deleteAllMarkers() で行う処理は、シンプルです。マーカーの配列を確認して、地図上から、すべてのマーカーを削除します。次に、配列から、すべてのデータを削除して、配列のインデックスを初期化します。
$scope.calculateDistance() では、地図上のマーカー間の距離を計算します。ここでは、Web 上で見つけた計算式を使用しています。この計算処理の結果と座標は、同じ形式を使用しているため、変換処理は必要ありません。
計算後、ons.notification.confirm 要素を使用して、特定のマーカー間の距離 ( Partial Distance ) を表示するか否か、メッセージを表示します。ユーザーの選択肢に応じて、ここでも、ons.notification.alert 要素を使用します。
CSS
Onsen UI がデフォルトで提供するスタイルシート ( CSS ) とは別に、DOM 要素用のスタイルを、新たに追加します。CSS の内容は、style.css をご確認ください。ここでは、Google Maps JavaScript API v3 関連の要素と Onsen UI 関連の要素の表示処理を、適当に行うため、スタイルを新たに追加します。Google Maps JavaScript API v3 と Onsen UI の提供元は異なるため、これらの要素を完全に連携させることはできません。よって、これらの要素を表示するため、2 層のレイヤーを使用します。
下位のレイヤーには、Google Maps の要素 ( 地図、マーカー ) を置き、上位のレイヤーには、Onsen UI の要素を置くことにします。
ここでは、スタイルシートに追加した z-index を使用して、各要素を振り分けます。Maps 関連の要素には、-1 を設定して、下位のレイヤーにプッシュし、Onsen UI 関連の要素には、1 を設定して、上位のレイヤーにプッシュします。
Onsen UI 側の要素の位置を、適切に指定して、Google Maps 側の要素との重複表示を防ぎます。また、要素を適切に配置するためには、画面の解像度も考慮に入れます。要素自体のサイズも重要です。たとえば、div が大きすぎでも、使いにくいマップとなります。
HTML
index.html、menu.html、map.html、settings.html の 4 つのファイルから、このアプリは構成されています ( settings.html の解説は割愛 )。これらのページには、HTML、Onsen UI、AngularJS の要素が記述されています。アプリの大枠には、Onsen UI 提供のスライディングメニューのテンプレートを使用しています。こちらのテンプレートは、Monacaから入手できます。どのテンプレートを使用するかは、開発者側の自由です。DOM の取り扱い方法などに、他のアイデアがある方は、他のテンプレートをご使用ください。
index.html
こちらが、アプリのメインページとなります ( Onsen UI のテンプレートの使用時には、デフォルトで作成されます )。HTML の宣言タグの後に、ng-app="myApp" が記述されています。このディレクティブ ( directive ) を使用して、AngularJS アプリの、いわゆる、自動初期化 ( bootstrap ) を行います。また、このディレクティブは、その役割から、アプリの root 要素を指し示し、通常、ページの root 要素 ( タグ、 タグなど ) 付近に置かれます。
スクリプトとシートを記述後、地図を表示するため、Google Maps のスクリプトを記述します。前のバージョンの Google Maps JavaScript API 以降、キーの取得・使用は、任意となりましたが、 Maps API の使用量の監視、追加の割り当ての購入の際には、必要となります。無料の Google Maps API キーの取得・記述方法に関しては、こちらのリンクをご確認ください。
以下のタグを使用して、地図を表示します。
body の内容を見ます。body の中には、 要素が、1 つ置かれています。こちらが、アプリ内で使用されている Onsen UI 要素の root になります。また、ここでは、属性をいくつか設定します。 var="slidingMenu" は、AngularJS 内部の 双方向 データ バインディング ( two way data binding ) の設定です。menu-page="menu.html" は、スライディングメニュー用の HTML ページです。main-page="map.html" は、最初に表示するメインページです。また、上述のように、デフォルトでは、メニューのスワイプ表示はできません ( swipeable="false" )。
menu.html
このページには、Monaca 側で自動作成した、 要素用のコードが記述されています。 が記述され、その中には、2 つの が置かれています。この 2 つの を使用して、map.html と settings.html へのページ遷移を、それぞれ行っています。これ以外のページも追加したい場合には、適宜、 を追加して、ページ遷移を行います。
map.html
こちらが、アプリの核となるページです。地図本体と複数の Onsen UI 要素から構成されています。ページ上部で、コントローラーの宣言 ( ng-controller="MapController" ) をしています。コントローラーの宣言は、root 要素で通常行われるので、それ以降の要素は、その影響 ( 設定 ) 下に置かれることが、一目でわかります。
また、その直下には、 が設定され、ページのタイトル部の設定と が記述されています。 には、スライディングメニューの開閉を行う記述をします。このため、 内で、別のコントローラー ( ng-controller="SlidingMenuController" ) を宣言しています。
残りのコードは、地図、検索ボックス、2 個のボタン ( ) を表示するためのものです。
結論
Onsen UI、Google Maps JavaScript API v3、AngularJS の使用方法を、このサンプルアプリでお見せしました。
このサンプルアプリをひな形として、後は、自由にカスタマイズしてください。Google Maps API では、上述以外でも、たくさんの機能を提供しています。
自作する前に、Google Maps API の詳細を読み、使用できるものがないか、確認しましょう。
以下のツールを使用して、このサンプルを構築します。
Onsen UI ( HTML5 を使用したハイブリッドアプリを作成するためのフレームワーク )
AngularJS ( Google 社が開発した JavaScript のフレームワーク )
Google Maps JavaScript API v3
ここでは、Monacaを使用して、アプリを開発します。Monaca は、クロウド型のアプリ開発環境です。このツールを使用すれば、マルチプラットフォーム ( iOS/Android/Windows8 ) に対応するハイブリッドアプリを開発できます。Monaca には、Onsen UI のフルサポート、テンプレートの提供など、開発を容易にしてくれる作り込みが多数してあります。これらの点が、今回、Monaca を使用して、開発を行う理由です。
このサンプルアプリに実装している機能は、上記ツールの解説に必要となる、最低限に抑えてあります。また、ここでは、複雑・大規模アプリの構築ではなく、拡張可能な、ひな形となるアプリの構築に焦点を当てています。よって、アプリ内の機能のいくつかは、表示されているだけで、機能しません。開発者側で自由に書き換えれるように、枠組みだけ、提供しています。
実装している機能を、以下に記します。
- マーカーの表示 ( 画面上で長押し )
- マーカーの削除 ( 1 件、画面上でタップ )
- マーカーの削除 ( 全件、
を使用) - マーカー間の距離 ( 2 点間の距離、総距離 ) の計算 (
を使用 ) - メニューの表示 (
を使用 )
上のサンプルアプリは、実際に操作できます。または、こちらのリンクからブラウザー表示も行えます。GitHub上にも、コードを置いていますので、開発者の環境で検証もできます。
また、上述の HTML コンテンツの他にも、controller.js と style.css の 2 つの重要な部品から、このアプリは構成されています。
コントローラー
コントローラーには、アプリのロジックを記述しています。このアプリには、2 つのコントローラーを使用しています。1 つは、ons-sliding-menu の制御用で、もう 1 つは、地図の制御用です。どちらのコントローラーも、controller.js 内に記述されています。
SlidingMenuController
ons-sliding-menu 要素と Google Maps 関連の要素を、同時に使用する際の問題点として、スクロール処理のイベントに、どちらも影響されることが挙げられます ( ここでは、水平方向のスワイプ )。よって、スライディングメニューのスワイプ時の挙動を、コントローラー側で制御する必要があります。
ここでは、この問題を解消するために、 'postopen' または 'postclose' イベントの制御を行う要素に、リスナーを登録します。スライディングメニューのスワイプは、デフォルトでは、無効化されていますが、ons-toolbar-button をクリックして、メニューを開くと有効化され、メニューが閉じるまで ( スワイプまたは ons-toolbar-button の再実行 )、そのまま有効化されています。このリスナーは、スライディングメニューを初回に開いた後に、設定されます。
MapController
このコントローラーには、map オブジェクト関連のロジックと Onsen UI 関連のロジック ( Google Maps と Onsen UI との連携部分 ) を記述しています。最初の処理は、maker 用の配列の作成 ( 後から使用 ) と map 要素の作成です。ここでは、地図
の初期化時に、AngularJS の $timeout を使用して、地図の読み込みを、100ms ほど、遅延させます。DOM を読み込む前に、AngularJS のコントローラーの初期化が行われるため、この処理が必要となります。
地図の読み込み後、タップイベント ( マーカーの表示 ) に対して、リスナーを設定します。ここでは、Hammer.JS ライブラリーを使用します。Hammer.JS は、Onsen UI に、初めから組み込まれています。
地図の初期化後、上述した機能が使用できます。上述の機能には、それぞれ、対応するメソッドがあります ( $scope.addOnClick()、$scope.deleteAllMarkers()、$scope.calculateDistance() )。
$scope.addOnClick() は、上述したリスナーと紐付けされています。画面のクリック/タップ位置 ( X値、Y値 ) を取得して、経緯・緯度の座標に変換します。Google Maps では、このような形式でエンコード化が行われているため、この変換処理が必要となります。この処理には、以下のような関数を使用します。
- $scope.overlay.getProjection().fromContainerPixelToLatLng(point);
地図を入れる div の左上の地点に、座標の原点があります ( 端末の画面の左上ではありません )。これが、Y 座標の取得時に、(-) 44px 分だけ、差し引く理由です ( 44px は、画面上部に置かれた
次に、マーカーに対するクリック/タップに備えて、リスナーを設定します。マーカーが押された場合、ons.notification.confirm 要素を使用して、マーカーを削除するか否か、ユーザー側に確認します。次に、ユーザーの選択肢に応じて、ons.notification.alert 要素を表示します。
- //
controller.js - (function()
{ var app = angular.module('myApp', ['onsen']); //Sliding menu controller, swiping management app.controller('SlidingMenuController', function($scope){ $scope.checkSlidingMenuStatus = function(){ $scope.slidingMenu.on('postclose', function(){ $scope.slidingMenu.setSwipeable(false); }); $scope.slidingMenu.on('postopen', function(){ $scope.slidingMenu.setSwipeable(true); }); }; $scope.checkSlidingMenuStatus(); }); //Map controller app.controller('MapController', function($scope, $timeout){ $scope.map; $scope.markers = []; $scope.markerId = 1; //Map initialization $timeout(function(){ var latlng = new google.maps.LatLng(35.7042995, 139.7597564); var myOptions = { zoom: 8, center: latlng, mapTypeId: google.maps.MapTypeId.ROADMAP }; $scope.map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); $scope.overlay = new google.maps.OverlayView(); $scope.overlay.draw = function() {}; // empty function required $scope.overlay.setMap($scope.map); $scope.element = document.getElementById('map_canvas'); $scope.hammertime = Hammer($scope.element).on("hold", function(event) { $scope.addOnClick(event); }); },100); //Delete all Markers $scope.deleteAllMarkers = function(){ if($scope.markers.length == 0){ ons.notification.alert({ message: 'There are no markers to delete!!!' }); return; } for (var i = 0; i < $scope.markers.length; i++) { //Remove the marker from Map $scope.markers[i].setMap(null); } //Remove the marker from array. $scope.markers.length = 0; $scope.markerId = 0; ons.notification.alert({ message: 'All Markers deleted.' }); }; $scope.rad = function(x) { return x * Math.PI / 180; }; //Calculate the distance between the Markers $scope.calculateDistance = function(){ if($scope.markers.length < 2){ ons.notification.alert({ message: 'Insert at least 2 markers!!!' }); } else{ var totalDistance = 0; var partialDistance = []; partialDistance.length = $scope.markers.length - 1; for(var i = 0; i < partialDistance.length; i++){ var p1 = $scope.markers[i]; var p2 = $scope.markers[i+1]; var R = 6378137; // Earth’s mean radius in meter var dLat = $scope.rad(p2.position.lat() - p1.position.lat()); var dLong = $scope.rad(p2.position.lng() - p1.position.lng()); var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos($scope.rad(p1.position.lat())) * Math.cos($scope.rad(p2.position.lat())) * Math.sin(dLong / 2) * Math.sin(dLong / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); totalDistance += R * c / 1000; //distance in Km partialDistance[i] = R * c / 1000; } ons.notification.confirm({ message: 'Do you want to see the partial distances?', callback: function(idx) { ons.notification.alert({ message: "The total distance is " + totalDistance.toFixed(1) + " km" }); switch(idx) { case 0: break; case 1: for (var i = (partialDistance.length - 1); i >= 0 ; i--) { ons.notification.alert({ message: "The partial distance from point " + (i+1) + " to point " + (i+2) + " is " + partialDistance[i].toFixed(1) + " km" }); } break; } } }); } }; //Add single Marker $scope.addOnClick = function(event) { var x = event.gesture.center.pageX; var y = event.gesture.center.pageY-44; var point = new google.maps.Point(x, y); console.log(x + " - " + y); var coordinates = $scope.overlay.getProjection().fromContainerPixelToLatLng(point); console.log(coordinates.lat + ", " + coordinates.lng); var marker = new google.maps.Marker({ position: coordinates, map: $scope.map }); marker.id = $scope.markerId; $scope.markerId++; $scope.markers.push(marker); $timeout(function(){ //Creation of the listener associated to the Markers click google.maps.event.addListener(marker, "click", function (e) { ons.notification.confirm({ message: 'Do you want to delete the marker?', callback: function(idx) { switch(idx) { case 0: ons.notification.alert({ message: 'You pressed "Cancel".' }); break; case 1: for (var i = 0; i < $scope.markers.length; i++) { if ($scope.markers[i].id == marker.id) { //Remove the marker from Map $scope.markers[i].setMap(null); //Remove the marker from array. $scope.markers.splice(i, 1); } } ons.notification.alert({ message: 'Marker deleted.' }); break; } } }); }); },1000); }; }); - })();
$scope.deleteAllMarkers() で行う処理は、シンプルです。マーカーの配列を確認して、地図上から、すべてのマーカーを削除します。次に、配列から、すべてのデータを削除して、配列のインデックスを初期化します。
$scope.calculateDistance() では、地図上のマーカー間の距離を計算します。ここでは、Web 上で見つけた計算式を使用しています。この計算処理の結果と座標は、同じ形式を使用しているため、変換処理は必要ありません。
計算後、ons.notification.confirm 要素を使用して、特定のマーカー間の距離 ( Partial Distance ) を表示するか否か、メッセージを表示します。ユーザーの選択肢に応じて、ここでも、ons.notification.alert 要素を使用します。
CSS
Onsen UI がデフォルトで提供するスタイルシート ( CSS ) とは別に、DOM 要素用のスタイルを、新たに追加します。CSS の内容は、style.css をご確認ください。ここでは、Google Maps JavaScript API v3 関連の要素と Onsen UI 関連の要素の表示処理を、適当に行うため、スタイルを新たに追加します。Google Maps JavaScript API v3 と Onsen UI の提供元は異なるため、これらの要素を完全に連携させることはできません。よって、これらの要素を表示するため、2 層のレイヤーを使用します。
下位のレイヤーには、Google Maps の要素 ( 地図、マーカー ) を置き、上位のレイヤーには、Onsen UI の要素を置くことにします。
ここでは、スタイルシートに追加した z-index を使用して、各要素を振り分けます。Maps 関連の要素には、-1 を設定して、下位のレイヤーにプッシュし、Onsen UI 関連の要素には、1 を設定して、上位のレイヤーにプッシュします。
Onsen UI 側の要素の位置を、適切に指定して、Google Maps 側の要素との重複表示を防ぎます。また、要素を適切に配置するためには、画面の解像度も考慮に入れます。要素自体のサイズも重要です。たとえば、div が大きすぎでも、使いにくいマップとなります。
- #map_canvas
{ position: absolute; width:100%; height: 100%; margin: 0; padding: 0; z-index: -1 - }
- .search-input-map{
width:60%; z-index:1; margin-left: auto; margin-right:auto; - }
- .par-search{
margin-top:10% - }
- .par-buttons{
position: absolute; text-align: center; width:100%; bottom:0px - }
- .btn-delete{
z-index:1 - }
- .btn-distance{
z-index:1; margin-left: 5px;
HTML
index.html、menu.html、map.html、settings.html の 4 つのファイルから、このアプリは構成されています ( settings.html の解説は割愛 )。これらのページには、HTML、Onsen UI、AngularJS の要素が記述されています。アプリの大枠には、Onsen UI 提供のスライディングメニューのテンプレートを使用しています。こちらのテンプレートは、Monacaから入手できます。どのテンプレートを使用するかは、開発者側の自由です。DOM の取り扱い方法などに、他のアイデアがある方は、他のテンプレートをご使用ください。
index.html
こちらが、アプリのメインページとなります ( Onsen UI のテンプレートの使用時には、デフォルトで作成されます )。HTML の宣言タグの後に、ng-app="myApp" が記述されています。このディレクティブ ( directive ) を使用して、AngularJS アプリの、いわゆる、自動初期化 ( bootstrap ) を行います。また、このディレクティブは、その役割から、アプリの root 要素を指し示し、通常、ページの root 要素 ( タグ、 タグなど ) 付近に置かれます。
スクリプトとシートを記述後、地図を表示するため、Google Maps のスクリプトを記述します。前のバージョンの Google Maps JavaScript API 以降、キーの取得・使用は、任意となりましたが、 Maps API の使用量の監視、追加の割り当ての購入の際には、必要となります。無料の Google Maps API キーの取得・記述方法に関しては、こちらのリンクをご確認ください。
以下のタグを使用して、地図を表示します。
- <script
type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
body の内容を見ます。body の中には、
- <!DOCTYPE
HTML> - <html
ng-app="myApp"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <script src="components/loader.js"></script> <link rel="stylesheet" href="components/loader.css"> <link rel="stylesheet" href="css/style.css"> <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"> </script> <script src="scripts/controller.js"></script> </head> <body> <ons-sliding-menu swipeable="false" var="slidingMenu" menu-page="menu.html" main-page="map.html" side="left" type="overlay" max-slide-distance="200px"> </ons-sliding-menu> </body> - </html>
menu.html
このページには、Monaca 側で自動作成した、
- <ons-page
style="background-color: white"> <ons-list> <ons-list-item modifier="tappable" class="list__item__line-height" onclick="slidingMenu.setMainPage('map.html', {closeMenu: true})"> <i class="fa fa-home fa-lg" style="color: #666"></i> Map </ons-list-item> <ons-list-item modifier="tappable" class="list__item__line-height" onclick="slidingMenu.setMainPage('settings.html', {closeMenu: true})"> <i class="fa fa-gear fa-lg" style="color: #666"></i> Settings </ons-list-item> </ons-list> - </ons-page>
map.html
こちらが、アプリの核となるページです。地図本体と複数の Onsen UI 要素から構成されています。ページ上部で、コントローラーの宣言 ( ng-controller="MapController" ) をしています。コントローラーの宣言は、root 要素で通常行われるので、それ以降の要素は、その影響 ( 設定 ) 下に置かれることが、一目でわかります。
また、その直下には、
残りのコードは、地図、検索ボックス、2 個のボタン (
- <ons-navigator
ng-controller="MapController"> <ons-page> <ons-toolbar fixed-style ng-controller="SlidingMenuController"> <div class="left"> <ons-toolbar-button ng-click="slidingMenu.toggleMenu()"><ons-icon icon="bars"></ons-icon></ons-toolbar-button> </div> <div class="center">Map</div> </ons-toolbar> <div id="map_canvas"></div> <p class="par-search"> <input type="search" class="search-input search-input-map"> </p> <p class="par-buttons"> <ons-button class="btn-delete" ng-click="deleteAllMarkers()"> Delete all markers </ons-button> <ons-button class="btn-distance" ng-click="calculateDistance()"> Distance </ons-button> </p> </ons-page> - </ons-navigator>
結論
Onsen UI、Google Maps JavaScript API v3、AngularJS の使用方法を、このサンプルアプリでお見せしました。
このサンプルアプリをひな形として、後は、自由にカスタマイズしてください。Google Maps API では、上述以外でも、たくさんの機能を提供しています。
自作する前に、Google Maps API の詳細を読み、使用できるものがないか、確認しましょう。