通过绑定新数据来操纵元素

Ric*_*ard 17 javascript d3.js

我试图找出如何通过绑定新数据更新一些D3.js元素.我不确定这是否可能,但感觉应该是这样.

首先,我创建了四个SVG圈,并将cx偏移量设置为数据的函数:

 <body><div id="container"></div></body>

 var svg = d3.select("div.container").append("svg")
     .attr("class", "chart")
     .attr("width", 1000)
     .attr("height", 500);

  // Create initial data and display
  var data = [0, 10, 20, 30];
  var circle = svg.selectAll("circle")
      .data(data)
      .enter()
      .append('circle')
      .attr("cx", function(d) {
        return d*10;
      })
      .attr("cy", 100)
      .attr("r", 10)
      .style("fill", "steelblue");
Run Code Online (Sandbox Code Playgroud)

接下来,我附加新数据和转换.我希望看到圆圈慢慢移动到新位置(这就是我想要实现的目标),但他们没有:

  var data1 = [40, 50, 60, 70];
  circle.data(data1).transition().duration(2500);
Run Code Online (Sandbox Code Playgroud)

我是否犯了一个基本错误?也许我选错了.或者仅仅通过操纵数据来更新元素是不可能的?

更新:如果我这样做,console.log(circle)那么我会看到一组SVG圈元素,这正是我所期望的.

Phr*_*ogz 24

强大(但令人讨厌)D3.js有时会迫使你重复自己的简单可视化.如果你告诉它你想要以某种方式创建一个具有从数据派生的属性的元素,然后你想要将这些属性转换为新数据,你必须再次告诉它如何派生这些值(如果你想要的话)做一些不同的事情,比如不同的视觉布局.正如@Andrew所说,你必须告诉它在转换时该怎么做.

您可以通过以下模式解决此"问题":

var foo = d3.select('foo');
function redraw(someArray){
  var items = foo.selectAll('bar').data(someArray);
  items.enter().append('bar');
  items.exit().remove();
  items
    .attr('foo',function(d){ return d });
}
Run Code Online (Sandbox Code Playgroud)

在2.0中,当您将append()新项目enter()自动添加到原始数据绑定选择中时,attr()以后对其的调用将适用于它们.这使您可以使用相同的代码来设置初始值和更新值.

由于您不希望每次更新都重新创建SVG包装器,因此您应该在redraw函数外部创建它.

如果要执行转换:

function redraw(someArray){
  var items = foo.selectAll('bar').data(someArray);
  items.enter().append('bar')
    .attr('opacity',0)
    .attr('foo',initialPreAnimationValue);
  items.exit().transition().duration(500)
    .attr('opacity',0)
    .remove();
  items.transition.duration(500)
    .attr('opacity',1)
    .attr('foo',function(d){ return d });
}
Run Code Online (Sandbox Code Playgroud)

请注意,上面通过索引将对象与数据相关联.如果要删除中间数据点以在删除之前淡出该数据点(而不是删除最后一项并将每个其他项转换为看起来那样),那么您应该指定一个唯一的(非索引)字符串值来关联每个项目:

var data = [
  {id:1, c:'red',   x:150},
  {id:3, c:'#3cf',  x:127},
  {id:2, c:'green', x:240},
  {id:4, c:'red',   x:340}
];
myItems.data(data,function(d){ return d.id; });
Run Code Online (Sandbox Code Playgroud)

你可以看到一个这样的例子,并在我的D3.js游乐场玩它.

首先,看看当您注释掉其中一条数据线时会发生什么,然后再将其重新放回.接下来,ƒ('id')从第data()4行的调用中删除参数,然后再次尝试注释掉数据行.

编辑:或者,正如杰出的mbostock评论,您可以使用selection.call()可重用的函数作为干扰代码的方法:

var foo = d3.select('foo');
function redraw(someArray){
  var items = foo.selectAll('bar').data(someArray);
  items.enter().append('bar').call(setEmAll);
  items.exit().remove();
  items.call(setEmAll);
}

function setEmAll(myItems){
  myItems
    .attr('foo',function(d){ return d*2 })
    .attr('bar',function(d){ return Math.sqrt(d)+17 });
}
Run Code Online (Sandbox Code Playgroud)

如上所示,.call()调用一个函数并将选择作为参数传递,以便您可以在多个位置对选择执行相同的设置.

  • 周到的答案.你也可以用与[selection.call]兼容的方式编写`redraw`函数(https://github.com/mbostock/d3/wiki/Selections#wiki-call).相关:[走向可重复使用的图表](http://bost.ocks.org/mike/chart/). (2认同)