简体   繁体   English

D3在过渡时从时标中删除旧元素

[英]D3 remove old elements from time scale while transitioning

Simple SVG with time scale of last five seconds on x-axis where every second I'm adding a circle and every 100ms moving all existing circles from right to left. 简单的SVG,在X轴上的时间刻度为最后五秒,其中我每秒添加一个圆圈,每100ms从右向左移动所有现有的圆圈。

var data = [];

setInterval(function() {

    var now = new Date();
    var fiveSecAgo = new Date(now.getTime() - 5000);
    x.domain([fiveSecAgo, now]);

    svg.selectAll("circle")
        .transition()
        .ease("linear")
        .duration(100)
        .attr("cx", function(d) {
            return x(d.date);
        });

}, 100);

// add circle every second
setInterval(function() {
    data.push({
        date: new Date()
    });

    svg.selectAll("circle")
        .data(data).enter()
        .append("svg:circle")
        .attr("r", 4)
        .attr("cx", function(d) {
            return x(d.date);
        })
        .attr("cy", height / 2);

}, 1000);

Working fiddle 工作提琴

Now that is all good, but after first 5 seconds, there will be elements with negative x value (older than 5 seconds) so I'd like to remove them, keeping the smooth transitioning for existing elements within last 5 seconds. 现在一切都很好,但是在开始的5秒钟之后,会有x值为负(大于5秒)的元素,因此我想删除它们,并在最后5秒钟内保持现有元素的平滑过渡。

So my approach was to keep my data array containing only last 5 seconds: 所以我的方法是让我的数据数组只包含最后5秒:

for (var i = 0; i < data.length; i++) {
    if (data[i].date < fiveSecAgo) {
        data.shift();
    } else {
        break;
    }
}

before doing the transitioning of existing circles and then doing .exit().remove(). 在进行现有圆的过渡之前,然后执行.exit()。remove()。 Although the old elements will get removed, the transition is not smooth anymore. 尽管将删除旧元素,但过渡不再平滑。

The problem is that by default, D3 is matching data by index. 问题在于,默认情况下,D3按索引匹配数据。 That is, your modified data is matched to the wrong DOM elements and hence you see them moving in weird ways. 也就是说,您修改后的数据与错误的DOM元素匹配,因此您会看到它们以奇怪的方式移动。 This is easily fixed by providing a key function to .data() that tells D3 how to do the matching: 通过为.data()提供一个关键函数来轻松解决此问题,该函数告诉D3如何进行匹配:

.data(data, function(d) { return d.date; })

In addition, it's not safe to modify an array that you iterate over, so don't .shift() inside a loop. 另外,修改迭代的数组并不安全,因此不要在循环内使用.shift() In your case, it's enough to do 就您而言,这足以

if(data[0].date < fiveSecAgo) data.shift();

Complete demo here . 在此处完成演示。 I've cleaned up some other stuff as well. 我也清理了一些其他东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM