JavaScript 陀螺儀檢測裝置方向(重力感應)

Bob-Chen發表於2019-03-04

隨著陀螺儀作為只能手機的標配,根據手機角度不同,讓圖片有點視差微動效果可以給使用者一點驚喜,於是簡單研究了一下 HTML5 下利用陀螺儀獲取裝置方向的 API。

處理方向變化的事件

HTML5 中與手機方向變化有關的 API 有兩個,一個是 deviceorientation 事件,一個是 devicemotion 事件。

今天這個根據手機動來動去產生微動效果的主要用到 deviceorientation 事件,這個事件主要是監聽並接收裝置方向變化資訊。
devicemotion 事件主要是用來監聽裝置在位置和方向上的加速度變化資訊,這個主要用在搖一搖等應用上。

監聽 deviceorientation 事件比較簡單:

 window.addEventListener(`deviceorientation`, handleFunc, false);複製程式碼

然後在回撥函式 handleFunc 中會有裝置轉過的角度:

 function handleFunc(evnet){
    var alpha = event.alpha;
    var beta = event.beta;
    var gamma = event.gamma;
 }複製程式碼

這裡的 alpha, beta, gamma 表示的是相對於座標軸,裝置在某個給定軸上的旋轉量。

  • alpha:表示裝置沿 Z 軸旋轉的角度,範圍為 0~360;
  • beta:表示裝置在x軸上的旋轉角度,範圍為-180~180。它描述的是裝置由前向後旋轉的情況;
  • gamma:表示裝置在y軸上的旋轉角度,範圍為-90~90。它描述的是裝置由左向右旋轉的情況。

另外放上座標系的圖,方便理解:

JavaScript 陀螺儀檢測裝置方向(重力感應)

光是這樣看可能不太好理解,我們可以開啟 chrome 開發者工具 Sensors 這一項看看直觀的感受。

JavaScript 陀螺儀檢測裝置方向(重力感應)

當我們手機出於直立狀態的時候:

JavaScript 陀螺儀檢測裝置方向(重力感應)

也就是隻有 beta 值是 90,其它兩個都是 0,可以自己改下 beta 值,體驗下什麼叫沿 X 軸轉。

JavaScript 陀螺儀檢測裝置方向(重力感應)

同樣的,沿著 Z 軸轉的 alpha 值,就是類似我們豎著轉手機。

JavaScript 陀螺儀檢測裝置方向(重力感應)

JavaScript 陀螺儀檢測裝置方向(重力感應)

gamma 值:

JavaScript 陀螺儀檢測裝置方向(重力感應)

JavaScript 陀螺儀檢測裝置方向(重力感應)

這樣大概就能理解這三個屬性是表示些什麼東西了,但是這幾個值麻煩的地方是,並不能通過單單一個值來表示出手機向某個方向運動,運動的方向還和手機放置的位置有很大關係。除此之外,還有一個坑是 android 中陀螺儀的資料本身不是很穩定,一般不能直接使用,需要加一些緩衝之類的方法來降噪。

還好,上面那些坑已經有人開始填了,就是 shrekwang 大大做的orienter 元件

orienter 元件

orienter 元件除了提供上面說到的 alpha,beta,gamma 值之外,還另外提供了兩個計算出來的值,分別是 lon 和 lat,字面意思是經度,緯度,可以大致用來當成平移距離來計算。

我們來簡單寫個小 demo,隨著手機動,圖片也有一些視差效果,原理是利用 deviceorientation 事件來獲取手機運動方向的改變,然後通過 transform:translate3d(x,y,z) 給設定到圖片上。

首先是 html:

    <div class="content">
        <img src="../img/test.jpg" class="img">
    </div>複製程式碼

HTML 比較簡單,我們只是放個圖片上去。

然後是利用 orienter 元件來實現我們的功能。

      var o = new Orienter();
      o.onOrient = function (obj) {
        var a, b;

        a = obj.lon < 180 ? obj.lon : obj.lon - 360;
        b = obj.lat;

        a = a > 0 ? a > 50 ? 50 : a : a < -50 ? -50 : a;
        b = b > 0 ? b > 50 ? 50 : b : b < -50 ? -50 : b;

        $(".img").css("-webkit-transform", "translate3d(" + a + "px," + b + "px,0)");

      };
      o.init();複製程式碼

程式碼比較簡單,其中我們對 lon 值進行了處理,lon 的取值範圍是 0~360,其中,小於 180 的我們認為是往右移,大於 180 的當成是往左邊移動,往左的我們要計算出一個負值。

然後下面有一堆三元運算子用來做判斷,因為我們平移的距離有一個極限,這裡我設定的是 50。

放上體驗地址:www.imbeta.cn/demo/demos/…

JavaScript 陀螺儀檢測裝置方向(重力感應)

PC 上記得開啟 chrome 模擬手機和試試在 Sensors 裡模擬轉向。

orienter 程式碼

最後,orienter 幫我們做了那麼多事情,當然要大概看下它的原始碼啦。

首先是前面一段是相容 AMD & CMD 和普通引入的程式碼:

(function (factory) {

    if (typeof define === `function` && define.amd) {
        define([`exports`], function(exports) {
            window.Orienter = factory(exports);
        });
    } else if (typeof exports !== `undefined`) {
        factory(exports);
    } else {
        window.Orienter = factory({});
    }

}(function (Orienter) {
    ……
    ……
}複製程式碼

之後最重點的是 _orient 方法,其中有個 switch,就是處理我們上面說的 lon 和 lat 兩個值的計算,還有運動的方向還和手機放置的位置的處理,以及對 android 陀螺儀不穩定的處理。

程式碼如下:

            switch (this.os) {
                case `ios`:
                    switch (this.direction) {
                        case 0:
                            this.lon = event.alpha + event.gamma;
                            if (event.beta > 0) this.lat = event.beta - 90;
                            break;
                        case 90:
                            if (event.gamma < 0) {
                                this.lon = event.alpha - 90;
                            } else {
                                this.lon = event.alpha - 270;
                            }
                            if (event.gamma > 0) {
                                this.lat = 90 - event.gamma;
                            } else {
                                this.lat = -90 - event.gamma;
                            }
                            break;
                        case -90:
                            if (event.gamma < 0) {
                                this.lon = event.alpha - 90;
                            } else {
                                this.lon = event.alpha - 270;
                            }
                            if (event.gamma < 0) {
                                this.lat = 90 + event.gamma;
                            } else {
                                this.lat = -90 + event.gamma;
                            }
                            break;
                    }
                    break;
                case `android`:
                    switch (this.direction) {
                        case 0:
                            this.lon = event.alpha + event.gamma + 30;
                            if (event.gamma > 90) {
                                this.lat = 90 - event.beta;
                            } else {
                                this.lat = event.beta - 90;
                            }
                            break;
                        case 90:
                            this.lon = event.alpha - 230;
                            if (event.gamma > 0) {
                                this.lat = 270 - event.gamma;
                            } else {
                                this.lat = -90 - event.gamma;
                            }
                            break;
                        case -90:
                            this.lon = event.alpha - 180;
                            this.lat = -90 + event.gamma;
                            break;
                    }
                    break;
            }複製程式碼

分別根據 ios/android 平臺對豎屏和左右橫屏做相應處理。

我們來看下 ios 下的豎屏:

           case 0:
               this.lon = event.alpha + event.gamma;
               if (event.beta > 0) this.lat = event.beta - 90;
               break;複製程式碼

先看下面那句處理 lat 的,if (event.beta > 0) this.lat = event.beta - 90; 這裡 -90 就是因為豎屏的時候,beta 值預設為 90。即下面這個圖:

JavaScript 陀螺儀檢測裝置方向(重力感應)

所以這裡 -90 比較好理解。

然後再看上面那句 this.lon = event.alpha + event.gamma; 這裡我想了好久,也沒想出來為什麼豎屏的時候 lon 的值是 alpha 和 gamma 之和。

要理解這個,要從我們平常使用手機的動作來看。現看 gamma 值,gamma 是沿著 y 軸轉動,拿出手機,豎直放置,沿著 y 軸轉一下,手機是這樣的狀態:

JavaScript 陀螺儀檢測裝置方向(重力感應)

這樣的時候我們一般是要看到更多的左右資訊,也就是橫向的經度值,所以手機豎直的時候 gamma 要算到 lon 裡面。

再來看 alpha 值,alpha 值是表示裝置沿 Z 軸的變化。要理解這個,我們要試著想象我們在拍全景照片。以自己為圓心,手臂與地面平行,豎著拿著手機,手臂作為半徑,嘗試像拍攝全景照片,以身體為圓心,移動手臂。會發現我們我們其實是在做一個圓,而在這途中,手機其實是沿著 Z 軸在轉動的。

如果覺得說的太抽象,可以看看下面這個例子,嘗試理解一下。

shrek.imdevsh.com/demo/kfc/

二維碼:

JavaScript 陀螺儀檢測裝置方向(重力感應)

結語

很多看起來很容易實現的功能,實際上卻有很多很多的坑,要填這些坑,又要有很多積累和思考,對於那些幫你填坑的人,要說一聲『謝謝』。

Demo 原始碼地址:github.com/bob-chen/de…

碎碎念

記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。

微信公眾號:程式設計師的詩和遠方

公眾號ID : MonkeyCoder-Life

JavaScript 陀螺儀檢測裝置方向(重力感應)

參考連結

developers.google.com/web/fundame…

www.w3.org/html/ig/zh/…

developer.mozilla.org/zh-CN/docs/…

github.com/shrekshrek/…

相關文章