- DeviceMotion は「端末がどれくらい“揺れているか・加速しているか”」を教えてくれるセンサー
- DeviceMotionEvent の基本イメージ
- acceleration と accelerationIncludingGravity の違いをイメージで掴む
- rotationRate は「どれくらいの速さで回転しているか」
- まずは「端末を振ったら色が変わる」簡単な例から
- iOS での権限リクエスト(DeviceOrientation と同じ罠)
- センサー値は「ノイズがある」「揺れる」前提で扱う
- DeviceMotion を使うときに意識してほしいポイント
- 初心者として「DeviceMotion」で掴んでほしいこと
DeviceMotion は「端末がどれくらい“揺れているか・加速しているか”」を教えてくれるセンサー
まずイメージからいきます。
DeviceMotion は、
スマホやタブレットの「動き」そのものを数値で教えてくれる仕組みです。
端末を振る
端末を素早く持ち上げる・下ろす
端末を急に止める
こういう「加速・減速・揺れ」を、JavaScript からリアルタイムに受け取れます。
「振ると何かが起きる」
「端末を振ってサイコロを振る」
「歩いているときだけカウントする」
みたいなインタラクションの土台になるのが DeviceMotion です。
DeviceMotionEvent の基本イメージ
「一定間隔で“動きの情報”がイベントとして飛んでくる」
DeviceMotion も DeviceOrientation と同じく、
イベントとして値が流れてきます。
基本形はこうです。
window.addEventListener("devicemotion", (event) => {
console.log(event.acceleration);
console.log(event.accelerationIncludingGravity);
console.log(event.rotationRate);
});
JavaScriptdevicemotion イベントが発生するたびに、
端末の「加速度」や「回転速度」が event に入って渡されます。
ここで特に重要なのがこの 3 つです。
accelerationaccelerationIncludingGravityrotationRate
名前が長くてちょっと怖いですが、
イメージさえ掴めばそんなに難しくありません。
acceleration と accelerationIncludingGravity の違いをイメージで掴む
acceleration: 「重力を除いた純粋な加速度」
event.acceleration は、
「重力を除いた加速度」です。
端末を静かに机の上に置いているとき、
本当は地球の重力(9.8 m/s²)がかかっていますが、
それを除いた値が acceleration です。
理想的には、
端末が完全に静止しているとき acceleration はほぼ 0 になります。
端末を急に右に動かすと、x 方向の加速度が出る
急に上に持ち上げると、y 方向の加速度が出る
といった感じで、「動かした瞬間の加速・減速」が見えます。
accelerationIncludingGravity: 「重力も含めた加速度」
event.accelerationIncludingGravity は、
「重力も含めた加速度」です。
端末を机の上に静かに置いていても、
重力のぶんだけ常に何かしらの値が出ます。
端末の向きによって、
重力が x / y / z のどの方向にどれくらい効いているかが変わるので、
端末を傾けると値も変わります。
ざっくり言うと、
acceleration… 「動かしたときの加速・減速」を見たいときaccelerationIncludingGravity… 「端末の向き+動き」をまとめて見たいとき
に使うイメージです。
初心者のうちは、
「とりあえず accelerationIncludingGravity を見て、
端末を動かすと値が変わるのを体感する」
ところから入ると分かりやすいです。
rotationRate は「どれくらいの速さで回転しているか」
端末を回すスピードを角速度として受け取る
event.rotationRate には、
端末の回転速度(角速度)が入っています。
window.addEventListener("devicemotion", (event) => {
const r = event.rotationRate;
if (!r) return;
console.log(r.alpha, r.beta, r.gamma);
});
JavaScriptここでの alpha / beta / gamma は、
DeviceOrientation の角度と似た名前ですが、
「角度そのもの」ではなく「角度の変化の速さ」です。
ざっくりイメージはこうです。
rotationRate.alpha… 端末を平面上でくるっと回す速さrotationRate.beta… 前後に倒す速さrotationRate.gamma… 左右に傾ける速さ
「どれくらい回転しているか」を見たいときに使いますが、
最初のうちは acceleration 系だけでも十分遊べます。
まずは「端末を振ったら色が変わる」簡単な例から
HTML と CSS
<div id="status">端末を振ってみてください</div>
<div id="box"></div>
#status {
text-align: center;
margin-top: 20px;
}
#box {
width: 150px;
height: 150px;
margin: 20px auto;
background: lightgray;
transition: background 0.2s;
}
JavaScript(加速度の大きさで「振った」と判定)
const statusEl = document.querySelector("#status");
const box = document.querySelector("#box");
let lastShakeTime = 0;
window.addEventListener("devicemotion", (event) => {
const acc = event.accelerationIncludingGravity;
if (!acc) return;
const x = acc.x || 0;
const y = acc.y || 0;
const z = acc.z || 0;
const magnitude = Math.sqrt(x * x + y * y + z * z);
const now = Date.now();
if (magnitude > 20 && now - lastShakeTime > 1000) {
lastShakeTime = now;
box.style.background = `hsl(${Math.random() * 360}, 70%, 60%)`;
statusEl.textContent = `振った! 加速度: ${magnitude.toFixed(2)}`;
} else {
statusEl.textContent = `加速度の大きさ: ${magnitude.toFixed(2)}`;
}
});
JavaScriptここでやっていることを日本語にすると、
accelerationIncludingGravity から x / y / z の値を取る
3 つを合成して「全体の強さ(大きさ)」を計算する
その大きさが一定以上(ここでは 20)なら「振った」とみなす
連続判定を防ぐために、1 秒に 1 回だけ反応するようにしている
という流れです。
実際にスマホで開いて振ってみると、
「振った瞬間だけ色が変わる」動きが体感できます。
ここで重要なのは、
「生のセンサー値」ではなく「そこから何を判定するか」 を考えていることです。
iOS での権限リクエスト(DeviceOrientation と同じ罠)
いきなり devicemotion が飛んでこないことがある
最近の iOS Safari では、
DeviceMotion も「ユーザーの許可」が必要です。
そのため、単に
window.addEventListener("devicemotion", handler);
JavaScriptと書いただけでは、
イベントが飛んでこないことがあります。
iOS では、ユーザーの操作(タップなど)をきっかけにDeviceMotionEvent.requestPermission() を呼んで、
「モーションと方向のアクセスを許可しますか?」
というダイアログを出す必要があります。
権限リクエストの例
const btn = document.querySelector("#requestBtn");
const info = document.querySelector("#info");
btn.addEventListener("click", async () => {
if (
typeof DeviceMotionEvent !== "undefined" &&
typeof DeviceMotionEvent.requestPermission === "function"
) {
try {
const state = await DeviceMotionEvent.requestPermission();
if (state === "granted") {
info.textContent = "センサーの利用が許可されました。端末を振ってみてください。";
window.addEventListener("devicemotion", handleMotion);
} else {
info.textContent = "センサーの利用が拒否されました。";
}
} catch (e) {
info.textContent = "センサーの権限リクエストに失敗しました。";
}
} else {
info.textContent = "このブラウザは iOS の権限リクエスト API に対応していません。";
window.addEventListener("devicemotion", handleMotion);
}
});
JavaScriptここでも、
ユーザーのタップ → 権限ダイアログ → 許可されたらイベント登録
という流れにするのがポイントです。
「勝手にセンサーを読み続ける」のではなく、
「ユーザーの意思を挟んでから使う」 のが今の Web のルールです。
センサー値は「ノイズがある」「揺れる」前提で扱う
完全に静止していても、値はピタッとは止まらない
加速度センサーは、
現実世界の物理量を測っているので、どうしてもノイズがあります。
端末を机の上に置いていても、
x / y / z の値が少しずつ揺れ続けることがあります。
そのまま使うと、
「何もしていないのに“振った”と判定される」
「微妙な揺れで UI がガタガタ動く」
みたいなことが起こります。
閾値とクールタイムで「落ち着いた判定」にする
さっきの「振った判定」の例では、
次の 2 つの工夫を入れていました。
一定以上の大きさ(ここでは 20)を超えたときだけ「振った」とみなす
最後に振ってから 1 秒経つまでは、再度「振った」と判定しない
こうすることで、
小さな揺れには反応しない
連続でガタガタ反応しない
という「落ち着いた挙動」になります。
センサー系の処理では、
「どこまでを無視して、どこからを“本当に動いた”とみなすか」
を決めるのがとても重要です。
DeviceMotion を使うときに意識してほしいポイント
PC では基本的に動かない前提で考える
DeviceMotion は、
スマホやタブレットのための API です。
PC には加速度センサーがないことが多いので、
devicemotion イベントがそもそも発生しないevent.acceleration が常に null
といった状態になります。
だからこそ、
スマホ前提の機能として設計する
PC では「この機能は利用できません」と案内する
という割り切りが必要です。
HTTPS と権限、そして「人間の感覚」
位置情報と同じく、
センサー系も基本的に HTTPS が前提です。
さらに、iOS では権限ダイアログも出ます。
ユーザーからすると、
「いきなり“モーションと方向へのアクセスを許可しますか?”と出る」
というのは、少し怖い体験です。
だからこそ、
なぜセンサーが必要なのかを事前に説明する
ボタンを押したときにだけ権限を求める
拒否されたときの代替手段やメッセージを用意する
といった「人間側の感覚」をちゃんと想像して設計することが大事です。
初心者として「DeviceMotion」で掴んでほしいこと
DeviceMotion の本質は、
「端末の加速度(動き)をリアルタイムにイベントとして受け取る」
ということです。
そのうえで、まずこの感覚を持っておいてほしいです。
devicemotion イベントで、加速度や回転速度が一定間隔で飛んでくるacceleration は重力を除いた加速度、accelerationIncludingGravity は重力込み
生の値は揺れるので、「閾値」や「クールタイム」で判定を安定させる
iOS では DeviceMotionEvent.requestPermission() で権限を取る必要があることがある
練習としては、
加速度の大きさを画面に表示して、端末を動かしてみる
一定以上の加速度で「振った」と判定して何かを起こす
この 2 つを自分の手で書いてみると、
「センサーの数値」と「体の動き」が頭の中でつながります。
そこまで行くと、
「振ってリロード」「振ってサイコロ」「歩数カウンタの原理」
みたいなアイデアが、
「自分でも組めそうなロジック」に見えてくるはずです。
