H5的加速度实现摇一摇计数

#### 1. 写在前面
手机设备的性能越来越强大,更多的好玩的H5功能,越来越多的出现在人们的面前,本篇文章中,我将要说的就是:H5设备的重力感应;

说到重力感应,其实也就是再说加速度了,官方文档,请查看:[DeviceMotionEvent](https://developer.mozilla.org/zh-CN/docs/Web/API/DeviceMotionEvent),文档中,有一些简单的介绍,这里我们也不会一一展开来讨论;

先上二维码,看最后的结果:

#### 2. 加速度
加速度的定义时什么,相比大家在学校的物理课上,都学过吧,也许工作多年之后,对于这个定义有一些模糊了,这里就先来看看加速度的定义:加速度(`Acceleration`)是速度变化量与发生这一变化所用时间的比值`Δv/Δt`,是`描述物体速度变化快慢的物理量`,通常用`a`表示,单位是`m/s2`。加速度是矢量,它的方向是物体速度变化(量)的方向,与合外力的方向相同。

或者也可以这么理解:
1. 当匀速运动时,加速度 = 0;
2. 当提速的时候,加速度 > 0 ;
3. 当减速的时候,加速度 < 0; 说到这里,相比大家也能想到了一个词语:匀加速运动(加速度不变的加速运动) ####3. DeviceMotionEvent事件 为什么前面会说加速度这个概念呢,就是因为:devicemotion事件,最终给我们的速度,就是一个加速度的值。 先看看如何使用: ``` window.addEventListener("devicemotion", handleDeviceMotion, false); function handleDeviceMotion(event){ // 提供了设备在X,Y,Z轴方向上加速度的对象。加速度的单位为 m/s2 event.acceleration; // 提供了设备在X,Y,Z轴方向上带重力的加速度的对象 event.accelerationIncludingGravity; // 提供了设备在 alpha,beta, gamma轴方向上旋转的速率的对象 event.rotationRate; // 表示从设备获取数据的频率,单位是毫秒。 event.interval; } ``` 这里,对回调中,我们可以获取的到属性,来进行一些说明: 1. `interval`就不说了,在上面的注释中,可以很简单的看出来; 2. `rotationRate` 其实就表示手机的立体空间位置,与[deviceOrientation简介](http://www.zhangyunling.com/725.html)类似。 3. `acceleration`和`accelerationIncludingGravity`表示的,都是获取加速度的对象,他们的区别在于:后者时移动加速度和重力加速度的综合; 而在本篇文章中,我们主要就是要说的`acceleration`和`accelerationIncludingGravity`属性,他们都包含了3个值,分别为:`x,y,z`,分别代表着三个方向的上的加速度,如下图;

#### 4. 示例代表一切
再好的理论,也不如实践来的好,这里,我们来出几个示例,来简单看一下上述的理论,以及验证一些总结和规律;

先来看示例吧:[加速度基础示例](/study/2019/20190119/index-1.html);

也可以直接扫码二维码:

在这个示例里,有三个按钮:开始,结束,清除;

是为了能录制一段时间内的加速度信息,这样可以有效的验证,在这段时间内,手机的加速度情况。比如你摇动一次手机,会产生什么样的数据;

#### 5. 实践
使用重力加速,可以做哪些H5呢,这个可能有很多,我这里只是拿摇一摇来做这个实验;

要做好这个,那首先要做的一个工作,就是结合加速度的概念,这里,本来有一个示意图才是最好的,但是我在图形制作上,能力有限,所以就直接拿语言进行一下描述,希望您可以读懂我的意思;

备注:我们这里的实践,是想试图计算出,用户摇动手机的次数,不是是否摇了手机(当某一个方向的加速度大于某个值时,就可以认为是用户摇动了手机);

在计算摇动次数之前,我们先要定义一下,什么状态算是摇动了一次手机,假设:在空间上,有`A`和`B`两个位置,
1. `A -> B -> A`这个过程算是两次(`A->B`和`B->A`),还是算是一次呢,这个可以最终实现的时候,再做定义,所以这里您可以先思考一下;
2. 平滑的移动(加速度一直很小的时候,不算是摇动吧),所以摇一摇必定会产生大值加速度的;

那么当`A -> B -> A`这个过程中时,触发了加速度发生了哪些变化呢?
这里就拿`A -> B` 来说明即可,`B -> A`与`A -> B`的加速度变化,基本是一致的;

在`A -> B`的时候:
1. 静止(加速度=0,A位置)
2. 加速度增加(加速度大于0,加速运动)
3. 加速度减小趋于零(加速完成,匀速运动)
4. 加速度增加(加速度小于0,减速运动)
5. 停止(加速度 = 0,B位置)

所以,如果不考虑加速值的正负(正加速,负减少),那么每次的`A -> B`运动,其实就是触发了两次加速度变化(大加速度 变化到 0 );

但是,摇一摇有一点不同的就是,它不会触发第三个阶段(匀速运动阶段),所以最后的结果,就变成:

1. 静止(加速度=0,A位置)
2. 加速度增加(加速度大于0,加速运动,加速度小于0,减速运动)
3. 停止(加速度 = 0,B位置)

这样,每次的`A -> B`过程中,其实加速度过大的情况只出现了1次,所以可以认为,在我们平常人手动去摇一摇手机的时候,只要加速度大于某一个值,那么就算是触发了一次`A -> B`的结构;

所以,这样我们就可以得出一个结论:

1:如果`A -> B`算是一次摇一摇,那么只要`不连续的`出现`一次`加速度大于`某一值`的情况,就算完成了一次摇一摇;
2:如果`A -> B -> A`算是一次摇一摇,那么只要`不连续的`出现`两次`加速度大于`某一值`的情况,就算完成了一次摇一摇;

所以,综上所述,我们可以给出以下的一个示例:

示例:[加速度摇一摇次数](/study/2019/20190119/index-2.html);

也可以直接扫码二维码:

你可以试试,计算出来的摇一摇次数,是否与真实的次数相近,示例的计算规则还不完善,所以不是完全准确的;

从测试结果来看,这个方法是受摇动方向的影响过大,你可以尝试一下,当你再Z轴方向摇动时,基本测试不出来任何数据;

#### 6. 优化
计算摇一摇次数的`demo`为什么还不完善呢,可以从哪里看到一些特殊的状况呢?

不知道你有没有试出来,什么情况下,会出现异常呢,大概有以下几种情况:
1. 摇动比较慢,即最高加速度在阈值附近时
2. 摇动不是完全按照某一个方向,而是沿着手机的斜角轨迹时
3. 加速度是按照所有方向的加速度的和计算的,这个也是误差的一个主要来源;

第三个问题,稍微复杂一些,所以先来解决上面的两个问题导致的误差:

上述两个问题,会导致的原因是,阈值是完全的一个值,简单的说来就是`非黑即白`,没有误差的容错,所以这里,我们想要优化的点就是:容错;

再增加一个最小的阈值,当摇动的加速度小于该值时,才认为摇动是停止的;

所以再看以下的示例:
示例:[加速度摇一摇次数](/study/2019/20190119/index-3.html);

也可以直接扫码二维码:

结果呢,依然是有问题的,毕竟大小阈值,与你的摇动幅度是相关的,如果设置了大小的阈值,那么不同的摇动幅度,产生的结果,就是完全不同的,所以直接按照摇动幅度来计算的话,是不可行的,所以这里,我们就尝试使用拐点来做这个计算,再上一个示例中,有显示一个柱状图,就是加速度之和的绝对值排列,自己测试的话,与摇动幅度,基本相同;

按照拐点来做这个处理的话,就变成了如下的示例:示例:
[加速度摇一摇次数](/study/2019/20190119/index-5.html);

也可以直接扫码二维码:

#### 7. 结尾
到此也算结束了,如您有更好的方法,或者建议,欢迎留言讨论;

本文地址:http://www.zhangyunling.com/888.html

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>