我从http://dev.w3.org/geo/api/spec-source-orientation获取了建议的公式(参见工作示例)并实现了以下功能:
function compassHeading(alpha,beta,gamma) { var a1,a2,b1,b2; if ( beta !== 0 || gamma !== 0 ) { a1 = -Math.cos(alpha) * Math.sin(gamma); a2 = Math.sin(alpha) * Math.sin(beta) * Math.cos(gamma); b1 = -Math.sin(alpha) * Math.sin(gamma); b2 = Math.cos(alpha) * Math.sin(beta) * Math.cos(gamma); return Math.atan((a1 - a2) / (b1 + b2)).toDeg(); } else { return 0; } }
而.toDeg()是一个Number对象扩展,由http://www.movable-type.co.uk/scripts/latlong.html提供
/** Converts radians to numeric (signed) degrees */ if (typeof Number.prototype.toDeg == 'undefined') { Number.prototype.toDeg = function() { return this * 180 / Math.PI; }; }
然而,问题在于,即使安装了设备(Google Galaxy Nexus)以保持静态位置,计算出的罗盘航向值也会从大约-75跳到80.这似乎发生在Google Chrome BETA和FF BETA 23中.
解决方法
>将返回的DeviceOrientation alpha,beta和gamma值从度数转换为弧度为alphaRad,betaRad,gammaRad.
>使用alphaRad,betaRad和gammaRad计算规范中每个工作示例的rotationA(rA)和rotationB(rB)组件(如下面的示例代码所示).
>计算compassHeading = Math.atan(rA / rB).
>将返回的半单位圆标题转换为[0-360]度范围内的整个单位圆标题.
>将compassHeading从弧度转换回度(可选).
这是用JavaScript实现的worked example from the specification:
function compassHeading(alpha,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; } window.addEventListener('deviceorientation',function(evt) { var heading = null; if(evt.absolute === true && evt.alpha !== null) { heading = compassHeading(evt.alpha,evt.beta,evt.gamma); } // Do something with 'heading'... },false);
你也可以view a demo of the code provided above.
截至撰写本文时(2014年2月17日),目前适用于:
> Google Chrome for Android
>适用于Android的Opera Mobile
>适用于Android的Firefox Beta
其他浏览器尚未符合DeviceOrientation事件规范中描述的DeviceOrientation校准和/或不提供绝对的DeviceOrientation数据值,因此无法确定带有非完整数据的compassHeading.
*确定向量的水平分量的罗盘方向,该向量与设备的屏幕正交并指向屏幕的背面.