跳至内容

值插值

这些是最通用的插值器,适用于大多数值。

interpolate(a, b)

示例 · 源代码 · 返回两个任意值 ab 之间的插值器。

js
d3.interpolate("red", "blue")(0.5) // "rgb(128, 0, 128)"

插值器实现基于结束值 b 的类型,使用以下算法

  1. 如果 b 为 null、undefined 或布尔值,则使用常量 b
  2. 如果 b 为数字,则使用 interpolateNumber.
  3. 如果 b颜色 或可转换为颜色的字符串,则使用 interpolateRgb.
  4. 如果 b日期,则使用 interpolateDate.
  5. 如果 b 为字符串,则使用 interpolateString.
  6. 如果 b类型化数组 的数字,则使用 interpolateNumberArray.
  7. 如果 b 为通用的 数组,则使用 interpolateArray.
  8. 如果 b 可转换为数字,则使用 interpolateNumber.
  9. 使用 interpolateObject.

基于所选插值器,a 被强制转换为适当的对应类型。

interpolateNumber(a, b)

示例 · 源代码 · 返回两个数字 ab 之间的插值器。

js
d3.interpolateNumber(20, 620)(0.8) // 500

返回的插值器等效于

js
function interpolator(t) {
  return a * (1 - t) + b * t;
}

注意

当插值器用于生成字符串时,避免插值为或从数字零插值。当非常小的值被转换为字符串时,它们可能会被转换为科学计数法,这在较旧的浏览器中是不合法的属性或样式属性值。例如,数字 0.0000001 被转换为字符串 "1e-7"。这在插值不透明度时尤其明显。为了避免科学计数法,在过渡开始或结束时使用 1e-6:最小的值,不会以科学计数法被转换为字符串。

interpolateRound(a, b)

示例 · 源代码 · 返回两个数字 ab 之间的插值器。

js
d3.interpolateRound(20, 620)(0.821) // 513

插值器类似于 interpolateNumber,除了它会将结果值四舍五入到最接近的整数。

interpolateString(a, b)

示例 · 源代码 · 返回两个字符串 ab 之间的插值器。

js
d3.interpolateString("20px", "32px")(0.5) // "26px"

字符串插值器查找嵌入在 ab 中的数字,其中每个数字都是 JavaScript 理解的形式。一些将被检测到的数字的示例:-1423.141596.0221413e+23

对于嵌入在 b 中的每个数字,插值器将尝试在 a 中找到一个对应的数字。如果找到了对应的数字,则使用 interpolateNumber 创建一个数值插值器。字符串 b 的其余部分用作模板:字符串 b 的静态部分在插值过程中保持不变,插值的数值嵌入在模板中。

例如,如果 a"300 12px sans-serif",而 b"500 36px Comic-Sans",则会找到两个嵌入的数字。其余静态部分(字符串 b 的)是两个数字之间的空格(" ")和后缀("px Comic-Sans")。插值器在 t = 0.5 时结果为 "400 24px Comic-Sans"

interpolateDate(a, b)

示例 · 源代码 · 返回两个 日期 ab 之间的插值器。

js
d3.interpolateDate(new Date("2014-01-01"), new Date("2024-01-01"))(0.5) // 2019-01-01

注意

没有对返回的日期进行防御性复制;对于每次插值器评估,都会返回同一个 Date 实例。为了性能考虑,没有进行复制,因为插值器通常是 动画过渡 内部循环的一部分。

interpolateArray(a, b)

示例 · 源代码 · 返回两个数组 ab 之间的插值器。

js
d3.interpolateArray([0, 0, 0], [1, 2, 3])(0.5) // [0.5, 1, 1.5]

如果 b 为类型化数组(例如,Float64Array),则会改为调用 interpolateNumberArray.

在内部,会创建一个与 b 长度相同的数组模板。对于 b 中的每个元素,如果在 a 中存在对应的元素,则使用 interpolate 为这两个元素创建一个通用插值器。如果没有这样的元素,则在模板中使用 b 中的静态值。然后,对于给定的参数 t,评估模板的嵌入插值器。然后返回更新后的数组模板。

例如,如果 a 为数组 [0, 1],而 b 为数组 [1, 10, 100],则插值器在 t = 0.5 时的结果为数组 [0.5, 5.5, 100]

注意

没有对模板数组进行防御性复制;对返回数组的修改可能会对插值器的后续评估产生不利影响。为了性能考虑,没有进行复制;插值器通常是 动画过渡 内部循环的一部分。

interpolateNumberArray(a, b)

示例 · 源代码 · 返回两个数字数组 ab 之间的插值器。

js
d3.interpolateNumberArray([0, 1], Float64Array.of(1, 3))(0.5) // [0.5, 2]

在内部,会创建一个与 b 类型和长度相同的数组模板。对于 b 中的每个元素,如果在 a 中存在对应的元素,则直接在数组模板中对这些值进行插值。如果没有这样的元素,则复制 b 中的静态值。然后返回更新后的数组模板。

注意

没有对模板数组和参数 ab 进行防御性复制;对这些数组的修改可能会影响插值器的后续评估。

interpolateObject(a, b)

示例 · 源代码 · 返回两个对象 ab 之间的插值器。

js
d3.interpolateObject({x: 0, y: 1}, {x: 1, y: 10, z: 100})(0.5) // {x: 0.5, y: 5.5, z: 100}

在内部,会创建一个与 b 具有相同属性的对象模板。对于 b 中的每个属性,如果在 a 中存在对应的属性,则使用 interpolate 为这两个元素创建一个通用插值器。如果没有这样的属性,则在模板中使用 b 中的静态值。然后,对于给定的参数 t,评估模板的嵌入插值器,然后返回更新后的对象模板。

例如,如果a 是对象 {x: 0, y: 1}b 是对象 {x: 1, y: 10, z: 100},则插值器在t = 0.5 时返回的对象为 {x: 0.5, y: 5.5, z: 100}

对象插值在数据空间插值中特别有用,其中插值的是数据而不是属性值。例如,可以插值描述饼图中圆弧的对象,然后使用 arc 计算新的 SVG 路径数据。

注意

不会创建模板对象的防御性副本;对返回对象的修改可能会对插值器的后续评估产生负面影响。出于性能原因,不会创建副本;插值器通常是 动画过渡 内循环的一部分。

interpolateBasis(values)

示例 · 源代码 · 返回通过指定values 数组的均匀非有理 B 样条插值器,这些values 必须为数字。

js
d3.interpolateBasis([0, 0.1, 0.4, 1])(0.5) // 0.2604166666666667

隐式控制点是生成的,以便插值器在t = 0 时返回values[0],在t = 1 时返回values[values.length - 1]。另请参见 curveBasisinterpolateRgbBasis

interpolateBasisClosed(values)

示例 · 源代码 · 返回通过指定values 数组的均匀非有理 B 样条插值器,这些values 必须为数字。

js
d3.interpolateBasisClosed([0, 0.1, 0.4, 1])(0.5) // 0.45

控制点被隐式重复,以便生成的单维样条在t 在 [0,1] 中重复时具有循环 C² 连续性。另请参见 curveBasisClosedinterpolateRgbBasisClosed

interpolateDiscrete(values)

示例 · 源代码 · 返回给定values 数组的离散插值器。

js
d3.interpolateDiscrete(["red", "blue", "green"])(0.5) // "blue"

返回的插值器将t 在 [0, 1 / n) 中映射到values[0],t 在 [1 / n, 2 / n) 中映射到values[1],依此类推,其中n = values.length。实际上,这是一个轻量级的 quantize 刻度,具有 [0, 1] 的固定域。

quantize(interpolator, n)

示例 · 源代码 · 从指定的interpolator 返回n 个均匀间隔的样本,其中n 是大于一的整数。

js
d3.quantize(d3.interpolate("red", "blue"), 4) // ["rgb(255, 0, 0)", "rgb(170, 0, 85)", "rgb(85, 0, 170)", "rgb(0, 0, 255)"]

第一个样本始终位于t = 0,最后一个样本始终位于t = 1。这在从给定插值器生成固定数量的样本时很有用,例如从 连续插值器 推导出 quantize 刻度 的范围。

注意

此方法不适用于不返回其输出的防御性副本的插值器,例如 interpolateArrayinterpolateDateinterpolateObject。对于这些插值器,必须包装插值器并为每个返回值创建一个副本。

piecewise(interpolate, values)

示例 · 源代码 · 返回分段插值器,为每对相邻的values 合成插值器。

js
d3.piecewise(d3.interpolateRgb.gamma(2.2), ["red", "green", "blue"])

如果未指定interpolate,则默认为 interpolate

js
d3.piecewise(["red", "green", "blue"])

返回的插值器将t 在 [0, 1 / (n - 1)] 中映射到interpolate(values[0], values[1]),t 在 [1 / (n - 1), 2 / (n - 1)] 中映射到interpolate(values[1], values[2]),依此类推,其中n = values.length。实际上,这是一个轻量级的 线性刻度