向我的 D3 力图添加节点/链接非常令人困惑,直到我更好地理解了添加初始节点集的方式。
假设 <g> 是您希望用于节点的:
// Select the element where you'd like to create the force layout
var el = d3.select("#svg");
// This should not select anything
el.selectAll("g")
// Because it's being compared to the data in force.nodes()
.data(force.nodes())
// Calling `.enter()` below returns the difference in nodes between
// the current selection and force.nodes(). At this point, there are
// no nodes in the selection, so `.enter()` should return
// all of the nodes in force.nodes()
.enter()
// Create the nodes
.append("g")
.attr("id", d.name)
.classed("manipulateYourNewNode", true);
现在让我们创建一个函数,该函数将在图形初始化后向布局添加一个节点!
newNodeData 是一个对象,其中包含您希望用于新节点的数据。
connectToMe 是一个字符串,其中包含您希望将新节点连接到的节点的唯一 ID。
function createNode (newNodeData, connectToMe) {
force.nodes().push(newNodeData);
el.selectAll("g")
.data(force.nodes(), function(datum, index) { return index })
.data() 中作为可选第二个参数给出的函数对选择中的每个节点运行一次,并为force.nodes() 中的每个节点运行一次,根据返回值匹配它们。如果未提供任何函数,则调用回退函数,该函数返回 index(如上)。
但是,您的新选择的索引(我相信顺序是随机的)和force.nodes() 中的顺序很可能会发生争议。相反,您很可能需要该函数返回每个节点独有的属性。
这一次,.enter() 只会将您尝试添加的节点返回为newData,因为.data() 的第二个参数没有找到它的键。
.enter()
.insert("g", "#svg")
.attr("id", d.name)
.classed("manipulatYourNewNode", true);
createLink(connectToMe, newNodeData.name);
force.start();
}
函数 createLink(定义如下)在您的新节点和您选择的节点之间创建一个链接。
另外,the d3js API states that force.start() should be called after updating the layout。
注意:当我第一次尝试弄清楚如何将节点和链接添加到我的图表时,在我的函数开始时调用 force.stop() 对我有很大帮助。
function createLink (from, to) {
var source = d3.select( "g#" + from ).datum(),
target = d3.select( "g#" + to ).datum(),
newLink = {
source: source,
target: target,
value: 1
};
force.links().push(newLink);
以下代码在以下假设下工作:
-
#links 是包含所有链接元素的包装元素
-
您的链接表示为<line> 元素:
d3.select("#links")
.selectAll("line")
.data(force.links())
.enter()
.append("line");