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の利用
参照:
宿題
何かマプレットを作ってみてください