html手机重力,HTML5重力传感设备

本文介绍了HTML5 DeviceAPI中的deviceorientation事件,用于获取移动设备的重力感应数据。通过示例展示了如何利用这些数据创建一个重力感应球的互动效果,当设备倾斜或翻转时,球会随之滚动。文章还讨论了传感器数据的滤波处理,以及在iOS和Android设备上的表现差异,并提供了实际代码示例。

重力传感器是一个非常常见的内置在智能手机等移动设备中的传感器,基本作用就是获得移动设备的重心。当移动设备倾斜或翻转时,重心会发生变化,而重力传感器将如实地记录下重心变化的过程并通过数据反映出来。

本文将通过HTML5的Device API中的deviceorientation制作一个重力感应球的例子,供读者参考。

deviceorientation所在的地址是:http://dev.w3.org/geo/api/spec-source-orientation.html。

由于安全问题,浏览器可能会默认关闭一些配置,因此读者需要从欧朋浏览器地址栏中输入opera:config后回车,找到需要的相关参数,进行调整

如果你在测试时,发现无法监测到deviceorientation传出来的值,有可能是因为关闭了对deviceorientation的支持,那你可以试着照上图所示的方式,在地址栏中输入opera:config,回车,然后找到Orientation选项并勾选上

1. 了解重力传感器

传感器是移动互联网Web App开发中非常重要的一个设备,涉及多个应用概念。在HTML5的Device API中,DeviceOrientation事件规范提供了3个DOM事件,分别是:deviceorientation、compassneedscalibration和devicemotion。本节主要讲解的是deviceorientation。

DeviceOrientation规范定义的是返回alpha、beta和gamma三个值,如下面的代码所示:

window.addEventListener("deviceorientation", function(event){

//返回值event.alpha、event.beta、event.gamma

}, true);

当设备水平放在桌面上时,其event返回的值如下:

{alpha: 90,

beta: 0,

gamma: 0};

而此时,其设备的朝向值应为360-alpha(当设备翻转时,以此公式为基础进行朝向运算),

当设备的转动变成以x轴为中心自转时,其event返回的值如下:

{alpha: 90,

beta: 90,

gamma: 0};

当设备的转动变成以z 轴为中心自转时,则alpha值发生变化,

当设备的转动变成以y 轴为中心自转时,则gamma值发生变化,

当DeviceOrientation规范的Devicemotion事件的加速度计还允许有重力时,则会出现:

{x: 0,

y: 0,

z: 9.81};

而这时,如果设备处于自由落体的情况时,它的值应该是:

{x: 0,

y: 0,

z: -9.81};

如果设备在高速行驶的汽车中时,它的值应该是(这是复杂应用,目前还没有良好的支持,

有兴趣的读者可以继续深入研究):

{acceleration: {x: v^2/r, y: 0, z: 0},

accelerationIncludingGravity: {x: v^2/r, y: 0, z: 9.81},

rotationRate: {alpha: 0, beta: 0, gamma:-v/r*180/pi} };

2. 重力感应球示例

为了让读者更好地了解重力传感器,建立起感性的认识,我们通过重力感应球的示例来展示重力传感器的开发过程和技巧。

重力传感器示例的代码如代码如下:

重力感应球

style=color:#fff;height:30px;line-height:60px;font-size:26px;margin-top:25px;

margin-bottom:35px;">重力感应球

style="color:#ccc;font-size:18px;margin-left:20px;margin-right:20px;margin-top:

16px;">HTML5的Device API集成了调取重力感应和重力加速的功能。基于此功能,欧朋浏览器 HTML5

体验版可以实现重力感应,并在网页上呈现效果。此demo就是利用了这个特性。晃动手机,便可实现小球在

网页上滚动的特效。

关闭提示

style="z-index:1000;position:absolute;left:0px;top:30px;">

onclick="showhelp('')">

function hiddeDiv(id){

document.getElementById('helpme').style.display='none';

}

function showhelp(){

document.getElementById('helpme').style.display='';

}

style="margin-top:0px;margin-left:0px;z-index:10;">

opera_ball.png

var cur_x = 0;

var cur_y = 0;

var ball_radius = 50; //球的半径,用来判断是否靠近边界,进行碰撞检测用

var initialized = false; //初始化的值

var ww;

var wh;

var speed_x = 0;

var speed_y = 0;

var accel_x;

var accel_y;

var friction_accel = 0.02; //摩擦系数

var interval = 33; //毫秒数, 约为30帧每秒

var bg_color = "#EEEEEE";

var fg_color = "#333";

var absorbing_rate = 0.5; //弹力消耗比例

var gunball=new Image();

gunball.src="opera_ball.png"; //实例化的滚球的图像

var opera_pix_bg=new Image();

opera_pix_bg.src="opera_pix_bg2.png"; //实例化的背景图

function inSameDirection(a, b){ //方向判断函数

return a > 0 && b > 0 || a <= 0 && b <= 0;

}

function getCurpos(cur_pos, speed, accel, boundary){ //当前位置判断函数

if(speed == 0 &&Math.abs(accel) <= friction_accel)

return [cur_pos, speed];

start_speed = speed;

f_accel = (speed > 0 ? -friction_accel:friction_accel); //摩擦力导致速度变慢

speed += accel + f_accel; //速度的方向被改变了

if(!inSameDirection(f_accel, accel) &&

!inSameDirection(f_accel, start_speed) &&

!inSameDirection(start_speed, speed)){

//因为摩擦,球的速度逐渐为0

speed = 0;

}

cur_pos += (start_speed + speed)/2; //边界检测

if(cur_pos> boundary - ball_radius){

cur_pos= boundary - ball_radius;

speed = -speed * absorbing_rate;

}

else if(cur_pos < 0){

cur_pos = 0;

speed = -speed * absorbing_rate;

}

return [cur_pos, speed];

}

function physics(){ //物理运动计算函数

var x = getCurpos(cur_x, speed_x, accel_x, ww);

cur_x = x[0];

speed_x = x[1];

var y = getCurpos(cur_y, speed_y, accel_y, wh);

cur_y = y[0];

speed_y = y[1];

}

function paint(){ //绘图函数

var ball_canvas = document.getElementById('ball');

var ctx = ball_canvas.getContext('2d');

physics(); //引入物理运动计算的函数

ctx.drawImage(opera_pix_bg, 0,0, ww, wh );

ctx.drawImage(gunball, cur_x,cur_y, 50, 50 );

setTimeout("paint()", interval);

}

function clearCanvas(){ //擦除画布的函数

var ball_canvas = document.getElementById('ball');

var ctx = ball_canvas.getContext('2d');

}

function update(evt){ //更新画布的函数

var ball_canvas = document.getElementById('ball');

if(ball_canvas.width != window.outerWidth ||

ball_canvas.height != window.outerHeight){

ball_canvas.width = window.outerWidth;

ball_canvas.height = window.outerHeight;

clearCanvas();

}

ww = ball_canvas.width;

wh = ball_canvas.height;

//根据重力传感器的值计算加速度

accel_x = Math.sin(evt.gamma/180 * Math.PI);

accel_y = Math.sin(evt.beta/180 * Math.PI);

if(!initialized){

cur_x = ww/2 + ball_radius; //滚球当前位置的x坐标值

cur_y = wh/2 + ball_radius; //滚球当前位置的y坐标值

initialized = true;

clearCanvas();

paint(); //调用绘图函数

}

}

function preload(){

var ball_canvas = document.getElementById('ball');

if(ball_canvas.width != window.outerWidth ||

ball_canvas.height != window.outerHeight){

ball_canvas.width = window.outerWidth;

ball_canvas.height = window.outerHeight;

}

ww = ball_canvas.width;

wh = ball_canvas.height;

paint();

}

preload();

window.addEventListener('deviceorientation', update, true);

晃动、翻转设备时,球会随着设备的变动而滚动弹跳。本代码的执行效果如下图:

3. 本例小结

本例是众多传感器设备通过HTML5标准在浏览器上实现的一个典型案例。到目前为止,如果开发者要做重力传感器的实验,又买不起iPhone或者iPad的话,搞个便宜的Android系统手机,装上欧朋H5就可以试验了。

在开发重力传感器的时候,新手往往会忽略几个问题,在此我们特意提出来供读者引以为鉴。

(1) 传感器得出来的值是非稳定态的,往往有噪声数据,因此,如果开发者直接使用传感器传过来的值进行绘图,一定会出现滚球闪动和瞬间不受控的现象。很多开发者在滤波面前往往一愁莫展,网上大量的各种滤波算法都是有用的,而且是合理的,例如平均值滤波、去除最大值和最小值的滤波、加权平均滤波,甚至卷积分滤波等。但是,经过实践,我们总结出一个很有效的。

小经验 通过setInterval这样的定时器去取值,把帧数定在30帧左右,就可以实现99%以上的完美滤波。我们把这个方法称为时间点抽样滤波。

(2) iOS系统里(iPhone、iPad和iPod)的Safari在直接获取传感器数据时,往往没有噪声,原因是浏览器已经消过噪了。这是好事,也是坏事。好事是开发者不用操心传感器的示波不稳定问题。坏事是开发者得到的数据都是经过过滤的,而且没有办法得到第一手数据,往往在特殊情况下不利。在摇动、晃动等行为发生时,用重力传感器是不合适的。在标准中, devicemotion事件可以判断摇动、晃动等行为的。

虽然在标准中有提示可以通过加速度和角度来计算摇动、晃动等行为,但很多开发者可能会不适应,建议使用devicemotion事件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值