d3-ease 缓动函数完全解析:d3 中时间扭曲与动画质感的实现原理
【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3
在 d3 中,缓动(easing)是一种通过"扭曲时间"来控制动画视觉运动的方法,最常用于实现 slow-in、slow-out(慢进慢出)效果,让 d3-transition 动画 更加平滑、更符合物理直觉。本文基于 d3 仓库的官方参考文档 docs/d3-ease.md 展开,完整覆盖ease函数契约、全部九种缓动类型(linear、poly、quad、cubic、sin、exp、circle、elastic、back、bounce)及其 In/Out/InOut 变体、exponent/amplitude/period/overshoot等可配置参数的取值与默认值,并结合仓库中的源码导出链与文档可视化组件,讲清每一类缓动"何时选、怎么配、底层怎么算"。
缓动函数:一个把时间映射时间的函数契约
d3-ease 模块中的每个缓动类型都实现同一个ease方法:接收一个归一化时间t,返回对应的"缓动后"时间tʹ。
- 输入t与输出tʹ通常都在[0, 1]区间内,0 代表动画起点,1 代表动画终点;
- 一个合格的缓动函数应当满足
ease(0) === 0且ease(1) === 1; - 个别类型(如
easeElastic)的缓动时间可能略微越出该区间——这正是"回弹""过冲"等动画质感的来源。
基本用法是给归一化时间直接套用某个缓动函数:
const te = d3.easeCubic(t);自定义参数时,先在动画开始前创建缓动函数:
const ease = d3.easeElastic.period(0.4);再在动画过程中调用它:
const te = ease(t);在 d3 生态中的位置:
- 从 src/index.js 可以看到,
d3顶层包通过export * from "d3-ease"将全部缓动函数并入统一命名空间,因此d3.easeCubic等可以直接访问;package.json 中声明的依赖为d3-ease: ^3.0.1(当前 d3 版本 7.9.0); - 在过渡动画中,缓动函数由 transition.ease(value) 指定:每一帧动画都会调用它一次,传入 [0, 1] 之间的归一化时间t,返回缓动时间tʹ;不显式指定时默认为
d3.easeCubic:
transition.ease(d3.easeCubic); transition.ease() // 读取当前缓动函数,返回 d3.easeCubic- 文档中的交互式曲线图由 ExampleEase.vue 组件渲染:该组件用
d3.ticks(0, 1, 500)在 [0, 1] 上取 500 个采样点,再用 Observable Plot 的Plot.lineX(ticks, ease)绘制每条缓动曲线,因此每类缓动的曲线形状都可以直观复现。
以下缓动类型大量参考了 Robert Penner 的经典 easing 公式体系。
基础族:easeLinear 与 easePoly
easeLinear:恒等函数
线性缓动即恒等函数:linear(t)直接返回t,时间完全不被扭曲。适合需要匀速运动的场景(如进度条扫过、循环滚动)。
easePoly:可配置指数的多项式缓动
easePoly是easePolyInOut的别名。其三个变体的语义:
| 变体 | 行为 | 与 easePolyIn 的关系 |
|---|---|---|
easePolyIn | 将t提升到指定指数,默认指数 3(等价easeCubicIn) | — |
easePolyOut | 反向多项式缓动 | 等价1 - easePolyIn(1 - t) |
easePolyInOut | 对称多项式缓动 | t∈ [0, 0.5] 用 In 段、t∈ (0.5, 1] 用 Out 段,各自缩放拼接 |
通过easePoly.exponent(e)返回一个带指定指数e的新多项式缓动,可精确复现 linear/quad/cubic:
const linear = d3.easePoly.exponent(1); const quad = d3.easePoly.exponent(2); const cubic = d3.easePoly.exponent(3);官方文档为指数提供了 0.5、1、1.5、2、3、4 六档对比曲线;指数越大,In 段前期越"压平"、末尾加速越猛,Out 段则相反。
easeQuad:二次缓动
easeQuad是easeQuadInOut的别名:
easeQuadIn:等价easePolyIn.exponent(2);easeQuadOut:反向,等价1 - easeQuadIn(1 - t),也等价easePolyOut.exponent(2);easeQuadInOut:对称,前半段缩放easeQuadIn、后半段缩放easeQuadOut,也等价easePoly.exponent(2)。
easeCubic:三次缓动(d3 的默认)
easeCubic是easeCubicInOut的别名:
easeCubicIn:等价easePolyIn.exponent(3);easeCubicOut:等价1 - easeCubicIn(1 - t),也等价easePolyOut.exponent(3);easeCubicInOut:对称拼接,也等价easePoly.exponent(3)。
由于transition.ease()未指定时默认就是easeCubic,它是 d3 过渡动画中出场率最高的缓动,也是最稳妥的默认选择。
曲线族:easeSin、easeExp 与 easeCircle
三者都是 In / Out / InOut 三件套,且 Out 一律是 In 的时间反转1 - fIn(1 - t),InOut 一律是"前半 In、后半 Out"的对称拼接。
easeSin:正弦缓动
easeSinIn:返回 sin(t)——以正弦曲线起势,起步柔和;easeSinOut:1 - easeSinIn(1 - t);easeSinInOut:对称拼接。
easeExp:指数缓动
easeExpIn:将 2 提升到10 × (t - 1)次幂,即2^(10(t-1))——起点几乎静止、终点极陡,加速感比三次缓动更强烈;easeExpOut:1 - easeExpIn(1 - t),常用于"快速冲入、缓缓收尾"的元素入场;easeExpInOut:对称拼接。
easeCircle:圆形缓动
基于圆弧(四分之一圆的斜率变化)定义:
easeCircleIn:圆形缓动;easeCircleOut:1 - easeCircleIn(1 - t);easeCircleInOut:对称拼接。
圆形缓动的拐点比正弦更"硬",接近抛物线末端行为,适合强调果断感的 UI 动效。
弹性族:easeElastic 及其两个配置参数
easeElastic是easeElasticOut的别名,效果像橡皮筋,允许缓动值在终点处来回振荡(这正是前文所述"缓动时间可略越出 [0, 1]"的典型)。
easeElasticIn:振幅与周期均可配置,默认振幅 1、默认周期 0.3;easeElasticOut:1 - easeElasticIn(1 - t),是最常用的"松手回弹"形态;easeElasticInOut:前半段 In、后半段 Out 的对称形式。
两个参数方法均返回新的缓动函数:
// 指定振幅(注意约束) const ease = d3.easeElastic.amplitude(1.2); // 指定周期 const ease = d3.easeElastic.period(0.4);easeElastic.amplitude(a):振幅a必须 ≥ 1,振荡偏离 [0, 1] 的程度随振幅增大而加剧;官方文档的交互式滑块范围为 1~4;easeElastic.period(p):周期p控制振荡频率,滑块范围为 0.1~1.5,周期越小振荡越密集。
文档中为两个参数分别提供了 1.0~1.5 的振幅对比曲线,可以看到振幅越大、回弹过冲越夸张。
预期族:easeBack 与过冲参数
easeBack是easeBackInOut的别名,属于"预期(anticipation)"类缓动——如同舞者起跳前先屈膝:
easeBackIn:先向反方向"蓄力"再冲出去,过冲度可配置,默认 1.70158;easeBackOut:1 - easeBackIn(1 - t);easeBackInOut:对称拼接。
const ease = d3.easeBack.overshoot(2.5); // 自定义过冲easeBack.overshoot(s)返回带指定过冲s的新 back 缓动;官方示例用d3.ticks(0.5, 3, 6)生成 0.5、1、1.5、…、3 共 6 档过冲对比曲线,交互式滑块范围为 0~5。过冲为 0 时退化为普通 In 行为,过冲越大,反方向的"下探"越深。
弹跳族:easeBounce
easeBounce是easeBounceOut的别名,效果像一颗橡胶球落地反弹,为分段折线式的非对称振荡:
easeBounceIn:弹跳缓动,先慢后快、末端以多次衰减反弹收束;easeBounceOut:1 - easeBounceIn(1 - t),即"先落下、逐级弹跳衰减"的经典形态;easeBounceInOut:前半段 In、后半段 Out 的对称拼接。
弹跳族没有可配置参数,是九类缓动中唯一不可调参的类型。
选型速查与在 d3-transition 中的落地
综合各类型的默认值与特性,选型可按此速查表决策:
| 缓动族 | 默认别名指向 | 关键参数(默认值) | 典型观感 |
|---|---|---|---|
easeLinear | 自身 | 无 | 匀速 |
easePoly | easePolyInOut | exponent(3) | 可调强度的多项式 |
easeQuad | easeQuadInOut | 无(即 exponent 2) | 温和的二次曲线 |
easeCubic | easeCubicInOut | 无(即 exponent 3) | d3 默认,平滑通用 |
easeSin | easeSinInOut | 无 | 柔和的正弦起势 |
easeExp | easeExpInOut | 无 | 强烈的指数加减速 |
easeCircle | easeCircleInOut | 无 | 偏硬的圆弧转折 |
easeElastic | easeElasticOut | amplitude(1,须 ≥1)、period(0.3) | 橡皮筋回弹 |
easeBack | easeBackInOut | overshoot(1.70158) | 先蓄力后过冲 |
easeBounce | easeBounceOut | 无 | 橡胶球弹跳 |
在真实动画中的落地方式(详见 docs/d3-transition/timing.md):
// 全局统一缓动 d3.select(".bar") .transition() .duration(750) .ease(d3.easeCubic) // 默认值,可省略 .attr("height", newHeight); // 每个元素使用不同缓动:easeVarying 接受工厂函数 selection.transition() .easeVarying((d) => d3.easePolyIn.exponent(d.exponent));要点回顾:
- 缓动函数只负责"时间 → 时间"的映射,每帧被
transition.ease调用一次,因此自定义缓动只需是纯函数即可; - 所有
*In/*Out/*InOut遵循统一构造规律:Out 是 In 的时间反转,InOut 是二者在 t = 0.5 处的对称拼接,记忆其中一半即可推导另一半; - 可调参的三类——
easePoly.exponent、easeElastic.amplitude/period、easeBack.overshoot——均以"返回新函数"的方式创建变体,不修改原函数,天然支持动画前批量预创建; - 曲线形状可用 ExampleEase.vue 同款方式快速验证:对任意缓动函数在
d3.ticks(0, 1, 500)上采样绘图,即可与官方文档中的曲线对照。
【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考