【问题标题】:d3 Exit / Update function in animationd3 动画中的退出/更新功能
【发布时间】:2017-06-06 19:27:47
【问题描述】:

我正在尝试制作一个显示来自十个不同点的数据的动画。图形经过编码,因此传感器(通过圆圈显示)根据一小时内获得的总体数据(条目总数和平均速度)改变其颜色和大小。

通过这个条目 (Transition not working d3) 和来自这个 Gapminder 模拟的代码 (https://bost.ocks.org/mike/nations/),我已经能够为图表制作动画。但是,由于代码的结构,退出和更新功能不起作用。 1 小时的数据中的第一个条目只有一个对象,因此只绘制了一个圆圈。这个圆圈随着时间的推移而更新,但其他传感器未绘制(因此未更新)。

我正在考虑为每个传感器重新创建第一个空对象,以便在动画开始时绘制它们。但是,我想避免这种情况。

代码是这样的:

//FUNCTION TO GET THE DATA BY HOUR
function getDataByHour (hour) {
    var allBridges = new Array();
    var found;
    for (b = 0; b < boatsByHour.length; b++){
        bridges.forEach(function(br,i){
            if (boatsByHour[b].sensorID== br.id){
                xy = projection([br.longitude, br.latitude])}
        });
        if (boatsByHour[b].hour == hour){
            found = true;
            bridgeNumber = boatsByHour[b].sensorID;
            allBridges.push({
                "numberBoats": (boatsByHour[b].numberBoats),
                "speed": (boatsByHour[b].speedAvg),
                "bridge": boatsByHour[b].sensorID,
                "longitude": xy[0],
                "latitude": xy[1],
                "hour": boatsByHour[b].hour
            })
        }
    }
    return allBridges;
}

//SENSORS
var sensor = plot.append("g")
    .attr("class","bridges")
    .selectAll(".sensors")
    .data(getDataByHour(timeRange[0]))
    .call(animateSensors)
    .enter()
    .append("circle")
    .attr("class","sensors")
    .attr("cx", function(d,i){return d.longitude})
    .attr("cy", function(d,i){return d.latitude})
    .on("mouseover",function(d){console.log(d)});

sensor.exit().remove();

plot
    .transition()
    .duration(300000)
    .ease(d3.easeLinear)
    .tween("hour", tweenHour)

//FUNCTION THAT UPDATES THE ANIMATION
function animateSensors (sensor){
    sensor
        .attr("r",function(d){return radiusScale(d.numberBoats)})
        .style("fill",function(d){return colorScale(d.speed)});
}

function tweenHour(){
    var hour = d3.interpolateNumber (timeRange[0],timeRange[1]);

    return function(h){
        displayHour(hour(h))}
}

function displayHour(hour) {
    sensor.data(getDataByHour(Math.floor(hour))).call(animateSensors);
}

我尝试了不同的方法来包含 enter() 和 exit()。如果我添加 enter() 并将圆圈附加到“animateSensors”函数中,则会绘制所有圆圈(传感器)。但是它们没有被更新,所以最后,即使 exit().remove() 更新在其中,我也会在 SVG 中绘制数千个圆圈。

谢谢

【问题讨论】:

  • 是更新圆的半径和填充属性的函数function animateSensors (sensor){ sensor .attr("r",function(d){return radiusScale(d.numberBoats)}) .style("fill",function(d){return colorScale(d.speed)}); }
  • 调用位置不会改变结果(只显示一个圆圈)。我已经检查过了,问题是所有数据都直接进入那个圆圈,而不是绘制其他的
  • 是的,allBridges 是一个对象数组。这些对象的选择取决于时间属性hour
  • 这里的问题是sensor 是一个“输入”选择,您不能通过“输入”选择调用exit()。因此,该方法应该是创建一个“更新”选择,即:var sensor = plot.append("g").attr("class","bridges").selectAll(".sensors").data(getDataByHour(timeRange[0])),一个“进入”选择,即:sensor.enter().append("circle").etc... 和一个“退出”选择,即:sensor.exit().remove()
  • 是的,我昨天试过了,但是如果我这样做了,就根本没有进入animateSensors 函数。我有sensor ... ..data(getDataByHour(timeRange[0])); 然后sensorEnter (没有调用动画);然后是sensor.exit().remove();,最后是`sensor.transition().duration(500).call(animateSensors)`

标签: animation d3.js transitions


【解决方案1】:

好的,现在可以了。我不必调用数据的第一部分(仅绘制 1 个圆圈而不是总共 10 个圆圈),而是必须调用具有所有圆圈数据的数据(如最后一点):

var sensor = plot.append("g")
        .attr("class","bridges")
        .selectAll(".bridge")
        .data(getDataByHour(timeRange[1])) // instead of getDataByHour(timeRange[0])
        .enter()
        .append("circle")
        .attr("class",function(d){return "bridge " + d.bridge})
        .attr("cx", function(d,i){return d.longitude})
        .attr("cy", function(d,i){return d.latitude})
        .on("mouseover",function(d){console.log(d)});

得益于 tweenHour 函数,动画正确开始

function tweenHour(){
        var hour = d3.interpolateNumber (timeRange[0],timeRange[1]);

        return function(h){
            displayHour(hour(h))}
    }

【讨论】:

    猜你喜欢
    • 2020-03-24
    • 1970-01-01
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 2019-11-09
    相关资源
    最近更新 更多