それでは、ピンポイントでお答えしましょう。

ディスカヴァー社長室blogディスカヴァー社長室blog: ここはどこ?〜干場
ディズニーシーより混んでいる。

(追記:IEでの不具合を修正)

ずばり、ここです。

Demo


なつかしいなあ。妻と入籍する前の婚前旅行で行きましたよ。Caffe Florianにはたちよりました?しっかり勘定に"Musica"って入ってました?

ということを簡単に実現するための仕組みです。

やってることは単純で、JPEGからEXIFをぶっこぬいて、そこにある緯度経度に Google Map をセンタリングしているだけ。強いて面倒な点をあげると、EXIFの緯度経度は度分秒で表現されているのに対し、Google Map は度のみなこと。これはdms2deg()で変換しています。

JS Source:

<script type="text/javascript" src="http://www.google.com/jsapi?key=yourkey"></script>
(function(d){

var gmap = {};

google.load('maps', '2');

google.setOnLoadCallback(function(){
    gmap.map = new google.maps.Map2(d.getElementById('gmap'));
    gmap.map.addControl(new GSmallMapControl());
    gmap.map.addControl(new GMapTypeControl());
    gmap.geocoder = new google.maps.ClientGeocoder();
});

window.onunload=function(ev){  GUnload() }

var dms2deg = function(src){
  var deg = 0; /* 45 deg 26' 1.80" N */
  src.replace(/(\d+)\D*(\d+)\D*(\d+\.\d+)\D*([NSEW])/, function(a,d,m,s,nsew){
    deg = parseInt(d,10) + parseInt(m,10)/60 + parseFloat(s)/3600;
    deg *= nsew === 'N' ? 1 : nsew === 'E' ? 1 : -1;
  });
  return deg;
}; 

JSONP = {
  get:function(uri, cb){
    if (!cb) cb = 'JSONP.run';
    d.getElementById('exifsrc').src = uri;
    var u = ['http://api.dan.co.jp/exif', cb, uri].join('/');
    var s = d.createElement('script');
    s.charset = 'UTF-8';
    s.id = s.src = u;
    d.body.appendChild(s);
  },
  run:function(json){
    var point = new GLatLng(
        dms2deg(json.GPSLatitude), 
        dms2deg(json.GPSLongitude)
    );
    gmap.map.setCenter(point, 12);
    var marker = new google.maps.Marker(point);
    gmap.map.addOverlay(marker);
    var html = [
      '緯度:' + point.y,
      '経度:' + point.x,
      '日時:' + json.DateTimeOriginal
    ].join('<'+'br>');
    google.maps.Event.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(html);
    });
  }
}

})(document);

Server Source:

EXIFをぶっこぬいてJSONPで返すだけの単純なScriptです。例によってCGIでもmod_perlでも動きます。

exif.cgi
#!/usr/local/bin/perl
#
# $Id: exif.cgi,v 0.1 2009/08/01 06:00:53 dankogai Exp dankogai $
#
use strict;
use warnings;
use LWP::UserAgent;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use Image::ExifTool;
use JSON::Syck;

my $q = CGI->new;
my ( $callback, $uri ) = ( $q->path_info =~ m,^/([^/]+)/(.*),o );
$callback or die 'no callback!';
$uri =~ s,^(https?:)/+,$1//,o
  or die 'invalid scheme: ', $q->escapeHTML($uri);
$uri .= '?' . $ENV{QUERY_STRING} if $ENV{QUERY_STRING};

my $res = LWP::UserAgent->new->get($uri);
die "$uri ", $res->status_line unless $res->is_success;
die "$uri ", $res->headers->header('content-type'), " is not supported"
  unless $res->headers->header('content-type') =~ m{\Aimage/jpeg};
my $image = $res->content;

my $tool = Image::ExifTool->new;
my $exif = $tool->ImageInfo( \$image );
$exif->{uri} = $uri;

print
  "Content-Type: application/x-javascript; charset=utf-8\n\n",
  "$callback(", JSON::Syck::Dump( $exif ), ");\n";

Enjoy!

Dan the AJAXen