将节点插入 D3 包布局(缩放分页)
Inserting nodes into D3 pack layout (pagination on zoom)
当 D3.js 包布局已经创建并显示在 SVG 元素中时,如何向它添加其他节点?重新计算整个 pack
是一种选择,但我想更无缝地进行插入。
我正在寻找的是一个 pack().addNode()
函数,它允许我将额外的子节点插入到现有的叶节点中。当用户放大到那个叶节点时,叶节点应该变成父节点并将插入的节点显示为其子节点。
请看at my fiddle here。名为 subnode_jane
的节点应接收 subnode_subnodes
中的子节点作为其新子节点。
var subnode_subnodes = [{
"name": "JanesDaughter",
"size": 1030
}, {
"name": "JanesSon",
"size": 12000
}];
function zoom(d) {
var focus0 = focus;
focus = d;
if (d.name === "subnode_jane") {
alert("Oh I see subnode_jane has unpaginated children; insert them now!");
}
/* ... */
}
可选:在执行此操作时,如果原始节点的整体外观保持完全相同就好了。谢谢!
相关:update a layout.pack in d3.js
Please find my workaround solution here。 (解决方法是因为我无法编写 D3 包布局的扩展函数)
我的解决方案是创建第二个 "virtual" 包并使用其圆坐标集成到原始包中。为我工作。
// hard-coded function
var virtualNodesByParentNode = function (d3NodeParentElement, nodeChildrenElementArray) {
root.children[0].children[0].children = subnode_subnodes;
// we need to do this because otherwise, the parent node object will be changed
var d3NodeParentElementClone = clone(d3NodeParentElement);
var pack = d3.layout.pack()
.padding(2)
// -1 is important to avoid edge overlap
.size([d3NodeParentElementClone.r * 2 - 1, d3NodeParentElementClone.r * 2 - 1])
.value(function (d) {
return d.size;
});
d3NodeParentElementClone.children = nodeChildrenElementArray;
var nodes = pack.nodes(d3NodeParentElementClone)
// absolute x,y coordinates calculation
var curChildnode;
for (var i = 1; i < nodes.length; i++) {
curChildnode = nodes[i];
curChildnode.x = curChildnode.x - nodes[0].x + d3NodeParentElement.x;
curChildnode.y = curChildnode.y - nodes[0].y + d3NodeParentElement.y;
curChildnode.depth = d3NodeParentElement.depth + 1;
curChildnode.parent = d3NodeParentElement;
}
nodes.splice(0, 1);
return nodes;
};
zoom
函数中的 if 条件:
if (d.name === "subnode_jane" && done === 0) {
done = 1;
var virtualNodes = virtualNodesByParentNode(d, subnode_subnodes);
d.children = virtualNodes;
//
nodes.push.apply(nodes, virtualNodes);
circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function (d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.style("fill", function (d) {
return "red";
})
.on("click", function (d) {
if (focus !== d) zoom(d), d3.event.stopPropagation();
});
text.remove();
text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function (d) {
return d.parent === root ? 1 : 0;
})
.style("display", function (d) {
return d.parent === root ? null : "none";
})
.text(function (d) {
return d.name;
});
circle = svg.selectAll("circle");
node = svg.selectAll("circle,text");
// zoom to current focus again (do the transformation of the updated elements)
zoomTo(view);
return zoom(d);
}
当 D3.js 包布局已经创建并显示在 SVG 元素中时,如何向它添加其他节点?重新计算整个 pack
是一种选择,但我想更无缝地进行插入。
我正在寻找的是一个 pack().addNode()
函数,它允许我将额外的子节点插入到现有的叶节点中。当用户放大到那个叶节点时,叶节点应该变成父节点并将插入的节点显示为其子节点。
请看at my fiddle here。名为 subnode_jane
的节点应接收 subnode_subnodes
中的子节点作为其新子节点。
var subnode_subnodes = [{
"name": "JanesDaughter",
"size": 1030
}, {
"name": "JanesSon",
"size": 12000
}];
function zoom(d) {
var focus0 = focus;
focus = d;
if (d.name === "subnode_jane") {
alert("Oh I see subnode_jane has unpaginated children; insert them now!");
}
/* ... */
}
可选:在执行此操作时,如果原始节点的整体外观保持完全相同就好了。谢谢!
相关:update a layout.pack in d3.js
Please find my workaround solution here。 (解决方法是因为我无法编写 D3 包布局的扩展函数)
我的解决方案是创建第二个 "virtual" 包并使用其圆坐标集成到原始包中。为我工作。
// hard-coded function
var virtualNodesByParentNode = function (d3NodeParentElement, nodeChildrenElementArray) {
root.children[0].children[0].children = subnode_subnodes;
// we need to do this because otherwise, the parent node object will be changed
var d3NodeParentElementClone = clone(d3NodeParentElement);
var pack = d3.layout.pack()
.padding(2)
// -1 is important to avoid edge overlap
.size([d3NodeParentElementClone.r * 2 - 1, d3NodeParentElementClone.r * 2 - 1])
.value(function (d) {
return d.size;
});
d3NodeParentElementClone.children = nodeChildrenElementArray;
var nodes = pack.nodes(d3NodeParentElementClone)
// absolute x,y coordinates calculation
var curChildnode;
for (var i = 1; i < nodes.length; i++) {
curChildnode = nodes[i];
curChildnode.x = curChildnode.x - nodes[0].x + d3NodeParentElement.x;
curChildnode.y = curChildnode.y - nodes[0].y + d3NodeParentElement.y;
curChildnode.depth = d3NodeParentElement.depth + 1;
curChildnode.parent = d3NodeParentElement;
}
nodes.splice(0, 1);
return nodes;
};
zoom
函数中的 if 条件:
if (d.name === "subnode_jane" && done === 0) {
done = 1;
var virtualNodes = virtualNodesByParentNode(d, subnode_subnodes);
d.children = virtualNodes;
//
nodes.push.apply(nodes, virtualNodes);
circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("class", function (d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.style("fill", function (d) {
return "red";
})
.on("click", function (d) {
if (focus !== d) zoom(d), d3.event.stopPropagation();
});
text.remove();
text = svg.selectAll("text")
.data(nodes)
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function (d) {
return d.parent === root ? 1 : 0;
})
.style("display", function (d) {
return d.parent === root ? null : "none";
})
.text(function (d) {
return d.name;
});
circle = svg.selectAll("circle");
node = svg.selectAll("circle,text");
// zoom to current focus again (do the transformation of the updated elements)
zoomTo(view);
return zoom(d);
}