Reputation: 969
I am writing a mobile application for Windows Phone in HTML5. I want to detect the phone's rotation around the z-axis (I mean the rotation that is used for example in Doodle jump to make the character jump to the left or to the right).
In my application, a line that is vertical in the screen must remain vertical (absolute position in the real world) if I rotate the screen to the left or to the right. To accomplish this, I use the relative values of the angle: each time the screen is rotated a little, I rotate the points of the line by the same amount, but negative.
This works PERFECTLY if the phone is laying on a table or almost horizontal, but the behaviour is much less precise if for example I watch the phone in front of me. Anyway this is not a big problem of course because most users watch the phone from up to down, but a game like doodle jump behaves perfectly also in this situation.
Here is part of the code:
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) {
alphaDiff = Math.floor(event.alpha) - alphaOld;
alphaOld = Math.floor(event.alpha);
//Rotation of the vertical line (x1,y1) - (x2,y2) around the center of the screen
var newPoint = rotate(225, 400, x1, y1, alphaDiff);
x1 = newPoint[0];
y1 = newPoint[1];
newPoint = rotate(225, 400, x2, y2, alphaDiff);
x2 = newPoint[0];
y2 = newPoint[1];
}
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle;
cos = Math.cos(radians);
sin = Math.sin(radians);
nx = (cos * (x - cx)) - (sin * (y - cy)) + cx;
ny = (sin * (x - cx)) + (cos * (y - cy)) + cy;
return [nx, ny];
}
Upvotes: 3
Views: 1651
Reputation: 6353
A combination of beta
and gamma
seems to give pretty good results.
Basically, I normalize the values to a specific range and get the ratio.
window.addEventListener("deviceorientation", function(event){
var b = Math.abs(event.beta)/90;
if(b>1) b = 2-b;
var g = event.gamma/90;
if(Math.abs(event.beta)>90) g = -g;
var x = g/Math.max(0.25,b);
});
The final value is in x
, positive means right, negative means left.
It works with the phone held horizontally or at any angle facing you.
Update: To make the detection work in a vertical position, the code calculates how much the phone is leaning and to which direction.
The value in x
is always positive if the phone is leaning right and negative if leaning left.
This example shows a blue box in the middle of the screen and moves it to whichever direction the phone is leaning:
<!DOCTYPE html>
<html>
<head><meta name="viewport" content="width=1000,user-scalable=no"/></head>
<body style="margin:0">
<pre id="log" style="font-size:4em;"></pre>
<div id="box" style="background:#69c;width:100px;height:100px;position:relative;left:450px"></div>
<script>
var box = document.getElementById("box");
var log = document.getElementById("log");
var smoothx = 0;
window.addEventListener("deviceorientation", function(event){
var b = Math.abs(event.beta)/90;
if(b>1) b = 2-b;
var g = event.gamma/90;
if(Math.abs(event.beta)>90) g = -g;
var x = g/Math.max(0.25,b);
smoothx = smoothx*0.7+x*0.3;
box.style.left = Math.max(0, Math.min(900, smoothx*500+450))+"px";
log.innerText = x.toFixed(1)+"\n"+smoothx.toFixed(1);
});
</script>
</body>
</html>
Because the sensor seems to be very sensitive to movement, I implemented a simple smoothing that gives a steadier value in smoothx
.
Use x
for immediate value without smoothing.
Upvotes: 0
Reputation: 730
Have you tried beta
(for the x-axis) or gamma
(for the y-axis)?
e.g.
function handleOrientation(event) {
var absolute = event.absolute;
var alpha = event.alpha; // z-axis
var beta = event.beta; // x-axis
var gamma = event.gamma; // y-axis
// Do stuff with the new orientation data
}
Orientation Values Explained
The value reported for each axis indicates the amount of rotation around a given axis in reference to a standard coordinate frame.
- The
DeviceOrientationEvent.alpha
value represents the motion of the device around the z-axis, represented in degrees with values ranging from0
to360
.- The
DeviceOrientationEvent.beta
value represents the motion of the device around the x-axis, represented in degrees with values ranging from-180
to180
. This represents a front to back motion of the device.- The
DeviceOrientationEvent.gamma
value represents the motion of the device around the y-axis, represented in degrees with values ranging from-90
to90
. This represents a left to right motion of the device.
It also worth checking browser compatibility for this API.
As well as deviceorientation
, you can check compassneedscalibration
and devicemotion
. For more details on deviceorientation
see MDN.
Upvotes: 2