大家可能还记得前段时间淘宝造物节的宣传动画效果,让自己对CSS 360全景更充满好奇之心。最近有关于这方面的文章也是层出不穷,比如@凹凸实验室团队的@J.c就整理了一篇有关于这方面的文章。尽从效果上,就吸引了大家不少的眼球,当然大家更期待的是如何自己能实现这样的效果。那么我们来开始一起探讨这方面的事情。
在具备独立完成这样的效果之前,咱们需要对几个知识点要有所了解:
- 设备的摄像头Camera(Camera API)
- 陀螺仪、重力感应
- CSS 3D (CSS3 Transform 3D)
而这些都涉及很多的知识面,但我们不会在这一篇文章中介绍完,今天我们先来介绍其中有关于陀螺仪相在的知识点。
HTML5 Orientation
HTML5 Orientation是HTML5中一个非常酷的特性,它主要用来检测智能设备(手机、平板等)的运动方向。在现在的移动端开发中已给用户带来更良好的体验,也在很多项目中发挥了重要的重用。
目前在下面的场景中常常能看到其相关的身影:
- 控制游戏:Web游戏应用监控设备方向,并将其解释为控制屏幕上的精灵在某方向上的倾斜。
- 手势识别:Web应用监控设备的加速,并将其应用于信号处理,以便识别特定首饰。距离说明,使用摇晃手势清除web表单。
- 地图:Web地图应用使用设备方向,将地图与实际情况对齐。
有关于HTML5 Orientation相关的扩展阅读,可以阅读下面文章:
- This End Up: Using Device Orientation
- Detecting device orientation
- Using Device Orientation in HTML5
- HTML5 for the Mobile Web: Device Orientation Events
在使用设备运动方向(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度与赤道的交点)构成右手坐标系。
地球坐标系统是由x
、y
、z
三个轴组成,基于重力和标准磁场方向。简单点讲,地球坐标系统是一个位于用户位置的东、北、上系,其拥有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
到约-90
到0
的变化 - 向右翻转时,Gamma(
γ
)在正数方向做0
到90
到0
的变化
综合上述,我们可以用图来更好阐述设备坐标和地球坐标之间的关系:
设备的初始位置,地球(XYZ
)与设备(zyz
)坐标系重合。
设备以z
轴为轴,旋转Alpha(α
)度,原坐标x
、y
轴显示为x0
、y0
。
设备以x
轴为轴,旋转Beta(β
)度,原坐标y
、z
轴显示为y0
、z0
。
设备以y
轴为轴,旋转Beta(β
)度,原坐标x
、z
轴显示为x0
、z0
。
因此,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
个属性值,包括accelerationIncludingGravity
、acceleration
。
让我们来看一个在平坦桌面上,屏幕朝上的手机的例子。
状态 | 旋转 | 加速(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
的值为90
,alpha
和gamma
无关。
用户手持设备,面向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
的转弯。设备记录acceleration
和accelerationIncludingGravity
在位置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有一定的了解。当然,相关的知识点还有很多,我们后面需要进一步加强。另外,如果文章中有不对之处,或者你有更好的相关知识,欢迎在下面的评论中与我们一起分享。
如需转载,烦请注明出处:http://www.w3cplus.com/animation/html5-device-orientation-basic-intro.html