jsとcssで等身大ディスプレイ上にスマホの挙動を再現してみた
こんにちは、2013年新卒エンジニアの鈴木です。
今回は、エンジニアの挑戦について紹介したいと思います。
メイン業務であるF.O.Xの開発と平行して、オフィスのエントランスのコンテンツ開発を行いました。CyberZのオフィスは2013年10月に移転し、それに合わせてエントランスに最先端な仕組みを取り入れています。
例えば、受付電話の部分にはセンサーを設定し、誰かが電話に近づくと目の前のモニターが切り替わり、機械音声で話しかける仕組みを作っています。
受付の機械音声の他、エントランスの一面を巨大なスクリーンと見立て、CyberZのロゴやF.O.Xのロゴをアニメーションさせたり、紹介ムービーを流すことで、近未来的な空間を演出しています。
移転から半年が経たない今年の3月にはオフィスの拡張工事が行われることになり、このタイミングでエントランスの仕掛けにも新しいものを取り入れようとなり、その開発エンジニアとして私が担当することになりました。
始めは、昨年リリースされて話題となったLeap Motionを使って、手をかざすだけで映像を操作できるコンテンツを制作していたのですが、プロトタイプの段階で納得の行く完成度に届かず、泣く泣く仕切り直しをすることにしました。
次に思い付いたのが、エントランスに巨大なスマホを表示し、訪れた方にそれを操作してもらうというものです。CyberZはスマホ広告のリーディングカンパニーなので、それに合った仕掛けを作ることになりました。
今回、導入したタッチパネルはDISPLAXというものです。これを採用することで、巨大なディスプレイをタッチパネルにすることができます。
今回は、タッチのできるエントランスの実現を計画しました。
このタッチパネルは裏でPCにつなぐことで、そのPCにクリックイベントを送ることができます。
ということは・・・・。
そう、ブラウジングができるということです。
そこで、既存にあるホームページをJavaScriptを使ってタッチパネルで動かせるようにしました。
今でこそ、スマートフォンに慣れ親しみ、画面を上や下になぞれば勝手にスクロールするものと思われがちです。しかし、PCのブラウザをマウスでドラッグしていただければわかりますが、マウスの動きに合わせて画面がスクロールされるわけではありません。そのため、タッチパネルのイベントから、ブラウザ上でスマホと同じ挙動を擬似的に再現する必要があります。
今回、ドラッグでスクロールの実現は、css3のtransitionを利用しました。
scrollToも考慮にいれたのですが、transition-durationの威力に屈服しましたw
理由は、scrollToではできない、細かい遷移のプロパティを transitionでは決めることができます。
ではそのtransitionについて
MDNより引用
トランジションを適用する CSS プロパティの名前を指定します。ここに指定したプロパティだけが、トランジションによりアニメーションします。通常、それ以外のプロパティの変更は即座に反映されます。
トランジションの実行にかける所要時間を指定します。単一の値を指定すると、すべてのプロパティのトランジションの所要時間として適用されます。または複数の値を指定すると、プロパティごとにトランジションの所要時間として異なる値を指定することができます。
トランジションの中間状態におけるプロパティの値の計算方法を定義する、3 次ベジェ曲線を指定します。
プロパティの変更とトランジションの実行が開始されるまでの待ち時間を定義します。
transitionは指定した要素を移動させる仕様です。
??実現させたいのは、スクロールではないのか??
問題ないのです。以下でスクロールが実現できます。
一番外を囲っているラッパーを動かしてしまえば、含まれている要素も一緒に動くため、以下のような実装でスクロールが実現できるのです。
// transform
$(scrollId).css({
"transform":"translateY("+scrollTop+"px)",
"-moz-transform":"translateY("+scrollTop+"px)",
"-webkit-transform":"translateY("+scrollTop+"px)"
});
jQueryで制御しているのですが、このように、スクロールさせる距離を指定してあげて、scrollIdに動かしたいクラスを代入してあげれば、見事にスクロールが実現します。
ただ、これだけではドラッグに応じて要素が動くだけです。
やはり、慣性を使って、ヌルヌル動かしたいですよね!?
そこで、5フレーム前までの指のドラッグ情報を保持しておき、その移動距離に応じて慣性を働かせるという仕組みを作りました。
// マウス座標履歴を保存
function saveMousePosition(point){
if (moveStack.length < 5){
moveStack.push(point);
} else {
moveStack.push(point);
moveStack.shift();
}
}
// 慣性によってスクロール
function scrollWindow(points){
if (points.length < 5) {
return;
}
var distance = points[4].y - points[0].y;
scrollTop += distance; // 画面がスクロールしすぎないように止める
scrollTop = shrinkStopper(scrollTop, shrink);
speed = Math.abs(distance) / 300;
deceleration = 0.0006;
duration = speed / deceleration;
// cssを変更して移動させる
$(scrollId).css({
"transition-timing-function":"cubic-bezier(0.1, 0.57, 0.1, 1)",
"transition-duration":+duration+"ms",
"transform":"translateY("+scrollTop+"px)",
"-moz-transform":"translateY("+scrollTop+"px)",
"-webkit-transform":"translateY("+scrollTop+"px)"
})
// スクロールが画面をはみ出した時に戻す
shrinkFixer(scrollTop);
points = [];
}
上のソースを見ると、transform-durationというプロパティを使っています。
これぞ、ヌルヌル感を出す必殺技。
このduration分だけ、時間をかけて移動します。
また、timing-functionを利用すると、時間内でどれくらいの移動をするか分配できます。
このようにして、ドラッグだけを用いてのヌルヌル感を実装しました。
もしCyberZにお越しの際は、ぜひタッチしてヌルヌル感を実感してみてください。