RICOH THETA?
これです RICOH THETA m15
なにかというと、ワンタッチで Google ストリートビューみたいな全天球写真 360° x 360° を撮影できるカメラなんです。真ん中にあるボタンでも撮影できますが、スマートフォンと Wifi 接続(THETA が親機になる)することでスマートフォンがシャッターになります。
ちょうどベトナムに旅行に行く機会があったので、すぐに買って持っていきました。
で、ツアーの方々と一緒に THETA を囲って撮影したりなんてことがあったのですが、撮影した写真は適切に処理してあげないとグニュァアアっと歪んでいて見られたものではありません。
どうやって共有したものか と悩んでいたところ three.js を使って全天球処理する話があったので、これを Knockout のカスタムバインディングにして独自ビューアを作ってみました。
カスタムバインディング theta
何はともあれ DEMO をご覧ください。
Github: knockout.theta
jQuery と Three.js に依存してるので、先に読み込む必要があります。
カスタムバインディング自体はかなり単純で、
- 指定された URL の全天球画像を 3D 表示する
- マウスドラッグで視点追従する
- マウスホイールで拡大縮小
の3つの機能しかありません。
KnockoutJS ですので、とことんシンプルにして View と ViewModel で独自に機能を追加できるように意識しました。
コード例1
撮影した全天球画像ファイルの URL をバインドするだけで 3D 表示されます。
この状態でマウスドラッグ/マウスホイールの操作に対応します。
<div data-bind="theta: 'path/to/image.jpg'"></div>
これだけなら、ko.applyBindings({}) だけで動くのでお手軽です。
ただ、div タグの領域サイズは自動で設定されないので、CSS などで指定してください。
DEMO では Twitter Bootstrap の Responsive embed で16:9にしています。
コード例2 : Observableで変更を反映
もちろん Observable にすれば簡単に写真を変更できます。
<div data-bind="theta: imageUrl"></div>
function ThetaViewModel() {
var self = this;
self.imageUrl = ko.observable('path/to/image.jpg');
// ... その後
self.imageUrl('path/to/other_image.jpg'); // これで写真が切り替わる
}
ko.applyBindings(new ThetaViewModel());
コード例3: thetaWheelZoom ズーム機能の On/Off 切り替え
大きな領域でマウスホイールの挙動を奪ってしまうと、サイト全体をスクロールする際の使い勝手が非常に悪くなってしまいます。何も考えずに Google Map を張り付けたりすると同じ事が起きますよね。
これをハンドリングするために、ホイールズームの有効/無効を切り替えられるようにしました。
<div data-bind="theta: imageUrl, thetaWheelZoom: zoomEnabled"></div>
function ThetaViewModel() {
var self = this;
self.imageUrl = ko.observable('path/to/image.jpg');
self.zoomEnabled = ko.observable(true);
// ... その後
self.zoomEnabled(false); // これでズームできなくなる
}
ko.applyBindings(new ThetaViewModel());
DEMO ではこれを使ってカーソルが真ん中にあるときにしかズームできないように細工してあります。
コード例4: thetaLoading 写真読み込み中を知る
theta で撮影した画像は 3584px x 1792px で、だいたい 2MB 以上あります。
キャッシュは効きますがこれを読み込むので、スタート時と変更時にどうしても待ち時間が発生します。
そこで、thetaLoading
を使って読み込み中はローディングスピナーを表示するといいです。
<div data-bind="theta: imageUrl, thetaLoading: isLoading"></div>
<p data-bind="visible: isLoading">Now loading...</p>
<p data-bind="visible: !isLoading()">Loading completed!</p>
function ThetaViewModel() {
var self = this;
self.imageUrl = ko.observable('path/to/image.jpg');
// 画像読み込み中は自動的に true になる
self.isLoading = ko.observable();
}
ko.applyBindings(new ThetaViewModel());
thetaLoading
は View → ViewModel の OneWay バインディングですので、必ずko.observable
で宣言したプロパティをバインドしてください。Knockout ES5 を使っている場合はobservable
がko.track
によってgetter/setter
にアップグレードされないように注意してください。
DEMO では whirl を使って読み込み中を表現しています。
何をつくろうか!
THETA で撮影した旅の思い出を記録するもよし、不動産屋さんや宿泊施設などのサイトで使うもよし、なにしろ MVVM で工夫し放題なのでよかったらみんなも THETA しましょう!
話は少し変わりますが、アプリのほうではSDKがあってDEVELOPPERS登録を受け付けているようです。
実はこの THETA、動画も撮影できるので Occulus Rift なんかと組み合わせたりと色々な可能性がありそうです。
※私は RICOH さんとは何の関係もございません。ご了承ください。
※Knockout日本語ドキュメントも進めます。お待たせして申し訳ございません。