MovableTypeで地図付きブログを作ってみよう
※書きかけです。後々ちゃんとまとめる予定
よそで地図付きブログみたいなのを作っているのですが、どうやって作ったのか忘れてしまいそうなので、やってみたことをメモしておきます。
やりたかったこと
- エントリ投稿時に、住所だけを入力したら座標を調べなくてもエントリに地図が表示されるようにする
- 具体的には、投稿画面で「住所入力」→「変換ボタンクリック!」→「座標に変換される」→「投稿する」→「エントリに地図が表示されてる!」という流れ
やってみたこと
1.エントリ投稿フォームに入力欄を追加
MovableTypeのエントリ投稿フォームに用意されている入力欄は「エントリーの内容」「追記」「概要」で、当然ながら「住所」という欄はありません。なのでこれを追加する必要がありました。入力欄の追加は、RightFieldsというプラグイン(シェアウェア:15$)を使えば可能になります。
RightFields(英語)
日本語だと下記の解説が詳しいです。
RightFields - Turn your MT into Google Base!
このRightFieldsを使って、「住所(データ名:rf_address)」「経度(rf_x)」「緯度(rf_y)」という入力欄を追加しました。
2.住所を座標情報(緯度・経度)に自動変換する仕組みを作る
Google Maps APIは今のところ日本の住所を座標に変換してくれないので、Geocoding APIというのを使います。
が。Geocoding APIはXMLで座標情報を返してくれるのですが、僕はXMLをパースする技術を持っていません。なので実際にはGeocoding APIの出力結果をJSONに変換してくれる下記のJavascriptを参考にしました。
JSONでBiddersインクリメンタル検索、をブログに貼ってみる、の応用(Google Maps API+Geocoding.jp)
上記で公開されているソースを元に、住所を渡すとエントリ投稿フォームの「緯度」「経度」欄に値が入るように書き直して自分のサーバに置きました。
こんな感じ。
/////////////////////////////////////////////
//
// geocoder.js
// enables HTML to access geocoding.jp using JSON
// (C) TEDDY-G 2005
//
// 05/10/17 add Callback Function
// 05/10/18 add geocoderCsis
// 06/03/27 edited by nac
//
/////////////////////////////////////////////
var geocoderjpAPI="http://www.got2do.com/api/proxyJSON.php?uri_xml=http://www.geocoding.jp/api/&q=";
var geocodingCsisAPI='http://www.got2do.com/api/proxyJSON.php?uri_xml=http://saya.s145.xrea.com/x/geocode.cgi&mode=TKY&addr=';
var geoURI='';
var __gmap=false;
var now=new Date();
var __count=now.getYear()*3600*24*31*12+now.getMonth()*3600*24*31+now.getDate()*3600*24+now.getHours()*3600+now.getMinutes()*60+now.getSeconds()-5;
var __count_old=__count;
var __loadId="message";
var __loadMes="Loading...";
var __alertId="message";
var __funcSuccess=null;
var __funcFault=null;
var __service='geocodingjp';
/////////////////////////////////////////////
//
// moveMap(JSON)
// handle GMap according to JSON output
//
/////////////////////////////////////////////
var moveMap = function(arrayGeo){
var html='';
getComponentById(__loadId).innerHTML='';
if (typeof arrayGeo.choices!="undefined") {
html+='検索結果:' + arrayGeo.choices.choice.length + '<br/>';
for (var i=0;i<arrayGeo.choices.choice.length;i++) {
var choice=arrayGeo.choices.choice[i];
html+='<a href="#" onClick="keyToGmap(\''+choice+'\')">'+choice+'</a><br>';
}
//document.getElementById(__alertId).innerHTML=html;
getComponentById(__alertId).innerHTML=html;
} else {
if (geocoderErr(arrayGeo)==false) {
//try {
var _lat=(__service=="geocodingCsis")?arrayGeo.y:arrayGeo.coordinate.lat;
var _long=(__service=="geocodingCsis")?arrayGeo.x:arrayGeo.coordinate.lng;
//document.getElementById(__alertId).innerHTML= '('+_lat + ',' +_long+')';
//getComponentById(__alertId).innerHTML= '検索結果:('+_lat + ',' +_long+')';
if (__funcSuccess!=null) {
__funcSuccess(_lat,_long,__alertId);
}
} else {
//}catch(e) {
//document.getElementById(__alertId).innerHTML=arrayGeo;
//getComponentById(__alertId).innerHTML='検索結果:0';
if (__funcFault!=null) {
__funcFault(__alertId);
}
}
}
//if (__gmap!=false) {
/*
_center=__gmap.getCenterLatLng();
if (typeof _long=="undefined") {_long=_center.x;}
if (typeof _lat=="undefined") {_lat=_center.y;}
__gmap.centerAndZoom(new GPoint(parseFloat(_long), parseFloat(_lat)), __gmap.getZoomLevel());
*/
/*ここから独自拡張*/
window.document.entry_form.rf_x.value = parseFloat(_long);
window.document.entry_form.rf_y.value = parseFloat(_lat);
/*ここまで独自拡張*/
//}
}
function geocoderErr(arrayGeo) {
return (__service=="geocodingCsis")?(arrayGeo.x=='fX'):(arrayGeo.error!=null);
}
/////////////////////////////////////////////
//
// handleGmap(gmap,loadId,loadMes,alertId,funcSuccess,funcFault,service)
// initialize data used for library
//
/////////////////////////////////////////////
function handleGmap(gmap,loadId,loadMes,alertId,funcSuccess,funcFault,service) {
if (gmap!=null) {__gmap=gmap;}
if (loadId!=null) {__loadId=loadId;}
if (loadMes!=null) {__loadMes=loadMes;}
if (alertId!=null) {__alertId=alertId;}
if (funcSuccess!=null) {__funcSuccess=funcSuccess;}
if (funcFault!=null){__funcFault=funcFault;}
if (service!=null) {__service=service;}
}
/////////////////////////////////////////////
//
// keyToGmap(keyword)
// generate URI of got2do proxy from keyword
//
/////////////////////////////////////////////
function keyToGmap(keyword) {
// check interval
var now=new Date();
__count_old=__count;
__count=now.getYear()*3600*24*31*12+now.getMonth()*3600*24*31+now.getDate()*3600*24+now.getHours()*3600+now.getMinutes()*60+now.getSeconds();
var wait=0;
if ((__service!="geocodingCsis")&&(__count-__count_old<5)) {
//alert("Do not submit the keyword within 5 seconds.");
//document.getElementById(__loadId).innerHTML='Waiting...';
getComponentById(__loadId).innerHTML='Waiting...';
wait=(5-(__count-__count_old))*1000;
};
//document.getElementById(__loadId).innerHTML=__loadMes;
geoURI = (__service=="geocodingCsis")?geocodingCsisAPI:geocoderjpAPI;
geoURI+= (__service=="geocodingCsis")?keyword:encodeURI(keyword);
geoURI+= '&name_f=moveMap';
//setTimeout('document.getElementById(__loadId).innerHTML=__loadMes;loadJSON(geoURI);',wait);
setTimeout('getComponentById(__loadId).innerHTML=__loadMes;loadJSON(geoURI);',wait);
}
/////////////////////////////////////////////
//
// loadJSON(uri)
// rereave JSON output from got2do proxy
//
/////////////////////////////////////////////
if (typeof loadJSON=="undefined") {
var loadJSON = function(_uri){
var s=document.createElement("script");
s.setAttribute('type','text/javascript');
s.setAttribute('src',_uri);
s.setAttribute('charset','UTF-8');
document.body.appendChild(s);
}
}
if (typeof getComponentById=="undefined") {
var getComponentById = function(_id) {
var docElmt=document.getElementById(_id);
if (docElmt!=null) {
return docElmt;
} else {
var dummy=new Object();
dummy.innerHTML='';
return dummy;
}
}
}
if (typeof $_GET=="undefined") {
var $_GET = function() {
var args=new Array();
if (location.search.length>1) {
var strs = location.search.substr(1).split("&");
for (str in strs) {
var item=strs[str].split("=");
args[item[0]]=item[1];
}
}
return args;
}
}
3.keyToGmap()をエントリ投稿画面から起動できるようにする
住所→座標への変換はgeocoder.jsのkeyToGmap(住所)という関数を使います。これを起動するためのリンクを投稿画面に仕込みます。
<a href='javascript:void(0);' onclick='keyToGmap(encodeURI(window.document.entry_form.rf_address1.value));'> 位置情報を自動取得 </a>
4.Google MapsをMovableTypeのテンプレートに設置
個別エントリテンプレートを修正。こんな感じで書きました。
<script src="http://maps.google.com/maps?file=api&v=1&key=ABQIAAAAXkmkZWEPZJQKsKr2dlrhohRBkvhQuCjUgeX5Q0p9bZA2XQgPnxTeaOmtbJFmj6rREqMpse30VpN0Zw" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
function loadGMap(){
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.centerAndZoom(new GPoint(<MTExtraFields><MTIfExtraFields><MTIfExtraField field="x"><$MTExtraFieldValue field="x"></MTIfExtraField></MTIfExtraFields></MTExtraFields>, <MTExtraFields><MTIfExtraFields><MTIfExtraField field="y"><$MTExtraFieldValue field="y"></MTIfExtraField></MTIfExtraFields></MTExtraFields>), 1);
//custom marker
var marker_food = new GIcon();
marker_food.image = "/images/common/marker-food.png";
marker_food.shadow = "/images/common/marker-food_shadow.png";
marker_food.iconSize = new GSize(35, 35);
marker_food.shadowSize = new GSize(35, 35);
marker_food.iconAnchor = new GPoint(12, 30);
marker_food.infoWindowAnchor = new GPoint(12, 35);
// Creates a marker whose info window displays the given number
function addMarker(map, lat, lng, html) {
var point = new GPoint(lat, lng);
var marker = new GMarker(point, marker_food);
// Show this marker's index in the info window when it is clicked
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
map.addOverlay(marker);
}
addMarker(map, <MTExtraFields><MTIfExtraFields><MTIfExtraField field="x"><$MTExtraFieldValue field="x"></MTIfExtraField></MTIfExtraFields></MTExtraFields>, <MTExtraFields><MTIfExtraFields><MTIfExtraField field="y"><$MTExtraFieldValue field="y"></MTIfExtraField></MTIfExtraFields></MTExtraFields>, "<b><$MTEntryTitle$></b><br/><MTEntryData field="address"><MTEntryDataFieldValue></MTEntryData>");
//]]>
}
</script>
以上です。完全に自分用ですね。わけわかんない(汗
※後々わかりやすくまとめる予定。。
posted by nac | permalink | comments (0) | trackbacks (0)








コメント