web-dev-qa-db-ja.com

d3:さまざまな選択で遷移を適切に連鎖させる方法

私は人気のあるd3ライブラリのV3を使用しており、基本的に3つのトランジションが必要です。最初のトランジションは出口選択に適用され、2番目は更新選択に適用され、3番目は入力選択に適用されます。それらは、選択の1つが空の場合、それぞれの遷移がスキップされるようにチェーンする必要があります。つまり出口の選択がない場合、更新の選択はすぐに開始されます。これまでのところ、私はこのコードを思いついた(delay関数を使用)。

_// DATA JOIN
var items = d3.select('#data').selectAll('.item');
items = items.data(data, function(d){ 
    return d.Twitter_screenname;
});


// EXIT
items.exit().transition().duration(TRANSITION_DURATION).style('opacity', 0).remove();

// UPDATE
// Divs bewegen
items.transition().duration(TRANSITION_DURATION).delay(TRANSITION_DURATION * 1)
    .style('left', function(d, i) {
        return positions[i].left + "px";
    }).style('top', function(d, i) {
        return positions[i].top + "px";
    });

// ENTER
// Divs hinzufügen
var div = items.enter().append('div')
    .attr('class', 'item')
    .style('left', function(d, i) {
        return positions[i].left + "px";
    }).style('top', function(d, i) {
        return positions[i].top + "px";
    });

 div.style('opacity', 0)
    .transition().duration(TRANSITION_DURATION).delay(TRANSITION_DURATION * 2)
    .style('opacity', 1);
_

まず第一に、遷移を「スキップ」することはできません。第二に、delayよりも良い方法があると思います。 http://bl.ocks.org/mbostock/3903818 を見てきましたが、何が起こっているのかよくわかりませんでした。

また、どういうわけか、items.exit().transition().duration(TRANSITION_DURATION).remove()を書くだけではitemsは機能しません。おそらく、それらはSVG要素ではなくdivsであるためです。

21
wnstnsmth

承知しました。これが2つの方法です。

まず、明示的な delay を使用できます。次に、 selection.empty を使用して計算し、空の遷移をスキップします。 (これは、すでに持っているもののマイナーな変更にすぎません。)

var div = d3.select("body").selectAll("div")
    .data(["enter", "update"], function(d) { return d || this.textContent; });

// 2. update
div.transition()
    .duration(duration)
    .delay(!div.exit().empty() * duration)
    .style("background", "orange");

// 3. enter
div.enter().append("div")
    .text(function(d) { return d; })
    .style("opacity", 0)
  .transition()
    .duration(duration)
    .delay((!div.exit().empty() + !div.enter().empty()) * duration)
    .style("background", "green")
    .style("opacity", 1);

// 1. exit
div.exit()
    .style("background", "red")
  .transition()
    .duration(duration)
    .style("opacity", 0)
    .remove();

http://bl.ocks.org/mbostock/5779682

ここで注意が必要なのは、更新要素でトランジションを作成する必要があることですbefore入力要素でトランジションを作成します。これは、 enter.append 入力要素を更新選択にマージし、それらを別々に保ちたいためです。詳細については、 更新のみの移行の例 を参照してください。

または、 transition.transition から chain transitions 、および transition.each を使用して、これらの連鎖遷移を既存の選択に適用することもできます。 transition.eachのコンテキスト内で、selection.transitionは、新しい遷移を作成するのではなく、既存の遷移を継承します。

var div = d3.select("body").selectAll("div")
    .data(["enter", "update"], function(d) { return d || this.textContent; });

// 1. exit
var exitTransition = d3.transition().duration(750).each(function() {
  div.exit()
      .style("background", "red")
    .transition()
      .style("opacity", 0)
      .remove();
});

// 2. update
var updateTransition = exitTransition.transition().each(function() {
  div.transition()
      .style("background", "orange");
});

// 3. enter
var enterTransition = updateTransition.transition().each(function() {
  div.enter().append("div")
      .text(function(d) { return d; })
      .style("opacity", 0)
    .transition()
      .style("background", "green")
      .style("opacity", 1);
});

http://bl.ocks.org/mbostock/577969

後者はもう少し慣用的だと思いますが、transition.eachを使用して(デフォルトのパラメータで遷移を導出するのではなく)選択範囲に遷移を適用することは、広く知られた機能ではありません。

33
mbostock