仮想と現実の真ん中あたり

主に舞台探訪とか聖地巡礼と呼ばれる記録をつづるブログ

「Kanon」横浜探訪記 JavaScript

■「咲-Saki-」舞台探訪記事の捕捉感謝。
 Temporary Feeling さん
 >今となっては平安堂すら懐かしいー。
 まさか、そういう反応があるとは思ってもみませんでした(笑)
 カトゆー家断絶 さん


以上、捕捉出来た限りですが、ありがとうございました。


京アニKanon」横浜探訪記 JavaScript公開(長文注意)
Kanon」横浜探訪記が難航中のためのお茶にごし企画。
今回から探訪記で使用しているGoogle Maps APIJavaScriptに手を加えてみたので、それを公開します。


1.データ部の作成
今まではJavaScrptプログラムの中に直接、マップの位置データ,情報ウィンドウ内のコメント等を埋め込んでいましたが、今回作成効率を上げるために、データ部分を分離することにしました。
分離するデータは、JSON形式とします。JSONと聞くと難しいような気がしますが、中身は単にJavaScriptの配列(構造体)記述と同じ形式です。シンプルでいながら、ハッシュ配列も使える強力な仕様です。
「諸君、私はExcelが好きだ」、というわけで、まずExcelで元データを作ります。





ここで、
 ・「中心座標」はマップの中心座標
・0〜10の番号の行が地図上のマーカの座標データとコメントのデータ
です。
この位置座標は、いつものように↓のような自作地図を作って、得た座標データをコピー&ペーストして作っています。
 http://www7a.biglobe.ne.jp/~uso9000/hatena/ichi.htm


次に、元データに対して文字列連結演算子を使って、表右側のようにJSON形式に変換します。この時、オートフィル機能を使ってお手軽に行を増やしてデータを作って行きます。
変換後のJSON形式のデータが、↓です。


{ POINTS_NUM: 11,
cent_dat: [ { "x": "139.647219479084", "y": "35.4398667657344" } ],
point_dat: [
{ "x": "139.645733535289", "y": "35.4391325145282", "txt": "<table border=0><tr><td><img src='yokohama1_0s.jpg' /></td><td><div class='infowin'>名雪と商店街へ<br /><br /><a href='kanon-tv3-1.htm#txt0' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.647219479084", "y": "35.4398667657344", "txt": "<table border=0><tr><td><img src='yokohama1_1s.jpg' /></td><td><div class='infowin'>フードショップコスモス前<br /><br /><a href='kanon-tv3-1.htm#txt1' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.647772014141", "y": "35.4401399229561", "txt": "<table border=0><tr><td><img src='yokohama1_2s.jpg' /></td><td><div class='infowin'>商店街を見回す祐一<br /><br /><a href='kanon-tv3-1.htm#txt2' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.648139476776", "y": "35.4403081873434", "txt": "<table border=0><tr><td><img src='yokohama1_3s.jpg' /></td><td><div class='infowin'>あゆと逃走行<br /><br /><a href='kanon-tv3-1.htm#txt3' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.648909270763", "y": "35.4407102722471", "txt": "<table border=0><tr><td><img src='yokohama1_4s.jpg' /></td><td><div class='infowin'>百花屋に逃げ込む二人<br /><br /><a href='kanon-tv3-1.htm#txt4' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.648922681808", "y": "35.4406490855435", "txt": "<table border=0><tr><td><img src='yokohama1_5s.jpg' /></td><td><div class='infowin'>追って来たたい焼き屋さん<br /><br /><a href='kanon-tv3-1.htm#txt5' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.645671844482", "y": "35.4392854840817", "txt": "<table border=0><tr><td><img src='yokohama1_6s.jpg' /></td><td><div class='infowin'>たい焼き屋で謝る二人<br /><br /><a href='kanon-tv3-1.htm#txt6' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.646259248256", "y": "35.4393816362237", "txt": "<table border=0><tr><td><img src='yokohama1_7s.jpg' /></td><td><div class='infowin'>商店街に戻る二人<br /><br /><a href='kanon-tv3-1.htm#txt7' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.646382629871", "y": "35.4394428238907", "txt": "<table border=0><tr><td><img src='yokohama1_8s.jpg' /></td><td><div class='infowin'>商店街を歩く二人<br /><br /><a href='kanon-tv3-1.htm#txt8' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.64665621519", "y": "35.4395804959713", "txt": "<table border=0><tr><td><img src='yokohama1_9s.jpg' /></td><td><div class='infowin'>あゆとお別れ<br /><br /><a href='kanon-tv3-1.htm#txt9' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" },
{ "x": "139.6479088068", "y": "35.4401792575197", "txt": "<table border=0><tr><td><img src='yokohama1_10s.jpg' /></td><td><div class='infowin'>少年祐一と少女あゆが駆け出す<br /><br /><a href='kanon-tv3-1.htm#txt10' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>" }
] }

これをExcelからコピー&ペーストで切り出してテキストファイルにし、FTPでWebサーバにアップします。
以上でデータ部の作成は完了です。


2.JavaScriptの作成
今回作成したJavaScriptを下記↓に示します。
※下記のJavaScriptは、商業利用以外の私的利用については、コピーおよび使用は自由にしていただいてかまいません。
※使用する場合、全角スペースは半角スペースに変換して下さい。


var map;
var markers = ;
var points =
;
var i;
var httpObj;


function startUp() {
  map = new GMap2(document.getElementById("mymap"));
  map.addControl(new GMapTypeControl());
  map.addControl(new GLargeMapControl());
  map.addControl(new GScaleControl());


  var msec = (new Date()).getTime();
  httpObj = GXmlHttp.create();
  httpObj.open("GET", "./kanon3_dat1.txt?cache="+msec);
  httpObj.onreadystatechange = function () {
    if ( (httpObj.readyState == 4) && (httpObj.status == 200) ) {
      setMap();
    }
  }
  httpObj.send(null);
}


function setMap() {
  eval("var mapData = "+httpObj.responseText);
  map.setCenter(new GLatLng(mapData.cent_dat[0].y, mapData.cent_dat[0].x), 17);


  for (i = 0; i < mapData.POINTS_NUM; i++) {
    points[i] = new GLatLng(mapData.point_dat[i].y, mapData.point_dat[i].x);
    addMarker(points[i], i, mapData.point_dat[i].txt);
  }
  var polyline = new GPolyline(points, "#99FFFF", 3, 0.5);
  map.addOverlay(polyline);  
}


function addMarker(latlng, num, comment) {
  var icon = new GIcon();
  icon.image = "../markers/marker"+num+".png";
  icon.iconSize = new GSize(20,34);
  icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
  icon.shadowSize = new GSize(37, 34);
  icon.iconAnchor = new GPoint(10, 34);
  icon.infoWindowAnchor = new GPoint(20, 10);
  markers[num] = new GMarker(latlng, icon);
  map.addOverlay(markers[num]);
  var f = function() {
    markers[num].openInfoWindowHtml(comment);
  }
  GEvent.addListener(markers[num], "click", f);


  var marker_field = document.getElementById('mark'+ num);
  var fzoom = function() {
    f();
    map.panTo(latlng);
    map.setZoom(18);
  }
  marker_field.onmousedown = fzoom;
}


if (GBrowserIsCompatible()) {
  onload=startUp;
  onunload=GUnload;
}

詳しい説明をすると長くなるので、以下、ポイントを絞って解説します。


今回のポイントは、13行目からの下記の部分です。


  var msec = (new Date()).getTime();
  httpObj = GXmlHttp.create();
  httpObj.open("GET", "./kanon3_dat1.txt?cache="+msec);
  httpObj.onreadystatechange = function () {
    if ( (httpObj.readyState == 4) && (httpObj.status == 200) ) {
      setMap();
    }
  }
  httpObj.send(null);

この部分が実行されると、先にWebサーバ上にアップされたデータ部を、Googleのサーバが読み込みます。(そのため、このJavaScriptは、ローカルではデバッグ出来ないという副産物が付くのですが…)
読み込みに成功すると、


    if ( (httpObj.readyState == 4) && (httpObj.status == 200) ) {
      setMap();
    }

 ↑のif文の中の、setMap関数が実行されます。setMap関数中ではどうなるかというと、


  eval("var mapData = "+httpObj.responseText);
  map.setCenter(new GLatLng(mapData.cent_dat[0].y, mapData.cent_dat[0].x), 17);

1行目で変数mapDataにサーバが読みとったJSON形式のデータを代入し、
2行目でmapDataからマップの中心データを読み込んで、マップの中心座標をセットします。


次に、setMap関数中では、


  for (i = 0; i < mapData.POINTS_NUM; i++) {
    points[i] = new GLatLng(mapData.point_dat[i].y, mapData.point_dat[i].x);
    addMarker(points[i], i, mapData.point_dat[i].txt);
  }

mapData変数中のマーカの個数分だけループを繰り返して、マップ中にマーカをセットします。
最後のsetMap関数中の、


  var polyline = new GPolyline(points, "#99FFFF", 3, 0.5);
  map.addOverlay(polyline);  

は、マーカ間にラインを引くための処理です。


以上のように、このJavaScriptは、マップが変わった時にでも15行目の↓の部分のファイル名だけを変更すれば良いようになっています。


  httpObj.open("GET", "./kanon3_dat1.txt?cache="+msec);



3.HTML(XML)の作成
探訪記のメイン部分である、XMLファイルの記述は従来とほとんど変わっていません。
が、1点だけ、ヘッダに↓の記述を追記する必要があります。


<html xmlns="http://www3.org/199/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xml:lang="ja" lang="ja">
<style type="text/css">
v\:* {
behavior:url(#default#VML);
}

これは、Google Mapsが、Internet Explorerでマップ上のラインを引くためにVMLの機能を使う必要があるため、だそうです。


こうして出来たのが、↓の試作版というわけです。
 京アニ「Kanon」横浜探訪記 第1話 試作版


以上、長文ですみませんでしたが、みなさんの舞台探訪記の参考になれば幸いです。