d3按顺序运行函数内部的动画

时间:2018-12-26 23:28:22

标签: javascript html animation d3.js

我正在尝试按顺序运行动画。这是一个例子。

function rect1() {
  d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}
function rect2() {
  d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}
function highlightRect(id) {
  d3.select(id)
    .style("fill", "yellow")
} 

所以我想创建一个这样的函数,以便可以依次rect1()rect2()highlightRect()(在每个动画结束之后)运行它们。

function startAnim (f1, f2, f3, f3a) {
  f1();
  f2();
  f3(f3a);
}
startAnim(rect1, rect2, highlightRect, "#r1");

我已经尝试过类似的操作,但是当有更多动画时,它会变得混乱。

// rect1
d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50)
    .on("end", () => {
      // rect2
      d3.select("svg")
        .append("rect")
        .attr("id", "r2")
        .attr("x", 300)
        .attr("y", 50)
        .attr("height", 0)
        .attr("width", 0)
        .transition()
        .duration(1000)
        .attr("height", 30)
        .attr("width", 50)
        .on("end", ....);
    });;

这可能是一个无知的问题,可以用诺言来做到吗?

谢谢

2 个答案:

答案 0 :(得分:-1)

您可能不需要Promises,因为您似乎想在开始下一个动画之前等待每个动画完成,因此这不是异步操作。我很难测试一下,但是我认为您可以将每个连续的函数作为上一个函数的参数来传递。看起来像这样:

function rect1(next) {
  d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
  next();
}

function rect2(next) {
  d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
  next();
}
function highlightRect(id, next) {
  d3.select(id)
    .style("fill", "yellow")
  next();
}

然后...

function startAnim(f1, f2, f3, f3a) {
  f1(f2(f3(f3a)));

startAnim(rect1, rect2, highlightRect, '#r1');

坦率地说,我不确定这是否适合您的情况,但值得尝试。

答案 1 :(得分:-1)

对这些进行承诺实际上很容易:

首先,我们将使函数返回要链接的对象。

function rect1() {
  return d3.select("svg")
    .append("rect")
    .attr("id", "r1")
    .attr("x", 300)
    .attr("y", 100)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}

function rect2() {
  return d3.select("svg")
    .append("rect")
    .attr("id", "r2")
    .attr("x", 300)
    .attr("y", 50)
    .attr("height", 0)
    .attr("width", 0)
    .transition()
    .duration(1000)
    .attr("height", 30)
    .attr("width", 50);
}

function highlightRect(id) {
  return d3.select(id)
    .style("fill", "yellow")
}

然后,我们可以使用通用的高阶函数为我们分配那些函数。

// Returns a promise that resolves after the given
// animation function finishes. Can optionally take args as a second parameter
// obviously this could just take a function and allow consumers
// to use anonymous functions for parameter-binding, but this function
// relies on the return value, so this is, maybe, slightly less easy to
// break on accident.
function runAnimation(fn, ...args) {
    return new Promise(resolve => fn(...args).on("end", resolve));
}

然后将它们链接起来非常简单:

runAnimation(rect1)
  .then(() => runAnimation(rect2))
  .then(() => runAnimation(highlightRect, "#r1"))

在这里创建一个需要一系列功能的助手也很容易。

未经测试,但我认为总体思路可以解决。