使用D3,我发现自己做了很多这样的事情:
selectAll('foo').data(['foo']).enter().append('foo')
我想简单地添加一个节点(如果它还不存在),因为我需要在DOM树中的不同位置进行更新,而且我方便的数据并不完全与DOM平行。< / p>
这是否表明我应该重新构建我的数据以使其 并行,或者是否有一种不那么愚蠢的模式,人们会使用这种“创建如果缺少”的东西?
答案 0 :(得分:16)
D3实现了DB世界中众所周知的JOIN + INSERT / UPDATE / DELETE模式。在d3中,您首先选择一些DOM元素,然后将其与数据连接:
//join existing 'g.class' DOM elements with `data` elements
var join = d3.select('g.class').data(data)
//get the join pairs that did not have 'g.class' join partner and
//INSERT new 'g.class' DOM elements into the "empty slots"
join.enter().append('g').attr('class', 'class')
//get the join pairs that did not have a `data` element as join partner and
//DELETE the existing 'g.class' DOM elements
join.exit().remove()
//get the join pairs that have a `data` element join partner and
//UPDATE the 'g.class' DOM elements
join.attr("name","value")
您会发现,如果您的数据非常符合您的UI要求,您可以编写非常易于维护的代码。如果您尝试使用此模式之外的hack,您的UI代码很快就会让您感到非常伤心。您应该预处理数据以满足UI的需要。
D3为某些用例提供了一些预处理器。例如,treemap布局函数将分层数据集展平为列表treemap.nodes
,然后您可以将其用作基于列表的简单数据集,为每个元素绘制一个矩形。树形图布局还会为您计算所有x,y,width,height
值。你只需绘制rects而不再关心层次结构。
以同样的方式,您可以开发自己的帮助函数
这些“提示”可能包含几何值,标签文本,颜色,以及基本上无法通过查看单个数据元素(例如树形图几何体)得出的所有内容,并且需要您将每个元素与一些/所有其他元素(例如,确定树中节点的嵌套深度)。在一个预处理步骤中执行此类任务,可以为该任务编写更清晰,更快速的代码,并将数据处理与UI绘图分开。