我有一些数据,有时会删除和添加数据。这种情况并不经常发生,但可能会快速连续发生。
我发现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/