Googleマプレット(Mapplets)開発(日本語版)
社内有志の英語勉強会での発表資料の翻訳版です。Google Mapplets開発の説明です。
要素技術
- Google Maps
- Google Maps API
- KML
- マイマップ
- マプレット
- Geocoding
要素技術; Google Maps
- Webアプリの名称(サービス)
- 今から話すことのベース技術です
要素技術; Google Maps API
- JavaScriptのAPIです
- このAPIを使うと、Google Mapsのサービスを自分のサイトで利用できます
要素技術; Google Maps API; アーキテクチャ
- 動作シーケンス (データ転送のみを記述)
- 'you'を開発者と想定しています
your web end-user google server server (browser) +-+ | | html ====> +-+ (js1) src="http://www.google.com/maps" +-+ <==== | | js2 +-+ jsが走る - js1が js2のAPIを 呼ぶ js2が - 画像のロード <=== images... をして - HTML上に描画
要素技術; KML
KML: Keyhole Markup Language
データフォーマット(XML)の定義
http://code.google.com/apis/kml/ から引用
KML is a file format used to display geographic data in an earth browser, such as Google Earth, Google Maps and Google Maps for mobile.
@fyi Keyhole: 会社名(Googleに買収された)
要素技術; マイマップ (cont.)
- 'マイマップ'はKMLのグラフィカルエディタです
- この見立てのオリジナルは以下のサイト
- http://as-is.net/blog/archives/001235.html
KMLの出力例
要素技術; マプレット
- Google Maps上のサービスのひとつ
- Google Mapsの新しいAPIです
- これもJavaScript APIです
- アプリ開発に必要なことはXMLファイルをひとつ作ることだけです (もっとも、JavaScriptのコードとHTMLの断片を含んだXMLですが)
- マプレットはGoogle Gadgetsの一種です
要素技術; マプレット; アーキテクチャ
- 動作シーケンス (データ転送のみを記述)
- 'you'を開発者と想定しています
your web end-user google server server (browser) <=== http://maps.google.co.jp contents(html,images,...) あなたのmappletを追加(URL-m) URL-m +-+ | | ====================> XML(Mapplet application) +-+ <=== js,html
要素技術; Geocoding
- アドレスから位置情報を取得できます
- GeocodingはGoogle固有の技術ではありません
- 以下のように試せます (注意; APIキーは不完全にしています)
Google Maps API vs. マプレットAPI
もしGoogle Mapsプログラミングを手軽に楽しみたいなら、マプレット APIを勧めます 理由は
- 作るのが簡単
- デプロイも簡単
Google Mapsを使った新しいサービスを作りたい場合、Google Maps APIを勧めます 理由は
- とりあえずなんでもできます(APIの範囲ですが)
- Google Mapsサイトを越えるサイトを作るかもしれません (マプレットを使う限り、Google Mapsサイトの手の中から出られません)
2.
マプレット APIで遊んでみましょう
始め方
- Google Mapsのアカウントを取得してください (アリエルの人は、gmap@ariel-networks.com を共用アカウントとして使えます)
- 以下のふたつのマプレットを選択追加してください
- Mapplet Scratch Pad
- Developer Mapplet
簡単な例
とりあえず、hello, world!
Googleのチュートリアルから引用
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Hello World" description="Displays a Hello World message in the left panel" author="ariel" author_email="gmap@ariel-networks.com" height="150"> <Require feature="sharedmap"/> </ModulePrefs> <Content type="html"><![CDATA[ <h2>Hello World!</h2> ]]></Content> </Module>
このコードを'Mapplet Scratch Pad'にペースして、'Preview'ボタンを押してください
簡単な例 (cont)
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Hello World" description="Displays a Hello World message in the left panel" author="ariel" author_email="gmap@ariel-networks.com" height="150"> <Require feature="sharedmap"/> </ModulePrefs> <Content type="html"><![CDATA[ <script type="text/javascript"> function init() { alert('init called'); } function onClick() { alert('onClick called'); _gel('content').innerHTML = 'innerHTML is our friend'; // _gel() is document.getElementById() } _IG_RegisterOnloadHandler(init); </script> <style type="text/css"> .highlight { color: red } </style> <h2 class="highlight" onclick="onClick()">Hello World!</h2> <div id="content"/> ]]></Content> </Module>
prototype.js
マプレットのアプリ開発では、多くの非同期呼び出しが必要です
個人的に、prototype.js無しでJavaScriptのコードが書けません。 prototype.jsは巨大なので、一部(非同期呼び出しまわり)のコードだけ拝借します
以下のコードをマプレットのアプリのコードにコピー&ペーストしてください
// derived from prototype.js =begin var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } } // derived from prototype.js =end
GEvent.bindがありますが...
- GEvent.bind
- GEvent.bindDom
一見良さそうですが、これらだけでは不充分です
汎用的な'bind()'が必要なので、prototype.jsのbind()を使います
開発プロセス
- 'Mapplet Scratch Pad'アプリを選択
- 以下のスケルトンコードをペースト
- 自分のコードを追加
- 'Preview'ボタンを押して動作確認
- デバッグ
クラスベースのスケルトンコード
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Hello World" description="Displays a Hello World message in the left panel" author="ariel" author_email="gmap@ariel-networks.com" height="150"> <Require feature="sharedmap"/> </ModulePrefs> <Content type="html"><![CDATA[ <script type="text/javascript"> // derived from prototype.js =begin var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } } // derived from prototype.js =end var MyMapplet = Class.create(); MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); // ADD YOUR CODE(initialization) }, // ADD YOUR CODE debug: function(msg) { // this is your only friend _gel('msg').innerHTML += '<div>' + msg + '</div>'; } } function init() { new MyMapplet(); } _IG_RegisterOnloadHandler(init); </script> <div id="msg"/> ]]></Content> </Module>
注意
以降、MyMapplet.prototype 内のみを表記します
簡単な非同期呼び出しの例
中心の座標を表示します(一回のみ)
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); this.map.getCenterAsync(function(latlng) { this.debug('lat = ' + latlng.lat() + ', lng = ' + latlng.lng()); }.bind(this)); }, debug: function(msg) { _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
簡単な非同期呼び出しの例 (cont.)
中心の座標を表示します(移動ごと)
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); GEvent.addListener(this.map, 'dragend', this.onMove.bind(this)); }, onMove: function() { this.map.getCenterAsync(function(latlng) { this.debug('lat = ' + latlng.lat() + ', lng = ' + latlng.lng()); }.bind(this)); }, debug: function(msg) { _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
マーカー(Marker)
クリックごとにマーカーを表示します
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); GEvent.addListener(this.map, 'click', this.onClick.bind(this)); }, onClick: function(overlay, point) { if (!overlay) { this.map.addOverlay(new GMarker(point)); } }, debug: function(msg) { // this is your only friend _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
InfoWindow
クリックすると、女性が現れます
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); GEvent.addListener(this.map, 'click', this.onClick.bind(this)); }, onClick: function(overlay, point) { if (point) { // point could be null if (!overlay) { this.map.openInfoWindowTabsHtml(point, [new GInfoWindowTab('tozawa', '<img src="http://www.ariel-networks.com/company/employee/images/tozawa.jpg"/>'), new GInfoWindowTab('takatera', '<img src="http://www.ariel-networks.com/company/employee/images/takatera.jpg"/>'), new GInfoWindowTab('tien', '<img src="http://www.ariel-networks.com/company/employee/images/tien.jpg"/>')]); } } }, debug: function(msg) { // this is your only friend _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
InfoWindow(cont.)
クリックすると、Google Maps上にありえりえりあが現れます
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); GEvent.addListener(this.map, 'click', this.onClick.bind(this)); }, onClick: function(overlay, point) { if (point) { this.map.openInfoWindowHtml(point, '<iframe src="http://dev.ariel-networks.com"/>'); } }, debug: function(msg) { // this is your only friend _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
プロットするなら、KML
静的な位置情報をプロットするだけならKMLを使ってください。 コードを書く必要はありません(書いてはいけません)。
MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); this.map.setCenter(new GLatLng(35.644307, 139.699157), 15); this.map.addOverlay(new GGeoXml("http://maps.google.co.jp/maps/ms?hl=ja&gl=jp&ie=UTF8&msa=0&msid=107061927227382858092.0004436b779d2ca57b1a9&z=17&om=1&output=kml")); this.map.addOverlay(new GGeoXml("http://maps.google.co.jp/maps/ms?ie=UTF8&hl=ja&msa=0&msid=107466427548098455555.00043a52ff3965b48e83c&z=17&om=1&output=kml")); }, debug: function(msg) { _gel('msg').innerHTML += '<div>' + msg + '</div>'; } }
上記コードは中目黒を中心に、ふたつのKMLをプロットします。 KMLは'マイマップ'で生成しています。
Geocodingを使う例
全コード掲載;
<?xml version="1.0" encoding="UTF-8"?> <Module> <ModulePrefs title="Hello World" description="Displays a Hello World message in the left panel" author="ariel" author_email="gmap@ariel-networks.com" height="150"> <Require feature="sharedmap"/> </ModulePrefs> <Content type="html"><![CDATA[ <script type="text/javascript"> // derived from prototype.js =begin var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } } // derived from prototype.js =end var MyMapplet = Class.create(); MyMapplet.prototype = { initialize: function() { this.map = new GMap2(); this.geocoder = new GClientGeocoder(); this.geo_input = _gel('geo-input'); GEvent.bindDom(this.geo_input, 'change', this, this.onInput); }, onInput: function(ev) { var address = this.geo_input.value; this.geocoder.getLatLngAsync( address, function(latlng) { if (!latlng) { alert(address + " not found"); } else { this.map.setCenter(latlng, 15); var marker = new GMarker(latlng); this.map.addOverlay(marker); marker.openInfoWindowHtml(address); } }.bind(this) ); }, debug: function(msg) { _gel('msg').innerHTML += '<div>' + msg + '</div>'; } } function init() { new MyMapplet(); } _IG_RegisterOnloadHandler(init); </script> <input type="text" id="geo-input"/> <div id="msg"/> ]]></Content> </Module>
外部のWeb APIの利用
参照:
宿題
何かマプレットを作ってみてください