我试图改变沿左右轴和上下轴的两个deviceorientation事件之间的方向变化,这些轴通常定义为手机x和y轴( https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained)

即,在那些电话轴从(x1,y1)移动到(x2,y2)的时刻t1和t2之间,它想得到(角度(x2-x1),角度(y1-y2)).

当设备处于纵向模式时(与横向模式相反),这些轴似乎对应于beta和gamma.然而,当手机处于垂直状态(底部朝向地面)时,伽马值变得非常不稳定,并且从90度跳到-90度(在相同的情况下,alpha跳跃180度)您可以很容易地看到here on your phone

我想避免这种情况,并获得360范围内的值.这是我到目前为止:

// assuming portrait mode
var beta0,gamma0;
window.addEventListener('deviceorientation',function(orientation) {
  if (typeof beta0 === 'undefined') {
    beta0 = beta;
    gamma0 = gamma;
  } 

  console.log('user has moved to the left by',gamma - gamma0,' and to the top by',beta - beta0);
});

当设备大部分是水平时,它可以正常工作,而当它是垂直时,它根本不工作

解决方法

好吧.首先,设备方向输入的简单说明:

绝对坐标系(X,Y,Z)是X是东,Y是北,Z是向上的.设备相对坐标系(x,y,z)使得x是正确的,y是顶部而z是向上的.然后,方向角(α,β,γ)是描述三个简单旋转连续的角度,这三个简单旋转将(X,Z)变为(x,z),如下所示:

>绕Z旋转α度,将(X,Z)转换为(X’,Y’,Z’),Z’= Z
>以β度旋转X’,将(X’,Z’)转换为(X”,Y”,Z”),X”= X’
>用γ度旋转Y”,将(X”,Z”)变换为(x,y = Y”

(它们被称为Z-X’-Y’型的内在Tait-Bryan角)

现在我们可以通过组合简单的旋转矩阵来获得相应的旋转矩阵,每个旋转矩阵对应于三个旋转中的一个.

[   cC   0    sC  ] [  1    0    0   ] [  cA   -sA  0  ]
R(A,B,C) = Ry(C)*Rx(B)*Rz(A) = |   0    1    0   |*|  0    cB  -sB  |*[  sA   cA   0  ]
                                 [  -sC   0    cC  ] [  0    sB   cB  ] [  0    0    1  ]

其中A,C是α,γ和s的缩写,c是sin,cos.

现在,我们感兴趣的是两个位置(x,z)和(x’,y’,z’)之间的右 – 左(y轴)和自上而下(x轴)旋转增量的角度到方向(A,C)和(A’,B’,C’)

(x’,z’)的坐标(x’,z’)由R(A’,C’)给出* R(A,C)^ – 1 = R(A’,C’)* R(A,C)^ T,因为逆是正交(旋转)矩阵的转置.最后,如果z’= p * xq * yr * z,那些旋转的角度是围绕左右轴的p和围绕自上而下的q的角度(对于小角度,这是假的,这假设频繁的方向更新,否则asin(p)和asin(r)离真相更近)

所以这里有一些javascript来获取旋转矩阵:

/*
 * gl-matrix is a nice library that handles rotation stuff efficiently
 * The 3x3 matrix is a 9 element array
 * such that indexes 0-2 correspond to the first column,3-5 to the second column and 6-8 to the third
 */
import {mat3} from 'gl-matrix';

let _x,_y,_z;
let cX,cY,cZ,sX,sY,sZ;
/*
 * return the rotation matrix corresponding to the orientation angles
 */
const fromOrientation = function(out,alpha,beta,gamma) {
  _z = alpha;
  _x = beta;
  _y = gamma;

  cX = Math.cos( _x );
  cY = Math.cos( _y );
  cZ = Math.cos( _z );
  sX = Math.sin( _x );
  sY = Math.sin( _y );
  sZ = Math.sin( _z );

  out[0] = cZ * cY + sZ * sX * sY,// row 1,col 1
  out[1] = cX * sZ,// row 2,col 1
  out[2] = - cZ * sY + sZ * sX * cY,// row 3,col 1

  out[3] = - cY * sZ + cZ * sX * sY,col 2
  out[4] = cZ * cX,col 2
  out[5] = sZ * sY + cZ * cY * sX,col 2

  out[6] = cX * sY,col 3
  out[7] = - sX,col 3
  out[8] = cX * cY                    // row 3,col 3
};

现在我们得到了角度增量:

const deg2rad = Math.PI / 180; // Degree-to-Radian conversion
let currentRotMat,prevIoUsRotMat,inverseMat,relativeRotationDelta,totalRightAngularMovement=0,totalTopAngularMovement=0;

window.addEventListener('deviceorientation',({alpha,gamma}) => {
  // init values if necessary
  if (!prevIoUsRotMat) {
    prevIoUsRotMat = mat3.create();
    currentRotMat = mat3.create();
    relativeRotationDelta = mat3.create();

    fromOrientation(currentRotMat,alpha * deg2rad,beta * deg2rad,gamma * deg2rad);
  }

  // save last orientation
  mat3.copy(prevIoUsRotMat,currentRotMat);

  // get rotation in the prevIoUs orientation coordinate
  fromOrientation(currentRotMat,gamma * deg2rad);
  mat3.transpose(inverseMat,prevIoUsRotMat); // for rotation matrix,inverse is transpose
  mat3.multiply(relativeRotationDelta,currentRotMat,inverseMat);

  // add the angular deltas to the cummulative rotation
  totalRightAngularMovement += Math.asin(relativeRotationDelta[6]) / deg2rad;
  totalTopAngularMovement += Math.asin(relativeRotationDelta[7]) / deg2rad;
}

最后,考虑到屏幕方向,我们必须更换

_z = alpha;
  _x = beta;
  _y = gamma;

通过

const getScreenorientation = () => {
  switch (window.screen.orientation || window.screen.mozOrientation) {
    case 'landscape-primary':
      return 90;
    case 'landscape-secondary':
      return -90;
    case 'portrait-secondary':
      return 180;
    case 'portrait-primary':
      return 0;
  }
  if (window.orientation !== undefined)
    return window.orientation;
};

const screenorientation = getScreenorientation();

_z = alpha;
if (screenorientation === 90) {
  _x = - gamma;
  _y = beta;
}
else if (screenorientation === -90) {
  _x = gamma;
  _y = - beta;
}
else if (screenorientation === 180) {
  _x = - beta;
  _y = - gamma;
}
else if (screenorientation === 0) {
  _x = beta;
  _y = gamma;
}

请注意,累积的左右和上下角度将取决于用户选择的路径,并且无法直接从设备方向推断,但必须通过移动进行跟踪.您可以通过不同的动作到达相同的位置:

>方法1:

>保持手机水平并顺时针旋转90度. (这既不是左右也不是上下旋转)
>将手机置于横向模式,然后向您旋转90度. (这不是90度左右旋转)
>让手机朝向你,然后旋转90度,这样就可以了. (这不是90度左右旋转)

>方法2:

>将手机旋转90度,使其面向您并垂直(这是一个90度的上下旋转)

html5 – 以相对坐标获取设备方向旋转的更多相关文章

  1. 【HTML5】3D模型--百行代码实现旋转立体魔方实例

    本篇文章主要介绍【HTML5】3D模型--百行代码实现旋转立体魔方实例,具有一定的参考价值,有需要的可以了解一下。

  2. ios – 在sendEvent方法上崩溃

    当我在选择几个项目后旋转应用程序两次时,它会崩溃.我重写了sendEvent方法,这是调试器停止的地方.当我尝试打印事件类型时,它会向我显示一些奇怪的东西(我认为这是一个不存在的内存位置):不知何故,我认为这与我如何处理轮换有关.我有一个主–细节风格的应用程序,它使用不同类型的导航来拍摄风景,拍摄肖像和手机.我创建了一个名为NavigationFlowController的类,它处理所有导航事件并

  3. ios – Autolayout旋转轮

    我正在尝试使用CGAffineTransformRotate旋转UIImageView约束,但是视图在旋转时抖动.如果我使用CATransform3DRotate旋转它的图层,则不会发生这种情况,但只要我编辑约束(更改常量),旋转的图像就会跳开.有谁有想法如何解决这个问题?这是跳过的旋转图像的屏幕截图解决方法自动布局作用于UIView的框架.框架根据视图的中心,边界和变换属性计算.默认情况下,vi

  4. ios – 在没有框架改变的情况下旋转UIView

    我有一个UIView,它的高度和宽度在旋转到90度时互换.现在,当我尝试增加高度或宽度时,我看起来异常.如何更改旋转的UIView的高度?解决方法Apple的文档声明,当视图的转换不是标识转换时,视图的frame属性将变为未定义.旋转视图会更改视图的变换.现在,为什么这会使框架无效?

  5. ios – UIDeviceOrientation ipad

    我有以下代码根据方向填充视图.这总是会返回景观.我正确地改变了视图–(void)animateRotation:(UIInterfaceOrientation)interfaceOrientation持续时间:(NSTimeInterval)持续时间{但是在更改播放列表时已经在横向或纵向中不起作用.解决方法而不是使用[[UIDevicecurrentDevice]orientation]来检查方向

  6. iOS 9中的强制视图控制器方向

    我正在制作一个摄影应用程序,允许以肖像或风景拍摄照片.由于项目的要求,我不能让设备方向自动旋转,但确实需要支持旋转.使用以下定位方法时:我可以在启动时正确设置旋转.通过更改方向值并调用UIViewController.attemptRotationToDeviceOrientation(),我能够支持旋转到新的所需接口.但是,此旋转仅在用户实际移动其设备时发生.我需要它自动发生.我可以调用:UID

  7. Swift Core Graphics教程之Gradients 与 Context

    你使用过UIBezierPath的就是在UIKit层中对CoreGraphics层中CGPath的封装。你可以看到CoreGraphics的对象和方法都是CG开头的,非常容易辨认。视图将包含一个Graph和CounterViews,确定他们是视图控制器的主视图的子视图,并且Graph在CounterViews之上。打开ViewController.swift,为Container和GraphViews添加outloets:@IBOutletweakvarcontainerView:UIView!最后,为了

  8. swift教程-使用UIGestureRecognizer

    swift教程-使用UIGestureRecognizer更新提示:这篇教程已经由CarolineBegbie为适配IOS8及Swift做了更新。假如你想要在你的应用中检测手势,例如点击,缩放,平移,或者旋转,用Swift和内建的UIGestureRecognizer类实现是非常容易的。UIGestureRecognizer概述在开始之前,先看一份如何使用UIGestureRecognizers以及为什么它们如此得心应手。在IOS3.0,苹果公司就开始拯救UIGestureRecognizer类!使用UI

  9. 小胖说swift11-------- ios 进入某个VC强转为横屏,出VC后复原

    今天做项目,某一个VC需要展现VR展览内容,产品要求这个VC可以横屏查看,因为横屏查看的时候,看的范围比较大,但是其余的VC都是竖屏显示的,为了达到某个VC横屏显示其余VC不变的效果,然后查询资料,撸代码。。

  10. 图层几何学与几何变换

    iOS图形几何学几何学的基础应用就是要在对应的坐标系统里面对事物进行布局操作,而这些布局位置也是所有动画实现的基石。而这些时间线上图片的状态变化无非就是平移、旋转、缩放以及它们组合起来的几何变换。下面我们开始来聊聊这些几何变换。仿射变换仿射变换是指在二维空间坐标系统中对图像进行平移、旋转、缩放等几何变换。

随机推荐

  1. 微信小程序canvas实现水平、垂直居中效果

    这篇文章主要介绍了小程序中canvas实现水平、垂直居中效果,本文图文实例代码相结合给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

  2. 使用HTML5做的导航条详细步骤

    这篇文章主要介绍了用HTML5做的导航条详细步骤,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. H5最强接口之canvas实现动态图形功能

    这篇文章主要介绍了H5最强接口之canvas实现动态图形功能,需要的朋友可以参考下

  4. Canvas高级路径操作之拖拽对象的实现

    这篇文章主要介绍了Canvas高级路径操作之拖拽对象的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. html5视频自动横过来自适应页面且点击播放功能的实现

    这篇文章主要介绍了h5视频自动横过来自适应页面且点击播放,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  6. 详解HTML5中的picture元素响应式处理图片

    这篇文章主要介绍了详解HTML5中的picture元素响应式处理图片,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  7. canvas像素点操作之视频绿幕抠图

    这篇文章主要介绍了canvas像素点操作之视频绿幕抠图的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  8. html5利用canvas实现颜色容差抠图功能

    这篇文章主要介绍了html5利用canvas实现颜色容差抠图功能,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  9. canvas绘制视频封面的方法

    这篇文章主要介绍了canvas绘制视频封面的方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  10. HTML5拖拽功能实现的拼图游戏

    本文通过实例代码给大家介绍了HTML5拖拽功能实现的拼图游戏,代码简单易懂,非常不错,具有一定的参考借鉴价值,需要的朋友参考下吧

返回
顶部