简介
在前端工作中,贝塞尔曲线
被多个地方应用。就如最近年会抽奖中,开始滚动的加速度和结束滚动时如何缓慢停止在中奖号码的位置,就用到了贝塞尔曲线
。所以顺势就介绍一下贝塞尔曲线
和简单应用。
其一般参数公式:
该曲线是由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) { |
最终效果如下: