Javascript dagre-d3中的边缘定位
我使用dagre-d3创建了这个示例图。是否有可能避免标记为1的样品中的交叉问题。也许这可以标记到节点底部的边缘连接。我不知道如何实现这个功能。有人能帮忙吗 此外,是否可以拉直边缘2、3和4。有足够的空间把它们弄直。我只是不知道怎么做 任何帮助都将不胜感激 泽山Javascript dagre-d3中的边缘定位,javascript,d3.js,graph,dagre-d3,Javascript,D3.js,Graph,Dagre D3,我使用dagre-d3创建了这个示例图。是否有可能避免标记为1的样品中的交叉问题。也许这可以标记到节点底部的边缘连接。我不知道如何实现这个功能。有人能帮忙吗 此外,是否可以拉直边缘2、3和4。有足够的空间把它们弄直。我只是不知道怎么做 任何帮助都将不胜感激 泽山 这是您试图解决的一个非常重要的问题。AFAIK dagre使用来自的算法的变体来计算路线。即使你能理解这个算法,调整它也是非常困难的。相反,使用完全不同的算法可能会得到更好的结果:在实现分层/杉山式布局时,使用单纯形网络秩分配算法,通常
这是您试图解决的一个非常重要的问题。AFAIK dagre使用来自的算法的变体来计算路线。即使你能理解这个算法,调整它也是非常困难的。相反,使用完全不同的算法可能会得到更好的结果:在实现分层/杉山式布局时,使用单纯形网络秩分配算法,通常不会遇到您在(其他非常好的)图形中看到的问题。GraphViz也是该算法的一部分,所以也许使用它也会为您的示例提供更好的结果。单纯形方法在计算上要昂贵得多,但很容易配置和微调
关于你的第一点:通过快速查看来源,我无法理解为什么在你的Dagre样本中出现问题。看起来传入边缘的端口分配工作不正常-端口的位置应根据上一层中节点的相对位置进行排序。看起来不仅仅是贝塞尔控制点出了问题。我认为最新的dagre库不再存在这些问题。我复制了您的图表()。这不完全一样,但很相似 演示站点由美人鱼提供动力,美人鱼由dagre提供动力
//创建一个新的有向图
var g=new dagreD3.graphlib.Graph().setGraph({});
//函数来洗牌列表。。。
函数洗牌(a){
变量j,x,i;
对于(i=a.length;i;i-=1){
j=Math.floor(Math.random()*i);
x=a[i-1];
a[i-1]=a[j];
a[j]=x;
}
返回a;
}
变量节点=[“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"
];
//将边收集到列表中
var edgeList=[
["10007154_1100", "148570017_1100", {
“标签”:”
}],
["148570017_1100", "148570018_1100", {
“标签”:”
}],
["148570018_1100", "148570019_1100", {
“标签”:”
}],
["148570018_1100", "148570025_1100", {
“标签”:”
}],
["148570019_1100", "148570020_1100", {
“标签”:”
}],
["148570019_1100", "148570021_1100", {
“标签”:”
}],
["148570019_1100", "148570010_1100", {
“标签”:”
}],
["148570025_1100", "148570010_1100", {
“标签”:”
}],
["148570025_1100", "148570026_1100", {
“标签”:”
}],
["148570021_1100", "148570022_1100", {
“标签”:”
}],
["148570010_1100", "148570011_1100", {
“标签”:”
}],
["148570010_1100", "148570010_1200", {
“标签”:”
}],
["148570020_1100", "148570020_1200", {
“标签”:”
}],
["148570026_1100", "148570026_1200", {
“标签”:”
}],
["148570026_1200", "148570011_1200", {
“标签”:”
}],
["148570010_1200", "148570011_1200", {
“标签”:”
}],
["148570022_1100", "148570023_1100", {
“标签”:”
}],
["148570023_1100", "148570023_1200", {
“标签”:”
}]
];
//自动标记每个节点
var svg=d3。选择(“svg”),
内部=svg。选择(“g”);
函数渲染图(渲染){
var max_cnt=100;//尝试100次,如果找不到最佳值,则放弃
var iter_cnt=0;
var最优阵列,最佳结果;
而(最大值--){
var g=new dagreD3.graphlib.Graph().setGraph({});
forEach(函数(节点){
g、 setNode(节点{
标签:节点
});
});
//设置边…随机化列表
var列表=洗牌(边缘列表);
如果(!optimalArray)optimalArray=列表;
边缘列表forEach((边缘)=>{
g、 设置边缘。应用(g,边缘);
})
//设置rankdir
g、 graph().rankdir=“LR”;
g、 图().nodesep=60;
渲染(内部,g);
var nn=svg.select(“.edgePaths”);
var路径=nn[0][0];
var fc=path.firstChild;
变量框=[];
while(fc){
//console.log(fc.firstChild.getAttribute(“d”))
var path=fc.firstChild.getAttribute(“d”);
var coords=path.split(/,| L/).map(函数(c){
var n=c;
如果((c[0]==“M”| c[0]==“L”))n=c子串(1);
返回浮点数(n);
})
推({
左:坐标[0],
顶部:coords[1],
右:coords[coords.length-2],
底部:坐标[coords.length-1]
});
//控制台日志(coords);
fc=fc.nextSibling;
}
//控制台日志(“框”,框);
var-collisionCnt=0;
框。forEach(函数(a){
//-->测试与其他节点的冲突。。。
框。forEach(功能(b){
如果(a==b)返回;
//测试是否在室外
如果((a.右b.右)||
(a.顶部>b.底部)||
(a.底部=b.left&&a.left=b.left&&a.right=0){
var g=new dagreD3.graphlib.Graph().setGraph({});
forEach(函数(节点){
g、 setNode(节点{
标签:节点
});
});
优化数组。forEach((边)=>{
g、 设置边缘。应用(g,边缘);
})
g、 graph().rankdir=“LR”;
g、 图().nodesep=60;
渲染(内部,g);
}
//将图表居中
var initialScale=0.75;
快速移动
.translate([(svg.attr(“width”)-g.graph().width*initialScale)/2,20])
.刻度(初始刻度)
.事件(svg);
// 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.