贝塞尔曲线:实现更好的动画效果和图形

3,997 阅读4分钟

纸上得来终觉浅,绝知此事要躬行

前言🎀

贝塞尔曲线是一种数学曲线,它拥有 灵活、平滑、可编辑 的特点,十分适合描述曲面形状、处理图形变形、模拟运动轨迹等场景。

动画.gif

使用贝塞尔曲线,我们可以绘制各种各样的图形,它对计算机的图形图像技术具有深远的影响。

我们熟知的 CSS 动画、 Canvas 以及 Photoshop 等也都可以看到贝塞尔曲线的身影。

本文我们一起学习贝塞尔曲线在前端中的基础应用,了解其实现原理~

简介

贝塞尔曲线由 控制点 组成,调整控制点曲线形状会发生变化。

动画11.gif

贝塞尔曲线根据 控制点(P) 的数量分为:

  • 一阶贝塞尔曲线(2 个控制点)

  • 二阶贝塞尔曲线(3 个控制点)

. . .

  • n阶贝塞尔曲线(n + 1个控制点)

应用

在前端开发中,我们使用贝塞尔曲线不限于以下几种方案:

  1. CSS提供了相关的属性 animation-time-function使用贝塞尔曲线的轨迹描述动画运行进度,让动画表现的更加平滑、自然

  2. Canvas提供了API quadraticCurveTobezierCurveTo,分别绘制二次贝塞尔曲线和三次贝塞尔曲线

  3. 直接绘制由贝塞尔曲线组成的图形,例如svg

CSS animation-time-function

image.png

CSS中animation-time-functionanimation 属性的子属性,它代表了动画速度的曲线,CSS提供了内置的几个值让我们可以快速、便捷的使用贝塞尔曲线:

animation-time-function: ease | ease-in | ease-out | ease-in-out | linear

动画2.gif

我们也可以通过自定义函数生成贝塞尔曲线:

animation-time-function: cubic-bezier(x1, y1, x2, y2)

例如实现一个回弹效果: 动画1.gif

分析

在CSS动画中,使用三次贝塞尔曲线控制动画,曲线的横坐标代表时间比率,纵坐标代表动画进度。

image.png

曲线的斜率代表了动画的运动速度,曲线越陡峭,速度越快;曲线越平缓,速度则越慢。

ease、ease-in ... 等属性值等同于自定义cubic-bezier函数生成的曲线,具体值可以去 MDN 了解# animation-timing-function-MDN

image.png

推荐一个可在线编辑贝塞尔曲线的网站 cubic-bezier.com/

Canvas API

Canvas提供了API:quadraticCurveTobezierCurveTo,用于绘制2阶、3阶贝塞尔曲线

Q: 对于更高阶的贝塞尔曲线该怎么办?
A: 平常尽量使用2-3阶贝塞尔曲线,更高阶的曲线尽量降阶为2-3阶贝塞尔曲线

下方案例演示了相关API的用法,支持拖拽控制点,并兼容了n阶曲线,你可以通过在controlPoints中添加控制点进行测试:

绘制图形

通过 CSS clip-path 从一个div中剪去两块贝塞尔的曲线覆盖的内容(本质是绘制svg),实现粘性下拉,软件与用户交互时更加顺滑

原理

贝塞尔曲线本质上是一系列点的集合,需要大量的计算。

以三次贝塞尔曲线举例:

  • 贝塞尔曲线由 控制点(P) 组成,控制点之间会连接成线段

image.png

  • 线段上会形成新的控制点(P')

image.png

  • 新控制点之间又会连接成线段,线段又会形成控制点 (类似递归) . . .

image.png

  • 直至形成的唯一控制点(图中是P''')

image.png

我们把线段上的所有控制点的进度用一个参数t = [0, 1] 表示,例:(P0 * P'0) / (P0 * P1)

参数t从0到1 所有控制点从头移动到尾,期间唯一控制点的运动轨迹便是贝塞尔曲线。

最后通过一张图片回顾贝塞尔曲线的生成过程:

6b6781dc8ccf5b5404343d5cbb026d53.gif

通过计算公式我们可以获取曲线当前的点坐标:

  • 一阶:B(t)=(1t)P0+tP1B(t) = (1-t)P_0 + tP_1

  • 二阶:B(t)=(1t)2P0+2t(1t)P1+t2P2B(t) = (1-t)^2P_0 + 2t(1-t)P_1 + t^2P_2

  • 三阶:B(t)=(1t)3P0+3t(1t)2P1+3t2(1t)P2+t3P3B(t) = (1-t)^3P_0 + 3t(1-t)^2P_1 + 3t^2(1-t)P_2 + t^3P_3

...

  • N阶:B(t)=i=0n(ni)(1t)nitiPiB(t) = \sum_{i=0}^{n} {n \choose i} (1-t)^{n-i} t^i P_i

总结

最后我们总结一下本文:

  1. 贝塞尔曲线,一种数学曲线,特点是灵活、平滑、可编辑,适用于设计、动画、图形
  2. 贝塞尔曲线由控制点组成,根据 控制点数(n) 被定义为 (n - 1) 阶贝塞尔曲线
  3. CSS中通过 animation-time-function 属性使用贝塞尔曲线的轨迹描述动画进度
  4. Canvas中通过 quadraticCurveTobezierCurveTo 绘制2、3阶贝塞尔曲线,更高阶的曲线通过降阶处理
  5. 贝塞尔曲线形成的原理:
    • 给定控制点连接成线段,线段创建新的控制点,控制点再连接成线段 . . .
    • 最后形成的唯一控制点根据 进度t 生成的运动轨迹,便是贝塞尔曲线
    • 贝塞尔曲线本质上是一系列点的集合,需要大量的计算
  6. 贝塞尔曲线的通用计算公式 B(t)=i=0n(ni)(1t)nitiPiB(t) = \sum_{i=0}^{n} {n \choose i} (1-t)^{n-i} t^i P_i

结语🎉

本文比较简单,后续会更新 Canvas结合贝塞尔曲线 实现带笔锋的画板/签名版,感兴趣点关注 不迷路~

不要光看不实践哦,后续会持续更新前端相关的知识 😉

脚踏实地不水文,真的不关注一下吗~

写作不易,如果觉得有收获还望大家点赞、收藏 🌹

才疏学浅,如有问题或建议欢迎大家指教。