最近在看設備傳感器的API,固然也少不了研究一下讓微信稱神的「搖一搖」了。關於「搖一搖」的實現,網上不少資料因此不詳細說了,但老是有佈局、效果不全等各類問題,因此做爲一名資深copypaster,代碼確定是要貼的: 源碼在此 html
手機掃二維碼看看效果,支持Chrome、Safari、微信(新版):git
核心代碼是這一段:github
this.deviceMotionHandler = function(eventData) { var acceleration = eventData.acceleration; var curTime = new Date().getTime(); //檢測頻率:每100ms一次 if ((curTime - that.last_update) > 100) { var diffTime = curTime - that.last_update; that.last_update = curTime; that.x = acceleration.x; that.y = acceleration.y; that.z = acceleration.z; var speed = Math.abs(that.x + that.y + that.z - that.last_x - that.last_y - that.last_z) / diffTime * 10000; if (speed > that.SHAKE_THRESHOLD) { //do something that.shakeAudio.play(); //搖一搖音效 window.navigator.vibrate(200); //振動效果 that.shakeEffect.className = 'shake-box shaking'; //搖一搖圖片動態 clearTimeout(shakeTimeout); var shakeTimeout = setTimeout(function() { that.shakeEffect.className = 'shake-box'; },4000); } that.last_x = that.x; that.last_y = that.y; that.last_z = that.z; } };
原理: 以100ms的間隔去掃描加速度計,當檢測到加速度發生突變(變化率大於閥值)時,就能夠認爲此時在甩動手機。由公式能夠看到,這裏檢測的是3個方向的加速度,因此不管往什麼方向甩均可以觸發搖一搖效果。web
注意點: 這裏加了一個搖一搖的音效,移動端關於音頻的坑太多,想必各位也是碰到很多。本次的坑是即便調用了play也沒法播放,解決辦法是讓用戶操做第一次播放或者加載,具體來講就是綁定一個事件,以下。並且加載須要必定時間,這裏原本應該再作緩衝處理,但我沒有,因此第一次播放會有很明顯的延遲。微信
window.addEventListener('touchstart',function () { if ( !shake1.audioLoaded ) { shake1.shakeAudio.load(); //load事件必須由用戶觸發 shake1.audioLoaded = true; } }, false);
佈局方面: 佈局方面嘗試使用了CSS3的彈性盒子,可是萬萬沒想到先進的X5內核竟然僅支持 display: -webkit-box; 因此這裏須要多寫一套兼容的樣式。動態效果原本想用 transition 湊合一下,看了效果仍是過不了本身這關,最後仍是換成 animation 實現。transition的問題是撐開和收縮時邊框的行爲不對,用動畫就比較好解決了。佈局須要注意的是:背景圖的上半部須要多加一層嵌套實現自適應。另外,微信的邊框還有陰影,這些細節我們暫時先忽略了。HTML結構以下:ide
<div class="bodymask"><h2>準備好了嗎?<br />點擊屏幕開始"搖"!</h2></div> <div class="shake-box"> <div class="shake-upside"> <div class="shake-upside-inner"></div> </div> <div class="shake-backimage"> <a href="http://www.cnblogs.com/qieguo/"><img id="id-shake-image" src="source/000.png"/></a> </div> <div class="shake-downside"></div> </div>
以上實現了「搖一搖」效果,但以樓主固然不會到此爲止。下面是樓主失敗而有益的探索(「有益」二字可無視)佈局
其實樓主是一個吃飯都不想動手的重度懶癌患者,拿着手機看得正爽的時候還要我伸出中指去點擊屏幕或者滑動,真的好累啊。。。特別是在躺着的時候,拇指是一個受力點,既要支撐手機還要伸出去滑動屏幕,很不天然。因此,爲何不能甩一甩就翻頁呢? 好比說下面的場景:測試
分析:動畫
這個需求貌似很簡單的樣子,加速度是有方向的,直接判斷x軸加速度正負不就能判斷是左甩仍是右甩了嗎? 搖一搖的代碼稍微改改貌似就能實現了呢,竊喜~~~然而,理想老是太豐滿,而現實卻太骨感。不管咱們往哪一個方向甩動,最後要中止仍是須要加一個阻力,因此一次甩動過程當中至少有一次加速度方向的變化。請注意,這裏有個「至少」,由於有時候咱們要向左甩的時候,可能開始會先向右退一點才左甩的;在剎停的時候也頗有可能剎過頭了,這裏加速度就會有一個抖動。this
想象老是沒說服力,咱們仍是看看數據吧。固然這裏先利用搖一搖相似的篩選規則來去掉非甩動的動做。當檢測到加速度發生突變(變化率大於閥值)時認爲發生了一次甩動,這時候輸出 x 軸的加速度值來看看,掃描頻率設置爲100ms的時候數據以下:
上面分別是左甩和右甩時候的數據,根據這個數據特色,判斷每個週期的第一個符合條件的加速度正負就能夠判斷甩動的方向了,樓主這裏定義每一個甩動週期爲1s。
var speed = Math.abs(that.x + that.y + that.z - that.last_x - that.last_y - that.last_z) / diffTime * 10000; if (speed > that.SHAKE_THRESHOLD) { if ((curTime - that.last_catch) > 1000) { if (that.x > 5) { output.innerHTML += '右甩x:' + that.x + '<br/>'; //加速度向右,右甩 that.last_catch = curTime; } else if( that.x < -5) { output.innerHTML += '左甩x:' + that.x + '<br/>'; //加速度向左,左甩 that.last_catch = curTime; } } }
理論上這個是能夠篩選掉不適合的加速度數據了,測試以下:
看起來像是獲得了準確的結果,但不一樣人有不一樣的習慣、力度,上面的方法並不能很好的獲得最準確的辦法。
更爲準確的辦法應該是求出x的位移,再加上 x軸加速度變化判斷是否甩動,二者結合就能夠很好的判斷甩動方向了。這裏位移只要求能判斷左右,因此直接用高中物理的公式便可。可是,在測試了 n 次以後,我纔開始想,這個需求是真實存在的嗎?仍是說只存在個人臆想裏面? 忽然想起紅衣教主的話,不少人啊都是掌握一門技術以後呢就會把這個技術包裝成一個產品,還會強行爲這個產品適配不少需求,但這些需求都是YY,都是僞需求!
真理!老周這一針見血啊!
不過呢,加速度計和陀螺儀仍是很是好玩的東西,好好利用它們仍是能夠實現不少有趣的東西,好比說這個:AIWI使用手機玩體感遊戲。
只要你能利用加速度計和陀螺儀計算出空間中的運動軌跡,那這一切都好辦了,不過要獲得比較好的精度可不能用高中物理那種簡單的時域積分哦,這個樓主就不敢強行裝逼了,有興趣的同窗自行搜索哈。
以上,這一篇都實在太水了,仍是放圖吧。
(圖片出處:小周同窗,轉載請註明)
原創文章,轉載請註明出處!本文連接:http://www.cnblogs.com/qieguo/p/5448786.html