隨著陀螺儀作為只能手機的標配,根據手機角度不同,讓圖片有點視差微動效果可以給使用者一點驚喜,於是簡單研究了一下 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。它描述的是裝置由左向右旋轉的情況。
另外放上座標系的圖,方便理解:
光是這樣看可能不太好理解,我們可以開啟 chrome 開發者工具 Sensors 這一項看看直觀的感受。
當我們手機出於直立狀態的時候:
也就是隻有 beta 值是 90,其它兩個都是 0,可以自己改下 beta 值,體驗下什麼叫沿 X 軸轉。
同樣的,沿著 Z 軸轉的 alpha 值,就是類似我們豎著轉手機。
gamma 值:
這樣大概就能理解這三個屬性是表示些什麼東西了,但是這幾個值麻煩的地方是,並不能通過單單一個值來表示出手機向某個方向運動,運動的方向還和手機放置的位置有很大關係。除此之外,還有一個坑是 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/…
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。即下面這個圖:
所以這裡 -90 比較好理解。
然後再看上面那句 this.lon = event.alpha + event.gamma;
這裡我想了好久,也沒想出來為什麼豎屏的時候 lon 的值是 alpha 和 gamma 之和。
要理解這個,要從我們平常使用手機的動作來看。現看 gamma 值,gamma 是沿著 y 軸轉動,拿出手機,豎直放置,沿著 y 軸轉一下,手機是這樣的狀態:
這樣的時候我們一般是要看到更多的左右資訊,也就是橫向的經度值,所以手機豎直的時候 gamma 要算到 lon 裡面。
再來看 alpha 值,alpha 值是表示裝置沿 Z 軸的變化。要理解這個,我們要試著想象我們在拍全景照片。以自己為圓心,手臂與地面平行,豎著拿著手機,手臂作為半徑,嘗試像拍攝全景照片,以身體為圓心,移動手臂。會發現我們我們其實是在做一個圓,而在這途中,手機其實是沿著 Z 軸在轉動的。
如果覺得說的太抽象,可以看看下面這個例子,嘗試理解一下。
二維碼:
結語
很多看起來很容易實現的功能,實際上卻有很多很多的坑,要填這些坑,又要有很多積累和思考,對於那些幫你填坑的人,要說一聲『謝謝』。
Demo 原始碼地址:github.com/bob-chen/de…
碎碎念
記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。
微信公眾號:程式設計師的詩和遠方
公眾號ID : MonkeyCoder-Life
參考連結
developers.google.com/web/fundame…