D3.js:“飞行中”;添加到数组中的元素不会刷新SVG图形

D3.js: "On the fly" added elements to array are not refreshing the svg graphic

本文关键字:元素 数组 图形 SVG 刷新 添加 js 飞行 飞行中 D3      更新时间:2023-09-26

我有一个气泡行,在任何给定的时间我有6个气泡。该数组有6个json对象。代码只显示加载时首先添加的圆圈。但是当我修改数组时,我想要删除第一个泡泡,并在行右端添加一个泡泡。我使用setInterval将元素插入到数组中以进行测试。数组正在正确地改变,因为我正在记录数组的状态,但svg图形没有刷新。我只是不知道问题是否在于重新利用createElementGroup()或如何在这种情况下删除节点(我看到常见的情况是使用exit() d3方法,但我不确定在这种特殊情况下在哪里实现它)。

另外,当我删除和添加元素时,我应该在哪里放置过渡以使其平滑?现场演示在这里:

http://codepen。io/juanf03/pen/BQyYBq(您可以点击气泡看到它展开并显示数据,通过这种方式我检查这是正确的节点)

代码:

//listener that will be executed on setIntervalCheck to update the graphic   
setInterval(function(){
  moveForwardOnBubbleList();
  createElementGroup();
  }, 100000);

var profile_pic_url="https://scontent.fsst1-2.fna.fbcdn.net/v/t1.0-9/13680856_103268503450198_1479797031996897052_n.jpg?oh=f43bced91822fb210c8be8a410825da9&oe=58D46460";
var dataset = [{unique_followers: 5, profile_pic:profile_pic_url}, {unique_followers: 10, profile_pic:profile_pic_url},{ unique_followers: 15, profile_pic:profile_pic_url}, { unique_followers: 20, profile_pic:profile_pic_url}, { unique_followers: 25, profile_pic:profile_pic_url}, {unique_followers: 40, profile_pic:profile_pic_url} ];
var w=600,h=600;
var svg=d3.select("body").append("svg")
                                  .attr("width",w)
                                  .attr("height",h);
//1st level:All circles group
var circlesGroup = svg.append("g").classed("general-group",true);
//2nd level: Group of circle and text
var elementGroup;
var circle;
var circleAttributes;
//create g's of existing data
createElementGroup();
elementGroup.on('click', function(d,i){
  var that=this;
  d3.selectAll('.element-group').each(function(d,i) {
    if(this.id!==that.id){
      d3.select(this).classed("selected",false);
    }
  });
  d3.select(this).classed("selected", !d3.select(this).classed("selected"));
  });
//adding circular background image to the circles
//var circlesSelection=svg.selectAll('circle');

function createElementGroup(){
  elementGroup = circlesGroup
  .selectAll('circle')
  .data(dataset)
  .enter()
  .append("g").classed("element-group",true);
  circle=elementGroup.append('circle');
  circleAttributes = circle
  .attr("r", 20)
  .attr("stroke","black")
  .attr("fill", "white")
  .classed("circle",true);
  //text to show
   elementGroup.append("text")
      .attr("text-anchor", "middle")
   .text(function(d) {
     return parseInt(d.unique_followers);
   })
     .style("pointer-events","none")
     .classed('tweet-number', true);
     //image to show as background
  //element group positioning for the text to be inside circle
  elementGroup.attr("transform", function(d,i){
    return "translate(" + (i*80+45) + "," + h/2 + ")"; 
});
  elementGroup.attr( "fill-opacity", 0 ).transition().duration(500).attr( "fill-opacity", 1 );
  elementGroup.attr("id", function(d, i) { return "c"+i; });

}
function addBubbleLast(){
    dataset.push({unique_followers: 40, profile_pic:profile_pic_url});
}
function removeFirstBubble(){
  dataset.shift();
}
function moveForwardOnBubbleList(){
  addBubbleLast();
  removeFirstBubble();
}

/*CSS*/
 body
        {
          /*padding-top: 50px;*/
          padding-left: 100px;
        }
        .tweet-number{
         opacity:0.25;
        }
        .circle{
        }

        .selected *{
          transform: scale(2);
          transition: all 0.5s ease, opacity 0.5s ease;
          opacity:1.0;
    }

编辑:修复了Gerardo Furtado的伟大建议之后的代码。我把它贴出来,以防有人遇到类似的问题:

//listener that will be executed on setIntervalCheck to update the graphic   
setInterval(function(){
  moveForwardOnBubbleList();
  createElementGroup();
  }, 6000);

var profile_pic_url="https://scontent.fsst1-2.fna.fbcdn.net/v/t1.0-9/13680856_103268503450198_1479797031996897052_n.jpg?oh=f43bced91822fb210c8be8a410825da9&oe=58D46460";
var dataset = [{unique_followers: 5, profile_pic:profile_pic_url}, {unique_followers: 10, profile_pic:profile_pic_url},{ unique_followers: 15, profile_pic:profile_pic_url}, { unique_followers: 20, profile_pic:profile_pic_url}, { unique_followers: 25, profile_pic:profile_pic_url}, {unique_followers: 40, profile_pic:profile_pic_url} ];
var w=900,h=600;
var svg=d3.select("body").append("svg")
                                  .attr("width",w)
                                  .attr("height",h);
//1st level:All circles group
var circlesGroup = svg.append("g").classed("general-group",true);
//2nd level: Group of circle and text
var elementGroup;
var circle;
var circleAttributes;
//create g's of existing data
createElementGroup();

//adding circular background image to the circles
//var circlesSelection=svg.selectAll('circle');

function createElementGroup(){
  elementGroup = circlesGroup
  .selectAll('.element-group')
  .data(dataset, function(d){ return d.unique_followers});
 //doesn't work the exit transition 
   var elementExit = elementGroup.exit().transition().duration(1000).style("opacity", 0).remove();
  var elementEnter = elementGroup.enter()
  .append("g").classed("element-group",true).style("opacity",0);
    elementEnter.merge(elementGroup).attr("transform", function(d,i){
   //option 1 generation by mod   
   if(i%2===0){   
    return "translate(" + (i*80+45) + "," + h/1.55 + ")"; 
   }else{
    return "translate(" + (i*80+45) + "," + h/1.45 + ")"; 
   }
  /*   
  //option 2 random
  var random= (Math.random() * (1.6 - 1.45) + 1.45).toFixed(4);
         return "translate(" + (i*80+45) + "," + h/random + ")";*/ 

}).transition().duration(2000).style("opacity", 1.0);
    circle=elementEnter.append('circle');

  circleAttributes = circle
  .attr("r", 20)
  .attr("stroke","black")
  .attr("fill", "white")
  .classed("circle",true);
  d3.selectAll('.element-group').on('click', function(d,i){
  var that=this;
  d3.selectAll('.element-group').each(function(d,i) {
    if(this.id!==that.id){
      d3.select(this).classed("selected",false);
    }
  });
  d3.select(this).classed("selected", !d3.select(this).classed("selected"));
  });
  //text to show
   var texts = elementEnter.append("text")
      .attr("text-anchor", "middle")
   .text(function(d) {
     return parseInt(d.unique_followers);
   })
     .style("pointer-events","none")
     .classed('tweet-number', true);
     //image to show as background
  //element group positioning for the text to be inside circle

}
function addBubbleLast(){
  var random=Math.floor(Math.random() * (40)) + 1;

    dataset.push({unique_followers: random, profile_pic:profile_pic_url});
}
function removeFirstBubble(){
  dataset.shift();
}
function moveForwardOnBubbleList(){
  addBubbleLast();
  removeFirstBubble();
}
//CSS
    body
    {
      /*padding-top: 50px;*/
      padding-left: 100px;
    }
    .tweet-number{
     opacity:0.25;
    }
    .circle{
    }
 .selected *{
      transform: scale(2);
      transition: all 0.5s ease;
      opacity:1.0;
}
.element-group *{
  transition: all 0.5s ease;
}
circle + text{
}

你需要一个"进入","退出"answers"更新"选项。

首先,我们绑定数据(使用一个键函数):

elementGroup = circlesGroup
    .selectAll('.element-group')
    .data(dataset, function(d){ return d.unique_followers});

然后,我们设置回车选择:

var elementEnter = elementGroup.enter()
    .append("g").classed("element-group",true);

现在一个重要的注意事项:因为这是D3 v4。x,您需要merge的选择有一个工作的更新选择:

elementEnter.merge(elementGroup).attr("transform", function(d,i){
    return "translate(" + (i*80+45) + "," + h/2 + ")"; 
});

最后,退出选择:

var elementExit = elementGroup.exit().remove();

这是你的CodePen: http://codepen.io/anon/pen/Wobyem

在我的情况下,我有svg圆圈,必须.remove()他们,并添加全新的相同的类。但在d3.selectAll(".dynamic_child).on("click"...上没有注册。我找到了一个不深入d3.js的解决方案,而是使用jQuery

我的解决方案如下:

$( ".static_parent" ).on("click", '.dynamic_child', function(){
    console.log("I'm working!")
    }

其中static_parent是您保留的父div, dynamic_child是您可以删除和添加的元素(html或svg)。

原文