There is a deviceorientation API in H5, which can detect the rotation state of the mobile device, and then realize the function of the compass, but it is based on the north.
The API provides three items of data, alpha (device Z-axis rotation angle), beta (X-axis), gamma (Y-axis). Generally, alpha is the angle difference from true north. However, different devices and different browsers understand this very differently. . .
webkitCompassHeading
You can use it directly under ios- You can calculate the angle yourself by implementing the standard algorithm of w3c, this value should be equivalent to
webkitCompassHeading
- Android browser
alpha
is generally ok - Chrome use
alpha
, need to subtract 270 (deg) - What about Firefox, minus 180
code show as below:
// 指南针
var compass = document.getElementById('compass');
// compass heading取值模式
var mode = '0';
// 最近一次动画的时间
var now = Date.now();
if (window.DeviceOrientationEvent) {
document.getElementById('options').addEventListener('click', function(e){
if (e.target.tagName === 'INPUT') {
mode = e.target.value;
}
}, false);
window.addEventListener('deviceorientation', function(event) {
var ntime = Date.now();
if (ntime - now < 100) return; // 避免过于频繁的动画
now = ntime;
var heading;
// iOS设备直接使用webkitCompassHeading
if ('webkitCompassHeading' in event) {
// 由于实际是指北的,需要反转角度,下同
heading = 360 - event.webkitCompassHeading;
} else if (window.chrome) {
// chrome浏览器的event.alpha是错误的,计算出来的值也是错的,需要修正
heading = event.alpha - 270;
if (heading < 0) heading += 360;
} else {
if (mode === '0') {
// 安卓浏览器的event.alpha直接可用,这样反应快点
heading = event.alpha;
} else {
// 按照w3c标准规则计算compass heading
heading = 360 - compassHeading(event.alpha, event.beta, event.gamma);
}
// TODO: 火狐始终减去180
// heading -= 180;
}
compass.style.Transform = 'rotate(' + heading + 'deg)';
compass.style.WebkitTransform = 'rotate(' + heading + 'deg)';
compass.style.MozTransform = 'rotate(' + heading + 'deg)';
var info = 'webkitHeading:' + event.webkitCompassHeading + '<br>' +
'heading: ' + heading + '<br>' +
'alpha: ' + event.alpha + '<br>' +
'beta:' + event.beta + '<br>' +
'gamma:' + event.gamma + '<br>' +
'chrome:' + !!window.chrome + '<br>';
document.getElementById('info').innerHTML = info;
}, false);
} else {
document.getElementById('info').innerHTML = '你的浏览器不支持陀螺仪!';
}
// http://stackoverflow.com/questions/18112729/calculate-compass-heading-from-deviceorientation-event-api/21829819#21829819
function compassHeading(alpha, beta, gamma) {
// Convert degrees to radians
var alphaRad = alpha * (Math.PI / 180);
var betaRad = beta * (Math.PI / 180);
var gammaRad = gamma * (Math.PI / 180);
// Calculate equation components
var cA = Math.cos(alphaRad);
var sA = Math.sin(alphaRad);
var cB = Math.cos(betaRad);
var sB = Math.sin(betaRad);
var cG = Math.cos(gammaRad);
var sG = Math.sin(gammaRad);
// Calculate A, B, C rotation components
var rA = - cA * sG - sA * sB * cG;
var rB = - sA * sG + cA * sB * cG;
var rC = - cB * cG;
// Calculate compass heading
var compassHeading = Math.atan(rA / rB);
// Convert from half unit circle to whole unit circle
if(rB < 0) {
compassHeading += Math.PI;
}else if(rA < 0) {
compassHeading += 2 * Math.PI;
}
// Convert radians to degrees
compassHeading *= 180 / Math.PI;
return compassHeading;
}
Online demo address: http://sandbox.runjs.cn/show/mysqbqeq
It should be noted that the accuracy of the gyroscope of the H5 is lower than that of the app, and it needs to be adjusted several times before it is generally reliable. Of course, this also has a lot to do with the algorithm.