13

D3 的抽象仍然让我心烦意乱,所以希望我能正确地呈现这一点。

在 D3版本 3中,给定一个元素(比如一个圆圈),并且给定每个元素可能只运行一个转换,如果有的话,确定该元素上当前正在运行的转换是什么的最佳方法是什么?

我知道我可以手动检查__transition__元素(尽管也欢迎帮助),但我真的希望有更高级别的东西。

我更大的目标是创建一个子转换 if-and-only-if 有一个到 sub 的转换。否则,我将创建一个新的过渡。

4

2 回答 2

4

d3.transition另一种方法:在存储实际对象数组的每个节点上创建自己的属性。创建新过渡时,从数组中获取最后一个过渡并创建子过渡。

复杂之处在于您的新过渡可能不是基于与活动过渡相同的选择。.each()因此,我在调用中基于每个元素创建新的“安全”转换。

function saveTransition(t) {
    //save the transition immediately (don't wait for "start")
    //clear it on "end"
    t.each(function() {
        var tArr = this.__tObj__
        if (!tArr) tArr = this.__tObj__ = [];

        tArr.push(t);
        //console.log("saving ", t, " for ",this);
      } )
     .each("end", function() {
        var test =  this.__tObj__.shift();
        // console.log("clearing ", t, " from " ,this, 
         //            (test == t ? "correctly" : "ERROR") );
       } );
}
function newSafeTransition(node) { 
    var tArr = node.__tObj__; 
    if ( tArr && tArr.length ) {

        var t = tArr[ tArr.length - 1 ];
        return t.filter( function(){ return this === node; } )
                .transition().call(saveTransition);
    }
    else {
        return  d3.select(node).transition().call(saveTransition);
    }
}

d3.selectAll("div.foo")
    .transition().duration(3000)
    .call( saveTransition )
    .style("left", "100px");

d3.selectAll("div.bar")
    .transition().duration(3000)
    .call( saveTransition )
    .style("top", "100px");

setTimeout( function() { 
    console.log("blue");

    d3.selectAll("div.blue")
      .each( function() {
            newSafeTransition(this).style("color", "blue");
        });
}, 1000);

setTimeout( function() { 
    console.log("reposition");

    d3.selectAll("div.foo")
      .each( function() {
            newSafeTransition(this).style("left", "0px");
        });
}, 2000);

http://jsfiddle.net/7SQBe/3/

它可能会被清理掉,你甚至可以重写selection.transition()transition.transition()方法来自动执行此操作。但是,您可能希望保留一种方法来指示您是要在任何预定的转换之后将新转换排队还是要中断。

于 2014-03-01T20:06:03.170 回答
3

简短的回答是,没有标准的方式来实现过渡,你也不是要这样做。如,不支持。

稍长一点的答案是,出于您的目的,您可能可以使用__transition__. 这个想法是检查是否__transition__存在,如果存在,等到它不存在才开始新的(子)转换。

为此,它有助于使用适当的功能扩展选择原型:

d3.selection.prototype.getTransition = function() {
  if(this[0][0].__transition__) {
    return this[0][0].__transition__[1];
  } else return undefined;
}

请注意,这在这里非常hacky,并且只有在选择中只有一个元素和一个transition时才会起作用。不过,您应该明白这一点。

现在,我们可以使用这个函数来确定一个转换是否正在运行。

if(sel.getTransition() !== undefined) {
  // transition is there
} else {
  // no transition
}

不幸的是,__transition__不允许您重建过渡对象,即以下内容不起作用。

sel.getTransition().transition()...

因此,要模拟在当前运行完成后开始的子转换,请使用setTimeout检查是否有东西在运行,一旦没有,就开始新的转换:

function check() {
  if(sel.getTransition() !== undefined) {
    setTimeout(check, 100);
  } else {
    sel.transition().duration(1000)...;
  }
}
check();

您可以减少检查之间的间隔(此处为 100 毫秒),以更好地印象紧跟前一个的过渡。

完整的例子在这里。请注意,在几乎所有情况下,在某处保留对过渡对象的引用并使用它要容易得多,也更好。这个例子实际上只是作为一个 hacky 的概念证明。

于 2014-03-01T00:09:46.357 回答