d3-ease 缓动函数完全解析: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)上采样绘图,即可与官方文档中的曲线对照。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00