共计 1354 个字符,预计需要花费 4 分钟才能阅读完成。
最近有一个需要要开发一个抽奖大转盘类的一个页面,原本想着这种货色必定有现成的,但找了一圈后发现基本上都与咱们的设计图有些出入,如果间接应用现成的包预计必定是验收不通过的
开源我的项目的布局个别都是这样的(转盘内的文字正对圆心),举荐一个比拟热门的开源我的项目,反对多端,多种游戏形式(大转盘、九宫格、老虎机)
而咱们的设计图却是设计成这样的(文字与半径平行)
无奈现成的包的不能应用,故筹备把开源我的项目 down 下来批改一下使之合乎咱们的业务场景要求
stackblitz 成果预览
上面总结了一些实现思路:分为 canvas 版本和 div+css 版本
canvas 思路实现
- canvas 转盘绘制,包含每片扇区上的文字及图片的绘制(其实就这一点须要更改)
- 递归 requestAnimationFrame 而后一直扭转绘制起始角度 (canvas 绘制的初始角度) 使转盘动起来
- 应用缓动算法,使转盘转动更加天然:转盘初始阶段迟缓
减速 -> 匀速 -> 加速
最终停在指定扇区(中奖后果必定是 api 返回的,前端须要管制最初要停在指定地位上,依照 lucky-canvas 上的说法就是守株待兔
)
上面别离说一下留神点:
-
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
- requestAnimationFrame 没什么好说的,当初浏览兼容性也不是什么问题了
- 缓动算法:其实就是依据一些列变量,算出一个值(动画的变动量),具体参考张鑫旭大大的 tween.js 的简略实现
- 转盘进行停在的扇区,依据 api 返回的中奖后果得出扇区索引 index 即:
const prizeDeg = 360 - index * (360 / 8) + initDeg;
(initDeg 即最开始旋转的初始角度)
在需要实现之后,我发现不必 canvas,用 div 也能很不便的实现这种成果
div 实现
除了第一步转盘绘制,其余两步思路大致相同
- 用 div + css 代替 canvas,次要用到了
transform: rotate(x) skew(y)
,须要留神的一点是,旋转扭曲之后 div 的子元素也会跟着旋转扭曲,我原本认为这样写就行了transform: rotate(-x) skew(-y)
,但殊不知 transform 变换是有程序的要这样写transform: skew(-y) rotate(-x)
参考 - 用了 div 之后,旋转就不是一直地重绘 canvas 了,只须要一直地扭转父集元素的
transform: rotate()
,相比 canvas 要简略了许多
代码参考 https://github.com/hugeorange…
- 外围代码采纳 ts 开发(不依赖框架)
- 思考到我的这个代码满足的场景比拟小众并没有封装成 npm 包
- 有同样场景需要的敌人能够间接拷贝代码
正文完
发表至: javascript
2022-06-20