設備定位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>
