2005年07月14日

Movable Type用 位置プラグイン

Google Mapsが日本地図対応になった。しかも詳細。
いやー、すごいです。

というわけで、Google Maps APIなどの位置情報ツールとMovable Typeをつなぐプラグインを作成。エントリーに含まれる緯度経度を返します。
(2005-07-15 01:00 ちょっと変更)
locations.pl
(測地系変換にNowralさんのコードを使用させていただきました。ありがとうございます。)

インストール:
locations.plをpluginsディレクトリに置く
Image::Info
HTML::Parserに含まれるHTML::LinkExtor
が必要。HTML::Parserは多くのサーバに最初からインストールされているようだが、Image::Infoがない場合はここ参照

対応する位置情報:
・エントリー本文にimgタグとして記述され、同じサーバに置かれている画像のExif GPSタグ
・エントリー本文に含まれる地図サービスのURL ( walk.eznavi.jp / www.gpspowered.jp / mapfan.com / www.mapion.co.jp )

タグ記述例:

<MTEntries> <MTLocations> <$MTLocation coordinate="latitude" datum="1"$><br /> </MTLocations> </MTEntries>

パラメータ:

coordinate 緯度か経度かの指定。無指定の場合「緯度,経度」とカンマで区切って返す latitude 緯度 longitude 経度 datum 測地系。無指定の場合WGS84 0 WGS84 1 Tokyo97 format 緯度経度の表記方法。無指定で度単位。 dms 度.分.秒

実例:
その1-1:Individual Entry Archiveテンプレートに

<MTLocations> <a href="http://maps.google.com/maps?q=<$MTLocation datum="1"$>+(HERE)&spn=0.004588,0.006136&hl=ja">Google Maps</a><br /> </MTLocations>
と記述すると、位置情報が含まれるエントリーの場合Google Mapsの該当する位置へのリンクが生成される。こんな感じ

その1-2:Individual Entry Archiveテンプレートに

<MTLocations> <a href="http://www.mapfan.com/index.cgi?MAP=E<$MTLocation coordinate="longitude" datum="1" format="dms"$>N<$MTLocation coordinate="latitude" datum="1" format="dms"$>&ZM=12">Mapfan</a><br /> </MTLocations>
と記述すると、位置情報が含まれるエントリーの場合Mapfanの該当する位置へのリンクが生成される

その1-3:たとえばこのようなCGIをMovable TypeのCGIと同じディレクトリに置き、Individual Entry Archiveテンプレートに

<MTLocations> <a href="<$MTCGIPath$>red2map.cgi?ll=<$MTLocation$>&entry_id=<$MTEntryID$>">Map</a><br /> </MTLocations>
と書くと、地図サービスを選択してリンクすることができる。Google Mapsを選ぶとこんな感じ

その2:data.xmlという出力ファイル名のインデックス・テンプレートを作る。中身は以下。

<markers> <MTEntries lastn="100"><MTLocations> <marker lat="<$MTLocation datum="1" coordinate="latitude"$>" lng="<$MTLocation datum="1" coordinate="longitude"$>" permalink="<$MTEntryPermalink$>"/> </MTLocations></MTEntries> </markers>

Google Maps APIのこれを参考に、

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> <title>My Blog with Google Maps</title> <style type="text/css"> v?:* { behavior:url(#default#VML); } </style> <script src="http://maps.google.com/maps?file=api&v=1&key=abcdefg" type="text/javascript"></script> </head> <body> <div id="map" style="width: 640px; height: 640px"></div> <script type="text/javascript"> //<![CDATA[ var map = new GMap(document.getElementById("map")); map.addControl(new GSmallMapControl()); map.addControl(new GMapTypeControl()); map.centerAndZoom(new GPoint(139.741308333333,35.6553083333333), 4); function createMarker(point, permalink) { // Create a lettered icon for this point using our icon class from above var icon = new GIcon(); icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png"; icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png"; icon.iconSize = new GSize(12, 20); icon.shadowSize = new GSize(22, 20); icon.iconAnchor = new GPoint(6, 20); icon.infoWindowAnchor = new GPoint(5, 1); var marker = new GMarker(point, icon); var html = "<a href=?"" + permalink + "?">" + permalink + "</a>"; GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(html); }); return marker; } var request = GXmlHttp.create(); request.open("GET", "data.xml", true); request.onreadystatechange = function() { if (request.readyState == 4) { var xmlDoc = request.responseXML; var markers = xmlDoc.documentElement.getElementsByTagName("marker"); for (var i = 0; i < markers.length; i++) { var point = new GPoint(parseFloat(markers[i].getAttribute("lng")), parseFloat(markers[i].getAttribute("lat"))); var marker = createMarker(point, markers[i].getAttribute("permalink")); map.addOverlay(marker); } } } request.send(null); //]]> </script> </body> </html>
というhtmlを作ると、地図上に最近100件のエントリーの位置がマップされる。こんな感じ