如果满足条件,则在另一个过渡期间添加并发过渡 [英] Add a concurrent transition during another transition if a condition is met

查看:68
本文介绍了如果满足条件,则在另一个过渡期间添加并发过渡的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在过渡运行时添加一个新过渡,条件是,如果bar1宽度与bar2匹配,则钢筋会改变位置.

I am trying to add a new transition while a transition is running with a condition that if bar1 width matches bar2 then the bars change positions.

我已经使用transition().tween来查看条件是否得到满足.当第二个转换开始时,第一个停止.我希望第一个转换能够继续运行直到其持续时间结束,即使第二个转换已经开始也是如此.

I have used transition().tween to see if the condition is met. When the 2nd transition starts, the 1st stops. I want the 1st transition to continue running until the end of its duration even though the 2nd one has started.

我有代码,但无法在第二次转换中继续进行第一次转换.请帮忙.

I have the code code but am unable to continue the 1st transition during the 2nd. Please help.

window.i1 = 0;
window.i2 = 0;

var svg = d3.select("body")
   .append("svg")
   .attr("width", 500)
   .attr("height", 500);

var bar1 = svg.append("rect")
   .attr("fill", "green")
   .attr("x", 20)
   .attr("y", 40)
   .attr("height", 20)
   .attr("width", 40)

var bar2 = svg.append("rect")
   .attr("fill", "blue")
   .attr("x", 20)
   .attr("y", 70)
   .attr("height", 20)
   .attr("width", 20)

update();

function update() {
   bar1.transition()
     .ease(d3.easeLinear)
     .duration(2000)
     .attr("width",100)
     .tween("attr.fill", function() {
        var node = this;
        return function(t) {
         window.bar1width = node.getAttribute("width");
         var bl = check();

         if(bl=="true"&&window.i1==0){

            chnPos(); 
           window.i1=window.i1+1;
         }
       }
      })
 

   bar2.transition()
     .ease(d3.easeLinear)
     .duration(2000)
     .attr("width",120)
     .tween("attr.fill", function() {
        var node = this;
        return function(t) {
          window.bar2width = node.getAttribute("width");
          var bl = check();
          if(bl=="true"&&window.i2==0){
          chnPos();
          window.i2=window.i2+1;
        }
       }
      })
    }

function check() {
 if (window.bar2width>=window.bar1width){
   console.log(window.bar1width +' ' + window.bar2width);
   return "true";
 }
 //console.log(true)
return "false";

}

function chnPos(){
    bar1.transition()
      .ease(d3.easeLinear)
      .duration(500)
      .attr("y",70)
    bar2.transition()
      .ease(d3.easeLinear)
      .duration(500)
      .attr("y",40)
}

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.3.0/d3.min.js"></script>
  </head>
  <body>

      <script type="text/javascript" src="index.js"></script>
      </body>
</html>

推荐答案

在d3v4 +中,您可以有多个并发过渡,但是它们需要有单独的名称:

In d3v4+ you can have multiple concurrent transitions, but they need to have separate names:

selection.transition([name])<>

使用指定的值返回给定选择的新过渡 姓名.如果未指定名称,则使用null.新的过渡是 仅与同名的其他转换互斥. (文档)

selection.transition([name]) <>

Returns a new transition on the given selection with the specified name. If a name is not specified, null is used. The new transition is only exclusive with other transitions of the same name. (docs)

让我们为过渡添加一些名称,我在下面使用增长"和切换"

Let's add some names to the transitions, I use "grow" and "switch" below

window.i1 = 0;
window.i2 = 0;

var svg = d3.select("body")
   .append("svg")
   .attr("width", 500)
   .attr("height", 500);


var bar1 = svg.append("rect")
   .attr("fill", "green")
   .attr("x", 20)
   .attr("y", 40)
   .attr("height", 20)
   .attr("width", 40)

var bar2 = svg.append("rect")
   .attr("fill", "blue")
   .attr("x", 20)
   .attr("y", 70)
   .attr("height", 20)
   .attr("width", 20)
   
   update();

function update() {
    bar1.transition("grow")
       .ease(d3.easeLinear)
       .duration(2000)
       .attr("width",100)
       .tween("attr.fill", function() {
         var node = this;
           return function(t) {
             window.bar1width = node.getAttribute("width");
         var bl = check();

         if(bl=="true"&&window.i1==0){

         chnPos(); 
         window.i1=window.i1+1;
      }
    }
  })

  bar2.transition("grow")
    .ease(d3.easeLinear)
    .duration(2000)
    .attr("width",120)
    .tween("attr.fill", function() {
       var node = this;
         return function(t) {
            window.bar2width = node.getAttribute("width");
            var bl = check();
            if(bl=="true"&&window.i2==0){
              chnPos();
              window.i2=window.i2+1;
            }
          }
     })
 }

function check() {
 if (window.bar2width>=window.bar1width){
   //console.log(window.bar1width +' ' + window.bar2width);
   return "true";
 }
 //console.log(true)
return "false";

}

function chnPos(){
bar1.transition("switch")
      .ease(d3.easeLinear)
      .duration(500)
      .attr("y",70)
bar2.transition("switch")
      .ease(d3.easeLinear)
      .duration(500)
      .attr("y",40)

}

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.3.0/d3.min.js"></script>
  </head>
  <body>

      <script type="text/javascript" src="index.js"></script>
      </body>
</html>

我要补充一点,这可能可以简化一些-因为为每个元素单独创建过渡的方法会引入很多额外的代码.代码的复杂性还增加了每个附加栏的数量.您应该能够使用绑定数据和一些排序来在长度转换期间对具有转换的元素进行重新排序.也许是这样的(这是一个粗略的片段,肯定有更好的方法):

I'll just add that this can probably be simplified a fair bit - as the approach of creating a transition for each element individually introduces a lot of extra code. The complexity of your code also increases a fair bit for each additional bar. You should be able to use bound data and some sorting to re-order elements with transitions during the length transition. Perhaps something like (this is a rough snippet, there are surely better ways):

var data = [
 { start:200, current: 200, end: 40 },
 { start:120, current: 120, end: 240 },
 { start:10, current: 10, end: 260 }
];
var colors =["crimson","steelblue","lawngreen","orange"];

var svg = d3.select("body")
   .append("svg")
   .attr("width", 500)
   .attr("height", 500);
   
var bars = svg.selectAll("rect")
  .data(data)
  .enter()
  .append("rect")
  .attr("x", 20)
  .attr("y", function(d,i) { return i*30+20; })
  .attr("width", function(d) { return d.start; })
  .attr("height", 20)
  .attr("fill",function(d,i) { return colors[i]; })
  .on("click", order);


 
bars.transition("length")
  .attr("width", function(d) { return d.end; })
  .tween("attr.current", function(d,i) {
    var bar = d3.select(this);
	  var that = this;
    return function() { 
      d.current = +bar.attr("width");
      bars = bars.sort(function(a,b) { 
        return b.current - a.current; 
      }).order();
	  // trigger new transition if needed:
	  var nodes = bars.nodes();
	  if(nodes[i] != that) {
	     for(var j = 0; j < nodes.length; j++) {
		   if(nodes[j] == that) { i=j; break;}
		 }
	     order();
      }
    }
  })
  .duration(4000);

function order(bar) {
  bars.transition("order")
    .attr("y", function(d,i) { return i*30+20; })
	//.ease(d3.easeLinear)
}

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.3.0/d3.min.js"></script>
  </head>
  <body>

      <script type="text/javascript" src="index.js"></script>
      </body>
</html>

更多解释,我将分解第二个片段的主要过渡:

For a bit more explanation, I'll break down the second snippet's primary transition:

// Transition each bar's width/length:
bars.transition("length")

  // set the final width value:
  .attr("width", function(d) { return d.end; })

  // Modify the datum throughout the transition
  // This function is called once for each element
  // This means we need to update d,i manually during the transition
  .tween("attr.current", function(d,i) {

    // Keep track of an individual bar being transitioned (element & selection):
    var bar = d3.select(this);
    var that = this;

    // This function is invoked each tick for each bar:
    return function() { 
      // Update a bar's datum to reflect current width: 
      d.current = +bar.attr("width");
      // Sort the bars based on current width:
      bars = bars.sort(function(a,b) { 
        return b.current - a.current; 
      })
      .order(); // Pull up the longest bar so it is drawn last (if there is overlap, it will be on top)

      // trigger new transition if needed:
      // Has the bar being transitioned been moved in the selection? 
      // If so, nodes[i] will not equal the element being moved (that)
      var nodes = bars.nodes();
      if(nodes[i] != that) {
         // If it has been moved, update i to reflect the element's new index
         for(var j = 0; j < nodes.length; j++) {
           if(nodes[j] == that) { i=j; break;}
         }
         // And apply the transition on the vertical spacing:
         order();
      }
    }
  })
  .duration(4000);

如果不检查节点顺序是否已更改,则将重复触发第二个过渡,以替换先前的第二个过渡.默认情况下使用d3.easeCubic会导致此结果最明显:转换开始很慢.如果不断重新启动第二个过渡,则第二个过渡将永远不会很快移动,直到第一个过渡完成.上面的摘录也可能是个问题,但前提是快速接班的地点发生了很多变化.

这篇关于如果满足条件,则在另一个过渡期间添加并发过渡的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆