使用D3数据()。输入()

时间:2014-07-20 03:01:40

标签: javascript svg d3.js coffeescript

以下玩具问题说明了我的问题。我有一系列“位置”,比如藏宝图。数组中的每个项目(例如怪物或宝藏)可以存在于地图上的多个位置。 e.g。

locations = [
  {name:'treasure', color: 'blue', coords:[[100,100], [200,300]]},
  {name:'monsters', color: 'red', coords:[[100,150], [220,420], [50,50]]}
]

现在我想用D3绘制这些图。糟糕/天真的方法(有效 - see here for fiddle)看起来像这样:

for location in locations
  for coords in location.coords
    svg.append('circle')
      .attr('cx', coords[0])
      .attr('cy', coords[1])
      .attr('r', 8)
      .style('fill', location.color)
      .datum(location)

然而,当我修改数据的内容时,我不想每次都要运行这个天真的代码。似乎使用data()和enter()是“正确”的方法,但我无法弄清楚它如何与子坐标一起工作。例如

svg.selectAll('circle').data(locations).enter().append('circle')
  .attr('cx', (d) -> d.coords[0][0])
  .attr('cy', (d) -> d.coords[0][1])
  .attr('r', 8)
  .style('fill', (d) -> d.color)

这很好用,但正如您所看到的,我只打印每个位置的FIRST坐标,我想在那里打印所有位置。我怀疑唯一的方法就是压扁我的数据阵列,这样总共有5个条目--3个怪物和2个宝物。

只是想知道是否有办法使用D3更好地处理这个问题。

1 个答案:

答案 0 :(得分:3)

为此,您需要nested selections。我们的想法是,不是每个数据项附加一个元素,而是附加几个元素。在代码中,它看起来像这样:

// append a `g` element for each data item to hold the circles
var groups = svg.selectAll("g.circle").data(locations)
   .enter().append("g").attr("class", "circle");

// now select all the circles in each group and append the new ones
groups.selectAll("circle")
   // the d in this function references a single data item in locations
   .data(function(d) { return d.coords; })
   .enter().append("circle")
   .attr("cx", function(d) { return d[0]; })
   .attr("cy", function(d) { return d[1]; });

对于更新和退出选择,它的工作原理相同。