javascript - 删除带有过渡的项目会阻止在该期间添加它们

标签 javascript d3.js

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

我发现dataGroups.exit().transition()....remove()“覆盖”了输入dataGroups.enter(...).append (...).transition().

似乎当一个项目被删除,然后再次“进入”时,它无法停止删除过程,因此该项目要么被删除,要么处于删除状态(例如透明或尺寸 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 选择是不可变的,因此按照您的方式在输入选择上使用 merge 没有效果。另外,如果您想正确地看到过渡,您应该将输入选择的不透明度设置为 0

回到问题,这里的问题是,当您选择具有 box 类的所有元素时,退出栏会被计数,因此您的输入选择为空。最简单的解决方案是使用 selection.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);,因此我们将淡入淡出栏的不透明度返回到 1。

关于javascript - 删除带有过渡的项目会阻止在该期间添加它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70596918/

相关文章:

javascript - D3 Zoom 的 translateExtent 未按预期工作

d3.js - 使用 .update、.enter 和 .exit 更新条形图?

javascript - D3 - 向简单折线图添加网格

javascript - Bootstrap 文件输入

javascript - Ionic、Cordova、Phonegap 加载消息

javascript - 如何使用 JS 或 JQuery 对表格进行滚动加载?

javascript - 热图矩形内的标签

javascript - Suitescript 2.0 ResultSet.Each 回调函数超过 4000

javascript - Javascript 中的 For 循环与 while 循环

javascript - D3力布局仅显示一个链接