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

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

舞台探訪資料作成ツールについて

■キャプチャ画像作成ツール
京アニKanon」横浜探訪記を作成中なのですが、その最中に、撮影した写真が作品の背景に対して左右が切れているのを発見して愕然。
原因は、XPの画像のサムネイル印刷機能にありました。
以前はキャプチャしたJPEGデータをExcelに貼りつけた資料をいちいち作っていたのですが、それが面倒になったので、京アニKanon」ではXPのサムネイル印刷機能で3×3枚のレイアウトでフォルダごと印刷してみたのです。
ところが、どうやらXPのサムネイル印刷機能は、4:3のアスペクト比よりも横長の画像は左右をカットする仕様のようで、16:9のアスペクト比京アニKanon」のキャプチャ画像は見事に左右が切られていて、当然それを参考に撮影した写真も左右が切れてしまっていた、というわけです…orz
そこで今日ネット上でサムネイル印刷機能のついたフリーウェアを探してみたところ、見つけたのがコレ↓
 ViX(統合画像ビュアー、Windows95/98/Me/NT4.0/2000/XP用、フリーソフトウェア)
実際にためしてみたところ、「画像」→「アルバム印刷」→「レイアウト」でレイアウトが変更出来て、京アニKanon」の横長画像も無事に印刷してくれました。
画像ビューアとしても、キャッシュを作ってアクセスするため、NAS(N/W接続ストレージ)に保存した写真データのアクセスでもなかなか快適でした。
しばらくこれを使ってみようと思います。


それと、DVDからキャプチャ画像を作成するツールで最近導入したのが、コレ↓
 Mediaunite
DVDを再生して、狙ったところで一時停止したら、キャプチャボタンで画像を取り込む事が出来ます。
この時、「連番保存」のチェックボックスをONにしておくと、後はボタンを押すだけで自動的に(001).jpg, (002).jpg…のようにファイル名を付けて保存して行ってくれるので便利です。
ポイントは、第1話なら、「01_」のように接頭番号を付けておくこと。こうすると、後で別の話数の画像を同じフォルダに放り込む時に名前変更しなくて済みます。なぜ同じフォルダに放り込むことになるかというと、舞台探訪するためには目的地ごとに「札幌」とか「横浜」とか分類して、上記のサムネイル印刷ツールに読み込ませて印刷する必要があるからなのですね(笑)


以上、どこまで需要があるかわかりませんが、舞台探訪プチ講座でした。

「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話 試作版


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

祝!はてな、対応

はてなGoogleマイマップ表示
先日書いたはてなでのGoogleマイマップ表示ですが、いつの間にかはてな側で対応していたようです。
京アニKanon」−立川編−を表示↓
※※※注意! マップ内のリンクをクリックすると表示が元に戻りません※※※




拡大地図を表示


iframe表示なもので、リンク先をクリックしてしまうとこのiflame内に表示してしまう難点はありますが、これならそこそこ使えるでしょう。

新たなGoogle Maps組み込み機能

簡単になったGoogle Maps組み込み機能を使ってみた - ほんとうに簡単!! (経由:カトゆー家断絶 さん)
早速このはてなダイアリーに貼ってみたけど、表示してくれなかったよ…orz


一般向けには「ようやく手軽になりましたよ〜。ぜひ試してみて下さい」とお薦め出来る機能なのですが、管理人のような人間にとってはあまり嬉しくありません。
前述したように、はてなダイアリーで使えないのがその理由の一つ(はてなの仕様のせいですが)。
もう一つは、HTML(XML)側のリンクをクリックすると地図のマーカが開いてくれるような、イベントトリガを埋め込む機能が無いことです。これではまだJavaScriptの代わりとして使えません。
最後にかなり致命的なのが、<iframe>タグを使って埋め込む方法をとるため、地図上のマーカに別URLへのリンクを貼ってクリックすると、このiframe内にページを読み込んでしまうか、あるいは別ウィンドウを開くようにするしかない、という点です。これはちょっと痛い制約です。


[追記]Googleマイマップ内のリンクは、target属性が使えないようなので、iframe内に読み込むしか手が無いようです。そのため、作りによっては、↓のようなトホホな結果になってしまうようです。
京アニ「Kanon」舞台探訪−立川編− Google Mapsテスト版


う〜ん、「もう少しがんばりましょう」、というところ。

JavaScriptの配列宣言

■メモリの動的確保と静的確保
今まで、JavaScriptの配列を、




  var markers = new Array(32);  /* 記述A */


のように宣言して使っていました。これは古い参考書を見たらこう書いてあったからですが、最近の参考書だと、



  var markers = ;  /* 記述B */


のように書いてあるようです。
後は普通に、



  markers[0] = ...
  markers[1] = ...


と値を代入して行くわけですね。
ですが、Cから学び始めた古い人間にしてみると、記述Bの宣言の後でこのように代入するのを見ると、「どのメモリに代入してるんだ!? 痛いのはイヤー!」と、過去のトラウマが蘇って非常に精神衛生に悪かったりしまして(笑)、あえて古い書き方で宣言してました。
C言語が配列の宣言時にサイズを指定する必要があるのは、コンパイル時点でメモリ領域が確定される、静的確保の処理系を(一般的に)採ることに由来しています。
しかしながら、JavaScriptの配列は動的確保されるわけでして、よく考えてみれば、記述Aにしたところで、型宣言が無いわけですから、この時点でメモリ領域が確定しているわけではありません。
それどころか、JavaScrptの配列は強力で、



  var ship = ;
  ship["長門"] = 224.94;
  ship["大和"] = 263.0;


のように、連想配列(ハッシュ)の機能まであったりします。
そんなこんなで、こういう言語仕様に対して、わざわざ古い宣言スタイルで記述するのも無意味な事だと思い直したわけです。


そんなわけで、現在、「Kanon」探訪記のJavaScrptは、新しい宣言スタイルに変更して作成中です。
サンプル↓
http://www7a.biglobe.ne.jp/~uso9000/travel/kanon-tv2/kanon2_test.htm


■近況
色々とあって、結局、本日は木崎湖へ遠征出来ず。
金融機関が開いている休暇日は、社会人には貴重だったりするわけで、ヤボ用を片づけているうちに日が暮れてしまいました。残念。


さて、明日はいよいよ、「Kanon」横浜探訪です! 楽しみだなぁ〜。
…前の立川探訪記がまだ完成してないけど。orz

GoogleマイマップとGoogle Maps API

Googleマイマップで描いた地図をGoogle Maps APIで貼り付ける方法 (geekなぺーじ さん)
検索してたらたまたま見かけた記事ですが。
ついにKMLGoogle Maps APIの融合がキターッ! って感じです。これでGoogleマイマップの「KMLエディタ」としての役割がクローズアップされて来たと思います。


今現在の私の使い方で言うと、GoolgeマイマップとGoogle Maps APIを両方使っています。「Kanon」札幌探訪記の例で言うと、こんな↓感じです。


 「Kanon」札幌探訪記Google Maps APIを使用)
 京アニ「Kanon」マップ−札幌−Googleマイマップを使用)


 Googleマイマップを別に作っている理由は、Googleの地図検索で、「ユーザーによるコンテンツ」で例えば「Kanon」と検索するとこんな感じになってしまうように、
「何てこった! 現実の場所を調べているのにアニメやゲームの場所がヒットするぜ!」
と思わせるためのイタズラ心から来てます(笑)
同様に、「神尾家」で検索すると、今やこうなってしまうわけです。
我ながらバカですね(笑)


だけど、これまではこの2つの間のインターフェースが提供されていなかったため、GoogleマイマップとGoogle Maps APIは別個のものとなっていました。
特にGoogle Maps APIの方はJavaScriptのプログラムなので、完全に手作業の世界で、その作成の手間は繁雑です。
例えば、「Kanon」札幌探訪記で言うと、JavaScriptの記述は、↓これだけ書いています。



−−− ↓以下、JavaScriptプログラム −−−
var map;
var markers = new Array(32);


function startUp() {
  map = new GMap2(document.getElementById("mymap"));
  map.addControl(new GMapTypeControl());
  map.addControl(new GLargeMapControl());
  map.addControl(new GScaleControl());
  map.setCenter(new GLatLng(43.055969766809476, 141.325), 13);
  addMarker(new GLatLng(43.032607759057385, 141.36190474033356), 0);
  /* --- 以下、26行略 --- */
  addMarker(new GLatLng(43.078895790391115, 141.29845440387726), 27);
}


function addMarker(latlng, num) {
  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() {
    switch (num) {
      case 0:
        markers[num].openInfoWindowHtml("<table border=0><tr><td><img src='kanon-tv1/sapporo0s.jpg' /></td><td><div class='infowin'>真琴と歩く高架横<br />第8話<br /><a href='kanon-tv1-1.htm#txt0' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>");
        break;
  /* --- 以下、case 1〜Case 26まで略 --- */
      case 27:
        markers[num].openInfoWindowHtml("<table border=0><tr><td><img src='kanon-tv1/sapporo27s.jpg' /></td><td><div class='infowin'>栞と別れた道<br />第17話<br /><a href='kanon-tv1-4.htm#txt27' onClick='map.closeInfoWindow()'>⇒旅行記へ</a></div></td></tr></table>");
        break;
      default: break;
    }
  };
  GEvent.addListener(markers[num], "click", f);
  if ((num > 8) && (num < 16)) {
    var marker_field = document.getElementById('mark'+ num);
    var fzoom = function() {
      f();
      map.panTo(latlng);
      map.setZoom(15);
    }
    marker_field.onmousedown = fzoom;
  }
}


if (GBrowserIsCompatible()) {
  onload=startUp;
  onunload=GUnload;
}
−−− ↑以上、JavaScriptプログラム −−−


10行目からの、

 addMarker(new GLatLng(43.032607759057385, 141.36190474033356), 0);
 /* --- 以下、26行略 --- */
 addMarker(new GLatLng(43.078895790391115, 141.29845440387726), 27);
の部分がマーカの位置を指定している箇所で、これは省略して書いてありますが、実際には全28箇所の地図上のマーカの位置を28行かけて、手で記述しています。
この位置情報をどうやって取得してるかというと、↓のような自作ツールを使っています。
 http://www7a.biglobe.ne.jp/~uso9000/diary/test/ichi.htm
クリックすれば分かると思いますが、クリックした場所の緯度・経度が表示されます。これを使って、旅行の後で地図上で再度探して、クリックして得た緯度・経度情報を手でエディタを使って先のプログラム部分に埋め込んでいくわけです。
SONYGPS-CS1Kも持ってますが、位置情報の精度が芳しくないので、直接使わずに参考データとしてだけ使っています。


以上を見ていただければ、現状ではGoogleマイマップとGoogle Maps APIの自作地図をそれぞれ作ろうとすると、完全に二度手間になってしまうのが分かると思います。


さて、前置きが(ホントに…)長くなりましたが、ここからが本題。
今回追加された「Googleマイマップ取り込みAPI」を使うとどうなるかと言うと、既にGoogleマイマップを作成済みならば、プログラム冒頭の28行の部分が、下記↓のように2行で済んでしまいます。



  var gx = new GGeoXml("http://www7a.biglobe.ne.jp/~uso9000/travel/kanon-tv1/kanon-tv1.kml");
  map.addOverlay(gx);


この記述を使ってためしに書いてみたのが、↓こちらです。


 「Kanon」札幌探訪記(Googleマイマップ取り込みテスト版)


場所の緯度・経度情報を手で取得&入力する手間が無くなりました。ヤッホウ!
…なのですが、ここで、「地図上のマーカ→記事」には飛べるけど、「記事→地図のマーカ」に飛べない事に気づいた方は鋭い!
実は、このAPI関数だけでは足りないんです。
最初のプログラムの中で、


 var marker_field = document.getElementById('mark'+ num);


と記述している部分が、地図上のマーカに外部(記事部分=HTML)からのイベントトリガを埋め込む箇所なんですが、これをKMLデータ中のマーカに対応させるAPIが用意されていないのです。
惜しい、あともう一歩!


ですが、そのAPI関数が用意されるのもそう遠くないことでしょう。
Googleの今後の更新を首を長くして待ちたいと思います。
(実は既にリリースされているのかも? Googleの本家の英文のサイトを読んでないもので…汗)