HyG Front-end Dev Engineer

摩天轮动画的实现揭秘

2022-10-15
HyG

摩天轮动画的实现揭秘

恰好近期业务上开发了类似这样的摩天轮动画,我将其中的实现原理分享给大家。摩天轮动画主要分为 2 部分,一个是摩天轮上每个房间位置布局,另一个就是旋转动画了。

摩天轮布局

我们需要将每个车厢均匀的布局在一个圆环上,这需要一些三角函数的知识。

以圆心为原点,半径为r,则正多边形的第1个顶点坐标为 (rcosθ, rsinθ),其中 θ 可以看做是 360/多边形边数。第2个顶点坐标为 (rcos2θ, rsin2θ),如下图

还需要注意 JavaScript 使用弧度制,而非角度,因此我们需要转换一下

degree2Radian.ts

/**
 * 角度转为弧度
 * @param radius 角度
 * @returns 弧度
 */
const getRadian = (radius: number) => (radius * Math.PI) / 180

export default getRadian

各个顶点坐标定位如下

import degree2Radian from './degree2Radian'

/**
 * 获取位置
 * @param r 半径
 * @param count 个数
 */
const getPos = (r: number, count: number) => {
  const angleRadian = degree2Radian(360 / count)
  const res: Array<{
    x: number
    y: number
  }> = []
  for (let i = 0; i < count; i += 1) {
    res.push({
      x: r * Math.cos(angleRadian * i),
      y: r * Math.sin(angleRadian * i),
    })
  }
  return res
}

export default getPos

我们尝试使用其渲染一下

<div className={styles.ferris}>
  <div className={styles.wheel} ref={wheelDomRef}>
    <div className={styles.roomsArea}>
      {
        getPos(202 / 2, 8).map((item, index) => (
          <div
            key={index}
            className={`${styles.room} wheelRooms`}
            style={{
              top: `${item.y}px`,
              left: `${item.x - 20}px`,
            }}
          />
        ))
      }
    </div>
  </div>
  <div className={styles.bottom} />
</div>

注意 left 值,我们减去了自身宽度的一半保证居中

我们可以通过控制 UI 来设置多个车厢,验证没有问题。

摩天轮旋转动画

接下来我们看看动画部分,这里动画的可以拆解为2部分,一个是主轮的旋转,另一个是周围的车厢要同步反向旋转。如下图

这里我们使用 anime.js 这个动画库来实现

使用 anime 动画库的原因是:

  • 代码简洁,api完善,便于控制暂停播放
  • 时间线 api,保证2部分动画同步
  • 适配高刷屏,不会出现倍速问题
  • anime.js 很小,17k,gzip后8.2k

核心代码如下,可以看到代码真的非常简洁。

this.timeline = anime.timeline({
  easing: 'linear',
  duration: 8000,
  loop: true,
  autoplay: autoPlay,
})
this.timeline
  .add({
    targets: this.wheelDom,
    rotate: 360,
  })
  .add(
    {
      targets: this.roomsDoms,
      rotate: -360,
    },
    0,
  )

我们使用了时间线 api,将大轮和车厢进行相反方向旋转。

并且要注意,要设置车厢的顶部中间为旋转圆心,有一种悬吊的感觉。

transform-origin: top center;

再添加一些动画播放控制的功能,stop、play、reverse、reset 等,在生产环境中可能会有用,例如在页面滚动到可视区外,或页面上有弹窗弹出时,我们可以暂停动画以提升页面运行时的性能。

最终 demo

可扫码访问

在线 demo 链接

demo 源码

最后附一张生产环境的引用截图,很不错吧~

小结

本文主要分析了如何开发一个摩天轮动画,包含摩天轮车厢的布局和旋转动画部分,复习了一点点三角函数的知识,创作出了非常棒的动画效果~


Comments

Content