贝塞尔曲线又叫贝兹曲线, 在大学高数中一度让我非常头疼. 前阵子练手写动画的时候, 发现贝塞尔曲线可以应用于轨迹的绘制以及定义动画曲线.
本文就来探究一下, 贝塞尔曲线到底是个什么样的存在.
贝塞尔曲线原理
贝塞尔曲线由 n 个点来决定, 其曲线轨迹可以由一个公式来得出:
其中 n 就代表了贝塞尔曲线是几阶曲线, 该公式描述了曲线运动的路径.
以下我们来讨论一下, 贝塞尔公式如何推导.
一阶贝塞尔曲线
设定图中运动的点为 Pt,t 为运动时间, t∈(0,1), 可得如下公式
二阶贝塞尔曲线
在二阶贝塞尔曲线中, 已知三点恒定(P0,P1,P2), 设定在 P0P1 中的点为 Pa, 在 P1P2 中的点为 Pb,Pt 在 PaPb 上的点, 这三点都在相同时间 t 内做匀速运动.
由公式 (1) 可知
将公式 (2)(3) 代入公式 (4) 中, 可得
三阶贝塞尔曲线
同理, 根据以上的推导过程可得
由此可以推导
n 阶贝塞尔曲线
放上一个网址, 随意感受一下贝塞尔曲线的绘制过程:
http://myst729.github.io/bezier-curve/
实际应用
贝塞尔曲线在前端中主要有两方面的应用, 一方面可以作为动画曲线应用于 CSS3 动画中; 另一方面可以通过 canvas 来绘制曲线达到需要的效果.
CSS3 中贝塞尔曲线的应用
在 CSS3 中, 有两属性经常被用到: transition-timing-function 和 animation-timing-function, 这两个分别代表了过渡的速度和动画的速度. CSS3 为我们提供了一个新的工具 --cubic-bezier(x1,y1,x2,y2). 这个工具能够生成一个速度曲线, 使我们的元素按照该曲线来调节速度.
在上面的推导中, 我们知道在贝塞尔公式中, 有两个点的位置恒定 --P0 和 P1,cubic-bezier 中定义了两个控制点的位置, 所以该曲线为三阶贝塞尔曲线.
有个网站可以方便我们快速建立一个贝塞尔曲线: http://cubic-bezier.com/
贝塞尔曲线与动画曲线的关联
先来一波动图简单粗暴的感受一下: 例一:
例二:
例三:
左边的是贝塞尔曲线, 横轴代表了事件, 竖轴代表了进度, 无法直观得感受出速度的变化.
右边的曲线是控制面板中的动画曲线, 横轴是时间, 竖轴是速度, 可以方面地看出速度的变化.
上述例子中, 以前进反向为速度正方向, 后退方向为速度反方向.
如何得知速度的变化
推导
例一中, 贝塞尔曲线为一条直线, 当时间均匀变化时, 进度也在均匀变大, 由此可知速度恒定不变, 时间和进度之间的关系可以用一个线性方程来表示:
y=ax+b (a=1,b=0)
其中 x 为时间, y 为进度, a 即为速度.
推导案例一
从上面结论中启发, 去观察其他贝塞尔曲线,
图中是一段变化的曲线, 我们取其中一小段, 将其看作稳定不变的一段直线, 通过下面的线性方程来表示, 并通过红线标注在图中:
y=ax+b
根据初中数学的内容, 我们知道, 当 a>1 时, 与 x 轴的夹角∈(45°,90°); 当 a∈(0,1)时, 与 x 轴的夹角在 (0,45°) 之间. 相同的时间内, 与 x 轴的夹角越大, a 越大, 速度越快.
观察上图的夹角变化趋势, 夹角逐渐变小趋向于 0, 而后逐渐变大, 趋向于 90°, 对应速度应是速度逐渐变慢趋向于 0, 之后逐渐变快.
放上动画曲线以及动图来验证一下我们的推测:
推导案例二
下图中的曲线部分在第四象限, 部分在第一象限, 这时对应的动画曲线该如何推导呢.
同样将该曲线视为由 n 段平滑的直线构成, 由线性方程来表示直线的趋势, 可知速度 a 方向一开始为负, 之后慢慢向正方靠近, a 的速率也在由大变小, 当为 0 时, 再向正方慢慢变大. 即该曲线表示元素一开始在朝反方向减速运动, 当速度为 0 后, 向正方向作加速运动.
通过动画曲线及动图来验证上述推导:
验证
用两个曲线来验证一下上面的结论:
曲线一:
曲线二:
从结果可以判断, 用上述推导方法可以正确得出贝塞尔曲线与动画曲线之间的关系.
动画曲线的应用
了解了如何用贝塞尔曲线来指定动画曲线后, 很多动画涉及到速度方面的效果就可以实现了, 例如小车加速刹车, 弹簧动画等速度轨迹都可以根据自己的需要来进行定制.
放上一个缓动函数速查网址, 可以让自己的动效更加真实: 缓动函数 https://easings.net/zh-cn
放一个小例子:
该动画模拟了小球落下回弹的过程
代码如下:
- <div class="ground">
- <div class="ball" id="ball"></div>
- </div>
- .ball {
- width: 30px;
- height: 30px;
- background: #000000;
- border-radius: 50%;
- position: absolute;
- top: 0;
- left: 50%;
- animation: move 4s cubic-bezier(0.36, 1.7, 0.26, 0.61) 1s infinite;
- }
- @keyframes move {
- 0% {
- top: 0;
- }
- 100% {
- top: 90%;
- }
- }
这类动画可以参考网上大大们的案例:
贝塞尔曲线与 CSS3 动画, SVG 和 canvas 的应用
理解与运用贝塞尔曲线 https://www.jianshu.com/p/103283df3ff7
利用 canvas 绘制贝塞尔曲线
canvas 中提供了 API 可以快速绘制一条贝塞尔曲线, 来达到需要的效果:
二阶贝塞尔曲线
- quadraticCurveTo(x1,y1,x2,y2)
- var c=document.getElementById("myCanvas");
- var ctx=c.getContext("2d");
- ctx.beginPath();
- ctx.moveTo(20,20);
- ctx.quadraticCurveTo(40,200,200,20);
- ctx.stroke();
其中 moveTo 定义了起始点, quadraticCurveTo(x1,y1,x2,y2)中的 (x1,y1) 为控制点,(x2,y2)为终点
三阶贝塞尔曲线
- bezierCurveTo(x1,y1,x2,y2,x3,y3)
- var c=document.getElementById("myCanvas");
- var ctx=c.getContext("2d");
- ctx.beginPath();
- ctx.moveTo(20,20);
- ctx.bezierCurveTo(40,100,200,150,200,20);
- ctx.stroke();
其中 moveTo 定义了起始点, bezierCurveTo(x1,y1,x2,y2)中的 (x1,y1),(x2,y2) 为控制点,(x3,y3)为终点
总结
为了弄清贝塞尔曲线是个什么东西, 和动画曲线, 速度又有什么关联, 作者跑去复习了一下那些早扔给老师的东西, 有说错的请轻拍 /(ㄒ o ㄒ)/~~
广而告之
来源: https://juejin.im/post/5c89f53e6fb9a049d05e9aad