这个故事是这样:
我们有个活动,需要让用户通过在长按一个按钮时,不断举高手机,来模拟掀桌子的动作,从而通过掀桌过程中的某个“物理量”来打分,进而执行不同的“下一步”。
首先,我们的手机支持devicemotion吗?
判断如下:
if (window.DeviceMotionEvent) {
console.log('support');
} else {
//
}
接下来,devicemotion给出了哪些参数来让辅助我们进行判断?
这里我们使用带重力参数的DeviceMotionEvent.accelerationIncludingGravity
。
在accelerationIncludingGravity下你又会看到x,y,z三个参数,他们是干嘛的?来跟我熟悉下设备的坐标系。
以上是使用devicemotion需要用到的预备知识。特别强调,x,y,z均为各个方向的加速度,单位是米每平方秒(m/s^2),它是描述物体运动变化快慢的物理量。有些网上流传的demo用加速度除以时间也是醉了。
接下来进入正题。
html代码就是一个button。顺带着记录一些移动过程中的信息:
<div class="noticeContainer">
<p id="dmEvent"></p>
<p id="current"></p>
</div>
<div id="button" class="buttonContainer">
<!--img id="im" src="images/click.png" alt=""-->
</div>
<div id="logContainer">
<p id="log"></p>
</div>
由于希望用户长按,那么必然要通过touchstart和touchend来进行判断。同时绑定\取消devicemotion的监听事件:
document.getElementById('button').addEventListener('touchstart', function(e){
e.preventDefault();
e.stopPropagation();
console.log('start')
log('start')
last_update = new Date().getTime() ;
window.addEventListener('devicemotion', deviceMotionHandler, false);
})
document.getElementById('button').addEventListener('touchend', function(e){
e.preventDefault();
e.stopPropagation();
log('end');
window.removeEventListener('devicemotion', deviceMotionHandler);
last_x == -10000 ;
})
里面有两点说明下:last_update代表上一时刻,那么应该记录为按钮开始被按住时的时刻;last_x代表上一时刻的x轴方向加速度。接下来会看到他的用法。
核心的deviceMotionHandler如下:
var SHAKE_THRESHOLD = 5; //速度的下限
var x, y, z, last_x, last_y, last_z, fastest = -1 ;
last_x = -10000 ;
function deviceMotionHandler(eventData) {
if( last_x == -10000 ){ //每次绑定,上一次的加速度们要重新记录
var acceleration =eventData.accelerationIncludingGravity;
last_x = acceleration.x;
last_y = acceleration.y;
last_z = acceleration.z;
}
var acceleration =eventData.accelerationIncludingGravity;
var curTime = new Date().getTime();
if ((curTime - last_update)> 300) { //当前时间与上一时刻的间隔下限,我们认为是用户掀桌一次的时间
var diffTime = curTime -last_update;
last_update = curTime;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;
var speed = Math.sqrt( Math.pow( Math.abs( y - last_y ) * diffTime /1000 , 2 ) + Math.pow( Math.abs( z - last_z ) * diffTime /1000 , 2 ) );
//合成两个方向的速度
document.getElementById("current").innerHTML = speed;
if (speed > SHAKE_THRESHOLD) {
if( speed > fastest ){
fastest = speed ; //每次按住按钮时得到的最高速度
document.getElementById("dmEvent").innerHTML = speed;
}
}
last_x = x;
last_y = y;
last_z = z;
}
}
然后就可以按住按钮掀桌子了。
这里作为掀桌判断依据的物理量为速度,也可以计算位移来进行判断。
时间间隔作为计算参考并不是最优,也期待以后看到更好的解法。
有很多对devicemition和deviceorientation的封装,例如gyronorm。
网友评论