news 2026/9/5 20:15:58

d3-ease 缓动函数完全解析:d3 中时间扭曲与动画质感的实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
d3-ease 缓动函数完全解析:d3 中时间扭曲与动画质感的实现原理

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与输出通常都在[0, 1]区间内,0 代表动画起点,1 代表动画终点;
  • 一个合格的缓动函数应当满足ease(0) === 0ease(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,返回缓动时间;不显式指定时默认为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:可配置指数的多项式缓动

easePolyeasePolyInOut的别名。其三个变体的语义:

变体行为与 easePolyIn 的关系
easePolyInt提升到指定指数,默认指数 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:二次缓动

easeQuadeaseQuadInOut的别名:

  • easeQuadIn:等价easePolyIn.exponent(2)
  • easeQuadOut:反向,等价1 - easeQuadIn(1 - t),也等价easePolyOut.exponent(2)
  • easeQuadInOut:对称,前半段缩放easeQuadIn、后半段缩放easeQuadOut,也等价easePoly.exponent(2)

easeCubic:三次缓动(d3 的默认)

easeCubiceaseCubicInOut的别名:

  • 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)——以正弦曲线起势,起步柔和;
  • easeSinOut1 - easeSinIn(1 - t)
  • easeSinInOut:对称拼接。

easeExp:指数缓动

  • easeExpIn:将 2 提升到10 × (t - 1)次幂,即2^(10(t-1))——起点几乎静止、终点极陡,加速感比三次缓动更强烈;
  • easeExpOut1 - easeExpIn(1 - t),常用于"快速冲入、缓缓收尾"的元素入场;
  • easeExpInOut:对称拼接。

easeCircle:圆形缓动

基于圆弧(四分之一圆的斜率变化)定义:

  • easeCircleIn:圆形缓动;
  • easeCircleOut1 - easeCircleIn(1 - t)
  • easeCircleInOut:对称拼接。

圆形缓动的拐点比正弦更"硬",接近抛物线末端行为,适合强调果断感的 UI 动效。

弹性族:easeElastic 及其两个配置参数

easeElasticeaseElasticOut的别名,效果像橡皮筋,允许缓动值在终点处来回振荡(这正是前文所述"缓动时间可略越出 [0, 1]"的典型)。

  • easeElasticIn:振幅与周期均可配置,默认振幅 1、默认周期 0.3
  • easeElasticOut1 - 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 与过冲参数

easeBackeaseBackInOut的别名,属于"预期(anticipation)"类缓动——如同舞者起跳前先屈膝:

  • easeBackIn:先向反方向"蓄力"再冲出去,过冲度可配置,默认 1.70158
  • easeBackOut1 - 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

easeBounceeaseBounceOut的别名,效果像一颗橡胶球落地反弹,为分段折线式的非对称振荡:

  • easeBounceIn:弹跳缓动,先慢后快、末端以多次衰减反弹收束;
  • easeBounceOut1 - easeBounceIn(1 - t),即"先落下、逐级弹跳衰减"的经典形态;
  • easeBounceInOut:前半段 In、后半段 Out 的对称拼接。

弹跳族没有可配置参数,是九类缓动中唯一不可调参的类型。

选型速查与在 d3-transition 中的落地

综合各类型的默认值与特性,选型可按此速查表决策:

缓动族默认别名指向关键参数(默认值)典型观感
easeLinear自身匀速
easePolyeasePolyInOutexponent(3)可调强度的多项式
easeQuadeaseQuadInOut无(即 exponent 2)温和的二次曲线
easeCubiceaseCubicInOut无(即 exponent 3)d3 默认,平滑通用
easeSineaseSinInOut柔和的正弦起势
easeExpeaseExpInOut强烈的指数加减速
easeCircleeaseCircleInOut偏硬的圆弧转折
easeElasticeaseElasticOutamplitude(1,须 ≥1)、period(0.3)橡皮筋回弹
easeBackeaseBackInOutovershoot(1.70158)先蓄力后过冲
easeBounceeaseBounceOut橡胶球弹跳

在真实动画中的落地方式(详见 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));

要点回顾:

  1. 缓动函数只负责"时间 → 时间"的映射,每帧被transition.ease调用一次,因此自定义缓动只需是纯函数即可;
  2. 所有*In/*Out/*InOut遵循统一构造规律:Out 是 In 的时间反转,InOut 是二者在 t = 0.5 处的对称拼接,记忆其中一半即可推导另一半;
  3. 可调参的三类——easePoly.exponenteaseElastic.amplitude/periodeaseBack.overshoot——均以"返回新函数"的方式创建变体,不修改原函数,天然支持动画前批量预创建;
  4. 曲线形状可用 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 20:09:43

osu!成绩标题解读:从1sb 264pp bp1看pp与bp机制

看到类似“Science 1sb 264pp bp1”这样的标题,很多刚玩 osu! 的人会一头雾水:这到底是在晒成绩,还是在告诉别人某种打法?其实这是音游社区里非常常见的成绩分享格式,用简单几个代号就把一次关键游戏的“谱面、失误情况…

作者头像 李华
网站建设 2026/9/5 20:04:30

3 步上手 Awesome-Linux-Software:一份完整的 Linux 软件清单

3 步上手 Awesome-Linux-Software:一份完整的 Linux 软件清单 【免费下载链接】Awesome-Linux-Software 🐧 A list of awesome Linux softwares 项目地址: https://gitcode.com/GitHub_Trending/aw/Awesome-Linux-Software 装完新系统不知道装什…

作者头像 李华
网站建设 2026/9/5 20:02:08

掌握unzip的正确姿势:编码乱码、路径安全与批量解压实践

如果你只把unzip命令当成“把一个 zip 文件解开”的黑盒,那当你在生产服务器上执行它、或整理一批从外部获得的压缩资料时,迟早会遇到下面某一种状况:文件名变成乱码、解压产物跑到预期目录之外、文件权限全部丢失,更严重的是在不…

作者头像 李华
网站建设 2026/9/5 19:59:40

发片刷色总刷不匀?从表面预处理到分区薄涂的完整流程

前阵子我想翻新一批旧发片,第一次上手就踩了一整套典型的新手坑:调好色料,刷子蘸得满满当当,从发根处一鼓作气往发尾拖,想靠一次覆盖把颜色刷均匀。结果十分钟后,有的地方发根堆积出一小撮深色,…

作者头像 李华
网站建设 2026/9/5 19:59:26

Intel核显跑本地大模型实测:OpenVINO加速与踩坑全记录

先交代一下背景。手头这台笔记本是某款很常见的办公轻薄本,CPU 是 Intel i5-1240P,集成 Iris Xe 核显(80EU),32GB 内存,没有独立显卡。买回来本来只打算写文档、跑跑报表,结果某天突然上头&…

作者头像 李华