Javascript dagre-d3中的边缘定位

Javascript dagre-d3中的边缘定位,javascript,d3.js,graph,dagre-d3,Javascript,D3.js,Graph,Dagre D3,我使用dagre-d3创建了这个示例图。是否有可能避免标记为1的样品中的交叉问题。也许这可以标记到节点底部的边缘连接。我不知道如何实现这个功能。有人能帮忙吗 此外,是否可以拉直边缘2、3和4。有足够的空间把它们弄直。我只是不知道怎么做 任何帮助都将不胜感激 泽山 这是您试图解决的一个非常重要的问题。AFAIK dagre使用来自的算法的变体来计算路线。即使你能理解这个算法,调整它也是非常困难的。相反,使用完全不同的算法可能会得到更好的结果:在实现分层/杉山式布局时,使用单纯形网络秩分配算法,通常

我使用dagre-d3创建了这个示例图。是否有可能避免标记为1的样品中的交叉问题。也许这可以标记到节点底部的边缘连接。我不知道如何实现这个功能。有人能帮忙吗

此外,是否可以拉直边缘2、3和4。有足够的空间把它们弄直。我只是不知道怎么做

任何帮助都将不胜感激

泽山


这是您试图解决的一个非常重要的问题。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.