2018/5/11 version 2.3.0がリリースされたので、書き直します。
2018/9/18 version 2.4.0からブラウザ上でも動作します。
cordova-googlemaps-pluginは、PhoneGap / Apache Cordova でGoogleマップをアプリ内に表示するためのプラグインです。Apache Cordovaは非常に有名なハイブリッドフレームワークで、このCordovaを使ったionic frameworkでも動きます。
日本ではこのApache Cordovaを使ってブラウザ上でアプリを作れるサービス Monacaが有名です。
1. 「ハイブリッド」ってなに
「ハイブリッド」とは「何かと何かを混ぜる」という意味です。
「ハイブリッドカー」なら「電気とガソリン」みたいな。
モバイルアプリにおける「ハイブリッドフレームワーク」とは、「ネイティブコードとその他コード」を指し、多くの場合は「ネイティブコード + HTML5」と思ってもらえばOKです。
つまりデザイン部分やメインコードは、HTML5 + JavaScriptで作成して、**それだけでは実装できないような機能は「ネイティブコード」の力を使ってアプリを簡単に作ろう!**というものです。
スライド拝借:https://www.slideshare.net/monaca_mobi/monaca-94729574
ハイブリッドフレームワークにはいくつかありますが、その中で有名なのが「Apache Cordova」です。
Apache Cordovaについては、これらの記事が参考になると思います。
CodeZine: Apache Cordovaで本格スマホアプリに挑戦しよう
Visual Studio+Apache Cordovaで始めるiOS/Androidアプリ開発
そのApache Cordovaをベースにしたフレームワークで、ネイティブコードのGoogleマップが動くようにしてくれるのが、紹介するcordova-googlemaps-pluginです。
2. AndroidとiOSの両方で動く
cordova-googlemaps-pluginは、一つのJavaScriptコードでAndroidとiOSとも動きます。
そしてGoogle Maps JavaScript API v3では出来ないような動きを簡単にできるのも、このプラグインのいいところです。
3. 地図を表示
地図を<div>の中に表示したければ、これだけです。
<div id="map_canvas" style="width:500px;height:500px"></div>
document.addEventListener("deviceready", function() {
var div = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(div);
}, false);
もし地図をもっと変更したければ、こんなこともできます。
var div = document.getElementById("map_canvas2");
var map = plugin.google.maps.Map.getMap(div, {
'mapType': plugin.google.maps.MapTypeId.HYBRID,
'controls': {
'compass': true,
'indoorPicker': true,
'zoom': true
},
'gestures': {
'scroll': true,
'tilt': true,
'rotate': true,
'zoom': true
},
camera: {
// 指定した位置を全部表示できるズームレベルに自動調整してくれる
target : [
{lat:41.79883, lng:140.75675},
{lat:41.799240000000005, lng:140.75875000000002},
{lat:41.797650000000004, lng:140.75905},
{lat:41.79637, lng:140.76018000000002},
{lat:41.79567, lng:140.75845},
{lat:41.794470000000004, lng:140.75714000000002},
{lat:41.795010000000005, lng:140.75611},
{lat:41.79477000000001, lng:140.75484},
{lat:41.79576, lng:140.75475},
{lat:41.796150000000004, lng:140.75364000000002},
{lat:41.79744, lng:140.75454000000002},
{lat:41.79909000000001, lng:140.75465},
{lat:41.79883, lng:140.75673}
],
'tilt': 60,
'bearing': 50
}
});
4. カメラアニメーション
cordova-googlemaps-pluginは、Google Maps Android API v2とGoogle Maps SDK for iOSを利用して地図を表示しています。
Google Maps JavaScript APIとは異なり、地図の描画をプログラム内でOpenGLを使用して行います。
だから
- ジェスチャーによる地図の回転
- カメラアニメーション
-
3Dによる建物の表示
などができます。
5. データ通信量の違い
前述のとおり、Google Maps Android API v2とGoogle Maps SDK for iOSは、プログラム内で地図を描画します。
つまりGoogleとAndroid / iOSデバイスは、どこにどういった地図を描画する、という地図データのやりとりだけをしています。
これはデータ通信量を抑えるので、デバイスのバッテリーの使用を抑えるのに役立ちます。またデータ通信量が少ないことで表示も素早く行われます。
6. 基本的な使い方
6.1 マーカーの追加
マーカーを追加したければ、これだけです。
var div = document.getElementById("map_canvas1");
var map = plugin.google.maps.Map.getMap(div);
var marker = map.addMarker({
'position': {
lat: 0,
lng: 0
}
});
6.2 情報ウィンドウの表示
cordova-plugin-googlemapsでは、**「RegularInfoWindow」と「HtmlInfoWindow」**の2種類の情報ウィンドウがあります。
RegularInfoWindowは、Googleが標準で用意している情報ウィンドウを使って文字や画像を表示する仕組みです。title
とsnippet
に表示したい文字を設定し、マーカーをクリックするか、marker.showInfoWindow()
メソッドを実行すると表示します。
var div = document.getElementById("map_canvas2");
var map = plugin.google.maps.Map.getMap(div);
var marker = map.addMarker({
'position': {
lat: 0,
lng: 0
},
title: "Hello Cordova Google Maps\n for iOS and Android",
snippet: "This plugin is awesome!"
});
// 情報ウィンドウの表示
marker.showInfoWindow();
6.3 クリック
クリックした時に対応したければ、こう書けます。
var marker = map.addMarker({
'position': GOOGLE_SYDNEY,
'title': 'Google Sydney',
'snippet': 'click, then remove',
});
mark.on(plugin.google.maps.event.MARKER_CLICK, function() {
marker.showInfoWindow();
});
marker.on(plugin.google.maps.event.INFO_CLICK, function() {
marker.remove();
});
6.4 HtmlInfoWindowの表示
HtmlInfoWindowを使うと、情報ウィンドウ内にHTMLを表示できます。
画像でもボタンでもブラウザで表示できるものは何でも表示できます。
var div = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(div);
var htmlInfoWindow = new plugin.google.maps.HtmlInfoWindow();
var html = [
'This is <b>Html</b> InfoWindow',
'<br>',
'<button onclick="javascript:alert(\'clicked!\');">click here</button>',
].join("");
htmlInfoWindow.setContent(html);
map.addMarker({
position: {lat: 0, lng: 0},
draggable: true,
infoWindow: htmlInfoWindow
});
どうやっているかというと、UIをブラウザビューにHTMLを表示して、それをマーカーが移動するのに合わせて位置を調整しているわけです。
6.5 ポリラインの描画
地図上のA点からB点, C点....に線を引きたい場合は、ポリラインを描画します。
使い方は簡単で、指定したい位置を指定していくだけです。
// 3つの空港の位置を定義
var HND_AIR_PORT = {lat: 35.548852, lng: 139.784086};
var SFO_AIR_PORT = {lat: 37.615223, lng: -122.389979};
var HNL_AIR_PORT = {lat: 21.324513, lng: -157.925074};
var AIR_PORTS = [
HND_AIR_PORT,
HNL_AIR_PORT,
SFO_AIR_PORT
];
var mapDiv = document.getElementById("map_canvas");
// 3空港が表示範囲内に収まるようにカメラ位置を調整した地図を作成
var map = plugin.google.maps.Map.getMap(mapDiv, {
camera: {
target: AIR_PORTS
}
});
// ポリラインの描画
var polyline = map.addPolyline({
'points': AIR_PORTS,
'color' : '#AA00FF',
'width': 10,
'geodesic': true // geodesic=trueにすると、地球の半径に合わせたカーブを描画します
});
6.6 ポリゴンの描画
多角形の図形を塗りつぶすには、ポリゴンを描画します。
ポリゴンの角となる位置のリストを渡すだけで描画します。
// 五稜郭公園の位置を定義
var GORYOKAKU_POINTS = [
{lat: 41.79883, lng: 140.75675},
{lat: 41.799240000000005, lng: 140.75875000000002},
{lat: 41.797650000000004, lng: 140.75905},
{lat: 41.79637, lng: 140.76018000000002},
{lat: 41.79567, lng: 140.75845},
{lat: 41.794470000000004, lng: 140.75714000000002},
{lat: 41.795010000000005, lng: 140.75611},
{lat: 41.79477000000001, lng: 140.75484},
{lat: 41.79576, lng: 140.75475},
{lat: 41.796150000000004, lng: 140.75364000000002},
{lat: 41.79744, lng: 140.75454000000002},
{lat: 41.79909000000001, lng: 140.75465},
{lat: 41.79883, lng: 140.75673}
];
// 地図を作成
var mapDiv = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(mapDiv, {
camera: {
target: GORYOKAKU_POINTS
}
});
// ポリゴンの追加
var polygon = map.addPolygon({
'points': GORYOKAKU_POINTS,
'strokeColor' : '#AA00FF',
'strokeWidth': 5,
'fillColor' : '#880000'
});
holes
プロパティを設定すれば、穴あきポリゴンも描画できます。
var points = [
{lat: 41.79873502198214,lng: 140.75676172883607}, // A(Blue)
{lat: 41.79916701538921, lng: 140.75850996560666}, // B
...
{lat: 41.79898498098061, lng: 140.75494811176304}, // W
{lat: 41.79872702373399, lng: 140.7566860846557} // X
];
var holes = [[
{lat: 41.795692, lng: 140.756214}, // A(Yellow)
{lat: 41.795492, lng: 140.756150}, // B
{lat: 41.795556, lng: 140.757813}, // C
...
{lat: 41.796004, lng: 140.755517}, // W
{lat: 41.795684, lng: 140.756225} // X
], [
{lat: 41.79509359115337, lng: 140.7559088009109}, // A(GREEN)
{lat: 41.795123461144776, lng: 140.75608584124757}, // B
{lat: 41.79546948885738, lng: 140.7556779973297}, // C
{lat: 41.79554756063853, lng: 140.7555651964035}, // D
{lat: 41.795647713509155, lng: 140.7550391871414}, // E
{lat: 41.794831758258425, lng: 140.75507730157472} // F
]];
var div = document.getElementById("map_canvas");
// Initialize the map view
var map = plugin.google.maps.Map.getMap(div, {
'camera' : {
target: points
}
});
var polygon = map.addPolygon({
points: points,
holes: holes,
strokeColor: "blue",
strokeWidth: 4,
fillColor: "#FF0000AA"
});
6.7 サークルの描画
サークル(円)を描画したければ、map.addCircle()
を使用します。
var GOOGLE = {"lat" : 37.422858, "lng" : -122.085065};
var mapDiv = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(mapDiv);
// Add circle
var circle = map.addCircle({
'center': GOOGLE,
'radius': 300,
'strokeColor' : '#AA00FF',
'strokeWidth': 5,
'fillColor' : '#880000'
});
map.moveCamera({
target: circle.getBounds()
});
6.8 タイルオーバーレイの追加
地図の上に異なる地図タイルを描画したい場合、タイルオーバーレイを追加することができます。
もしくはGoogleの地図を表示せずに、自分で用意したタイル画像だけをしようして、オフラインでも地図を表示することができるようにもできます。
var mapDiv = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(mapDiv, {
//'mapType' : plugin.google.maps.MapTypeId.NONE,
'preferences': {
'zoom': {
'minZoom': 0,
'maxZoom': 4
}
}
});
var tileOverlay = map.addTileOverlay({
debug: true, // draw the debug information on tiles
opacity: 0.75, // from 0.0 to 1.0
// Load image files from the local file path
getTile: function(x, y, zoom) {
return "http://tile.openstreetmap.org/" + zoom + "/" + x + "/" + y + ".png";
}
});
7. 位置の取得
デバイスの位置を取得したければ、LocationService.getMyLocation()
を実行するだけです。GPSとかネットワークから取得とか気にする必要はありません。
var div = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(div);
var button = div.getElementsByTagName('button')[0];
button.addEventListener('click', function() {
// 現在位置の取得を試みる
LocationService.getMyLocation()
.then(function(location) {
// 現在位置が取得できた
var msg = ["Current your location:\n",
"latitude:" + location.latLng.lat,
"longitude:" + location.latLng.lng,
"speed:" + location.speed,
"time:" + location.time,
"bearing:" + location.bearing].join("\n");
// マーカーを追加
var marker = map.addMarker({
'position': location.latLng,
'title': msg
});
// カメラの位置を移動する
map.animateCamera({
target: location.latLng,
zoom: 16
});
// 情報ウィンドウを表示する
marker.showInfoWindow();
})
.catch(function(error) {
// 位置情報が取得できなかったとき
alert(JSON.stringify(error));
});
});
8. オーバーレイのクリック
cordova-googlemaps-plugin では、クリックの認識を独自に実装しています。
それによって、PolylineやPolygonなどをクリックしたときに、その緯度経度を取得することが出来ます。
Google Maps Android API v2とGoogle Maps SDK for iOSでは、『クリックしたことはわかりますが、緯度経度は取得できません』
地味ですが重要です。
var GORYOKAKU_POINTS = [
{lat: 41.79883, lng: 140.75675},
{lat: 41.799240000000005, lng: 140.75875000000002},
{lat: 41.797650000000004, lng: 140.75905},
{lat: 41.79637, lng: 140.76018000000002},
{lat: 41.79567, lng: 140.75845},
{lat: 41.794470000000004, lng: 140.75714000000002},
{lat: 41.795010000000005, lng: 140.75611},
{lat: 41.79477000000001, lng: 140.75484},
{lat: 41.79576, lng: 140.75475},
{lat: 41.796150000000004, lng: 140.75364000000002},
{lat: 41.79744, lng: 140.75454000000002},
{lat: 41.79909000000001, lng: 140.75465},
{lat: 41.79883, lng: 140.75673}
];
var mapDiv = document.getElementById("map_canvas");
var map = plugin.google.maps.Map.getMap(mapDiv, {
camera: {
target: GORYOKAKU_POINTS
}
});
// ポリゴンの追加
var polygon = map.addPolygon({
'points': GORYOKAKU_POINTS,
'strokeColor' : '#AA00FF',
'strokeWidth': 5,
'fillColor' : '#880000',
'clickable' : true // default = false
});
// クリックイベントを捉える
// latLng:ポリゴン上でクリックした位置の緯度経度
polygon.on(plugin.google.maps.event.POLYGON_CLICK, function(latLng) {
// ポリゴンの色を変更
polygon.setFillColor("blue");
polygon.setStrokeColor("green");
polygon.setStrokeWidth(10);
// マーカーの追加
var marker = map.addMarker({
position: latLng,
title: "You clicked here on the polygon!",
snippet: latLng.toUrlValue()
});
marker.showInfoWindow();
});
9. KMLファイルの読み込みができます!
KMLファイルとは、地図のどこにマーカーを追加して、どこにポリゴンを描画して、、、などを記述するファイル形式です。
GoogleマイマップやGoogle Earthで作成することが出来ます。
cordova-plugin-googlemapsでは、このKMLファイルを読み込むことが出来るので、コードとデータを分離することが出来ます。
ただし、KMZファイルには対応していません。
map.addKmlOverlay({
'url':"polygon.kml",
'clickable': true,
'suppressInfoWindows': false
}, function(kmlOverlay) {
// デバッグ用(試してみてください)
//console.log(kmlOverlay);
// クリックイベントを捉える
kmlOverlay.on(plugin.google.maps.event.KML_CLICK, function(overlay, latLng) {
console.log(overlay);
});
// 地図のカメラは自動で調整されないので、
// 全体を表示するにはkmlOverlay.getDefaultViewport()を使って
// 全体を含む範囲を取得してください
map.moveCamera(kmlOverlay.getDefaultViewport());
});
10. 複数箇所のジオコーディング
複数箇所のジオコーディングは割と面倒ですが、このプラグインを使えば楽勝です。
plugin.google.maps.Geocoder.geocode({
address: [
"住所1", "住所2", ..., "住所N"
]
}, function(baseArray) {
baseArray.on('finish', function() {
var positionList = baseArray.getArray();
});
});
例えば下の画像は、アメリカ51州の位置を緯度経度に変換しています。
11. マーカークラスター
1,000箇所とか10,000箇所とかのマーカーを地図上に追加すると、すぐにメモリ不足になってしまいます。
そこで密度の高い箇所は、一つのマーカーにまとめてくれるのが、マーカークラスターです。
var markerCluster = map.addMarkerCluster({
//maxZoomLevel: 5,
boundsDraw: true,
markers: dummyData(),
icons: [
{min: 2, max: 100, url: "./img/blue.png", anchor: {x: 16, y: 16}},
{min: 100, max: 1000, url: "./img/yellow.png", anchor: {x: 16, y: 16}},
{min: 1000, max: 2000, url: "./img/purple.png", anchor: {x: 24, y: 24}},
{min: 2000, url: "./img/red.png",anchor: {x: 32,y: 32}},
]
});
// クリックされたら、マーカーの情報を取得して表示
var htmlInfoWnd = new plugin.google.maps.HtmlInfoWindow();
markerCluster.on(plugin.google.maps.event.MARKER_CLICK, function (position, marker) {
var html = [
"<div style='width:250px;min-height:100px'>",
"<img src='img/starbucks_logo.gif' align='right'>",
"<strong>" + (marker.get("title") || marker.get("name")) + "</strong>",
"<div style='font-size:0.8em;'>" + marker.get("address") + "</div>",
"<a href='tel:" + marker.get("phone") + "' style='font-size:0.8em;color:blue;'>Tel: " + marker.get("phone") + "</div>"
].join("");
htmlInfoWnd.setContent(html);
htmlInfoWnd.open(marker);
});
12. Googleストリートビュー
version 2.3.0からGoogleストリートビューがを表示できます。
cordova-googlemaps-pluginなら、数行のコードで簡単に実装することが出来ます。
var div = document.getElementById("pano_canvas1");
var panorama = plugin.google.maps.StreetView.getPanorama(div, {
camera: {
target: {lat: 42.345573, lng: -71.098326}
}
});
13.地理的な計算を行うための sphericalユーティリティ
例えばspherical.interpolate()は、2地点間の曲線の中間地点を計算するメソッドです。
面積の計算はspherical.computeArea()メソッドで出来ます。
14. 使用しやすいライセンス
cordova-googlemaps-pluginは、Apache Software License 2.0を採用しています。
概略としては、以下のとおりです。(Wikipediaより抜粋・編集)
- 開発者は、アプリにApache Licenseのコードが使われていることを知らせる文言を入れることは必須。
- ライセンスされたファイルそれぞれに元々ある著作権と特許権の記述はそのまま保持されなければならず、何らかの修正が施されている場合は、その旨を追加記述しなければならない。
- 上記2項目が遵守されれば、フリーソフトウエア、オープンソースソフトウェアとして頒布されることを要求しない。つまり商用利用も可。
ただし、Google Maps Android API v2および、Google Maps SDK for iOSそのものにもソフトウェア・ライセンスがあります。
- Google Maps/Google Earth APIs Terms of Serviceに従う必要がある
- アプリ内に**"Legal Notices"**セクションを用意して、SDKが使用しているOpen Source Projectのソフトウェアライセンスを表示する必要がある。
詳しくは、ここのページに書いてあります。
https://github.com/mapsplugin/cordova-plugin-googlemaps-doc/blob/master/v2.0.0/Terms-of-Services/README.md
15. ドキュメント
ドキュメントが必要ですよね。全部英語ですが、こちらを見てください。
https://github.com/mapsplugin/cordova-plugin-googlemaps-doc/tree/master/v2.0.0
英語は苦手な方も大丈夫です。 API Reference > Classes を見ていただければ、大量のサンプルコードとスクリーンキャプチャがあります。
コードだけ読んでもらえば分かると思います。
そのうち誰か日本語訳してくれたらありがたいです。
16. 日本語で質問
Issue listに日本語で質問していただければ、日本語で返します。
もしくは 公式コミュニティに日本語で投稿してもらっても構いません。
17. デモアプリ
ここのレポジトリで公開しています。
APKファイルもあるので、Androidユーザの人はインストールすることができます。
以上、cordova-googlemaps-pluginを使うべき理由を挙げてみました。
Google Maps JavaScript API v3と比較すると機能面は劣りますが、パフォーマンスは抜群です。
海外では、ionic frameworkのnative機能として採用されています。
ぜひ使ってみてください。