获取给定元素的活动(运行)D3 v3转换的标准方法是什么?

时间:2012-12-12 16:28:31

标签: javascript d3.js transitions

D3的抽象仍然让我的思绪弯曲,所以希望我能正确地呈现这一点。

在D3 版本3 中,给定一个元素(比如一个圆圈)和given only one transition possibly running per element什么是确定该元素当前运行转换的最佳方法,如果有的话一个人呢?

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

我在这里的更大目标是,如果只有转换到sub,则创建子转换。否则,我将创建一个新的过渡。

2 个答案:

答案 0 :(得分:3)

另一种方法:在每个存储实际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()方法来自动执行此操作。但是,您可能希望保留一种方法来指示是否要在任何计划的转换之后对新转换进行排队,或者是否要中断。

答案 1 :(得分:2)

简短的回答是,没有标准的方法来实现转换,而你并不打算这样做。如同,它不受支持。

稍微长一点的答案是,出于您的目的,您可以使用__transition__来破解它。我们的想法是检查__transition__是否存在,如果存在,请在开始新的(子)转换之前等到它不存在。

为此,有助于使用适当的函数扩展选择原型:

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

请注意,这里非常hacky 并且只有 过渡。你应该明白这个想法。

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

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毫秒),以便为紧跟前一个过渡的转换创建更好的印象。

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