D3 - 如何将相同的数据绑定到多个对象?

时间:2013-07-18 18:29:08

标签: 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.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]);
    });
});

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

3 个答案:

答案 0 :(得分:2)

我会为g中的条目创建myData元素:

groups = d3.select('body').append('svg')
           .selectAll('g').data(myData).enter()
           .append('g');

并将形状单独附加到这些组元素:

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

答案 1 :(得分:2)

也许,你想要的是d3中的.datum()功能。其中一个具体的用例是将相同的数据绑定到多个DOM元素(即将一个数据绑定到整个d3选择)。

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

直接从https://github.com/mbostock/d3/wiki/Selections#datum

报价
  

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

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

然而,这是对你的问题的字面答案;你的问题可能有一个更加面向设计的答案,这可能解释了处理你整体目标的“常规”d3方式......在这种情况下,你应该参考一些教程,比如

http://mbostock.github.io/d3/tutorial/circle.html

答案 2 :(得分:0)

TLDR;

使用 Selection.data key ”参数函数。

  

A key function may be specified to control which datum is assigned to which element «This function is evaluated for each selected element, in order, […] The key function is then also evaluated for each new datum in data, […] the returned string is the datum’s key.

(搜索《如果未指定键功能…》段落)

更多详细信息...

D3将数据绑定到元素。默认情况下使用«join-by-index»方法(首先找到的元素映射到索引0处的原点,依此类推……)。如果按索引联接不足以正确标识元素,则应使用 Selection.data key ”,以便D3在渲染阶段正确同步输入数据集: “更新”(调用data()方法的结果),“创建” 输入选择,“删除”(退出选择)。

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

const dataSet = [
  [ 15, "#440154" ]
  [ 238.58, "#414487" ]
  // ...
]

我们首先决定使用<rect>元素绘制彩色正方形。

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();

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

  

… If multiple elements have the same key, the duplicate elements are put into the exit selection …

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

// 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();