首先让我说明我对D3和Javascript完全不熟悉。通过一点点实验,我试图开发一个Tree Like结构,其中catch可以有多个父节点。
输入:
Json与节点和链接等信息,
var graph = {
"nodes": [ { "id" : 0},
{ "id" : 1},
{ "id" : 2},
{ "id" : 3},
{ "id" : 4},
{ "id" : 5}
],
"links": [ { "target": 5, "source": 1 },
{ "target": 2, "source": 0 },
{ "target": 3, "source": 4 },
{ "target": 1, "source": 2},
{ "target": 1, "source": 0 },
]
};
注意:这仅供参考,因为我有数据,可能是数千个节点。
输出
我希望输出像树结构一样,有点像this,就像说节点必须以深度/层次结构绘制,其中根位于顶部,同一级节点排列在这样的结构中最小化链接重叠的方法。
我面临的问题:
或者
请注意,节点可以有多个父节点,我的主要焦点是以正确/层次顺序绘制这些节点,因此我面临的主要问题是计算所有节点的X / Y坐标。输入如上所述。
请帮助我更好地理解这个主题,谢谢。
答案 0 :(得分:2)
一整天都在考虑这件事。使用内置的d3
构造,我认为this与您将获得的距离非常接近。我已经将您的数据转换为版本4示例:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.links line {
stroke: #aaa;
stroke-width: 5px;
}
.nodes circle {
pointer-events: all;
stroke: none;
}
</style>
<svg width="600" height="300"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force("y", d3.forceY())
var graph = {
"nodes": [{
"id": 0
}, {
"id": 1
}, {
"id": 2
}, {
"id": 3
}, {
"id": 4
}, {
"id": 5
}],
"links": [{
"target": 5,
"source": 1
}, {
"target": 2,
"source": 0
}, {
"target": 3,
"source": 4
}, {
"target": 1,
"source": 2
}, {
"target": 1,
"source": 0
},
]
};
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line");
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter().append("circle")
.attr("r", 10);
node.append("title")
.text(function(d) {
return d.id;
});
simulation
.nodes(graph.nodes)
.on("tick", ticked);
simulation.force("link")
.links(graph.links);
function ticked() {
var k = 6 * simulation.alpha();
// Push sources up and targets down to form a weak tree.
link
.each(function(d) {
d.source.y -= k, d.target.y += k;
})
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
</script>
如果您不想要移动和稳定效果,可以预先计算布局以使其成为static。
我还尝试将您的数据转换为分层格式,以便与d3.tree一起使用,但没有太多运气复制您的图片:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node circle {
fill: #999;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>
<svg width="300" height="300"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var graph = {
"nodes": [{
"id": 0
}, {
"id": 1
}, {
"id": 2
}, {
"id": 3
}, {
"id": 4
}, {
"id": 5
}],
"links": [{
"target": 5,
"source": 1
},{
"target": 2,
"source": 0
}, {
"target": 3,
"source": 4
}, {
"target": 1,
"source": 2
}, {
"target": 1,
"source": 0
}]
};
var root = {
id: 0,
data: graph.nodes[0],
children: []
}
function recurChild(obj) {
graph.links.forEach(function(d) {
if (d.source === obj.id) {
var c = {
id: d.target,
data: graph.nodes[d.target],
children: []
};
obj.children.push(c);
recurChild(c);
}
});
}
recurChild(root);
root = d3.hierarchy(root);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(40,0)");
var tree = d3.tree()
.size([height, width - 160]);
tree(root);
console.log(root.descendants())
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.y + "," + d.x + "C" + (d.y + d.parent.y) / 2 + "," + d.x + " " + (d.y + d.parent.y) / 2 + "," + d.parent.x + " " + d.parent.y + "," + d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) {
return "node" + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
node.append("circle")
.attr("r", 2.5);
node.append("text")
.attr("dy", 3)
.attr("x", function(d) {
return d.children ? -8 : 8;
})
.style("text-anchor", function(d) {
return d.children ? "end" : "start";
})
.text(function(d) {
return d.data.id;
});
</script>
d3.hierarchy实际上意味着没有多个父结构的直接层次结构。