明日もデザインで食べていこう![33]WebデザイナーでもiPhoneアプリを!──はじめてのTitanium Studio(4)/秋葉秀樹

投稿:  著者:  読了時間:12分(本文:約5,800文字)


こんにちは、秋葉です。先日は、大阪でも結構規模の大きいIT/Web技術を中心としたイベント「まにまにフェスティバル」が開催されました。中でも注目なのは、Google, Microsoft, Opera, Mozilla, Fenrirというブラウザベンダーが大阪に集まるというもの。

私は司会進行をつとめさせていただきましたが、GoogleがMicrosoftのIEをイジるという一瞬ヒヤっとする場面もあり、本音にせまる各ブラウザベンダーの考えとか、大阪ならでは、というすごいおもしろいセッションもあり、司会でありながら一瞬たじろいだりした場面もあり。

いやいや、参加者された方の反応は上々でした。取り繕ったはなしよりぶっちゃけるとこうだよ、的なイベントって最近ないですね。そういった意味では、今回のまにフェスは意義があったと考えています。

さて前回にひきつづき、Titanium Studioを使った簡単な位置情報つき写真投稿アプリを完成させましょう。今回のテーマは写真撮影、そして投稿。撮影した緯度、経度に投稿した写真をGoogle Mapで表示させてみましょう。




◆Titaniumで写真撮影

まず、シャッターとなるボタンをつくりますが、今回は変数label1に設定した「はじめてのiPhoneアプリ」の文字をボタンがわりにしましょう。
以下のコードに変えます。

var label1 = Titanium.UI.createLabel({
color:'#f00',
text:'写真を撮ります',
font:{fontSize:20,fontFamily:'Helvetica Neue'},
textAlign:'center',
width:'auto'
});


textの部分を「写真を撮ります」に変更します。そこにタップされたときの処理を書きます。JavaScriptと同じ書き方でaddEventListenerでclickイベントを設定します。

下記のコードでは、タップされたらカメラUIが起動し、撮影後「USE」ボタンをタップすると、success: function (e) {〜 が処理されます。
また、カメラを持っていないデバイス、あるいはシミュレータなどではerror: function (e) {〜の処理が走ります。

label1.addEventListener("click", function (){
Titanium.Media.showCamera({
success: function (e){
//撮影後、USEボタンが選ばれたら...
var photo = e.media.imageAsResized(240,320);
},
error: function (error){
alert("error");
}
});
})


なお、撮影した画像データはsuccessメソッドの引数を利用して、e.mediaで取得できます。

今回はあまり大きな画像だと処理が大変なので、一旦Titanium側でリサイズ処理をしたあとに、サーバ側に送りましょう。

(本来は写真の縦、横の長さでどちらが長いかを計り、長辺を320pxに、短辺を240pxにという処理をしたいところですが、コード短縮のため、縦長写真を前提に解説しています)

var photo = e.media.imageAsResized(240,320);
これはiOSのみの機能でして、非常に残念ながらAndroidではエラーになります。
何とかしてほしいところです。

iPhoneではこれでリサイズされた画像データが取得できました。サムネイルをつくることもTitaniumでは簡単にできます。
このphotoをPHPに送信して保存させるという仕組みです。

それでは、これに緯度、経度をまとめて送らないといけません。それぞれをJavaScriptのオブジェクトでまとめるので、以下のようにコードを修正しましょう。

var coords = ev.coords;
xhr.open("POST", "http://akibahideki.com/digicre/120416/post.php");
var sendData = {
locate: JSON.stringify({"ido":coords.latitude, "keido":coords.longitude}),
media: photo
}
xhr.send(sendData);


データを送る先はPHPで処理するので、一旦緯度と経度をJSON文字列という形に直してやります。

JavaScriptのオブジェクトと呼ばれるデータをPHPでは直接理解できないので文字列に直して送信する、と思っておいてください。
これでTItanium側は完了です。

◆PHPの設定

先ほどのサンプルの送信先のURLを
< http://akibahideki.com/digicre/120416/post.php >
としました。ではそのpost.phpを書いていきましょう。

<?php

// POSTで受け取ったデータはJavaScriptのオブジェクトなので、緯度、経度、写真をパースする
$json = (json_decode(str_replace("\\","",$_POST["locate"]), true));
$ido = $json["ido"];
$keido = $json["keido"];

//ファイルは仮の場所に一時保存されるので、その画像にファイル名(保存場所)を指定する。
$img_tmp = $_FILES["media"]["tmp_name"];
//$img_name = $_FILES["media"]["name"];
//写真はphoto/年月日時刻.jpgのような名前にする。
$FilePath = "photo/".date("Ymdhis").".jpg";
//仮の場所に置かれた写真を指定したphotoディレクトリに保存しなおす。
move_uploaded_file($img_tmp,$FilePath);

//テキストファイルに、緯度、経度、写真のファイル名をカンマ区切りで保存する。
$fp = fopen("photo/data.txt","a");
$saveData = $FilePath.",".$ido.",".$keido;
fputs($fp,$saveData."\n");
fclose($fp);

//Titaniumにメッセージを返す
print("正常にアップロードしました");

?>


実機からひとかたまりで送られてきたデータを分解して、写真のファイルパスと緯度と経度をカンマ区切りで data.txt に文字を書き込みます。
ひとつのデータが書き込まれたら改行をいれます。
画像はphotoディレクトリの中に入れられるようになります。

◆実機で試そう

fig01.png

さて、ここからはiPhone実機により確認します。
そのためには「iPhone Developer Program」に参加しておく必要があり、アプリと実機をひも付ける作業などが必要ですがここでは割愛します。前回の記事にリンクを入れておきましたので参考にしてください。

さていよいよ実機で起動しましょう。「写真を撮ります」をタップするとカメラのUIが起動するはずです、これで撮影をしてみましょう。

うまく成功したらalert画面が出てきて「正常にアップロードしました」が表示されます。

fig02.png

このとき、撮影したら1行ずつ情報が追加されていきます。
これは2回送信したときのdata.txtの中です。

photo/20120415071710.jpg,34.6671142578,135.517410278
photo/20120415071733.jpg,34.6671142578,135.517410278


◆Google Mapに表示して完成

いよいよ別のHTMLファイルにGoogle Mapを表示して、ピンと写真付きのふきだしをつけましょう。index.htmlを用意し以下の通りコーディングしていきます。

<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Map に落とし込むテスト</title>
<link href="css/styles.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-1.7.min.js"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>

<script>

$(function (){
var map, allData, completeData=[];
$.ajax({
url: "photo/data.txt",
success: function (res){
allData = res.split("\n");
//data.txtの1行分を配列に分解する
for(var i=0,l=allData.length-1; i<l; i++) {
var oneData = allData[i].split(",");
completeData.push(oneData);
}

//Google Mapの設定
var latlng = new google.maps.LatLng(completeData[0][1], completeData[0][2]);
var opt = {
zoom: 16,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), opt);

//ピンとふきだしに写真を追加していく
for(var t=0,l=allData.length-1; t<l; t++) {
var oneData = allData[t].split(",");
var marker = new google.maps.Marker({
position: new google.maps.LatLng(oneData[1],oneData[2]),
map: map
});

var contentString = "<div class='photoWrap'><img src='"+oneData[0]+"' alt></div>";
var infowindow = new google.maps.InfoWindow({
content: contentString
});

infowindow.open(map,marker);
}
}
});
})

</script>
</head>
<body>
<div id="map_canvas" style="width: 600px; height: 600px;"></div>
</body>

</html>


fig03.jpg

これで今まで撮影して送信した写真が、その位置に関連付けられて表示されました。ただし、Google Mapに画像を置くのは非常に重たくなります。多くの画像を置くのはやめて、最新数件といったような処理を入れた方がよいかもしれません。

◆まとめ

やはりiPhoneとAndroidのアプリ、同じソースで両方できると言われていますが、今回のケースのようになんでもそうとは限りません。iOSのみの機能というものもあるので注意も必要です。もっとチャレンジされたい方は、書籍などを購入して試されてはいかがでしょうか?

◎Titanium Mobileで開発する iPhone/Androidアプリ(Smart Mobile Developer)[大型本]
< http://www.amazon.co.jp/exec/obidos/ASIN/4798123986/hsjjp-22/ >

◎Titanium Mobile iPhone/Androidアプリ開発入門─JavaScriptだけで作る[単行本]
< http://www.amazon.co.jp/exec/obidos/ASIN/479803231X/ >


以上で、4回にわたってお送りした未経験者向けTitanium Studio入門シリーズ、終了です。おつかれさまでした。

【あきば・ひでき】hidetaro7@gmail.com
< http://www.akibahideki.com/blog/ >

テクニカルディレクター・デザイナー。DTP黎明期からグラフィックデザインを学び、東京都営団地下鉄など交通広告を多数手がける。同時に音楽活動も活発に行い、西日本半全国ツアーなどを展開、某専門学校のテーマソングを作詞作曲、編曲から楽器全てを演奏してレコーディングするなど、マルチなクリエイティブ活動も。最近では東京と大阪の教育施設などで講師業をも務める。HTML CSS JavaScript Flash ActionScript 3DCG Movie DTP GraphicDesign......多種スキルを持つ。Web標準技術だけに執着せず、すべてのメディアで説得力のある表現にチカラを注ぎたい、そんな仕事をしたい。