Data binding D3-如何将同一数据绑定到多个对象?

Data binding D3-如何将同一数据绑定到多个对象?,data-binding,d3.js,Data Binding,D3.js,我试图在一个选择中使用相同的数据绘制多个形状,因此假设我有: myData = [ { shape: 'rect', attr: { width: 100, height: 100, x: 100, y:100 } } , { shape: 'circle', attr: {cx, cy, etc...} } ] node.selectAll('*').data([myData]); myData.ob

我试图在一个选择中使用相同的数据绘制多个形状,因此假设我有:

myData = [
    { 
        shape: 'rect',
        attr: { width: 100, height: 100, x: 100, y:100 }
    } , {
        shape: 'circle',
        attr: {cx, cy, etc...}
    }
]

node.selectAll('*').data([myData]);

myData.obj.forEach(function(obj) {
    // Append different shapes based on data
    var shape = node.enter().append(obj.shape);
    Object.keys(obj.attrs).forEach(function(attr) {
        // Bind attrs to shapes based on data
        shape.attr(attr, obj.attrs[attr]);
    });
});

这里的node是一个“g”元素,myData是一个单独的数据对象。我的目标是基于myData修改g中的子形状,因此,如果稍后绑定另一个myData并再次调用此函数,则可以更新这些子形状。但我相信我的数据只绑定到第一个附加的形状。有没有一种方法可以轻松地将相同的数据绑定到多个形状?

我将创建一个
g
元素,以便在
myData
中输入:

groups = d3.select('body').append('svg')
           .selectAll('g').data(myData).enter()
           .append('g');
并将形状分别附加到这些组元素:

groups.append('rect')
groups.append('circle')

也许,这里需要的是d3中的
.datum()
函数。它的一个特定用例是将同一个基准绑定到多个DOM元素(即,将一个基准绑定到整个d3选择)

例如,
d3.selectAll('div').datum({foo:'bar'})
将同一对象
{foo:'bar'}
绑定到文档上当前存在的所有
..
元素

直接引用

selection.datum([value])
…如果指定了
value
,则设置元素的 将数据绑定到所有选定元素上的指定值。如果
是一个常数,所有元素都有相同的数据[sic]

(有点讽刺的是,他在解释.datum()函数时将常量数据称为“数据”)

然而,这是对你问题的字面回答;对于您的问题,可能会有一个更面向设计的答案,这可能解释了处理总体目标的“传统”d3方式。。。在这种情况下,您可能应该参考一些教程,如

TLDR; 使用Selection.data“key”参数函数

(搜索«如果未指定键函数…»段落)

更多细节… D3将数据绑定到元素。默认情况下,is使用«按索引连接»方法(首先找到的元素映射到索引0处的基准面,依此类推…)。如果按索引联接不足以正确标识元素,则应使用Selection.data“key”,以便D3在呈现阶段正确同步输入数据集:“update”(数据()方法调用的结果),“creation”输入选择,“remove”(退出选择)

假设我们需要绘制一些图例,给定以下数据集

const dataSet = [
  [ 15, "#440154" ]
  [ 238.58, "#414487" ]
  // ...
]
我们首先决定使用
元素绘制彩色正方形

const updateSelection = d3.select('rect').data(dataSet);
// join-by-index strategy is enough here so there is no need to supply the key fn arg
// Key function could be `d => d[0]` (given data source cannot produce two entries
// with value at index 0 being the same, uniqness is garanteed)

updateSelection.enter()
    .append('rect')
    .attr('width', 15).attr('height', 15)
    .merge(updateSelection)
    .style('fill', d => d[1])
;

// Dispose outdated elements
updateSelection.exit().remove();

我们现在需要为每个给定的数据绘制一个
元素,以直观地显示数值。保持按索引连接(默认)策略将导致D3首先绘制rect和text元素,但由于只能有一个元素绑定到特定的数据键,在更新阶段只考虑第一个找到的元素,并且具有相同基准键的任何其他元素将在退出选择中结束,并在调用选择移除方法时从DOM中移除

解决方案是将数值与元素nodeName连接起来


谢谢你的回答,这就是我正在做的。我所说的节点已经是一个“g”元素了。我希望“g”中的形状根据数据发生变化,因此它们也需要以某种方式进行绑定。你能发布myData的示例吗?@AdamPearce谢谢你的评论,请查看myData结构的更新问题。谢谢你的回答,这个问题几乎是一年前提出的,该项目早就结束了。我最初的意图是将一个巨大的实体绑定到画布上,画布包含多个子组件,如果母实体的属性发生变化,这些子组件将发生变化。我后来做了一个更好的实现,实际进入画布并将这些单独的属性绑定到单独的组件上,并在这些属性发生更改时循环这些属性以更新子实体。尽管如此,你的回答是最具信息性的,我将接受它作为将来的参考。
// Notice how the selector has changed
const updateSelection = d3.select('rect, text').data(dataSet, function(d) { 
      // Concatenate the numeric value with the element nodeName
      return `${d[0]}:${this.nodeName}`;
  })
  , enterSelection = updateSelection.enter()
;

// Add rect element
enterSelection
    .append('rect').attr('width', 15).attr('height', 15)
    .merge(updateSelection)
    .style('fill', d => d[1])
;

// Add text label
enterSelection
    .append('text')
    .merge(updateSelection)
    .text(d => d[0])
;

// Dispose outdated elements
updateSelection.exit().remove();