D3:如何有条件地将SVG对象绑定到数据?

时间:2016-02-22 07:35:48

标签: javascript d3.js svg

我在这里有一组我正在使用D3可视化的对象。我将每个对象绑定到一个组元素,并附加一个依赖于某些对象属性的SVG图形,大致如下:

var iconGroups = zoomArea.selectAll("g.icons")
        .data(resources)
        .enter()
        .append("g")

var icons = iconGroups.append(function(d){
         if(d.type == "Apple"){
             return appleIcon;
         }else if(d.type == "Orange"){
             return orangeIcon;
         })

等。现在我想用额外的一行扩展其中一些图标。我可以为每个数据点添加一个行元素,并将它们设置为仅在适用的地方可见,但由于我只想将它们添加到100个数据点中的一个,这似乎效率低下。有没有办法将SVG行绑定到只有d.type == "Apple"

的对象

3 个答案:

答案 0 :(得分:1)

您可以为要选择的图标添加一个类(例如appleIcon),并在选择器中使用该类添加行。

答案 1 :(得分:1)

使用d3过滤器。

selection.filter(selector)

过滤选择,返回仅包含指定选择器为true的元素的新选择。

参考:https://github.com/mbostock/d3/wiki/Selections#filter

演示:http://bl.ocks.org/d3noob/8dc93bce7e7200ab487d

答案 2 :(得分:1)

我会为图标和线创建单独的选择,这样:

var iconGroups = zoomArea.selectAll('g.icons')
  .data(resources);
iconGroups
  .enter()
  .append('g')
  .classed('icons', true);
iconGroups.exit().remove();

var icons = iconGroups.selectAll('.icon').data(function(d) {return [d];});
icons
  .enter()
  .append(function(d) {
    if(d.type === 'Apple'){
      return appleIcon;
    }else if(d.type === 'Orange'){
      return orangeIcon;
    }        
  }).classed('icon', true);
icons.exit().remove();

var lines = iconGroups.selectAll('.line').data(function(d) {
  return d.type === 'Apple' ? [d] : [];
});
lines
  .enter()
  .append('line')
  .classed('line', true);
lines.exit().remove();

.exit()。remove()的添加只是因为我总是添加它以确保更新更好。 :)

也许代码比.filter()长,但我一直使用以下结构,并且它更容易扩展。

编辑:apropos comment - 如果你需要传递索引,你应该在绑定数据中传递它们:

var iconGroups = zoomArea.selectAll('g.icons')
  .data(resources.map(function(resource, index) {
    return Object.create(resource, {index: index})
  }));

(Object.create()仅用于不改变数据,你可以使用_.clone,Object.assign()或者只要它不打扰你就改变它)

然后您可以像访问它一样访问它:

lines.attr("x1", function(d){ console.log(d.index);})