贝塞尔曲线介绍

贝塞尔曲线(Bezier Curve)在计算机图形领域应用非常广泛,比如我们熟知的 CSS 动画、 Canvas 以及 Photoshop 等都可以看到贝塞尔曲线的身影。

百度百科:https://baike.baidu.com/item/%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/1091769?fr=ge_ala

css中的时间函数

css3的transition和animation可以实现动画效果,二者都支持贝塞尔曲线。CSS动画过渡时间函数是三阶贝塞尔曲线。动过时间函数,我们在用transition和animation做动画时,可以控制从起点到终点之间的值随时间的变化,如线性变化,先快后满,等等。

CSS animation-timing-function 属性 https://www.w3school.com.cn/cssref/pr_animation-timing-function.asp

CSS transition-timing-function属性 https://www.w3school.com.cn/cssref/pr_transition-timing-function.asp

时间函数的一些预设值如下,也支持自定义值:

描述
linear 规定以相同速度开始至结束的过渡效果(等于 cubic-bezier(0,0,1,1))。
ease 规定慢速开始,然后变快,然后慢速结束的过渡效果(cubic-bezier(0.25,0.1,0.25,1))。
ease-in 规定以慢速开始的过渡效果(等于 cubic-bezier(0.42,0,1,1))。
ease-out 规定以慢速结束的过渡效果(等于 cubic-bezier(0,0,0.58,1))。
ease-in-out 规定以慢速开始和结束的过渡效果(等于 cubic-bezier(0.42,0,0.58,1))。
cubic-bezier(n,n,n,n) 在 cubic-bezier 函数中定义自己的值。可能的值是 0 至 1 之间的数值。

比如我们要实现dom元素从一个点p1到位置p2,就可以用transition来移动,移动的方向是直线的,但是移动的速度就可以由时间函数来控制。

1
2
3
4
5
6
7
8
9
.box{
x: 0;
y: 0;
transition: all ease 1s;
}
.box:hover{
x: 100;
y: 100;
}

chrome浏览器中,有一个按钮点击可以实现自己拖拽生成合适的贝塞尔曲线。

codepen: https://codepen.io/ahao430/pen/gOJbOyg

tween.js补间动画

tween.js是一款简单易用的JavaScript补间动画库,它可以让Web开发者很方便地创建和控制复杂的动画效果。它的特点是功能全面、易于使用,支持各种类型的动画插值器和缓动函数,以及灵活的回调函数和参数调整。

tween.js文档:https://github.com/tweenjs/tween.js/blob/main/README_zh-CN.md

下面是tween.js的easing function的值:

刚刚说到的dom元素移动,也可以用tween.js来实现相同的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const box = document.getElementById('box') // Get the element we want to animate.

const coords = {x: 0, y: 0} // Start at (0, 0)

const tween = new TWEEN.Tween(coords, false) // Create a new tween that modifies 'coords'.
.to({x: 100, y: 100}, 1000) // Move to (300, 200) in 1 second.
.easing(TWEEN.Easing.Quadratic.InOut) // Use an easing function to make the animation smooth.
.onUpdate(() => {
// Called after tween.js updates 'coords'.
// Move 'box' to the position described by 'coords' with a CSS translation.
box.style.setProperty('transform', 'translate(' + coords.x + 'px, ' + coords.y + 'px)')
})
.onComplete(() => {
console.log('complete')
})
.start() // Start the tween immediately.

// Setup the animation loop.
function animate(time) {
tween.update(time)
requestAnimationFrame(animate)
}
requestAnimationFrame(animate)

只不过一般出于性能考虑,能用css实现的,就不用js来做。

codepen: https://codepen.io/ahao430/pen/RwmNNbG


应用示例

css实现大转盘抽奖动画

这里的实现思路是,直接用transition实现过渡,初始rotate角度是0,后面旋转超过1圈,角度可以超过360deg。然后用ease,或者ease-in-out,或者用chrome拖一个先加速再减速的贝塞尔曲线。

codepen: https://codepen.io/ahao430/pen/VwOYYbm

css实现购物车小球抛物线动画

这里要理解抛物线的实质,当我们水平或斜抛出一个物体,实际上可以分解为两个方向的运动。水平方向上x我们可以理解为匀速,这个时间函数是线性的。而竖直方向上,由于收到重力的作用,y实际上是一个向下的匀加速运动,当有初始向上的速度时,可以理解为是一个初始的负值,然后逐渐增大。

这样我们实际上可以包装两层div,一层做水平方向的线性运动,一层做竖直方向的一个加速运动。这样两层分别做直线运动,但是时间函数一个线性一个不断加速即可。

codepen: https://codepen.io/ahao430/pen/LYoEEyN

tween.js实现数字缓动

这个很简单,直接用tween.js做缓动计算,把数字实时展示就行了,这种一般展示人数变化之类的都是整数,可以取整。

codepen: https://codepen.io/ahao430/pen/MWdYwgY

tween.js实现九宫格抽奖动画

同样的,这个要用到tween.js, 这里css是实现不了的。九宫格抽奖的时候,外层的8个位置转圈圈,实际上类似大转盘的转圈,虽然视觉上是循环的,但是我们的角度一直在增加。这里同样的,这里要转N圈的话,让数字从0开始,到 8*N + 停止位置结束,用缓动函数变化,每次得到的值取整,再mod 8,得到动画的实时位置。

codepen: https://codepen.io/ahao430/pen/JjqodmL