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件のエントリーの位置がマップされる。こんな感じPosted by jiro at 2005年07月14日 18:46 | トラックバック (24)
コメント

面白い記事ありがとうございます。
この記事を参考に、自サイトでも「地図上に最近100件のエントリーの位置がマップされる」ようにしたいのですが、IEだと何も表示されず、うまく表示されません。Firefox、ネスケ、Operaだと表示されます。

Posted by: ぺが at 2005年07月26日 21:45

あ、ほんとですね。IEはほとんど使っていないので気付きませんでした。ご指摘ありがとうございます。
http://www.google.com/apis/maps/documentation/#XHTML_and_VML
を参考に動くようにしました。

Posted by: motonaga at 2005年07月27日 01:07

IEでも見れるようになりました。
ご対応いただきありがとうございました。

Posted by: ぺが at 2005年07月27日 08:16

すばらしいプラグインありがとうございます。ところで、アップロードでEXIF画像をサムネイル化した場合、本文に位置座標が記述されませんが、対応は予定されていますか?

Posted by: foxhound at 2005年08月25日 16:48

すばらしいプラグインありがとうございます。ところで、アップロードでEXIF画像をサムネイル化した場合、本文に位置座標が記述されませんが、対応は予定されていますか?

Posted by: foxhound at 2005年08月25日 16:49

すばらしいプラグインありがとうございます。ところで、アップロードでEXIF画像をサムネイル化した場合、本文に位置座標が記述されませんが、対応は予定されていますか?

Posted by: foxhound at 2005年08月25日 16:50

サムネイル化した場合、html的には単なる静的に生成されたhtmlファイルへの「リンク」になり、それがサムネイルのつもりで記述されたものなのか、同一サイト内へのリンクとして任意に記述されたものなのかを厳密に見分ける方法はありません。
いろいろ条件を付ければ判別可能だとは思いますが、実際に運用する際の汎用性が下がります。

サムネイルのリンク先が「そのエントリーに記述された位置」なのかどうかも迷うところです。位置を取る手をそこまで延ばすと、「blogエントリーの位置情報」という原理が揺らぐ気もします。

というわけで今のところ対応の予定はありません。

Posted by: jm at 2005年10月15日 19:31

はじめまして面白いプラグインありがとうございます。いま必死にMTのエントリーをMapにリンクするように作業してるのですが、どうしてもエントリーの画像を抜き出す部分の記述方がわかりません。
MTCollectを使用する方法で試してみたのですがうまく行かず行き詰まりの状態です。
どうかご教授いただけないでしょうか。
よろしくお願いします。

Posted by: Shou at 2005年10月29日 14:46

エントリーの画像を色々試して、表示する事ができました。おさがわせしました。

Posted by: Shou at 2005年10月30日 00:51

何度もコメント失礼致します。
位置情報が含まれるエントリーに表示する
地図のリンクURLを自分の地図にリンクURLする事はできないのでしょうか。
てぃーだ
↑このブログようにリンクできないでしょうか。
どうか、ご教授お願いできないでしょうか。
よろしくお願いします。

Posted by: Shou at 2005年10月30日 05:59

先日はサムネイルのコメントに対する回答ありがとうございました。ところで、GoogleMapが12月から世界測地形になってしまうみたいですが、location.plは今のままでも使えるのでしょうか?それとも改修が必要になるのでしょうか?

Posted by: foxhound at 2005年11月27日 23:37

このページの「パラメータ:」の部分にも記載していますが、datum="1"になっている部分を省略すれば世界測地系になります。datum="0"と明示しても構いません。

Posted by: jm at 2005年11月27日 23:45

すみません。
その1-3のred2map.cgiを使った場合、GoogleMapをWGS84(世界測地系)にするにはどうすればよいのでしょうか?

Posted by: 朱雀ぱ at 2005年12月11日 22:01

cgiの309行目
} elsif ($map_service eq 'Google Maps') {
($lon, $lat) = geoconv($lon, $lat, 1);

} elsif ($map_service eq 'Google Maps') {
($lon, $lat) = geoconv($lon, $lat, 0);
にすればよいです。

Posted by: jm at 2005年12月12日 10:45

早速のご回答ありがとうございました。
cgiの該当部分を変更して位置表示を試してみました。

その結果ですが、Google Mapのみ位置が違います。他のNAVITIME、MapFan Web、livedoor MAPの3つは同じ場所を指しますが、Google Mapのみ違います。

更に、その1-1の方法でdatum="0"にし表示したのGoogle Mapの位置とも違います。datum="0"の場合、先ほどのNAVITIME、MapFan Web、livedoor MAPと同位置です。

どうすれば、cgiのGoogle Mapでも他の地図と同じ位置を表示することができるのでしょうか?

Posted by: 朱雀ぱ at 2005年12月12日 22:31

失礼しました。渡される緯度経度はすでに世界測地系になっているはずですので、測地系変換の行をコメントアウトするだけでした。
} elsif ($map_service eq 'Google Maps') {
#($lon, $lat) = geoconv($lon, $lat, 1);

Posted by: jm at 2005年12月12日 22:58

素晴らしいプラグインをありがとうございます。

今まで有り難く使用させて頂いていたのですが、MT Version 3.2-ja-2で複数のブログを管理している状態のところに導入したら、やが全く出なくなってしまいました。

それまでは別々のMTで管理していたブログを一つのMTで管理するようにしたのですが、このプラグインは複数のブログがある環境に対応しておりますでしょうか。
エラーも出ませんし、画像にもGPS情報がしっかりある(移設前はちゃんと出てたもの)のですが、MAPへのリンクが出ない状態です。
何が原因か全く分かりません。

Posted by: かず at 2005年12月14日 15:37

すいません。タグが抜けました。
「<MTLocations>や<$MTLocation$>が」と書きました。

Posted by: かず at 2005年12月14日 15:39

画像を置いているのがBLOGディレクトリ下でなかったのが原因でした。
ありがとうございました。

Posted by: かず at 2005年12月16日 09:29

原因を書いたら何が悪かったかスパムコメント扱いされてしまったのでお礼だけ。
解決しました。ありがとうございました。

Posted by: かず at 2005年12月16日 09:31

新しいドコモGPS携帯に対応させたくて、location.plを改良しているのですがうまくできません。これをhttp://www.gpspowered.jp/gpsmenu.cgi?pos=N35.41.30.71E139.43.57.82&geo=wgs84&X-acc=1
→これにhttp://docomo.ne.jp/cp/map.cgi?lat=%2B35.41.32.995&lon=%2B139.43.41.976&geo=wgs84&x-acc=1
取替えようとしています。こんな感じ→
/http:\/\/docomo\.ne\.jp\/cp\/.*?lat=%2B([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)&lon=%2B([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) {
$lat = (/http:\/\/docomo\.ne\.jp\/cp\/.*?lat=%2B([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef;
$lon = (/http:\/\/docomo\.ne\.jp\/cp\/.*?lat=.*&lon=%2B([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+).*/) ? $1 + $2/60 + ($3 + $4/100)/3600 : undef;とまあみよう見まねでこんな感じにしたのですが、perlがよくわからないのでやっぱだめでした。ご指南いただければ助かります。

Posted by: foxhound at 2006年01月16日 19:42

そういうときは正規表現部分だけ取り出して、テストしてみるのが手っ取り早いです。例えば

#!/usr/bin/perl
$_ = 'http://hogehoge/gps/no/value';
if (/kono/moji/wo/mitsuketara/) {
$lat = (/hoge(foo)(bar)/) ? $1 + $2/60 : 0;
print $lat;
}

みたいなテストコードを書いて、シェルで
$ perl test.pl

Posted by: jm at 2006年01月22日 18:42

ありがとうございます。さっそく実行します。

Posted by: foxhound at 2006年01月23日 14:28
コメントする









名前、アドレスを登録しますか?