首页 > 解决方案 > Trying to get two circles to transition simultaneously

问题描述

Trying to get two circles (one red, one blue) to move to center of screen from opposite directions. Can only get the second circle to do it - unsure as to why.

I tried everything from switching up the order of functions being called to switching variable names

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


    var circles = svg.append('circle')
    .attr('cx',50).attr('cy',50).attr('r',10).style('fill','red');

    var circlesTwo = svg.append('circle')
    .attr('cx',50).attr('cy',50).attr('r',10).style('fill','blue');

    animation();
    animationTwo();

    function animation() {
    svg.transition()
        .duration(750)
        .tween("precision", function() {
          var area = d3.interpolateRound(0, 300);
          return function(t) {
            minArea = area(t);
            render();
          };
          
        })
    }

    function animationTwo() {
    svg.transition()
        .duration(750)
        .tween("precision", function() {
          var area = d3.interpolateRound(600, 300);
          return function(t) {
            minArea = area(t);
            renderTwo();
          };
          
        })
    }

    function render() {
  
    circles.attr('cx',minArea);

    }

    function renderTwo() {
  
    circlesTwo.attr('cx',minArea);


    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Expected results are two circles coming to their respective positions (from off screen originally). Actual results are I am only getting my blue circle to work.

标签: javascriptd3.jsdata-visualization

解决方案


Applying the transitions to the SVG selection is not a very idiomatic D3: you should apply them to the elements that are moving (i.e., the circles). That, by the way, is the cause of the problem you're facing: one transition is cancelling the other.

This happens because since your transitions have no name, null is used (link):

selection.transition([name]) <>

Returns a new transition on the given selection with the specified name. If a name is not specified, null is used.

Then, because all of them have the same name (null), the last one cancels the first one:

The starting transition also cancels any pending transitions of the same name on the same element that were created before the starting transition.

Therefore, to apply multiple transitions to the same element, you have to name them:

function animation() {
    svg.transition("foo")
    //etc...
}

function animationTwo() {
    svg.transition("bar")
    //etc...
}

Here is your code with that change:

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

var circles = svg.append('circle')
  .attr('cx', 50).attr('cy', 50).attr('r', 10).style('fill', 'red');

var circlesTwo = svg.append('circle')
  .attr('cx', 50).attr('cy', 50).attr('r', 10).style('fill', 'blue');

animation();
animationTwo();

function animation() {
  svg.transition("foo")
    .duration(750)
    .tween("precision", function() {
      var area = d3.interpolateRound(0, 300);
      return function(t) {
        minArea = area(t);
        render();
      };

    })
}

function animationTwo() {
  svg.transition("bar")
    .duration(750)
    .tween("precision", function() {
      var area = d3.interpolateRound(600, 300);
      return function(t) {
        minArea = area(t);
        renderTwo();
      };

    })
}

function render() {

  circles.attr('cx', minArea);

}

function renderTwo() {

  circlesTwo.attr('cx', minArea);


}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Again, have in mind that I'm simply answering your question here: my advice is that you should refactor that transition code completely.


推荐阅读