简介
在前端工作中,贝塞尔曲线被多个地方应用。就如最近年会抽奖中,开始滚动的加速度和结束滚动时如何缓慢停止在中奖号码的位置,就用到了贝塞尔曲线。所以顺势就介绍一下贝塞尔曲线和简单应用。
其一般参数公式:
该曲线是由P0开始,止于Pn,中间有n-2个点控制曲线的走势。根据控制点个数不同,得到不同的特殊曲线公式。
在实际工作中,常用的是二次贝塞尔曲线和三次贝塞尔曲线。一次贝塞尔曲线,呈现出来的是一条直线。下面是几种常见的贝塞尔曲线的介绍和应用。
常见的曲线
线性公式
n=1时,控制点个数: 0,仅有开始和结束两个点,得到的是一条直线。
二次方公式
n=2时,控制点个数: 1
三次方公式
n=3时,控制点个数: 2
公式说明
以二次方公式为例,转换为函数如下,其中P0为起点,P2为终点,P1为控制点。得到的是从P0到P2的点关于t的二次函数,t的范围[0, 1]。
1 | function QuadraticBezier(P0, P1, P2){ |
应用
SVG的应用
在SVG中,用q或者Q可以绘制二次方贝塞尔曲线(q指相对位置,Q指绝对位置)。以svg为例,
关键代码<path d="M 100 350 Q 250 50 400 350"/>,起点P0(100 350), 终点P2(400 350), 控制点P1(250 50)。将X坐标和Y坐标分别带入函数QuadraticBezier中,可以获得某个时刻的具体坐标。
1 | // 分别计算X、Y |
随着t的增加,分别计算出point的top和left,可以得到如下动画:
canvas中的apiquadraticCurveTo、bezierCurveTo与绘制SVG类似。
CSS animation-timing-function
在CSS动画中由animation-timing-function规定动画的速度曲线,已经预设了几个值:linear、ease、ease-in、ease-out、ease-in-out,自定义速度时使用cubic-bezier()灵活控制。
可以修改例子中数字看看效果。
JS中应用
CSS属性animation-timing-function的值cubic-bezier接收的值正常范围是[0, 1]的,即在三次贝塞尔曲线中,默认起始点P0(0, 0),终点P3(1, 1),可以推导出公式
1 | const CubicBezier = P0 * (1-t)^3 + 3 * P1 * t * (1-t)^2 + 3 * P2 * t^2 * (1-t) + P3 * t^3 |
将X和Y的函数结合起来,即可计算t时刻的值:
1 | CubicBezier.prototype.solve = function(t){ |
此时简单结合起来,误差较大。因为根据绘制SVG例子中可以看出,函数sampleCurveX和sampleCurveY计算的是t时刻的坐标x和y,能画出该三次贝塞尔曲线。但是应用到属性值的变化上时,曲线上t时刻的切线代表t时刻属性值变化的速度,与t时刻的坐标x和y不是直接关系。所以需要在对函数进行再加工。牛顿迭代法:
1 | CubicBezier.prototype.solve = function(x){ |
开始滚动
- 创建获取当前时间对应速度的函数
getSpeed - 根据
top值使图片偏移,达到移动效果 top = top + speed, 修改speed的值使增量变化,达到加速效果- 速度未达到最大速度时,
getSpeed获取新的速度 - 重复2-4,主要代码如下
- 创建获取当前时间对应速度的函数
1 | function start() { |
结束滚动
- 需要结束时根据
top计算当前显示的数字showNum - 根据中奖数字
targetNum和showNum计算出,停止滚动时的值targetTop - 创建获取某时刻的top函数
getTop - 计算此刻图片的偏移量
top - 判断
top < targetTop时,说明还未滚动中奖号码,继续滚动 - 判断
top >= targetTop时,停止滚动。
- 需要结束时根据
1 | function end(targetNum) { |
最终效果如下: