删除具有过渡的项目可防止在该期间添加它们

Removing items with a transition prevents them from being added during that period

我有一些数据偶尔会被删除和添加。这种情况不经常发生,但可以快速连续发生。

我发现 dataGroups.exit().transition()....remove() 'overrides' 输入 dataGroups.enter(...).append(...).transition()

似乎当一个项目被移除时,然后再次 'enters',它无法停止移除过程,所以项目要么被移除,要么处于被移除状态(例如透明或尺寸 0) .

这是一个工作示例,缓慢单击按钮,它会按预期工作,但如果速度太快,您会在应该出现的时候丢失下面的栏。

我尝试添加 interupt() 来尝试中断退出动画,但它似乎不起作用。找不到对此的任何参考,但我很惊讶这不是有人以前见过并提出解决方案的问题:

const dataset1 = [
  { name: "item 1", value: 200 },
  { name: "item 2", value: 100 }
];
const dataset2 = [{ name: "item 1", value: 100 }];
let currentDataset = undefined;

function refresh() {
  const newDataset = currentDataset === dataset1 ? dataset2 : dataset1;
  currentDataset = newDataset;

  // Join new data with old elements, if any.
  const dataGroups = d3
    .select(".vis")
    .selectAll(".box")
    .data(newDataset, (d) => d.name);

  // Remove old elements as needed.
  dataGroups
    .exit()
    .transition("remove")
    .duration(400)
    .attr("opacity", 0.2)
    .remove();

  // Create new elements as needed.
  const newGroups = dataGroups
    .enter()
    .append("rect")
    .attr("class", "box")
    .attr("height", 10);

  newGroups.transition("add").duration(400).attr("opacity", 1);

  // Merge and update
  newGroups
    .merge(dataGroups)
    .attr("width", (d) => d.value)
    .attr("y", (d, i) => i * 12);
}

document.getElementById("button").onclick = () => {
  refresh();
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <button id="button">Update data</button>

    <svg class="vis" width="200" height="30"></svg>

    <p>
      Click the button slowly, and see it add and remove elements with a
      transition
    </p>

    <p>
      Click the button twice in quick succession, and see it doesn't correctly
      represent the data
    </p>

    <p>It should look like:</p>
    <pre>
|====
|==
        </pre
    >
    <p>Or:</p>
    <pre>
|==
|
        </pre
    >
    <p>Never:</p>
    <pre>
|====
|
        </pre
    >

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

https://codesandbox.io/s/focused-almeida-dp58f?file=/src/index.js

首先,应该注意到 D3 selection 是不可变的,因此在您输入 selection 时使用 merge 是没有效果的。另外,如果你想正确地看到过渡,你应该将输入 selection 的不透明度设置为 0

回到问题,这里的问题是,当您 select 所有具有 box class 的元素时,退出柱被计算在内,因此您输入 select离子是空的。最简单的解决方案是使用 selection.interrupt()。与你所说的相反 interrupt 确实 有效,但问题只是因为你命名了退出转换,所以你需要使用相同的名称:

  dataGroups.interrupt("remove");

这是您的代码,其中包含该更改:

const dataset1 = [{
    name: "item 1",
    value: 200
  },
  {
    name: "item 2",
    value: 100
  }
];
const dataset2 = [{
  name: "item 1",
  value: 100
}];
let currentDataset = undefined;

function refresh() {
  const newDataset = currentDataset === dataset1 ? dataset2 : dataset1;
  currentDataset = newDataset;

  // Join new data with old elements, if any.
  let dataGroups = d3
    .select(".vis")
    .selectAll(".box")
    .data(newDataset, (d) => d.name);

  dataGroups.interrupt("remove");
  
  dataGroups.attr("opacity", 1);

  // Remove old elements as needed.
  dataGroups
    .exit()
    .transition("remove")
    .duration(400)
    .attr("opacity", 0.2)
    .remove();

  // Create new elements as needed.
  const newGroups = dataGroups
    .enter()
    .append("rect")
    .attr("class", "box")
    .attr("height", 10)
    .attr("opacity", 0)

  newGroups.transition("add").duration(400).attr("opacity", 1);

  // Merge and update
  dataGroups = newGroups.merge(dataGroups);

  dataGroups.attr("width", (d) => d.value)
    .attr("y", (d, i) => i * 12);
}

document.getElementById("button").onclick = () => {
  refresh();
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<!DOCTYPE html>
<html>

<head>
  <title>Parcel Sandbox</title>
  <meta charset="UTF-8" />
</head>

<body>
  <button id="button">Update data</button>

  <svg class="vis" width="200" height="30"></svg>

  <p>
    Click the button slowly, and see it add and remove elements with a transition
  </p>

  <p>
    Click the button twice in quick succession, and see it doesn't correctly represent the data
  </p>

  <p>It should look like:</p>
  <pre>
|====
|==
        </pre
    >
    <p>Or:</p>
    <pre>
|==
|
        </pre
    >
    <p>Never:</p>
    <pre>
|====
|
        </pre
    >

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

此外,我在中断过渡后放了一个 dataGroups.attr("opacity", 1);,所以我们 return 将渐变条的不透明度设置为 1。