设备定位API
引用W3C中的设备定位API的规范描述可知,该API“……定义了多种新型DOM事件,旨在提供与主机设备相关的物理朝向与运动状态信息。”由API提供的数据产生自多种来源,其中包括设备上的陀螺仪、加速计以及指南针等。不同的设备所配备的数据来源也有所区别,具体情况取决于其上搭载的传感器类型。
该API从属于W3C Working Draft,也就是说相关规范并非最终确定、在未来其具体内容可能还会出现一定程度的变动。另外值得注意的是,已知该API在多种浏览器以及操作系统之上可能出现不一致性。举例来说,在基于Blink渲染引擎的Chrome与Opera浏览器上,该API会与Windows 8系统产生deviceorientation事件的兼容性冲突。另一个实例则是,该API中的 interval属性在Opera Mobile版本中并非恒定的常数。
实际使用
该API所显示的三个事件全部用于提供与设备定位相关的信息:
• deviceorientation
• devicemotion
• compassneedscalibration
这些事件在window对象当中执行,也就是说我们需要为window对象附加一个处理程序。下面让我们对这三个事件进行逐一分析。
deviceorientation
事件
实现本规范的用户代理必须提供一个名为deviceorientation
新DOM事件。相应事件的类型必须为DeviceOrientationEvent
,且必须在window
对象上触发。对deviceorientation
事件的注册和触发必须遵循DOM Level 2事件的默认行为,[DOMEVENTS]。
用户代理同时还必须提供一个window
对象上名为ondeviceorientation
的事件处理函数IDL属性[HTML5]。该事件处理函数的类型必须是DeviceOrientationEvent
。
interface DeviceOrientationEvent : Event { readonly attribute double? alpha; readonly attribute double? beta; readonly attribute double? gamma; readonly attribute boolean absolute; void initDeviceOrientationEvent(in DOMString type, in boolean bubbles, in boolean cancelable, in double? alpha, in double? beta, in double? gamma, in boolean absolute); }
该事件应当在方向发生较大改变时触发。在此上下文中对较大改变的定义由实现给出。另外,在注册此事件新的监听器时,实现应该在获得足够的新信息之后立即触发该事件。
本事件的alpha
、beta
和gamma
属性必须指示设备的方向,其表现形式为从固定在地球上的坐标系到固定在设备上的坐标系的转换。坐标系必须按照下面的描述调整。
地球坐标系是一个位于用户位置的“东、北、上”系。其拥有3个轴,地面相切与1984世界测地系统的spheriod的用户所在位置。
- 东(X)在地面上,垂直于北轴,向东为正。
- 北(Y)在地面上,向正北为正(指向北极)。
- 上(Z)垂直于地面,向上为正。
对于一个移动设备,例如电话或平板,设备坐标系的定义于屏幕的标准方向相关。这意味着类似于键盘的滑动元素没有展开、类似于显示器的选择元素折叠至其默认位置。如果在设备旋转或展开滑动键盘时屏幕方向发生变化,这不会影响关于设备的坐标系的方向。用户希望获得这些屏幕方向的变化可以使用现有的orientationchange
事件。对于膝上电脑,设备的坐标系定义于集成键盘。
- x在屏幕或键盘平面上,屏幕或键盘的右侧为正。
- y在屏幕或键盘屏幕上,屏幕或键盘的上方为正。
- z垂直于屏幕或键盘屏幕,离开屏幕或键盘为正。
从地球坐标系到设备坐标系的转变必须按照下列系统转换。
旋转必须使用右手规则,即正向沿一个轴旋转为从该轴的方向看顺时针旋转。从两个系重合开始,旋转应用下列规则:
- 以设备坐标系z轴为轴,旋转
alpha
度。alpha
的作用域为[0, 360)。 - 以设备坐标系x轴为轴,旋转
beta
度。beta
的作用域为[-180, 180)。 - 已设备坐标系y轴为轴,旋转
gamma
度。gamma
的作用域为[-90, 90)。
File:Http://www.w3.org/TR/orientation-event/start.png 设备的初始位置,地球(XYZ)与设备(zyz)坐标系重合。
File:Http://www.w3.org/TR/orientation-event/c-rotation.png 设备以z轴为轴,旋转alpha度,原坐标x、y轴显示为x0、y0。
File:Http://www.w3.org/TR/orientation-event/a-rotation.png 设备以x轴为轴,旋转beta度,原坐标y、z轴显示为y0、z0。
File:Http://www.w3.org/TR/orientation-event/b-rotation.png 设备以y轴为轴,旋转beta度,原坐标x、z轴显示为x0、z0。
因此,alpha
、beta
和gamma
组成一组Z-X'-Y''式的固有Tait-Bryan角度。[[EULERANGLES]]注意这里对角度的选择遵循数学惯例,但这意味着alpha
与罗盘指向相反。这还意味着这些角度不匹配车辆动力学中的roll-pitch-yaw惯例。
对于不能提供三个角度绝对值的实现,作为替代,可以提供关于任意方向的相对值。在这种情况下,必须设absolute
属性为false
,否则必须设absolute
属性为true
。
对于不能提供所有三个角度的实现,其必须设未知的角度的值为null。如果提供了某一角度,必须恰当的设置absolute
属性。如果实现不能提供任何方向信息,则触发事件时所有属性都必须被设为null。
compassneedscalibration 事件
实现了本规范的用户代理必须提供一个名为compassneedscalibration
的新DOM事件,其使用定义于DOM Leve 2事件规范的Event
接口[DOMEVENTS]。此事件必须在window
对象上触发。对deviceorientation
事件的注册和触发必须遵循DOM Level 2事件的默认行为,[DOMEVENTS]。
用户代理同时还必须提供一个window
对象上名为oncompassneedscalibration
的事件处理函数IDL属性[HTML5]。该事件处理函数的类型必须是Event
。
该事件必须在用户代理确定用于获得方向数据的罗盘需要校准时触发。此外,用户代理应当仅在校准罗盘可以提高deviceorientation事件获得的的数据的精准度时触发该事件。
该事件的默认行为应当是向用户提示如何校准罗盘。事件必须可以被撤销,以允许网站提供替代的校准界面。
devicemotion 事件
实现本规范的用户代理必须提供一个名为devicemotion
新DOM事件。相应事件的类型必须为DeviceMotionEvent
,且必须在window
对象上触发。对devicemotion
事件的注册和触发必须遵循DOM Level 2事件的默认行为
用户代理同时还必须提供一个window
对象上名为ondevicemotion
的事件处理函数IDL属性[HTML5]。该事件处理函数的类型必须是DeviceMotionEvent
。
[Callback, NoInterfaceObject] interface DeviceAcceleration { readonly attribute double? x; readonly attribute double? y; readonly attribute double? z; }
[Callback, NoInterfaceObject] interface DeviceRotationRate { readonly attribute double? alpha; readonly attribute double? beta; readonly attribute double? gamma; }
interface DeviceMotionEvent : Event { readonly attribute DeviceAcceleration? acceleration; readonly attribute DeviceAcceleration? accelerationIncludingGravity; readonly attribute DeviceRotationRate? rotationRate; readonly attribute double? interval; void initAccelerometerEvent(in DOMString type, in boolean bubbles, in boolean cancelable, in DeviceAcceleration? acceleration, in DeviceAcceleration? accelerationIncludingGravity, in DeviceRotationRate? rotationRate, in double? interval); }
acceleration
属性必须提供宿主设备相对于地球坐标系的加速信息,单位必须是m/s2。
对于不能提供排除重力影响的加速数据的实现(例如缺少陀螺仪),作为替代,可以提供受重力影响的加速数据。这对于许多应用来说并不好用,但提供这些信息意味着提供了最大力度的支持。在此情况下,accelerationIncludingGravity
属性必须提供宿主设备的加速信息,并加上一个加速度相等方向相反的反重力加速度。加速信息的单位必须是m/s2。
rotationRate
属性必须提供宿主设备在空间中旋转的速率,单位必须是deg/s。
interval
属性必须提供从硬件获得数据的间隔,单位必须是毫秒。其必须是一个常量,以简化Web应用对数据的过滤。
对于不能提供所有属性的实现,其必须将位置的属性的值设为null。如果一个实现不能提供移动信息,则触发该事件时,所有属性都应被设为null。
检测支持能力
检测浏览器或者用户代理是否支持前面提到的两个事件,即deviceorientation与devicemotion,本身非常简单,只需要添加一条微不足道的状态声明即可。大家可以查看以下代码片段,我们会在其中检测对deviceorientation事件的支持能力:
- if (window.DeviceOrientationEvent) {
- // We can listen for change in the device's orientation...
- } else {
- // Not supported
- }
为了测试compassneedscalibration事件,我们要用到以下代码片段:
- if (!('oncompassneedscalibration' in window)) {
- // Event supported
- } else {
- // Event not supported
- }
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width,initial-scale=1.0"/> <title>摇一摇功能</title> <script type="text/javascript"> window.onload=function(){init();} var SHAKE_THRESHOLD=3000;//定义一个摇动的阈值 var last_update=0;//定义一个变量记录上一次摇动的时间 var x=y=z=last_x=last_y=last_z=0;//定义x、y、z记录三个轴的数据以及上一次触发的时间 function init(){ //判断移动浏览器是否支持运动传感器事件 if(window.DeviceMotionEvent){ //添加一个事件监听器 window.addEventListener('devicemotion',deviceMotionHandler,false); }else{ alert('not support mobile event'); } } //运动传感器处理 function deviceMotionHandler(eventData){ //获取含重力加速 var acceleration=eventData.accelerationIncludingGravity; var curTime=new Date().getTime();//获取当前时间戳 var diffTime=curTime-last_update; if(diffTime>100){ last_update=curTime;//记录上一次摇动的时间 x=acceleration.x;//获取加速度X方向 y=acceleration.y;//获取加速度Y方向 z=acceleration.z;//获取加速度垂直方向 var speed=Math.abs(x+y+z-last_x-last_y-last_z)/diffTime*10000;//计算阈值 if(speed>SHAKE_THRESHOLD){ alert("摇动了,关闭播放自动播放"); var media=document.getElementById("musicBox");//获取音频控件 media.setAttribute("src","http://192.168.1.125/mohe/upload/audio/20140930/20140930114522_485.mp3"); media.load();//加载音频 media.play();//播放音频 } //记录上一次加速度 last_x=x; last_y=y; last_z=z; } } </script> </head> <body> <p>摇一摇播放音乐吧</p> <audio id="musicBox" controls="true" src=""/> </body> </html>