【问题标题】:Chaining transitions using the transition.end() promise使用 transition.end() 承诺链接转换
【发布时间】:2019-06-13 03:49:12
【问题描述】:

transition.end() 承诺解决时,我试图通过调用我的update 函数来链接转换。以下 sn-p 位于此 update 函数中。这个 sn-p 是其中一部分的完整示例,可以在 https://jsfiddle.net/fmgreenberg/1npLeguh/10/ 找到。

let t = d3
    .transition()
    .duration(3000)
    .end()
    .then(() => update(newData));

问题是转换几乎是瞬间发生的,然后可视化会在那里停留约 3 秒,直到再次调用更新。为什么是这样?如果我注释掉 sn-p 的最后两行,则转换需要预期的 3 秒。 (当然,在这种情况下只有一个转换,因为我已经删除了循环。)

【问题讨论】:

    标签: javascript animation d3.js data-visualization es6-promise


    【解决方案1】:

    不要命名过渡实例,而是在过渡选择本身中使用承诺:

    d3.select("#figure")
        .selectAll("circle")
        .data(newData, d => d)
        .transition()
        .duration(3000)
        .attr("cx", (_, i) =>
          i < N ? (i + 1) * (2 * r + s) : 300 - (i - N + 1) * (2 * r + s)
        )
        .end()
        .then(() => update(newData));
    

    这里是更新的 JSFiddle:https://jsfiddle.net/k9gf8ybL/

    以及相应的 S.O. sn-p:

    let N = 5;
    let r = 5;
    let s = 2;
    
    let data = d3.range(2 * N);
    
    d3.select("#figure")
      .selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("cx", (_, i) =>
        i < N ? (i + 1) * (2 * r + s) : 300 - (i - N + 1) * (2 * r + s)
      )
      .attr("cy", 26)
      .attr("r", r)
      .attr("stroke", "blue")
      .attr("fill", d => (d < N ? "white" : "black"));
    
    update(data);
    
    function update(data) {
      let I = data.slice(0, N);
      let J = data.slice(N, 2 * N);
      let i = randInt(N);
      let x = I[i];
      let j = randInt(N);
      let y = J[j];
      let newData = [
        ...I.slice(0, i),
        ...I.slice(i + 1),
        y,
        ...J.slice(0, j),
        ...J.slice(j + 1),
        x
      ];
    
      d3.select("#figure")
        .selectAll("circle")
        .data(newData, d => d)
        .transition()
        .duration(3000)
        .attr("cx", (_, i) =>
          i < N ? (i + 1) * (2 * r + s) : 300 - (i - N + 1) * (2 * r + s)
        )
        .end()
        .then(() => update(newData));
    }
    
    function randInt(n) {
      return Math.floor(Math.random() * n);
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.0/d3.min.js"></script>
    <svg id="figure" viewBox="0 0 300 50" style="background-color: papayawhip; border-radius: 1rem" xmlns="http://www.w3.org/2000/svg"></svg>

    但是,如果出于任何原因您仍想使用命名转换实例,只需使用更常见的 on("end"...) 方法而不是 end() 承诺:

    let t = d3
        .transition()
        .duration(3000)
        .on("end", () => {
          update(newData)
        });
    

    然后:

    selection.transition(t)
        //etc...
    

    这是采用这种方法的 JSFiddle:https://jsfiddle.net/8od3vkc1/

    【讨论】:

    • 根据github.com/d3/d3-transition#transition_ontransition.on("end", callback) 将为选择中的每个元素触发一次callback。我希望它在整个过渡结束时触发一次,即整个选择一次,因此我使用end() 承诺。在您的第二个解决方案中,回调是否只触发一次,因为您在转换本身而不是选择上定义了它?
    • 是的,它只触发一次,但你是对的:它在特定场景中只触发一次,如果你在转换选择中使用它,就像我回答中的第一个 sn-p 一样,它会为每个元素触发。
    猜你喜欢
    • 2015-07-08
    • 2013-12-03
    • 1970-01-01
    • 2016-11-06
    • 2015-04-15
    • 2023-01-27
    • 2015-01-21
    • 2016-01-17
    • 1970-01-01
    相关资源
    最近更新 更多