d3-transition

transition(过渡)是一个类似于选集的接口,用于对DOM进行动画更改。过渡会在给定的持续时间内平滑地将DOM从当前状态修改到所需的目标状态,而不是立即应用变化。

要应用一个过渡,首先选择元素,调用selection.transition,然后进行期望的变化。例如:

d3.select("body")
  .transition()
    .style("background-color", "red");

过渡支持大多数选集方法(如transition.attrtransition.style可以代替selection.attr和selection.style),但不是所有的方法都是支持的;例如,你必须在过渡开始前添加元素或绑定数据。 transition.remove用于在过渡结束时移除元素。

为了计算中间状态,过渡借用了大量的内置插值器。自动检测颜色、数字和转换。还可以检测嵌有数字的字符串,因为这在样式和路径中很常见(如padding或font sizes)。使用transition.attrTweentransition.styleTweentransition.tween可以指定自定义插值器。

Installing

如果你使用npm,请键入npm install d3-transition。否则,请下载最新版本。你也可以直接从d3js.org加载,作为standalone library(独立库)或D3 4.0的一部分来使用。支持AMD,CommonJS和vanilla环境。在vanilla环境下,会输出一个全局的d3

<script src="https://d3js.org/d3-color.v1.min.js"></script>
<script src="https://d3js.org/d3-dispatch.v1.min.js"></script>
<script src="https://d3js.org/d3-ease.v1.min.js"></script>
<script src="https://d3js.org/d3-interpolate.v1.min.js"></script>
<script src="https://d3js.org/d3-selection.v1.min.js"></script>
<script src="https://d3js.org/d3-timer.v1.min.js"></script>
<script src="https://d3js.org/d3-transition.v1.min.js"></script>
<script>

var transition = d3.transition();

</script>

API Reference

Selecting Elements

过渡源于对选集调用selection.transition。你也可以使用d3.transition在文档根元素上创建一个过渡。

selection.transition([name])

以给定name返回给定选集的新过渡。如果不指定name,则使用null。新的过渡与其他同名过渡无关。

如果name过渡的一个实例,则返回的过渡具有与给定过渡相同的id和name。如果在选定的元素上已有具有相同id的过渡,则返回该元素现有的过渡。否则,返回过渡的timing将从每个选定元素的最近祖先上继承已有id相同的过渡的timing。因此,此方法可用于在多个选集之间同步过渡,或者给定元素重新选择一个过渡并修改其配置。例如:

var t = d3.transition()
    .duration(750)
    .ease(d3.easeLinear);

d3.selectAll(".apple").transition(t)
    .style("fill", "red");

d3.selectAll(".orange").transition(t)
    .style("fill", "orange");

如果在选定的节点或其祖先(例如,如果过渡已经结束)上没有找到给定的过渡,则使用默认的timing parameter;但是,在将来的版本中,这可能会更改为抛出一个错误。另请参阅#59

selection.interrupt([name])

根据给定name中断选定元素上已激活的过渡,并且根据给定name取消即将激活的过渡(如果有的话)。如果不指定name,则使用null。

中断元素上的过渡对其后代元素上的任何过渡都没有影响。例如,axis transition由多个后代G元素(刻度线,刻度标签,domain路径等)的独立的、同步的过渡组成。因此,要中断axis transition,你必须中断其后代:

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

universal selector(通用选择器)*选择所有后代元素。如果你也想中断G元素本身:

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

d3.interrupt(node[, name])

根据给定name中断给定node上已激活的过渡,并且根据给定name取消即将激活的过渡(如果有的话)。如果不指定name,则使用null。另请参阅selection.interrupt

d3.transition([name])

根据给定name返回根元素document.documentElement上的一个新过渡。如果不指定name,则使用null。新的过渡与其他同名过渡无关。name也可以是过渡的一个实例;另请参阅selection.transition。此方法相当于:

d3.selection()
  .transition(name)

此函数也可用于检测过渡(instanceof d3.transition)或者扩展过渡的原型。

transition.select(selector)

对于每个选定元素,选择与给定selector字符串匹配的第一个后代元素(如果有的话),并返回选择结果的过渡。selector可以指定为字符串或函数。如果为函数,它将对每个选定的元素求值,依次传递当前数据d和索引i,并将this上下文作为当前DOM元素。新的过渡与此过渡具有相同的id,name和timing;但是,如果选定的元素上已经具有相同id的过渡,则将返回该元素的现有过渡。

此方法相当于通过transition.selection选中此过渡,通过selection.select创建一个子过渡,然后通过selection.transition创建一个新的过渡。

transition
  .selection()
  .select(selector)
  .transition(transition)

transition.selectAll(selector)

对于每个选定元素,选择与给定selector字符串匹配的第一个后代元素(如果有的话),并返回选择结果的过渡。selector可以指定为字符串或函数。如果为函数,它对每个选定的元素求值,依次传递当前数据d和索引i,并将this上下文作为当前DOM元素。新的过渡与此过渡具有相同的id,name和timing;但是,如果选定的元素上已经具有相同id的过渡,则将返回该元素的现有过渡。

此方法相当于通过transition.selection选中此过渡,通过selection.selectAll创建一个子过渡,然后通过selection.transition创建一个新的过渡。

transition
  .selection()
  .selectAll(selector)
  .transition(transition)

transition.filter(filter)

对于每个选定元素,只选择与指定filter匹配的元素,并返回选择结果的过渡。filter可以指定为字符串或函数。如果为函数,它对每个选定的元素求值,依次传递当前数据d和索引i,并将this上下文作为当前DOM元素。新的过渡与此过渡具有相同的id,name和timing;但是,如果选定的元素上已经具有相同id的过渡,则将返回该元素的现有过渡。

此方法相当于通过transition.selection选中此过渡,通过selection.filter创建一个子过渡,然后通过selection.transition创建一个新的过渡。

transition
  .selection()
  .filter(filter)
  .transition(transition)

transition.merge(other)

返回一个新的过渡,将此过渡与其他过渡合并,该过渡必须具有与此过渡相同的id。返回的过渡具有与此过渡相同的groups,相同的parents以及相同的id。此过渡中任何缺失(null)的元素都将由other过渡中对应的元素填充(如果存在,且不为null)。

此方法相当于通过transition.selection选中此过渡,同样通过selection.merge合并来自other的过渡,然后通过selection.transition创建一个新的过渡。

transition
  .selection()
  .merge(other.selection())
  .transition(transition)

transition.transition()

返回与此过渡相同的选定元素的一个新过渡,将在此过渡结束后启动。新的过渡继承了一个参考时间,等于此过渡的time加上delayduration。新的过渡也继承了此过渡的name,duration,和easing。此方法可用于排定一系列链式过渡。例如:

d3.selectAll(".apple")
  .transition() // First fade to green.
    .style("fill", "green")
  .transition() // Then red.
    .style("fill", "red")
  .transition() // Wait one second. Then brown, and remove.
    .delay(1000)
    .style("fill", "brown")
    .remove();

每个过渡的延迟与其先前的过渡有关。因此,在上面的例子中,apples在最后一次转变为brown(棕色)前会保持一秒钟的red(红色)。

transition.selection()

返回与此过渡对应的选集

d3.active(node[, name])

根据给定name返回给定node已上激活的过渡(如果有的话)。如果不指定name,则使用null。如果给定node上没有对应激活的过渡则返回null。此方法可用于创建一系列链式过渡。例如,启动迪斯科模式:

d3.selectAll("circle").transition()
    .delay(function(d, i) { return i * 50; })
    .on("start", function repeat() {
        d3.active(this)
            .style("fill", "red")
          .transition()
            .style("fill", "green")
          .transition()
            .style("fill", "blue")
          .transition()
            .on("start", repeat);
      });

另请参阅chained transitions查看更多示例。

Modifying Elements

选择好元素并用selection.transition创建好过渡后,对文档内容使用过渡的转化方法。

transition.attr(name, value)

对于每个选中元素,根据给定name和目标value设置属性的attribute tween(属性补间)。补间的起始值为过渡开始时的属性值。目标value可以常量或函数,如果为函数,它将立即对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。

如果目标value为null,则在过渡开始时移除该属性。否则会根据目标value的类型选择一个插值器,使用以下算法:

  1. 如果value为数字,使用interpolateNumber.。
  2. 如果value为颜色或可以转换为颜色的字符串,使用interpolateRgb.。
  3. 使用interpolateString。

要想应用不同的插值器,使用transition.attrTween

transition.attrTween(name[, factory])

如果指定了factory且不为null,则根据给定name设置其属性的属性tween为给定factory。插值器工厂函数为一个函数,返回一个interpolator;当过渡开始时,它将对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。然后返回的插值器将被过渡每一帧按序调用,传入的eased时间t通常在[0,1]之间。最后,插值器的返回值将用于设置属性值。插值器必需返回一个字符串。(要想在过渡开始时移除一个属性,可以使用transition.attr;要想在过渡结束时移除个属性,可以使用transition.on监听结束事件)

如果给定factory为null,则根据给定name删除先前分配的属性不见。如果不指定factory,则根据给定name返回属性当前的插值器工厂函数,如果不存在相应的补间,则返回undefined。

例如,将fill属性从红色变为蓝色:

transition.attrTween("fill", function() {
  return d3.interpolateRgb("red", "blue");
});

或者从当前的fill改为blue,就像transition.attr

transition.attrTween("fill", function() {
  return d3.interpolateRgb(this.getAttribute("fill"), "blue");
});

或者应用一个自定义的彩虹插值器:

transition.attrTween("fill", function() {
  return function(t) {
    return "hsl(" + t * 360 + ",100%,50%)";
  };
});

此方法对于指定自定义插值器(如:理解SVG路径的)非常有用。一个有用技术是data interpolation, d3.interpolateObject用来插入两个数据值,然后用结果值(比如,一个shape)来计算一个新的属性值。

transition.style(name, value[, priority])

对于每个选中元素,根据给定namevaluepriority设置样式的style tween(样式补间)。补间的起始值为内联样式值(如果有的话),否则则为过渡开始时的计算值。目标value可以为常量或函数,如果为函数,它将立即对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。

如果目标value为null,则在过渡开始时移除该样式。否则会根据目标value的类型选择一个插值器,使用以下算法:

  1. 如果value为数字,使用interpolateNumber.。
  2. 如果value为颜色或可以转换为颜色的字符串,使用interpolateRgb.。
  3. 使用interpolateString。

要想应用不同的插值器,请使用transition.styleTween

transition.styleTween(name[, factory[, priority]]))

如果指定了factory且不为null,则根据给定name设置其样式补间为给定factory。插值器工厂函数为一个函数,返回一个插值器;当过渡开始时,它将对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。然后返回插值器将被过渡每一帧按序调用,传入的eased时间t通常在[0,1]之间。最后,插值器的返回值将用于根据priority设置样式值。插值器必需返回一个字符串。(要想在过渡开始时移除一个样式,可以使用transition.style;要想在过渡结束时移除一个样式,可以使用transition.on监听结束事件)

如果给定factory为null,则根据给定name删除先前分配的样式补间。如果不指定factory,则根据给定name返回样式当前的插值器工厂函数,如果不存在相应的补间,则返回undefined。

例如,将fill样式从红色改为蓝色:

transition.styleTween("fill", function() {
  return d3.interpolateRgb("red", "blue");
});

或者从当前的fill修改为蓝色,就像transition.style

transition.styleTween("fill", function() {
  return d3.interpolateRgb(this.style.fill, "blue");
});

或者应用一个自定义的彩虹插值器:

transition.styleTween("fill", function() {
  return function(t) {
    return "hsl(" + t * 360 + ",100%,50%)";
  };
});

此方法对于指定自定义插值器(如:data interpolation)非常有用, d3.interpolateObject用来插入两个数据值,然后用结果值(比如,一个shape)来计算一个新的样式值。

transition.text(value)

对于每个选中元素,在过渡开始时将text content设置为给定目标valuevalue可以为常量或函数,如果为函数,它将立即对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。函数返回值将用于设置每个元素的text content。null将清除内容。

要想在开始时插入文本而不是设置,可以使用transition.tween例子)或使用淡入淡出效果追加一个替代元素(子)。默认情况下不会插入文本,因为这通常是不可取的。

transition.remove()

对于每个选定元素,只要元素没有其他已激活或挂起的过渡,则在过渡结束时移除该元素。否则,不执行任何操作。

transition.tween(name[, value])

对于每个选中元素,根据给定namevalue函数设置补间。value必须为函数,且返回函数。当过渡开始后,它将对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。然后返回的函数将被过渡每一帧按序调用,传入的eased时间t通常在[0,1]之间。如果给定value为null,则根据给定name删除先前分配的补间(如果有的话)。

例如,将当前的fill修改为蓝色,就像transition.attr

transition.tween("attr.fill", function() {
  var node = this, i = d3.interpolateRgb(node.getAttribute("fill"), "blue");
  return function(t) {
    node.setAttribute("fill", i(t));
  };
});

此方法可用于指定自定义插值器,或执行side-effects,例如设置一个scroll-offset动画。

Timing

过渡的easingdelayduration是可以配置的。例如,单元素的延迟可用于元素的stagger the reordering,以提升视觉效果。另请参阅Animated Transitions in Statistical Data Graphics

transition.delay([value])

对于每个选中元素,设置过渡延迟为给定value(毫秒)。value可以为常量或函数,如果为函数,它将立即对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。然后,函数的返回值用于设置每个元素的过渡延迟。如果不指定过渡,则默认为0。

如果不指定value,则返回过渡中第一个(非null)元素的延迟的当前值。这通常只有当你知道过渡仅包含一个元素时有用。

将延迟设置为索引i的倍数是在一组元素之间交错过渡的便利方式。例如:

transition.delay(function(d, i) { return i * 10; });

当然,你也可以计算延迟,或者在计算基于索引的延迟前对选集进行排序。

transition.duration([value])

对于每个选中元素,设置过渡持续时间为给定value(毫秒)。value可以为常量或函数,如果为函数,它将立即对每个选中元素求值,按顺序传入当前数据d、索引i,并将this上下文作为当前DOM元素。然后,函数的返回值用于设置每个元素的过渡持续时间。如果不指定持续时间,则默认为250ms。

如果不指定value,则返回过渡中第一个(非null)元素的持续时间的当前值。这通常只有当你知道过渡仅包含一个元素时有用。

transition.ease([value])

为所有选择元素指定过渡easing函数value必须为一个函数。动画的每一帧都会调用easing函数,并传入正常的时间t(范围为[0,1]);它将返回一个eased后的时间(范围为[0,1])。一个良好的easing函数会在t=0时返回0,在t=1时返回1。如果不指定easing函数,则默认为d3.easeCubic

如果不指定value,则返回过渡中第一个(非null)元素当前的easing函数。这通常只有当你知道过渡仅包含一个元素时有用。

Control Flow

对于高级用法,过渡提供了自定义control flow(控制流)的方法。

transition.on(typenames[, listener])

为每个选中元素添加或移除一个监听给定事件typenameslistenertypenames为下列字符串事件类型中的一个:

  • start- 过渡开始。
  • end- 过渡结束。
  • interrupt- 过渡中断。

另请参阅The Life of a Transition。注意,这些都不是由selection.on和selection.dispatch实现的原生DOM事件,而是transition事件。

类型可以选择后跟一个句点(.)和一个name;可选的name允许注册多个回调函数以接收同一类型的多个事件。如start.foostart.bar。想要指定多个typenames,可以使用空格进行分隔,如interrupt endstart.foo start.bar

当选定节点上给定的过渡事件派发时,处于过渡中的元素将调用给定listener,传入当前数据d和索引i,并将this上下文作为当前DOM元素。监听器始终会检测到其对应元素的最新数据,但索引是选集的一个属性,在侦听器被分配时是固定的;想要更新索引,可以重新分配监听器。

如果选定元素上已经注册了一个typename相同的事件监听器,则将在添加新listener前移除原来的监听器。想要移除一个监听器,传入null作为listener。想要根据给定name移除所有的监听器,传入null作为listener.foo作为typenamefoo即为name);想要移除没有name的监听器,传入.作为typename

如果不指定listener,则返回第一个(非null)元素上给定事件typename当前分配的监听器(如果有的话)。如果指定了多个typename,则返回第一个匹配的监听器。

transition.each(function)

为每个选定元素调用给定的function,传入当前数据d和索引i,并将this上下文作为当前DOM元素。此方法可用于为每个选定元素调用任意代码,并有助于创建一个可同时访问父子数据的上下文。相当于selection.each。

transition.call(function[, arguments…])

调用一次给定function,并传入任意可选的arguments。返回此过渡。这相当于手动调用function,但有助于链式调用。例如,想要在一个可重用的函数中设置一些属性:

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

现在可以这样:

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

这相当于:

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

相当于selection.call。

transition.empty()

如果此过渡中没有(非null)元素,则返回true。相当于selection.empty。

transition.nodes()

返回一个包含此过渡中所有(非null)元素的数组。相当于selection.nodes。

transition.node()

返回此过渡中第一个(非null)元素。如果过渡为空,则返回null。相当于selection.node。

transition.size()

返回此过渡中的元素总数。相当于selection.size。

The Life of a Transition

创建一个偶读后立即调用,如selection.transitiontransition.transition,你可以使用一些方法配置过渡,如transition.delaytransition.durationtransition.attrtransition.style。指定目标值的方法(如,transition.attr)将同步求值;但是,需要有初始值的方法,如transition.attrTweentransition.styleTween,则必须等到过渡开始以后。

在创建之后不久,要么在当前帧的结尾,要么在下一帧中,将排定过渡。此时,延迟和start事件监听器不能再修改;如果尝试这样做则会显示一个错误:“太迟了:已经排定”(或者如果过渡结束了,“过渡未找到”)。

当过渡开始时,它会中断同一元素上相同名称的已激活的过渡(如果有的话),并将interrupt(中断)事件派发给已注册的监听器。(注意,中断发生在开始时,而不是创建时,因此,即使是零延迟过渡也不会立即中断已激活的过渡:会给旧的过渡最后一帧。使用selection.interrupt可立即中断。)启动过渡也会取消同一元素上相同名称的创建于其之前的挂起过渡。然后过渡将start事件派发给已注册的监听器。这是过渡可被修改的最后时刻:启动后,过渡的时间,补间和监听器都不可以再修改;如果尝试这样做则会显示一个错误:“太迟了:已经启动”(或者如果过渡结束了,“过渡未找到”)。过渡启动后会立即初始化其补间。

在过渡启动的这一帧,但在所有过渡都启动了这一帧后,过渡第一次调用其补间。限制补间的初始化数量),通常涉及从DOM中读取,通过避免交错读写DOM来提高性能。

对于过渡激活的每一帧,都将使用一个eased t-value(范围为[0,1])调用其补间。在每一帧中,过渡都将按注册顺序调用其补间。

当过渡结束,它将使用一个(非eased)t-value(值为1)最后一次调用其补间。然后将end事件派发给已注册的监听器。这是可以监测到过渡的最后时刻:结束后,过渡将从元素上移除,并销毁其配置。(在中断或取消时,一个过渡的配置也会被销毁。)试图监测已销毁的过渡将显示一个错误:“过渡未找到”

results matching ""

    No results matching ""