陀螺仪的基础知识

发布于 大漠

大家可能还记得前段时间淘宝造物节的宣传动画效果,让自己对CSS 360全景更充满好奇之心。最近有关于这方面的文章也是层出不穷,比如@凹凸实验室团队的@J.c就整理了一篇有关于这方面的文章。尽从效果上,就吸引了大家不少的眼球,当然大家更期待的是如何自己能实现这样的效果。那么我们来开始一起探讨这方面的事情。

在具备独立完成这样的效果之前,咱们需要对几个知识点要有所了解:

而这些都涉及很多的知识面,但我们不会在这一篇文章中介绍完,今天我们先来介绍其中有关于陀螺仪相在的知识点。

HTML5 Orientation

HTML5 Orientation是HTML5中一个非常酷的特性,它主要用来检测智能设备(手机、平板等)的运动方向。在现在的移动端开发中已给用户带来更良好的体验,也在很多项目中发挥了重要的重用。

目前在下面的场景中常常能看到其相关的身影:

  • 控制游戏:Web游戏应用监控设备方向,并将其解释为控制屏幕上的精灵在某方向上的倾斜。
  • 手势识别:Web应用监控设备的加速,并将其应用于信号处理,以便识别特定首饰。距离说明,使用摇晃手势清除web表单。
  • 地图:Web地图应用使用设备方向,将地图与实际情况对齐。

有关于HTML5 Orientation相关的扩展阅读,可以阅读下面文章:

在使用设备运动方向(Device Orientation)API之前,先得确保浏览器支持这些API。要得到相关的数据,可以直接从Can I Use.com得到相关数据:

当然,用户是不知道自己的浏览器是否支持,所以在我们的代码中要做一些事情,就是在使用运动方向API之前先做一些检测,如果支持就使用该API,如果不支持,就提供相关的提示信息:

if (window.DeviceOrientationEvent) {
  	//  支持DeviceOrientation API写在这里
} else {
  	console.log("对不起,您的浏览器还不支持Device Orientation!!!");
}

大家先不要急着这里面的代码怎么填,咱们先来了解一些相关的知识点。帮助大家更好的理解设备方向(Device Orientation)和更好的使用好设备方向。

地球坐标系统

先来看一张地球坐标系统的图:

地球坐标系统

地心地固坐标系(Earth-Centered, Earth-Fixed,简称ECEF)简称地心坐标系,是一种以地心为原点的地固坐标系(也称地球坐标系),是一种笛卡儿坐标系。原点 O (0,0,0)为地球质心,z 轴与地轴平行指向北极点,x轴指向本初子午线与赤道的交点,y 轴垂直于xOz平面(即东经90度与赤道的交点)构成右手坐标系。

地球坐标系统是由xyz三个轴组成,基于重力和标准磁场方向。简单点讲,地球坐标系统是一个位于用户位置的东、北、上系,其拥有3个轴,地面相切与1984世界测地系统的Spheriod的用户所在位置。

  • 东(x)在地面上,垂直于北轴,向东为正 (东西方向)
  • 北(y)在地面上,向正北为正(指向北极)(南北方向)
  • 上(z)垂直于地面,向上为正(上下方向)

对于一个移动设备,例如电话或平板,设备坐标系的定义于屏幕的标准方向相关。这意味着类似于键盘的滑动元素没有展开、类似于显示器的选择元素折叠至其默认位置。如果在设备旋转或展开滑动键盘时屏幕方向发生变化,这不会影响关于设备的坐标系的方向。用户希望获得这些屏幕方向的变化可以使用现有的orientationchange事件。对于膝上电脑,设备的坐标系定义于集成键盘。

  • x在屏幕或键盘平面上,屏幕或键盘的右侧为正。
  • y在屏幕或键盘屏幕上,屏幕或键盘的上方为正。
  • z垂直于屏幕或键盘屏幕,离开屏幕或键盘为正。

如下图所示:

地球坐标系统

从地球坐标系到设备坐标系的转变必须按照下列系统转换。旋转必须使用右手规则,即正向沿一个轴旋转为从该轴的方向看顺时针旋转。从两个系重合开始,旋转应用下列规则:

  • 以设备坐标系z轴为轴,旋转alpha度。alpha的作用域为(0, 360)
  • 以设备坐标系x轴为轴,旋转beta度。beta的作用域为(-180, 180)
  • 已设备坐标系y轴为轴,旋转gamma度。gamma的作用域为(-90, 90)

如下图所示:

地球坐标系统

Alpha, Beta 和 Gamma 角

Alpha(α), Beta(β) 和 Gamma(γ)角也称之为旋转数据。旋转数据作为欧拉角(Euler Angle)返回,是设备坐标系和地球坐标系之间的差异值。

在解释Alpha、Beta和Gamma这三个角之前,我们需要定义存在的空间。如下图所示,展示了移动设备上使用的三维坐标系统:

地球坐标系统

在手机或者平板上,设备定位方向是基于屏幕方向的。对于手机和平板来说,他们都是基于纵向模式的设备,对于台式机或笔记本电脑来说,他们的定位方向和键盘有关。

Alpha(α)角

Alpha(α)角代表的是z轴。因此,任何沿着z轴旋转都会使用Alpha(α)角变化。Alpha(α)的变化范围是(0~360)度之间。当α = 0时,设备是直接每日向地球的北极。下图显示了α旋转。

地球坐标系统

设备逆时针旋转,Alpha(α)值增加。

Beta(β)角

Beta(β)角代表的是x轴。设备绕着x轴旋转将导致Beta(β)角变化。Beta(β)的变化范围是(-180 ~ 180)度之间。当设备平行于地球表面时β = 0,比如说,你把手机平放在桌面上。下图显示了β旋转:

地球坐标系统

Gamma(γ)角

Gamma(γ)角代表的是y轴。设备绕着y轴旋转将导致Gamma(γ)角变化。Gamma(γ)角的变化范围是(-90 ~ 90)度。当设备平行于地球表面时γ = 0。下图显示了γ旋转:

地球坐标系统

上面简单介绍了Alpha(α), Beta(β) 和 Gamma(γ)角。从网上整了几张有关于Beta(β) 和 Gamma(γ)角旋转的数据示意图:

Beta(β)上下翻动

地球坐标系统

地球坐标系统

从上面的图片中,不难观察出相应的结果,在向上翻动手势过程中:

  • Beta(β)值有较明显变化,由初始值变化至约90
  • Gamma(γ) 和 Alpha(α) 绝对值之差趋近于0
  • Beta(β)开始变化早于Gamm(γ)和Alpha(α)

Gamma(γ)左右翻动

地球坐标系统

从图中,很明显的可以看出,Gamma(γ)做着优雅的 “正弦曲线”变化,而Alpha(α)和Beta(β)基本保持着不变, 所以我们可以得出以下结论:

  • Alpha(α)和Beta(β)值基本保持不变
  • 向左翻转时,Gamma(γ)在负数方向做0到约-900的变化
  • 向右翻转时,Gamma(γ)在正数方向做0900的变化

综合上述,我们可以用图来更好阐述设备坐标和地球坐标之间的关系:

地球坐标系统

设备的初始位置,地球(XYZ)与设备(zyz)坐标系重合。

地球坐标系统

设备以z轴为轴,旋转Alpha(α)度,原坐标xy轴显示为x0y0

地球坐标系统

设备以x轴为轴,旋转Beta(β)度,原坐标yz轴显示为y0z0

地球坐标系统

设备以y轴为轴,旋转Beta(β)度,原坐标xz轴显示为x0z0

因此,Alpha(α)、Beta(β)和Gamma(γ)组成一组Z-X'-Y''式的固有Tait-Bryan角度。注意这里对角度的选择遵循数学惯例,但这意味着Alpha(α)与罗盘指向相反。这还意味着这些角度不匹配车辆动力学中的roll-pitch-yaw惯例。

对于不能提供三个角度绝对值的实现,作为替代,可以提供关于任意方向的相对值。在这种情况下,必须设absolute属性为false,否则必须设absolute属性为true

对于不能提供所有三个角度的实现,其必须设未知的角度的值为null。如果提供了某一角度,必须恰当的设置absolute属性。如果实现不能提供任何方向信息,则触发事件时所有属性都必须被设为null

什么是重力感应

说到重力感应有一个东西不得不提,那就是就是陀螺仪,陀螺仪就是内部有一个陀螺,陀螺仪一旦开始旋转,由于轮子的角动量,陀螺仪有抗拒方向改变的特性,它的轴由于陀螺效应始终与初始方向平行,这样就可以通过与初始方向的偏差计算出实际方向。

deviceorientation事件

设备方向事件会返回设备旋转角度数据,如果手机或者笔记本电脑有指南针的话,返回数据中还会包括设备当前的朝向。在HTML5 OrientationAPI提供了三个相应的DOM事件:

  • deviceorientation,其提供设备的物理方向信息,表示为一系列本地坐标系的旋角
  • devicemotion,其提供设备的加速信息,表示为定义在设备上的坐标系中的卡尔迪坐标。其还提供了设备在坐标系中的自转速率。若可行的话,事件应该提供设备重心处的加速信息。
  • compassneedscalibration,其用于通知Web站点使用罗盘信息校准上述事件。

何时使用设备方向事件

设备方向事件有几种使用场景,例如:

  • 更新移动的用户的地图
  • UI调整,像是增加Paralax(视差滚动:指让多层背景以不同的速度移动,形成立体的运动效果,带来非常出色的视觉体验)效果
  • 结合地理定位,用于导航

检测和监听方向事件

在监听DeviceOrientationEvent事件前,我们首先要检查浏览器是否支持。然后再在window中增加deviceorientation事件监听。

if (window.DeviceOrientationEvent) {
      window.addEventListener('deviceorientation', deviceOrientationHandler, false);
      document.getElementById("doeSupported").innerText = "";
}

处理设备方向事件

当设备移动或者方向改变时,设备方向事件就会被触发。它会返回当前位置相对于地球坐标的差值。

事件通常会返回Alipha、Beta和Gamma三个值。在移动端Safari浏览器中,还会返回webkitCompassHeading属性值,这个属性值与指南针(compass)的导向有关。

检测和监听移动事件

监听DeviceMotionEvents事件前,首先要检查浏览器是否支持,然后再在window上监听devicemotion事件。

if (window.DeviceMotionEvent) {
    window.addEventListener("devicemotion", deviceMotionHandler);
    setTimeout(stopJump, 3*1000);
}

处理设备移动事件

当需要每隔一定时间返回设备的旋转速率(以度每秒为单位)或者移动速率数据时,设备移动事件就会被触发。有些设备没有可以排除重力影响的硬件装置。

该事件返回4个属性值,包括accelerationIncludingGravityacceleration

让我们来看一个在平坦桌面上,屏幕朝上的手机的例子。

状态 旋转 加速(m/s2)度 重力加速度(m/s2)
不移动 [0, 0, 0] [0, 0, 0] [0, 0, 9.8]
朝着天空移动 [0, 0, 0] [0, 0, 5] [0, 0, 14.81]
向右侧移动 [0, 0, 0] [3, 0, 0] [3, 0, 9.81]
向上且向右移动 [0, 0, 0] [5, 0, 5] [5, 0, 14.81]

相反,如果手机被握住,保持手机屏幕和地面垂直,且屏幕面对观察者:

状态 旋转 加速(m/s2)度 重力加速度(m/s2)
不移动 [0, 0, 0] [0, 0, 0] [0, 9.81, 0]
朝着天空移动 [0, 0, 0] [0, 5, 0] [0, 14.81, 0]
向右侧移动 [0, 0, 0] [3, 0, 0] [3, 9.81, 0]
向上且向右移动 [0, 0, 0] [5, 5, 0] [5, 14.81, 0]

有关于deviceorientation事件常用方法:

注册一个deviceorientation事件的接收器:

window.addEventListener("deviceorientation", function(event) {
    // 处理event.alpha、event.beta及event.gamma
}, true);

将设备放置在水平表面,屏幕顶端指向西方,则其方向信息如下:

{
    alpha: 90,
       beta: 0,
       gamma: 0
};

为了获得罗盘指向,可以简单的使用360度减去alpha。若设被平行于水平表面,其罗盘指向为(360 - alpha)。若用户手持设备,屏幕处于一个垂直平面且屏幕顶端指向上方。beta的值为90alphagamma无关。

用户手持设备,面向alpha角度,屏幕处于一个垂直屏幕,屏幕顶端指向右方,则其方向信息如下:

{
      alpha: 270 - alpha,
       beta: 0,
       gamma: 90
};

只用自定义界面通知用户校准罗盘:

window.addEventListener("compassneedscalibration", function(event) {
    alert('您的罗盘需要校准,请将设备沿数字8方向移动。');
    event.preventDefault();
}, true);

注册一个devicemotion时间的接收器:

window.addEventListener("devicemotion", function(event) {
    // 处理event.acceleration、event.accelerationIncludingGravity、
    // event.rotationRate和event.interval
}, true);

将设备放置在水平表面,屏幕向上,acceleration为零,则其accelerationIncludingGravity信息如下:

{
    x: 0,
       y: 0,
       z: 9.81
};

设备做自由落体,屏幕水平向上,accelerationIncludingGravity为零,则其acceleration信息如下:

{
    x: 0,
    y: 0,
       z: -9.81
};

将设备安置于车辆至上,屏幕处于一个垂直平面,顶端向上,面向车辆后部。车辆行驶速度为v,向右侧进行半径为r的转弯。设备记录accelerationaccelerationIncludingGravity在位置x处的情况,同时设备还会记录rotationRate.gamma的负值:

{
    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
    } 
};

旋转的立方体

既然有HTML5 Orientation这样的API,那么我们之前制作的CSS 3D盒子就可以在称动设备上做一些重力感应的效果,比如旋转你的手机,让立方体动起来。接下来,来看一个这方面的示例。

有关于CSS 3D立方体相关的制作方法,这里就不做过多的介绍,如果你以前没有玩过,不仿看看这篇文章《接受前端挑战:用CSS实现3D立方体》和《玩轉 CSS 3D - 正四面體與正六面體》,可以快速帮助你完成这一方面的任务。

<div id="wrapper">
    <div id="platform">
        <div id="dice">
            <div class="side front">
                <div class="dot center"></div>
            </div>
            <div class="side front inner"></div>
            <div class="side top">
                <div class="dot dtop dleft"></div>
                <div class="dot dbottom dright"></div>
            </div>
            <div class="side top inner"></div>
            <div class="side right">
                <div class="dot dtop dleft"></div>
                <div class="dot center"></div>
                <div class="dot dbottom dright"></div>
            </div>
            <div class="side right inner"></div>
            <div class="side left">
                <div class="dot dtop dleft"></div>
                <div class="dot dtop dright"></div>
                <div class="dot dbottom dleft"></div>
                <div class="dot dbottom dright"></div>
            </div>
            <div class="side left inner"></div>
            <div class="side bottom">
                <div class="dot center"></div>
                <div class="dot dtop dleft"></div>
                <div class="dot dtop dright"></div>
                <div class="dot dbottom dleft"></div>
                <div class="dot dbottom dright"></div>
            </div>
            <div class="side bottom inner"></div>
            <div class="side back">
                <div class="dot dtop dleft"></div>
                <div class="dot dtop dright"></div>
                <div class="dot dbottom dleft"></div>
                <div class="dot dbottom dright"></div>
                <div class="dot center dleft"></div>
                <div class="dot center dright"></div>
            </div>
            <div class="side back inner"></div>
        </div>
    </div>
</div>

有关于样式代码,这里就不展示了。咱们直接上JavaScript代码:

(function() {
    var space = document.getElementById('dice');
    if (window.DeviceOrientationEvent) {

        window.addEventListener('deviceorientation', function(event) {
            var alpha = event.alpha,
                beta = event.beta,
                gamma = event.gamma;

            space.style.webkitTransform = 'rotateX(' + beta + 'deg) rotateY(' + gamma + 'deg) rotateZ(' + alpha + 'deg)';
            space.style.transform = 'rotateX(' + beta + 'deg) rotateY(' + gamma + 'deg) rotateZ(' + alpha + 'deg)';
            space.style.mozTransform = 'rotateX(' + beta + 'deg) rotateY(' + gamma + 'deg) rotateZ(' + alpha + 'deg)';

        }, false);
    } else {
        document.querySelector('body').innerHTML = '你的瀏覽器不支援喔';
    }
})();

最终效果可以点击这里,记得,得用手机看,才有效果。建议你使用手机直接扫下面的二维码:

地球坐标系统

转动你的手机,可以看到骰子在转动。当然还有更有意思的,可以写一个简单的示例,旋转手机,可以看到对应的几个角度值的变化,感兴趣的可以点击这里查看页面代码,并且扫下面的二维码可以直接看到效果:

地球坐标系统

总结

上面简单介绍了陀螺仪的基础知识,让大家对Alpha(α), Beta(β) 和 Gamma(γ)角和HTML5 Orientation API有一定的了解。当然,相关的知识点还有很多,我们后面需要进一步加强。另外,如果文章中有不对之处,或者你有更好的相关知识,欢迎在下面的评论中与我们一起分享。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/animation/html5-device-orientation-basic-intro.htmlJordan Extra Fly