今天看一个网页版大转盘抽奖:

    css animation大转盘抽奖

    这个转盘和一般的转盘实现方式不太一样,一般的转盘都是利用js去控制转盘的旋转的角度,然后利用canvas绘制或者直接操作DOM元素控制,再配上一些缓动动画,我之前写过一篇 小程序抽奖转盘的文章,那里面就是利用js控制角度配合缓动动画去实现的转盘。

    这个转盘主要是利用transition,animation去实现,因为css的animation比js控制旋转更加流畅,主要难点就是如何利用transition,animation来达到转盘的目的。

    主要思路

    我之前写过一篇 小程序抽奖转盘的文章,这里的思路和那里类似,也是把转盘的转动分成三个部分,加速,匀速,减速。与那个不同的是,这里要用css的transition和animation来替代用js控制旋转角度。

    加速,匀速:

    加速过程我们可以定义一个过渡效果为easeIn的transition,耗时1s,从0度转到360度。

    上面的加速过程最后达到了一个最大速度,之前说过在匀速过程我们是要请求数据的,这个过程可能很长也可能很短,因此我们要做一个无限循环的animation,每圈耗时.6s,为什么加速的时候,一圈耗时1s,这里耗时.6s呢?因为匀速的速度相当于最大速度,因此每圈耗时肯定比加速的时候更少。

    transition+animation实现加速,匀速

    上面用到的关键css代码如下:

    1. @-webkit-keyframes start_rotate{
    2.     0%{
    3.         transform: rotate(0deg);
    4.         -webkit-transform: rotate(0deg);
    5.     }100%{
    6.         transform: rotate(360deg);
    7.         -webkit-transform: rotate(360deg);
    8.     }
    9. }
    10. .img.start_rotate{
    11.     transition:transform 1s ease-in;
    12.     -webkit-transition:transform 1s ease-in;
    13.     transform: rotate(360deg) !important;
    14.     -webkit-transform: rotate(360deg) !important;
    15.     animation:start_rotate .6s linear 1s infinite forwards;
    16.     -webkit-animation:start_rotate .6s linear 1s infinite forwards;
    17. }

    在匀速旋转的时候请求数据,如果数据到了现在就要减速了,因为匀速的时候我们已经添加了一个animation,因此减速的时候我们只能用另一个animation来替换当前的animation,不过这里有问题就是得到当前转盘转了多少度了。

    我之前写过一篇 transform之不规则形变的文章,里面说了在transform中旋转θ角度后,得到的结果和θ的关系为:matrix(cos(θ),sin(θ),-sin(θ),cos(θ),0,0);也就是说拿matrix的第一个参数进行Math.acos操作就可以求出真正的度数了:

    1. var transform_match = getComputedStyle(document.querySelector('.img')).transform.replace(/[a-zA-Z()]/g, '').split(',');
    2. var _angle=Math.acos(+transform_match[0])/ (Math.PI / 180),_angle_direction=+transform_match[1];//旋转的角度和角度方向
    3. if(_angle!=_angle){//90度270度数
    4.     if(_angle_direction>0){//90度
    5.         _angle=90;
    6.     }else{//270度
    7.         _angle=270;
    8.     }
    9. }else{//其他度数
    10.     if(_angle_direction!=_angle_direction){//180度和0度
    11.     }else{
    12.     if(_angle_direction<0){//超过180度
    13.         _angle=360-_angle;
    14.     }
    15. }
    16. }

    不过要注意一些特殊情况,在90度和270度的时候,Math.cos理论上得到的结果为0,但是matrix计算的结果是一个很小的数字,不是0,并且用科学计数法表示,需要注意。

    matrix的第一个参数用来获取角度,但是这个角度似乎有些“问题”,就是如果角度大于180度,那么就是补角大小了,例如本来是280度,但是第一个参数得到为80度,因此要配合matrix第二个参数来看现在到底是多少度。第二个参数大于0,表示没有超过180度,如果第二个参数小于0,表示超过180度了。

    生成动态的animation

    刚才在讲减速的时候,说到了用另一个animation来替代匀速的animation,但是实际上减速的animation是不固定的,因为你无法知道什么时候停止,停在哪里。因此对于减速,你需要动态创建animation。

    动态创建style,可以用insertRule和deleteRule,这两个可以增加样式规则和删除样式规则,关键代码如下:

    1. function insertRule(sheet, selectorText, cssText, position) {//插入样式
    2.     if (sheet.insertRule) {
    3.     sheet.insertRule(selectorText + "{" + cssText + "}", position);
    4.     } else if (sheet.addRule) {
    5.     sheet.addRule(selectorText, cssText, poistion);
    6.     }
    7. }
    8. function deleteRule(sheet, index) {//删除规则
    9.     if (sheet.deleteRule) {
    10.     sheet.deleteRule(index);
    11.     } else if (sheet.removeRule) {
    12.     sheet.removeRule(index);
    13.     }
    14. }

    知道了如何动态创建style规则,那么减速的时候创建一个简单的easeOut动画就好了,开始旋转角度就是得到数据那个时候的角度,最终角度就是根据结果得到的角度。

    最后的代码在加速的时候也用到了动态animation技术,因为多次旋转,不一定每次都是从0度开始旋转,而是从上一次最后的停止的位置开始旋转。

    两个animation卡顿优化

    本来到上面基本上就结束了,但是这里其实有一个小卡顿的地方,就是从匀速animation到减速animation的时候,因为匀速animation是高速旋转的,然后减速的animation是突然从匀速animation停止的位置开始减速,这样会有一个卡顿的效果。

    匀速旋转的时候是.6s旋转了360度,而一般浏览器绘制间隔为16.7ms,因此为了让两个animation过度的时候不至于太“生硬”,我们减速运动开始的角度上加上(167/600)*360=100.2度,虽然这样无法消除卡顿,但是可以缓解一下这种卡顿效果。

    DEMO下载

    点击下载[0积分]一共下载0
    回到顶部
    我要评论

    所有评论

      相关文章