乐趣区

关于javascript:开发一个抽奖大转盘-Luckyspin

最近有一个需要要开发一个抽奖大转盘类的一个页面,原本想着这种货色必定有现成的,但找了一圈后发现基本上都与咱们的设计图有些出入,如果间接应用现成的包预计必定是验收不通过的

开源我的项目的布局个别都是这样的(转盘内的文字正对圆心),举荐一个比拟热门的开源我的项目,反对多端,多种游戏形式(大转盘、九宫格、老虎机)

而咱们的设计图却是设计成这样的(文字与半径平行)

无奈现成的包的不能应用,故筹备把开源我的项目 down 下来批改一下使之合乎咱们的业务场景要求

stackblitz 成果预览

上面总结了一些实现思路:分为 canvas 版本和 div+css 版本

canvas 思路实现

  1. canvas 转盘绘制,包含每片扇区上的文字及图片的绘制(其实就这一点须要更改)
  2. 递归 requestAnimationFrame 而后一直扭转绘制起始角度 (canvas 绘制的初始角度) 使转盘动起来
  3. 应用缓动算法,使转盘转动更加天然:转盘初始阶段迟缓 减速 -> 匀速 -> 加速 最终停在指定扇区(中奖后果必定是 api 返回的,前端须要管制最初要停在指定地位上,依照 lucky-canvas 上的说法就是 守株待兔)

上面别离说一下留神点:

  1. canvas 绘制须要留神,起始角度是从 三点钟开始的,绘制一圈是 2 * Math.PI,为了让起始地位落在第一个扇区上须要逆时针旋转肯定的角度(按我的需要是有 8 个扇区,也就是须要旋转 2 * Math.PI / 8 * 2),开发时倡议将弧度(不晓得此处用弧度示意对不对😄)转换成角度,这样运算过程更加便捷,也会缩小有限不循环小数产生的误差

    /**
     * 转换为运算角度
     * @param {number} deg 数学角度
     * @return {number} canvas 画圆角度
     */
    const getAngle(deg: number): number => (Math.PI / 180) * deg
  2. requestAnimationFrame 没什么好说的,当初浏览兼容性也不是什么问题了
  3. 缓动算法:其实就是依据一些列变量,算出一个值(动画的变动量),具体参考张鑫旭大大的 tween.js 的简略实现
  4. 转盘进行停在的扇区,依据 api 返回的中奖后果得出扇区索引 index 即:const prizeDeg = 360 - index * (360 / 8) + initDeg; (initDeg 即最开始旋转的初始角度)

在需要实现之后,我发现不必 canvas,用 div 也能很不便的实现这种成果

div 实现

除了第一步转盘绘制,其余两步思路大致相同

  1. 用 div + css 代替 canvas,次要用到了 transform: rotate(x) skew(y),须要留神的一点是,旋转扭曲之后 div 的子元素也会跟着旋转扭曲,我原本认为这样写就行了 transform: rotate(-x) skew(-y),但殊不知 transform 变换是有程序的要这样写 transform: skew(-y) rotate(-x) 参考
  2. 用了 div 之后,旋转就不是一直地重绘 canvas 了,只须要一直地扭转父集元素的 transform: rotate(),相比 canvas 要简略了许多

代码参考 https://github.com/hugeorange…

  1. 外围代码采纳 ts 开发(不依赖框架)
  2. 思考到我的这个代码满足的场景比拟小众并没有封装成 npm 包
  3. 有同样场景需要的敌人能够间接拷贝代码
退出移动版