2013/02/07更新

[JS] iPhoneに搭載されているセンターの値を、JavaScriptから取得する

このエントリーをはてなブックマークに追加      

こんにちは、@yoheiMuneです。
iPhoneでは、搭載されている加速度センサー/ジャイロセンサー/デジタルコンパスで取得している値を、JavaScriptから取得することが可能となってい増す。
今回はその取得方法と、取得値を利用した簡単なサンプルを紹介したいと思います。

画像



加速度センサーから値を取得する

iPhoneに搭載された加速度センサーを用いることで、iPhoneがどちらに動いたか(どちらに加速度がかかったか)を把握することができます。
具体的には以下のような実装を行います。
(JavaScript)
// devicemotionイベントで、加速度センサーの値を継続的に取得することができます。
window.ondevicemotion = function(event) {

  // ユーザーによる加速度 + 重力
  var x = event.accelerationIncludingGravity.x; // 左右
  var y = event.accelerationIncludingGravity.y; // 上下
  var z = event.accelerationIncludingGravity.z; // 前後
  var html = 'ユーザー加速度+重力: <br>x=' + x + "<br> y=" + y + "<br> z=" + z;
  info.innerHTML = html;

  // ユーザーによる加速度
  var x = event.acceleration.x; // 左右
  var y = event.acceleration.y; // 上下
  var z = event.acceleration.z; // 前後
  var html = 'ユーザー加速度: <br>x=' + x + "<br> y=" + y + "<br> z=" + z;
  info2.innerHTML = html;

  // 前回呼び出しからの経過時間
  info3.innerHTML = '前回からの時間: <br>' + event.interval;
  };}
APIの詳細は、Safari Developer Library - DeviceMotionEvent Class Referenceで説明されています。



ジャイロセンサーの値を取得する

ジャイロセンサーの値を取得することで、iPhone端末の回転運動(x軸/y軸/z軸での回転)を取得することができるようになります。
具体的には以下のように値を取得します。

// deviceorientationイベントで、デバイスの回転を継続的に取得できます。
window.ondeviceorientation = function(event) {
  // 回転軸
  var alpha = event.alpha;   // z-axis
  var beta = event.beta;     // x-axis
  var gamma = event.gamma;   // y-axis
  var html = '回転: <br>alpha(z-axis)=' + alpha + "<br> beta(x-axis)=" + beta + "<br> gumma(y-axis )=" + gamma;
  info.innerHTML = html;
}
APIの詳細は、Safari Developer ibrary - DeviceOrientationEvent Class Referenceで説明されています。



デジタルコンパスの値を取得する

デジタルコンパスの値を取得することで、方位を知ることができます。これはiOS5.0以降で利用可能です。
具体的には、以下のような実装を行います。
window.ondeviceorientation = function(event) {

	// コンパスの向き
	// 0から360の間の値を取得でき、0が北、90が東、180が南、270が西を示す。
	// 取得した値がマイナスの場合、正しい値が取得できていないことを示す。
	var compassHeading = event.webkitCompassHeading;
	info5.innerHTML = 'コンパスの向き: ' + compassHeading;

	// CompassHeadingの精度。
	// 例えば10という値を取得した場合、compassHeadingの値は前後10の誤差があることを示す。
	// -1の値を取得する場合には、正しいcompassHeadingの値が取得できていないことを示す。
	var compassAccuracy = event.webkitCompassAccuracy;
	info6.innerHTML = 'コンパスの正確性: ' + compassAccuracy;
}
APIの詳細は、Safari Developer ibrary - DeviceOrientationEvent Class Referenceで説明されています。



デバイスから取得した値を利用したサンプル

YoheiM.NETのTOP画面のヘッダーに、デバイスの回転量に応じて動く青半透明のボールを設置してみました。
こんな感じです。
画像

deviceorientationイベントで取得した値をもとに、ボールの位置が変化します。
(ソースコード)
<div class="header" style="position:relative;">
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="ball" style="position:absolute;"></div>
  <div class="title">
    <a href="/">
      <span style="font-size:25px;">YoheiM.NET</span>
      <span id="header_subtitle" style="font-size:small;">  - 世の中のWeb情報に、体験と意見を添えて発信します</span>
    </a>
  </div>
</div>
<script type="text/javascript">
$(function(){
// ジャイロセンサーが使える場合には、TOPに配置したボールを傾きによって動かせるようにする。(遊び)
  var
    balls = $('.ball'),
    bounceRaito = 0.4,
    bounceLimitSpeed = 1.5,
    min = Math.min,
    max = Math.max,
    abs = Math.abs,
    floor = Math.floor,
    rValues = [1.0, 0.76, 0.8, 0.7, 0.6, 0.55, 0.612, 0.9, 0.65, 0.95, 0.62, 0.87, 0.33, 0.45, 0.23, 0.987, 0.67, 0.99, 0.34, 0.77, 0.69, 0.44, 1.2, 1.05],
    ballCanMove = false,
    areaHeight = $(".header").height(),
    areaWidth = $(".header").width(),
    bottomLimit = Math.floor(areaHeight - $(".ball").height()),
    rightLimit = Math.floor(areaWidth - $(".ball").width())
  ;


  console.debug('limit = ', bottomLimit, rightLimit, balls);

  // ボールを動かすサインを出す。
  setTimeout(function() {ballCanMove = true; console.debug('gyro start.')}, 2000);

  // 回転を取得する。
  window.ondeviceorientation = function(event) {
    console.debug('ondeviceorientation is called.');

    // 回転量
    var alpha = event.alpha;   // z-axis
    var beta = event.beta;     // x-axis
    var gamma = event.gamma;   // y-axis

    // ボールを動かす。
    if (ballCanMove) {

      balls.each(function(index, ball) {

        // betaの値が正なら下へ、負なら上へ動かす。
        var oldSpeed = ball.speedY || 0;
        var y = parseInt(ball.style.top || 0);
        if (y === bottomLimit && oldSpeed === 0 && beta > 0) {
          // 何もしない
        } else if (y === 0 && oldSpeed === 0 && beta < 0) {
          // 何もしない
        } else {
          var speed = oldSpeed + ((beta) / 300) * rValues[index%rValues.length];
          var y = y + speed;
          y =  max(0, min(bottomLimit, y));
          ball.style.top = y + 'px';
          ball.speedY = speed;
          // ここからは跳ね返りの実装
          if (y == bottomLimit && oldSpeed > bounceLimitSpeed) {
            ball.speedY = -speed * bounceRaito;
          } else if (y === bottomLimit && oldSpeed <= bounceLimitSpeed) {
            ball.speedY = 0;
          }
          if (y == 0 && oldSpeed < -bounceLimitSpeed) {
            ball.speedY = -speed * bounceRaito;
          } else if (y === 0 && oldSpeed >= -bounceLimitSpeed) {
            ball.speedY = 0;
          }
        }

        // gammaの値が正なら右へ、負なら左へ動かす。
        var oldSpeed = ball.speedX || 0;
        var x = parseInt(ball.style.left || 0);
        if (x === rightLimit && oldSpeed === 0 && gamma > 0) {
          // 何もしない
        } else if (x === 0 && oldSpeed === 0 && gamma < 0) {
          // 何もしない
        } else {

          var speed = oldSpeed + ((gamma) / 300) * rValues[index%rValues.length];
          var x = x + speed;
          x =  max(0, min(rightLimit, x));
          ball.style.left = x + 'px';
          ball.speedX = speed;
          // ここからは跳ね返りの実装
          if (x == rightLimit && oldSpeed > bounceLimitSpeed) {
            ball.speedX = -speed * bounceRaito;
          } else if (x === rightLimit && oldSpeed <= bounceLimitSpeed) {
            ball.speedX = 0;
          }
          if (x == 0 && oldSpeed < -bounceLimitSpeed) {
            ball.speedX = -speed * bounceRaito;
          } else if (x === 0 && oldSpeed >= -bounceLimitSpeed) {
            ball.speedX = 0;
          }
        }
      });
    }
  };

  // デバイスの向きが変わったら、横幅の再計算をする。
  window.onorientationchange = function () {
    console.debug('orientationchange: is called.');
    areaHeight = $(".header").height(),
    areaWidth = $(".header").width(),
    bottomLimit = Math.floor(areaHeight - $(".ball").height()),
    rightLimit = Math.floor(areaWidth - $(".ball").width())
  };
});
</script>

遊びにしてはちょい長いソースコードだ。。
デバイス向きが変わった際に少し不具合があったり、跳ね返りが時々おかしかったりと少し変なところがありますが、 お試しで作ってみたにはいい感じにできたのではと内心うきうきしてます。

deviceorientaionが動作しない端末では、ondeviceorientationイベントが発火しないようなので、 青いボールが左上にあるだけの状態となります。



最後に

デバイスのセンサーをJavaScriptで使えるようになると、また面白いアプリがいろいろとできそうで楽しみです。
動かない端末は最低限の機能を提供しつつ、動くやつではより楽しいユーザー体験を提供できる作りをしていきたいと思う次第です。

最後までご覧頂きましてありがとうございました。





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。