我正在使用dagre-d3并创建了此示例图。是否可以避免标记为1的样本中的交叉问题。也许可以将边缘连接标记到节点的底部。我不知道如何实现这个功能。有人可以帮忙吗?
此外,是否可以拉直边缘2,3和4.有足够的空间来拉直它们。我只是不知道该怎么做。
任何帮助都将不胜感激。
Zeeshan
答案 0 :(得分:0)
这是您要解决的一个非常重要的问题。 AFAIK dagre使用Brandes-Köpf算法的变体来计算对齐。即使您能理解该算法,调整它也很困难。相反,使用完全不同的算法可能会给你带来更好的结果:在yFiles for HTML's层次/ Sugiyama样式布局的实现中,使用单纯形网络秩分配算法,它通常不会遇到你在你身上看到的问题(否则非常好)绘图。 GraphViz也是该算法的has an implementation,因此使用它可能会为您的示例提供更好的结果。 Simplex方法在计算上要贵得多,但很容易配置和微调。
关于你的第一点:从快速查看来源我无法理解为什么问题出现在你的Dagre样本中。看起来传入边缘的端口分配不能正常工作 - 端口的位置应根据前一层中节点的相对位置进行排序。它看起来不像是错误的bezier控制点。
答案 1 :(得分:0)
答案 2 :(得分:0)
// Create a new directed graph
var g = new dagreD3.graphlib.Graph().setGraph({});
// function to shuffle the list...
function shuffle(a) {
var j, x, i;
for (i = a.length; i; i -= 1) {
j = Math.floor(Math.random() * i);
x = a[i - 1];
a[i - 1] = a[j];
a[j] = x;
}
return a;
}
var nodes = ["10007154_1100", "148570017_1100", "148570018_1100", "148570019_1100",
"148570025_1100", "148570010_1100", "148570021_1100", "148570020_1100",
"148570026_1100", "148570011_1100", "148570022_1100", "148570010_1200", "148570020_1200", "148570026_1200", "148570023_1100", "148570011_1200",
"148570023_1200"
];
// collect edges to a list
var edgeList = [
["10007154_1100", "148570017_1100", {
"label": ""
}],
["148570017_1100", "148570018_1100", {
"label": ""
}],
["148570018_1100", "148570019_1100", {
"label": ""
}],
["148570018_1100", "148570025_1100", {
"label": ""
}],
["148570019_1100", "148570020_1100", {
"label": ""
}],
["148570019_1100", "148570021_1100", {
"label": ""
}],
["148570019_1100", "148570010_1100", {
"label": ""
}],
["148570025_1100", "148570010_1100", {
"label": ""
}],
["148570025_1100", "148570026_1100", {
"label": ""
}],
["148570021_1100", "148570022_1100", {
"label": ""
}],
["148570010_1100", "148570011_1100", {
"label": ""
}],
["148570010_1100", "148570010_1200", {
"label": ""
}],
["148570020_1100", "148570020_1200", {
"label": ""
}],
["148570026_1100", "148570026_1200", {
"label": ""
}],
["148570026_1200", "148570011_1200", {
"label": ""
}],
["148570010_1200", "148570011_1200", {
"label": ""
}],
["148570022_1100", "148570023_1100", {
"label": ""
}],
["148570023_1100", "148570023_1200", {
"label": ""
}]
];
// Automatically label each of the nodes
var svg = d3.select("svg"),
inner = svg.select("g");
function render_graph(render) {
var max_cnt = 100; // try 100 times, if optimal not found, give up
var iter_cnt = 0;
var optimalArray, best_result;
while (max_cnt--) {
var g = new dagreD3.graphlib.Graph().setGraph({});
nodes.forEach(function(node) {
g.setNode(node, {
label: node
});
});
// set edges... randomize the list
var list = shuffle(edgeList);
if (!optimalArray) optimalArray = list;
edgeList.forEach((edge) => {
g.setEdge.apply(g, edge);
})
// Set the rankdir
g.graph().rankdir = "LR";
g.graph().nodesep = 60;
render(inner, g);
var nn = svg.select(".edgePaths");
var paths = nn[0][0];
var fc = paths.firstChild;
var boxes = [];
while (fc) {
// console.log(fc.firstChild.getAttribute("d"))
var path = fc.firstChild.getAttribute("d");
var coords = path.split(/,|L/).map(function(c) {
var n = c;
if ((c[0] == "M" || c[0] == "L")) n = c.substring(1);
return parseFloat(n);
})
boxes.push({
left: coords[0],
top: coords[1],
right: coords[coords.length - 2],
bottom: coords[coords.length - 1]
});
// console.log(coords);
fc = fc.nextSibling;
}
// console.log("boxes", boxes);
var collisionCnt = 0;
boxes.forEach(function(a) {
// --> test for collisions against other nodes...
boxes.forEach(function(b) {
if (a == b) return;
// test if outside
if ((a.right < b.left) ||
(a.left > b.right) ||
(a.top > b.bottom) ||
(a.bottom < b.top)) {
// test if inside
if (a.left >= b.left && a.left <= b.right || a.right >= b.left && a.right <= b.right) {
if (a.top <= b.top && a.top >= b.bottom) {
collisionCnt++;
}
if (a.bottom <= b.top && a.bottom >= b.bottom) {
collisionCnt++;
}
}
} else {
collisionCnt++;
}
})
})
console.log("collisions ", collisionCnt);
if (collisionCnt == 0) {
optimalArray = list.slice();
console.log("Iteration cnt ", iter_cnt);
break;
}
if (typeof(best_result) == "undefined") {
best_result = collisionCnt;
} else {
if (collisionCnt < best_result) {
optimalArray = list.slice();
best_result = collisionCnt;
}
}
iter_cnt++;
}
// if no optimal was found just render what was found...
if (best_result >= 0) {
var g = new dagreD3.graphlib.Graph().setGraph({});
nodes.forEach(function(node) {
g.setNode(node, {
label: node
});
});
optimalArray.forEach((edge) => {
g.setEdge.apply(g, edge);
})
g.graph().rankdir = "LR";
g.graph().nodesep = 60;
render(inner, g);
}
// Center the graph
var initialScale = 0.75;
zoom
.translate([(svg.attr("width") - g.graph().width * initialScale) / 2, 20])
.scale(initialScale)
.event(svg);
svg.attr('height', g.graph().height * initialScale + 40);
}
// Set up zoom support
var zoom = d3.behavior.zoom().on("zoom", function() {
inner.attr("transform", "translate(" + d3.event.translate + ")" +
"scale(" + d3.event.scale + ")");
});
svg.call(zoom);
// Create the renderer
var render = new dagreD3.render();
render_graph(render);
// Run the renderer. This is what draws the final graph.