使用 D3,我发现自己经常这样做:
selectAll('foo').data(['foo']).enter().append('foo')
如果节点不存在,我想简单地添加一个节点,因为我需要在 DOM 树的不同位置进行更新,而且我手头的数据与 DOM 并不完全平行。
这是否表明我应该重新格式化我的数据以使其平行,或者人们是否有一种不那么愚蠢的模式用于这种“如果丢失则创建”的事情?
使用 D3,我发现自己经常这样做:
selectAll('foo').data(['foo']).enter().append('foo')
如果节点不存在,我想简单地添加一个节点,因为我需要在 DOM 树的不同位置进行更新,而且我手头的数据与 DOM 并不完全平行。
这是否表明我应该重新格式化我的数据以使其平行,或者人们是否有一种不那么愚蠢的模式用于这种“如果丢失则创建”的事情?
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
为您计算所有值。您只需绘制矩形,不再关心层次结构。
以同样的方式,您可以开发自己的辅助函数来
这些“提示”可能包括几何值、标签文本、颜色,以及基本上您无法通过查看单个数据元素(例如树形图几何)直接得出的所有内容,这需要您将每个元素与部分/全部相关联其他元素(例如,确定树中节点的嵌套深度)。在一个预处理步骤中执行此类任务可以让您为该任务编写更清晰、更快的代码,并将数据处理与 UI 的绘制分开。