D3 具有非树数据的可折叠力有向图 - 链接对齐
Posted
技术标签:
【中文标题】D3 具有非树数据的可折叠力有向图 - 链接对齐【英文标题】:D3 Collapsible force directed graph with non-tree data - link alignment 【发布时间】:2020-10-15 21:52:39 【问题描述】:如果您看到现有代码,https://jsfiddle.net/sheilak/9wvmL8q8 第一次加载图表时,连接父节点和子节点的链接来自父节点的边框,但一旦折叠和展开,您可以看到相同的链接来自中心的父节点。我不想链接到父节点的中心。
代码
var width = 960,
height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.size([width, height])
//gravity(0.2)
.linkDistance(height / 6)
.charge(function(node)
if (node.type !== 'ORG') return -2000;
return -30;
);
// build the arrow.
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", function(d)
return d;
)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 12)
.attr("refY", 0)
.attr("markerWidth", 9)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("class", "arrow")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var json = dataset;
var edges = [];
json.edges.forEach(function(e)
var sourceNode = json.nodes.filter(function(n)
return n.id === e.from;
)[0],
targetNode = json.nodes.filter(function(n)
return n.id === e.to;
)[0];
edges.push(
source: sourceNode,
target: targetNode,
value: e.Value
);
);
for(var i = 0; i < json.nodes.length; i++)
json.nodes[i].collapsing = 0;
json.nodes[i].collapsed = false;
var link = svg.selectAll(".link");
var node = svg.selectAll(".node");
force.on("tick", function()
// make sure the nodes do not overlap the arrows
link.attr("d", function(d)
// Total difference in x and y from source to target
diffX = d.target.x - d.source.x;
diffY = d.target.y - d.source.y;
// Length of path from center of source node to center of target node
pathLength = Math.sqrt((diffX * diffX) + (diffY * diffY));
// x and y distances from center to outside edge of target node
offsetX = (diffX * d.target.radius) / pathLength;
offsetY = (diffY * d.target.radius) / pathLength;
return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
);
node.attr("transform", function(d)
return "translate(" + d.x + "," + d.y + ")";
);
);
update();
function update()
var nodes = json.nodes.filter(function(d)
return d.collapsing == 0;
);
var links = edges.filter(function(d)
return d.source.collapsing == 0 && d.target.collapsing == 0;
);
force
.nodes(nodes)
.links(links)
.start();
link = link.data(links)
link.exit().remove();
link.enter().append("path")
.attr("class", "link")
.attr("marker-end", "url(#end)");
node = node.data(nodes);
node.exit().remove();
node.enter().append("g")
.attr("class", function(d)
return "node " + d.type
);
node.append("circle")
.attr("class", "circle")
.attr("r", function(d)
d.radius = 30;
return d.radius
); // return a radius for path to use
node.append("text")
.attr("x", 0)
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.attr("class", "text")
.text(function(d)
return d.type
);
// On node hover, examine the links to see if their
// source or target properties match the hovered node.
node.on('mouseover', function(d)
link.attr('class', function(l)
if (d === l.source || d === l.target)
return "link active";
else
return "link inactive";
);
);
// Set the stroke width back to normal when mouse leaves the node.
node.on('mouseout', function()
link.attr('class', "link");
)
.on('click', click);
function click(d)
if (!d3.event.defaultPrevented)
var inc = d.collapsed ? -1 : 1;
recurse(d);
function recurse(sourceNode)
//check if link is from this node, and if so, collapse
edges.forEach(function(l)
if (l.source.id === sourceNode.id)
l.target.collapsing += inc;
recurse(l.target);
);
d.collapsed = !d.collapsed;
update();
【问题讨论】:
【参考方案1】:有两种简单的方法可以解决这个问题,只需对现有代码进行少量修改。
当你定义你的路径数据时,因为每个链接的目标已经偏移了,所以前半部分已经完成了:
return "M" + d.source.x + "," + d.source.y + "L" + (d.target.x - offsetX) + "," + (d.target.y - offsetY);
);
您可以很容易地将其扩展为从源节点偏移,只需将偏移量添加到 sourceX 和 sourceY 为here。这样,节点是在链接上方还是在链接下方都没有关系,因为它们不会重叠。 (可能会有轻微的重叠,因此您可以在偏移量中添加一两个像素以说明链接宽度)。
第二个选项在 d3v4+ 中可能更容易,因为它具有 selection.raise()
(docs)。此方法将所选项目提升到 SVG 的顶部(作为父元素的最后一个子元素)。相当于:
this.parentNode.appendChild(this);
在您的点击函数中,更新图表后,我们可以使用这条线来确保被点击的节点上升到顶部(在链接上方)。这是that 的示例。
【讨论】:
以上是关于D3 具有非树数据的可折叠力有向图 - 链接对齐的主要内容,如果未能解决你的问题,请参考以下文章