Skip to content

控制流

🌐 Control flow

对于高级用法,转换提供了自定义控制流的方法。

🌐 For advanced usage, transitions provide methods for custom control flow.

生命过渡

🌐 The life of a transition

在创建过渡后立即,例如通过 selection.transitiontransition.transition,你可以使用诸如 transition.delaytransition.durationtransition.attrtransition.style 等方法来配置过渡。指定目标值的方法(如 transition.attr)是同步评估的;然而,需要插值起始值的方法,如 transition.attrTweentransition.styleTween,必须延迟到过渡开始时才能执行。

🌐 Immediately after creating a transition, such as by selection.transition or transition.transition, you may configure the transition using methods such as transition.delay, transition.duration, transition.attr and transition.style. Methods that specify target values (such as transition.attr) are evaluated synchronously; however, methods that require the starting value for interpolation, such as transition.attrTween and transition.styleTween, must be deferred until the transition starts.

创建后不久,无论是在当前帧结束时还是在下一帧期间,都会安排过渡。在此时,延迟和 start 事件监听器可能无法再更改;如果尝试更改,会抛出错误,提示消息为“太晚:已安排” (或者如果过渡已经结束,则提示“未找到过渡”)。

🌐 Shortly after creation, either at the end of the current frame or during the next frame, the transition is scheduled. At this point, the delay and start event listeners may no longer be changed; attempting to do so throws an error with the message “too late: already scheduled” (or if the transition has ended, “transition not found”).

当随后过渡开始时,它会中断同一元素上同名的活动过渡(如果有的话),并向已注册的监听器分发一个 interrupt 事件。(注意,中断发生在开始时,而不是创建时,因此即使是零延迟的过渡,也不会立即中断活动过渡:旧过渡会有一个最终帧。使用 selection.interrupt 可以立即中断。)开始的过渡也会取消同一元素上在其之前创建的任何同名待处理过渡。然后,过渡向已注册的监听器分发一个 start 事件。这是对过渡进行修改的最后时刻:过渡运行时,其定时、补间和监听器都不能更改;尝试更改会抛出错误,消息为“太晚:已在运行”(如果过渡已结束,则为“未找到过渡”)。过渡在开始后立即初始化其补间。

🌐 When the transition subsequently starts, it interrupts the active transition of the same name on the same element, if any, dispatching an interrupt event to registered listeners. (Note that interrupts happen on start, not creation, and thus even a zero-delay transition will not immediately interrupt the active transition: the old transition is given a final frame. Use selection.interrupt to interrupt immediately.) The starting transition also cancels any pending transitions of the same name on the same element that were created before the starting transition. The transition then dispatches a start event to registered listeners. This is the last moment at which the transition may be modified: the transition’s timing, tweens, and listeners may not be changed when it is running; attempting to do so throws an error with the message “too late: already running” (or if the transition has ended, “transition not found”). The transition initializes its tweens immediately after starting.

在帧过渡开始时,但在此帧开始的所有过渡都已启动之后,过渡会首次调用其缓动。批量初始化缓动,通常涉及从 DOM 中读取数据,通过避免交错的 DOM 读写来提高性能。

🌐 During the frame the transition starts, but after all transitions starting this frame have been started, the transition invokes its tweens for the first time. Batching tween initialization, which typically involves reading from the DOM, improves performance by avoiding interleaved DOM reads and writes.

对于每一帧处于过渡状态的帧,它都会以从 0 到 1 的 缓动 t 值调用其补间。在每一帧中,过渡会按照注册的顺序调用其补间。

🌐 For each frame that a transition is active, it invokes its tweens with an eased t-value ranging from 0 to 1. Within each frame, the transition invokes its tweens in the order they were registered.

当过渡结束时,它会最后一次以(非缓动的)t 值为 1 调用其 tween。然后它向已注册的监听器派发 end 事件。这是最后一次可以检查过渡的时刻:过渡结束后,过渡会从元素中被删除,其配置也会被销毁。(过渡的配置在中断或取消时也会被销毁。)在过渡被销毁后尝试检查它会抛出错误,错误信息为“未找到过渡”。

🌐 When a transition ends, it invokes its tweens a final time with a (non-eased) t-value of 1. It then dispatches an end event to registered listeners. This is the last moment at which the transition may be inspected: after ending, the transition is deleted from the element, and its configuration is destroyed. (A transition’s configuration is also destroyed on interrupt or cancel.) Attempting to inspect a transition after it is destroyed throws an error with the message “transition not found”.

selection.interrupt(name)

来源 · 中断所选元素上指定 name 的活动过渡,并取消任何待处理的使用指定 name 的过渡(如果有)。如果未指定名称,则使用 null。

中断一个元素上的过渡不会影响其任何后代元素上的过渡。例如,一个 轴过渡 由轴的后代 G 元素 上的多个独立、同步的过渡组成(刻度线、刻度标签、域路径等)。因此,要中断轴过渡,必须中断其后代元素:

🌐 Interrupting a transition on an element has no effect on any transitions on any descendant elements. For example, an axis transition consists of multiple independent, synchronized transitions on the descendants of the axis G element (the tick lines, the tick labels, the domain path, etc.). To interrupt the axis transition, you must therefore interrupt the descendants:

js
selection.selectAll("*").interrupt();

通用选择器*,选择所有后代元素。如果你还想选择 G 元素本身:

🌐 The universal selector, *, selects all descendant elements. If you also want to interrupt the G element itself:

js
selection.interrupt().selectAll("*").interrupt();

interrupt(node, name)

来源 · 中断指定 node 上的指定 name 的活动过渡,并取消任何待处理的同名过渡(如果有)。如果未指定名称,则使用 null。另请参见 selection.interrupt

transition.end()

来源 · 返回一个在每个选定元素完成过渡时解决的 promise。如果任何元素的过渡被取消或中断,promise 将被拒绝。

transition.on(typenames, listener)

来源 · 为每个选定的元素添加或移除指定事件 typenames监听器typenames 是以下字符串事件类型之一:

  • start - 当过渡开始时。
  • end - 当过渡结束时。
  • interrupt - 当过渡被中断时。
  • cancel - 当过渡被取消时。

请参阅 过渡的生活 了解更多。注意,这些 不是selection.onselection.dispatch 实现的原生 DOM 事件,而是过渡事件!

🌐 See The Life of a Transition for more. Note that these are not native DOM events as implemented by selection.on and selection.dispatch, but transition events!

类型后面可选择性地跟一个点(.)和一个名称;可选名称允许注册多个回调以接收同一类型的事件,例如 start.foostart.bar。要指定多个类型名,请用空格分隔类型名,例如 interrupt endstart.foo start.bar

🌐 The type may be optionally followed by a period (.) and a name; the optional name allows multiple callbacks to be registered to receive events of the same type, such as start.foo and start.bar. To specify multiple typenames, separate typenames with spaces, such as interrupt end or start.foo start.bar.

当在选定的节点上分发指定的过渡事件时,指定的监听器将被调用以处理过渡元素,并传入当前数据(d)、当前索引(i)和当前组(nodes),同时this为当前的 DOM 元素。监听器总是看到其元素的最新数据,但索引是选择的属性,并在分配监听器时固定;要更新索引,需要重新分配监听器。

🌐 When a specified transition event is dispatched on a selected node, the specified listener will be invoked for the transitioning element, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element. Listeners always see the latest datum for their element, but the index is a property of the selection and is fixed when the listener is assigned; to update the index, re-assign the listener.

如果在所选元素上之前已经为同一个 typename 注册了事件监听器,则在添加新监听器之前会先移除旧监听器。要移除监听器,请将 listener 传递为 null。要移除给定名称的所有监听器,请将 listener 传递为 null,并将 .foo 作为 typename,其中 foo 是名称;要移除所有未命名的监听器,请将 . 指定为 typename

🌐 If an event listener was previously registered for the same typename on a selected element, the old listener is removed before the new listener is added. To remove a listener, pass null as the listener. To remove all listeners for a given name, pass null as the listener and .foo as the typename, where foo is the name; to remove all listeners with no name, specify . as the typename.

如果未指定listener,则返回在第一个(非空)选定元素上为指定事件typename分配的当前监听器(如果有)。如果指定了多个类型名,则返回第一个匹配的监听器。

🌐 If a listener is not specified, returns the currently-assigned listener for the specified event typename on the first (non-null) selected element, if any. If multiple typenames are specified, the first matching listener is returned.

transition.each(function)

来源 · 对每个选定的元素调用指定的函数,传入当前的数据(d)、当前的索引(i)和当前的组(nodes),并将this作为当前的 DOM 元素。此方法可用于对每个选定元素调用任意代码,并且对于创建同时访问父级和子级数据的上下文非常有用。等同于 selection.each

transition.call(function, ...arguments)

来源 · 精确调用指定的函数一次,同时传入此转换和任何可选的参数。返回此转换。这等同于手动调用函数,但便于方法链。例如,要在可重用函数中设置多个属性:

js
function color(transition, fill, stroke) {
  transition
      .style("fill", fill)
      .style("stroke", stroke);
}

现在说:

🌐 Now say:

js
d3.selectAll("div").transition().call(color, "red", "blue");

这等同于:

🌐 This is equivalent to:

js
color(d3.selectAll("div").transition(), "red", "blue");

等同于 selection.call

🌐 Equivalent to selection.call.

transition.empty()

来源 · 如果此转换不包含任何(非空)元素,则返回 true。等同于 selection.empty

transition.nodes()

· 返回此转换中所有(非空)元素的数组。等同于 selection.nodes

transition.node()

来源 · 返回此转换中的第一个(非空)元素。如果转换为空,则返回 null。等同于 selection.node

transition.size()

来源 · 返回此转换中的元素总数。 等同于 selection.size