首页 > 解决方案 > D3.js 在具有不同持续时间的每个元素上重复转换

问题描述

我正在尝试沿圆形路径转换点。每个变换都有不同的持续时间。结束时,一旦具有最短速度持续时间的变换结束,所有点的过渡就会重新开始。如何独立地为每个点重新开始过渡?

const graphWidth = 500;
const graphHeight = 500;
const svg = d3.select("svg")
  .attr("width", graphWidth)
  .attr("height", graphHeight);
const testData = [{
    "country": "Netherlands",
    "speed": 4000
  },
  {
    "country": "Belgium",
    "speed": 2000
  },
  {
    "country": "Austria",
    "speed": 1000
  },
  {
    "country": "Germany",
    "speed": 5000
  },
  {
    "country": "USA",
    "speed": 4000
  }
];

const dots = svg.selectAll('circle')
  .data(testData)
  .enter()
  .append('circle')
  .attr('transform', `translate(${graphWidth / 2}, ${graphHeight / 2})`)
  .attr('cx', 223)
  .attr('r', 5)
  .attr('fill', 'yellow')
  .attr('stroke', 'black');


function transition() {
  svg.selectAll('circle').each(function(d) {
    d3.select(this)
      .transition()
      .ease(d3.easeLinear)
      .duration(d.speed)
      .attrTween('transform', rotTween)
      .on('end', transition);
  })
}
transition();

function rotTween() {
  var i = d3.interpolate(0, 360);
  return function(t) {
    return `translate(${graphWidth / 2}, ${graphHeight / 2}) rotate(${i(t)}, 0, 0)`;
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>

标签: d3.js

解决方案


最简单的方法是通过取出函数来改变你的transition函数来处理一个圆的一个转换.each()

const graphWidth = 500;
const graphHeight = 500;
const svg = d3.select("svg")
  .attr("width", graphWidth)
  .attr("height", graphHeight);
const testData = [{
    "country": "Netherlands",
    "speed": 4000
  },
  {
    "country": "Belgium",
    "speed": 2000
  },
  {
    "country": "Austria",
    "speed": 1000
  },
  {
    "country": "Germany",
    "speed": 5000
  },
  {
    "country": "USA",
    "speed": 4000
  }
];

const dots = svg.selectAll('circle')
  .data(testData)
  .enter()
  .append('circle')
  .attr('transform', `translate(${graphWidth / 2}, ${graphHeight / 2})`)
  .attr('cx', 223)
  .attr('r', 5)
  .attr('fill', 'yellow')
  .attr('stroke', 'black');


function transition(circle, d) {
  d3.select(circle)
    .transition()
    .ease(d3.easeLinear)
    .duration(d.speed)
    .attrTween('transform', rotTween)
    .on('end', function() {
      transition(circle, d);
    });
}

svg.selectAll('circle').each(function(d) {
  transition(this, d);
});

function rotTween() {
  var i = d3.interpolate(0, 360);
  return function(t) {
    return `translate(${graphWidth / 2}, ${graphHeight / 2}) rotate(${i(t)}, 0, 0)`;
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>

或者,您可以命名您传递给的其他匿名函数.each()(在这种情况下我命名它repeat),然后在.on("end"子句中再次调用该函数

const graphWidth = 500;
const graphHeight = 500;
const svg = d3.select("svg")
  .attr("width", graphWidth)
  .attr("height", graphHeight);
const testData = [{
    "country": "Netherlands",
    "speed": 4000
  },
  {
    "country": "Belgium",
    "speed": 2000
  },
  {
    "country": "Austria",
    "speed": 1000
  },
  {
    "country": "Germany",
    "speed": 5000
  },
  {
    "country": "USA",
    "speed": 4000
  }
];

const dots = svg.selectAll('circle')
  .data(testData)
  .enter()
  .append('circle')
  .attr('transform', `translate(${graphWidth / 2}, ${graphHeight / 2})`)
  .attr('cx', 223)
  .attr('r', 5)
  .attr('fill', 'yellow')
  .attr('stroke', 'black');

svg.selectAll('circle')
  .each(function repeat(d) {
    d3.select(this)
      .transition()
      .ease(d3.easeLinear)
      .duration(function(d) { return d.speed; })
      .attrTween('transform', rotTween)
      .on("end", repeat);
  });

function rotTween() {
  var i = d3.interpolate(0, 360);
  return function(t) {
    return `translate(${graphWidth / 2}, ${graphHeight / 2}) rotate(${i(t)}, 0, 0)`;
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>


推荐阅读