-.- -.-
首页
  • 分类
  • 标签
  • 归档
  • Lodash 源码分析 (opens new window)
Mozilla (opens new window)
GitHub (opens new window)

江月何年初照人

首页
  • 分类
  • 标签
  • 归档
  • Lodash 源码分析 (opens new window)
Mozilla (opens new window)
GitHub (opens new window)
  • 关于陀螺仪的一些问题

    • 前景
      • 技术
        • 实现
          • 小球及动画
            • iOS 设备的相关问题
            江月何年初照人
            2021-05-26
            随笔

            关于陀螺仪的一些问题

            # 关于陀螺仪的使用

            # 前景

            在做个人首页的时候,PC端做了一个 跟随鼠标旋转的效果,但是在移动端时,又没有鼠标,那么旋转要根据什么判断呢?

            于是想到了,可以判断重力感应 (陀螺仪) 来实现旋转

            也是因为种种原因,最后在 移动端,是以小球来做的跟随陀螺仪的移动

            # 技术

            这里主要用到的 api 为 DeviceOrientationEvent (opens new window)

            DeviceOrientationEvent 会返回当前设备在浏览页面是的物理旋转信息

            我们这里会用到的信息主要有 3 个

            alpha: 一个表示设备绕 z 轴旋转的角度(范围在 0-360 之间)的数字

            beta: 一个表示设备绕 x 轴旋转(范围在-180 到 180 之间)的数字,从前到后的方向为正方向。

            gamma: 一个表示设备绕 y 轴旋转(范围在-90 到 90 之间)的数字,从左向右为正方向。

            而 做小球跟随陀螺仪移动的效果,我们只需要用到 beta 和 gamma

            # 实现

            首先我们需要监听 DeviceOrientationEvent 事件,来获取到 陀螺仪的信息

            window.addEventListener("deviceorientation", handleOrientation, true);
            
            function handleOrientation(event) {
              var x = event.beta; // range [-180,180]
              var y = event.gamma; // range [-90,90]
            }
            
            1
            2
            3
            4
            5
            6

            监听获取到 陀螺仪的 信息之后,这里可以拿到 beta 和 gamma 的值

            可以看到 beta 在 -180 和 180 之间, gamma 在 -90 到 90 之间

            我们可以通过 chrome 的模拟器来模拟一下 这些角度下,手机都是什么状态

            通过 chrome 的 sensors 可以来模拟手机陀螺仪,开启方法如下

            打开之后可以看到会出现手机的模拟状态

            可以看到 在 beta 90° 时,手机是竖直向下的

            我们可以试着调整角度来模拟不同的状态

            我们调整 gamma 的角度来看看手机的情况

            可以看到,在 70° 时,手机是向右旋转的,同理可以推算 90°时,手机正面完全转到右侧,反之如果度数为负值,则是向左旋转

            接着调整 beta 的角度来观察手机的状态

            旋转 20°

            旋转 150°

            旋转 -20°

            可以看到 0-180 是属于手机正面的旋转角度

            -180 - 0 则是手机背面的

            对此,我们这里采用的事手机正面的陀螺仪 ,背面的则不做处理,至此,我们已经拿到了 手机的角度,以及各个角度所表达的意思,那么接下来就是 小球以及小球动画的问题

            # 小球及动画

            这里我创建了一个 小球,默认就当做是在屏幕的正中央,宽度为 20vmin

            首先拿到设备的宽和高

              viewportH = window.innerHeight || document.documentElement.clientHeight
              viewportW = window.innerWidth || document.documentElement.clientWidth
            
            1
            2

            接着确定小球的宽度,我这里是使用 border 实现的,所以取 0.1 即可

            _ball = viewportH > viewportW ? viewportW * 0.1 : viewportH * 0.1;
            
            1

            此时就确定了,小球的直径,以及获取到了设备的宽高,接着我们要确定一些安全距离

                maxX = viewportW - ballSize
                maxY = viewportH - ballSize
                midX = maxX / 2
                midY = maxY / 2
            
            1
            2
            3
            4

            我们是通过 left 和 top 来修改小球的位置的,那么 left 最大的值,则就是 设备宽度 减去 小球的直径,top 同理

            这里同时也取到了 中位数,也就是小球默认所处的位置 left 和 top 的值

            这些是我们获取到的初始状态,那么此时就可以根据这些值 还有 陀螺仪的角度来对应修改小球的位置

              window.addEventListener("deviceorientation", handleOrientation, true);
              function handleOrientation(event) {
                var x = event.beta;
                var y = event.gamma;
                if (x > 90) { x = 90}
                if (x < -90) { x = -90}
                ball.css({
                  top: ( midY - maxY * x / 180 ) + "px",
                  left: ( midX - maxX * y / 180 ) + "px"
                })
              }
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11

            首先 对于 x 也就是 beta 的值做了一个修正,我们取 -90 - 90 之间的度数,也就是手机 正面朝上 然后 上下倾斜的度数

            对此就做了一个修正

                if (x > 90) { x = 90}
                if (x < -90) { x = -90}
            
            1
            2

            接着 可以看到 x 和 y 都是 180 度的跨度,那么 就除以 180,拿到当前度数对应的距离,得到的值有正有负

            通过之前得出的 中位数 midY 和 midX ,来算出 上下左右的偏移,同步修改 ball 所对应的 css 即可

            至此,正常的陀螺仪小球动画就完成了,当然也有很多其他的效果,可以自己尝试一下

            # iOS 设备的相关问题

            在 iOS 中,按照上述步骤完成后,是不能实现小球动画的,那是因为 iOS 的陀螺仪做了一定的限制

            1. 项目的地址必须是 https 协议
            2. 在 iOS 13+ ,需要申请用户权限 window.DeviceOrientationEvent.requestPermission(), 返回值是个 promise,promise 中会返回 用户的 允许(“granted”)/ 拒绝(”denied“) 状态;
            3. requestPermission 方法的 首次 调用 需要 由用户交互触发(目前发现 click,touchend 事件可以)
              • 先说下 首次 的含义。指的是用户 完全退出 app(而不是 app 切换到后台运行) 后再次打开为首次。用户在首次进入后 如果页面需要陀螺仪权限,需要用户交互才能触发 requestPermission 方法。之后系统会记录 用户对本网址的授权信息,不退出 app 的情况下就不需要重复申请本权限了,本记录信息会一直保留 直到完全退出 app。
              • 非首次调用的话 则不需要用户交互 触发,我们在页面初始化时调用来拿到 用户的 授权状态 进而做一些处理。
              • 如果首次调用 不是由 用户触发,比如 页面初始化时 调用,则此方法的 promise 会返回 reject 状态

            基于以上问题,对于 ios 端做一定的兼容处理,将事件绑定在 body 上

                isIOS = !!navigator.userAgent.match(/(iPhone|iPad|iPod|iOS)/i);
                if (isIOS && typeof window.DeviceMotionEvent.requestPermission === 'function') {
                  $(document).one('click', 'body', function () {
                    window.DeviceMotionEvent.requestPermission()
                      .then(permissionState => {
                        if (permissionState === 'granted') {
                          window.addEventListener('deviceorientation', handleOrientation);
                        }
                      })
                      .catch(console.error);
                  })
                } else {
                  window.addEventListener("deviceorientation", handleOrientation, true);
                }
            
            1
            2
            3
            4
            5
            6
            7
            8
            9
            10
            11
            12
            13
            14

            对于 iOS 没有点击授权之前,可以考虑做一个小球自动反弹的动画,那个是后话了,或者加一点其他的状态,提醒用户点击授权等等 ~

            编辑 (opens new window)
            上次更新: 2021/05/26 14:18:07
            最近更新
            01
            a标签下载限制
            08-08
            02
            必应每日一图
            05-27
            03
            小球碰壁反弹动画
            05-26
            更多文章>
            Theme by Vdoing | Copyright © 2021-2023 Himawari | MIT License
            • 跟随系统
            • 浅色模式
            • 深色模式
            • 阅读模式