D3.js 颜色插值完全指南:d3-interpolate 中 interpolateRgb、HSL、Lab、HCL、Cubehelix 与 Hue 插值器详解
【免费下载链接】d3Bring data to life with SVG, Canvas and HTML. :bar_chart::chart_with_upwards_trend::tada:项目地址: https://gitcode.com/GitHub_Trending/d3/d3
本文以 d3 v7 官方文档docs/d3-interpolate/color.md为核心,系统讲解 d3-interpolate 模块提供的全部颜色插值器:从基础的 RGB 双端插值、多色 B 样条插值,到 HSL/CIELAB/CIELChab/Cubehelix 等感知色彩空间插值与 gamma 校正。读完后你能够:为任意两种颜色构建平滑过渡函数、创建循环(cyclical)颜色比例尺、按需控制色相的最短/长路径,并结合 ColorRamp 渲染组件 的思路在 Canvas 上可视化验证任意插值器的输出。
1. 颜色插值器是什么
d3-interpolate 是一组"插值器工厂"(interpolator factory):你传入起始与结束颜色,它返回一个函数t ∈ [0, 1] → 颜色。这正是 d3 中所有颜色过渡的底层机制——比例尺(d3-scale)、过渡动画(d3-transition)、色板(d3-scale-chromatic)最终都依赖这些函数在两个或多个颜色之间取值。
从仓库结构看,src/index.js 中export * from "d3-interpolate"将本模块全部 API 汇入 d3 主命名空间,因此d3.interpolateRgb等函数在引入整个 d3 包后直接可用;本仓库 package.json 声明其依赖为d3-interpolate: ^3.0.1。
所有双端插值器遵循统一约定:
- 参数
a、b可以是任何 d3 可解析的颜色输入(字符串、数字色、已解析的颜色对象); - 返回的插值器在
t = 0处给出颜色a,在t = 1处给出颜色b; - 返回值统一为RGB 颜色字符串(如
rgb(93, 98, 202)),可直接用于 SVG/Canvas/CSS。
下表汇总了docs/d3-interpolate/color.md中列出的全部颜色插值 API:
| 插值器 | 色彩空间 | 色相路径 | gamma 支持 | 多色 B 样条变体 |
|---|---|---|---|---|
interpolateRgb | RGB | — | ✔ | interpolateRgbBasis/interpolateRgbBasisClosed |
interpolateHsl/interpolateHslLong | HSL | 最短 / 长路径 | ✘ | — |
interpolateLab | CIELAB | — | ✘ | — |
interpolateHcl/interpolateHclLong | CIELChab | 最短 / 长路径 | ✘ | — |
interpolateCubehelix/interpolateCubehelixLong | Cubehelix | 最短 / 长路径 | ✔ | — |
interpolateHue | 色相角(0–360) | 最短路径 | ✘ | — |
2. interpolateRgb(a, b):默认选择
d3.interpolateRgb("purple", "orange")在 RGB 色彩空间中对两个颜色做线性插值,并支持可配置的 gamma(缺省为 1.0)。关键特性:
- 输入不限于 RGB。
a和b可以是任何 d3 能解析的颜色(如"hsl(120, 50%, 40%)"、十六进制、d3.hcl(...)对象),内部会先经d3.rgb转换为 RGB 空间(参见 d3-color 文档); - 插值器返回 RGB 字符串。
RGB 插值计算简单、速度快,且interpolateRgb是d3.interpolate在两个可解析颜色之间的默认实现之一。缺点是在色相差异大时(如紫到橙)可能经过"灰败"的中段,这正是下面各感知色彩空间插值器存在的意义。
3. 多色 B 样条插值:interpolateRgbBasis 与 interpolateRgbBasisClosed
标准插值器只在两个端点之间混合;spline 插值器则在t∈ [0,1] 上用分段多项式函数平滑地穿过多个输入值,目前 d3 仅支持三次均匀非有理 B 样条(cubic uniform nonrational B-spline,即 basis spline)。
3.1 interpolateRgbBasis(colors)
d3.interpolateRgbBasis(["purple", "green", "orange"])返回一个穿过给定颜色数组的均匀非有理 B 样条插值器,颜色会被转换到 RGB 空间。其隐式控制点保证:
t = 0时返回colors[0];t = 1时返回colors[colors.length - 1]。
注意:透明度插值目前不受支持。该函数是通用版本 interpolateBasis 在颜色上的特化;d3-scale-chromatic 文档 中有大量基于它构建连续色板的实例(如d3.interpolateRdYlGn等顺序色板本质上都是interpolateRgbBasis对一组精心挑选颜色的封装)。
3.2 interpolateRgbBasisClosed(colors)
d3.interpolateRgbBasisClosed(["purple", "green", "orange"])与interpolateRgbBasis的区别在于控制点会被隐式重复,使样条在t绕 [0,1] 循环时具有C² 连续性——即t = 1与t = 0处颜色及其一阶、二阶变化率都平滑衔接。这正是构建循环颜色比例尺(cyclical color scales,如风向、相位、一天中的时刻)的关键工具。透明度插值同样不受支持。其通用版本见 interpolateBasisClosed。
4. 感知色彩空间插值:HSL、Lab、HCL
RGB 是设备空间,人眼对其三个通道的变化并不敏感等权。下面三种插值器在感知均匀性更好的空间中进行过渡,输出仍为 RGB 字符串。
4.1 interpolateHsl(a, b) 与 interpolateHslLong
d3.interpolateHsl("purple", "orange") d3.interpolateHslLong("purple", "orange")在 HSL 色彩空间插值。输入不限于 HSL,会先经d3.hsl转换(见 d3-color 文档)。行为要点:
- NaN 通道回填:若某个颜色的色相(hue)或饱和度(saturation)为 NaN,则取对方颜色对应通道的值;
- 最短色相路径:
interpolateHsl沿色相环上较短的一侧过渡; interpolateHslLong与它相同,但不使用最短路径——当两端色相需要"绕远路"经过互补色区域时(例如从 350° 到 10° 经过红、黄而不是直接跨过 0° 缝隙),使用 Long 变体。
4.2 interpolateLab(a, b)
d3.interpolateLab("purple", "orange")在 CIELAB 色彩空间插值。CIELAB 设计目标是对人眼感知的均匀性,L通道表示亮度,a、b表示色度,因此 Lab 插值通常在中间调上比 RGB 插值更鲜艳、更自然。输入会先经d3.lab转换(见 d3-color 文档)。
4.3 interpolateHcl(a, b) 与 interpolateHclLong
d3.interpolateHcl("purple", "orange") d3.interpolateHclLong("purple", "orange")在 CIELChab(CIELAB 的柱状表示:亮度 L、色度 C、色相 h)空间插值。输入经d3.hcl转换(见 d3-color 文档)。NaN 处理与最短色相路径语义和 HSL 版本一致:色相或色度为 NaN 时取对方通道值;默认走最短路径,Long 变体不走最短路径。
4.4 如何选择
- 需要精确控制"沿色相环走哪一边":选 HSL 或 HCL 及其 Long 变体;
- 追求中间颜色饱满、视觉均匀:选 Lab 或 HCL;
- 与 CSS/通用工具链兼容性最高、性能优先:选 RGB。
5. Cubehelix 插值与 gamma 校正
5.1 interpolateCubehelix / interpolateCubehelixLong
d3.interpolateCubehelix("purple", "orange") // 配置 gamma d3.interpolateCubehelix.gamma(3)("purple", "orange")Cubehelix 是一个螺旋形的颜色空间:沿色相旋转的同时亮度单调变化,专为顺序数据(sequential data)设计,能在单色系中同时表达"色相变化 + 明暗层次"。输入会先经d3.cubehelix转换(见 d3-color 文档)。与 HSL/HCL 相同,NaN 通道取对方值、默认最短色相路径;interpolateCubehelixLong为不走最短路径的版本:
d3.interpolateCubehelixLong("purple", "orange") d3.interpolateCubehelixLong.gamma(3)("purple", "orange")5.2 interpolateColor.gamma(gamma)
d3.interpolateRgb.gamma(2.2)("purple", "orange")gamma 机制是 d3 颜色插值中最容易被忽视、但影响最大的一个参数。屏幕显示的亮度与存储的像素值之间是 gamma 幂律关系(典型值 2.2)。若在 gamma 校正后的"线性光"空间直接插值,中间颜色会比预期更暗或更亮;d3 的做法是:
- 用
pow(γ)将通道值映射到线性空间; - 在线性空间中线性插值;
- 再用
pow(1/γ)映射回显示空间。
interpolateColor.gamma(γ)适用于三个插值器:interpolateRgb、interpolateCubehelix 和 interpolateCubehelixLong。调用gamma(γ)不修改原插值器,而是返回同类型、带指定 gamma 的新插值器工厂(无副作用的柯里化风格)。关于 gamma 校正的数学原理,可参考文档引用的 Eric Brasseur 的 "Gamma error in picture scaling" 一文。
缺省 gamma 为 1.0,即不做校正的普通线性插值。
6. interpolateHue(a, b):色相角插值
d3.interpolateHue(20, 340)(0.5) // 0返回两个色相角之间的插值器:
- 输入是数字(角度)而非颜色;
- 若某个色相为 NaN,取对方的值;
- 沿色相环最短路径过渡;
- 返回值是
[0, 360)区间内的数字。
上例中 20° 到 340° 的最短路径是向上跨过 0°:20° → 0°(=360°) → 340°,故t = 0.5时恰为 0。这个插值器常被嵌入自定义插值中,用来单独控制色相通道(例如保持亮度不变、只旋转色相),也是理解 HSL/HCL/Cubehelix 内部色相处理逻辑的参照。
7. 用 Canvas 验证插值器:ColorRamp 的渲染思路
官方文档中每个插值器下方都展示了一条由 组件绘制的渐变色带,其源码在 docs/components/ColorRamp.vue。该组件是一个极小的通用"插值器可视化器",值得学习其实现:
function render(canvas, color, n) { canvas.width = n; canvas.height = 1; const context = canvas.getContext("2d"); for (let i = 0; i < n; ++i) { context.fillStyle = color(i / (n - 1)); // 依次取 t = 0, 1/(n-1), ..., 1 context.fillRect(i, 0, 1, 1); } }- 它把插值器当作
t → 颜色的纯函数,以n(默认 256)等距采样点铺满一条 1 像素高的画布; - 模板部分用
image-rendering: pixelated将画布拉伸显示,使色带呈像素化条状,便于肉眼检查插值是否平滑、循环版本在首尾是否连续; - 组件接收
color(Function)与n(Number)两个 props,任何t → 颜色的插值器都可以直接复用,例如interpolateRgbBasisClosed(['purple', 'green', 'orange'])验证其首尾衔接。
在你的项目里复刻这个模式只需 10 行 Canvas 代码,即可对任意插值器做可视化回归检查。
8. 与周边模块的协作
- d3-scale-chromatic:全部顺序/发散/循环色板(如
d3.interpolateTurbo、d3.schemeTableau10系列)都是在interpolateRgbBasis/interpolateRgbBasisClosed之上构建的,理解本文的 B 样条小节即可读懂色板源码。参见 d3-scale-chromatic 文档。 - d3-color:所有"输入颜色不限于目标空间"的自动转换,依赖
d3.rgb、d3.hsl、d3.lab、d3.hcl、d3.cubehelix五个解析/转换入口。参见 d3-color 文档。 - d3-transition:过渡动画中颜色属性的默认插值即经由
d3.interpolate分发到上述颜色插值器,因此本文的 gamma、最短路径等语义同样作用于动画中间帧。 - 通用插值器对照:
interpolateBasis/interpolateBasisClosed的数值版本语义与颜色版本一一对应,见 d3-interpolate 数值插值文档。
9. 实践要点小结
- 双端平滑变色默认
interpolateRgb;中间色发灰时改用interpolateHsl/interpolateLab/interpolateHcl; - 需要"沿色相环走远路"时选用
*Long变体(HSL、HCL、Cubehelix 均提供); - 多颜色连续渐变用
interpolateRgbBasis,首尾要无缝循环(方向图、时钟刻度)用interpolateRgbBasisClosed; - 对亮度一致性要求高的场景(如科学可视化中相邻数据不应有明暗跳变),为
interpolateRgb或interpolateCubehelix配置gamma(2.2); - 透明度(opacity)目前未被 B 样条颜色插值器支持,需要透明度过渡时应另行对 alpha 通道插值;
- 用 Canvas 等距采样(ColorRamp 思路)在实现后快速目检色带连续性,是低成本高收益的验证手段。
以上 API 以本仓库 d3 v7(d3-interpolate ^3.0.1)为准;interpolateHue的输出范围[0, 360)、interpolateRgb缺省 gamma 1.0 等取值细节均可在 docs/d3-interpolate/color.md 原文中逐条核对。
【免费下载链接】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),仅供参考