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

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代码如下:

@-webkit-keyframes start_rotate{
    0%{
        transform: rotate(0deg);
        -webkit-transform: rotate(0deg);
    }100%{
        transform: rotate(360deg);
        -webkit-transform: rotate(360deg);
    }
}
.img.start_rotate{
    transition:transform 1s ease-in;
    -webkit-transition:transform 1s ease-in;
    transform: rotate(360deg) !important;
    -webkit-transform: rotate(360deg) !important;
    animation:start_rotate .6s linear 1s infinite forwards;
    -webkit-animation:start_rotate .6s linear 1s infinite forwards;
}

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

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

var transform_match = getComputedStyle(document.querySelector('.img')).transform.replace(/[a-zA-Z()]/g, '').split(',');
var _angle=Math.acos(+transform_match[0])/ (Math.PI / 180),_angle_direction=+transform_match[1];//旋转的角度和角度方向
if(_angle!=_angle){//90度270度数
    if(_angle_direction>0){//90度
        _angle=90;
    }else{//270度
        _angle=270;
    }
}else{//其他度数
    if(_angle_direction!=_angle_direction){//180度和0度
    }else{
    if(_angle_direction<0){//超过180度
        _angle=360-_angle;
    }
}
}

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

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

生成动态的animation

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

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

function insertRule(sheet, selectorText, cssText, position) {//插入样式
    if (sheet.insertRule) {
    sheet.insertRule(selectorText + "{" + cssText + "}", position);
    } else if (sheet.addRule) {
    sheet.addRule(selectorText, cssText, poistion);
    }
}
function deleteRule(sheet, index) {//删除规则
    if (sheet.deleteRule) {
    sheet.deleteRule(index);
    } else if (sheet.removeRule) {
    sheet.removeRule(index);
    }
}

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

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

两个animation卡顿优化

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

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

DEMO下载

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

所有评论

返回
邮箱:
绑定
取消
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

邮箱:
绑定邮箱后,若有回复,会邮件通知。
提交
还可以输入500个字