Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何制作无节点边缘重叠的力导向布局_Javascript_Algorithm_Graph_Force Layout_Graph Layout - Fatal编程技术网

Javascript 如何制作无节点边缘重叠的力导向布局

Javascript 如何制作无节点边缘重叠的力导向布局,javascript,algorithm,graph,force-layout,graph-layout,Javascript,Algorithm,Graph,Force Layout,Graph Layout,我正在尝试制作更好的力定向布局算法(针对有向图) 基本算法有效,即满足以下代码中的isStable条件,算法结束,但边缘和节点可能重叠。因此,我想在边缘的中间添加一个虚拟顶点(如下面的图像),它应该解决这个问题,因为虚拟顶点会使边缘排斥其他边缘和节点。 我添加了addDummies方法,它为每个不是循环的边添加一个节点。 我将添加的节点称为中间节点 然后在每次迭代(迭代方法)时,我将中间节点的位置设置为边缘的中间。 其余的是旧算法 我获得了一个更好的布局,没有边缘重叠,但始终不满足结束条件,而

我正在尝试制作更好的力定向布局算法(针对有向图) 基本算法有效,即满足以下代码中的isStable条件,算法结束,但边缘和节点可能重叠。因此,我想在边缘的中间添加一个虚拟顶点(如下面的图像),它应该解决这个问题,因为虚拟顶点会使边缘排斥其他边缘和节点。

我添加了addDummies方法,它为每个不是循环的边添加一个节点。 我将添加的节点称为中间节点

然后在每次迭代(迭代方法)时,我将中间节点的位置设置为边缘的中间。 其余的是旧算法

我获得了一个更好的布局,没有边缘重叠,但始终不满足结束条件,而且,正如下图所示,图形不是很好,因为中间节点在中心节点周围形成了一种“圆环”(中间节点在红色圆圈内)

我正在寻找一个算法的详细描述,该算法在边上使用虚拟节点,或者寻找任何建议,使算法终止并具有更好的图形(我希望中间节点不要排斥其他节点到外部区域)

是否还要将新边从中间节点添加到旧节点

一个解决方案可能是改变isStable条件,但这个数字通常能保证图形的布局正确,所以我不想碰它

编辑:我以这种方式使用以下代码

var layouter = new Graph.Layout.Spring();
while !(layouter.isStable()) {
    layouter.iterate(1);
}
以下是当前代码的摘录

Graph.Layout.Spring = function() {
    this.maxRepulsiveForceDistance = 10;
    this.maxRepulsiveForceDistanceQ = this.maxRepulsiveForceDistance * this.maxRepulsiveForceDistance;
    this.k = 2.5;
    this.k2 = this.k * this.k; 
    this.c = 0.01;

    this.maxVertexMovement = 0.2;

    this.damping = 0.7;
};
Graph.Layout.Spring.prototype = {
resetForUpdate : function() {
    this.addDummies();
    this.currentIteration = 0;
    this.resetVelocities();
},

reset : function() {
    this.pastIterations = 0;
    this.currentIteration = 0;
    this.layoutPrepare();
    this.resetForUpdate();
},


isStable: function() {
    var nARR= this.graph.nodeArray;
    var i = nARR.length -1;
    do {
        var vel = nARR[i].velocity;
        var vx = vel.x;
        var vy = vel.y;
        var v = vx*vx+vy*vy;
        if (v > 0.0002) {
            return false;
        }
    } while (i--);

    return true;
},



addDummies: function() {
    for (e in this.graph.edges) {
        var edge = this.graph.edges[e];
        var s = edge.source;
        var t = edge.target;
        var id = s.id+"#"+t.id;
        console.log("adding ", id);
        if (!this.graph.nodes[id]) {
            if (s.id != t.id) {
                this.graph.addNode(id, "");
                var node = this.graph.nodes[id];

                node.dummy = true;
                node.fx = 0;
                node.fy = 0;

                node.next1id = s.id;
                node.next2id = t.id;

                node.velocity = {
                        x: 0,
                        y: 0
                };
            }
        }
    }
},


layoutPrepare : function() {
    for ( var i = 0; i < this.graph.nodeArray.length; ++i) {
        var node = this.graph.nodeArray[i];

        var x = -1+Math.random()*2;
        var y = -1+Math.random()*2;

        node.layoutPosX = x;
        node.layoutPosY = y;
        node.fx = 0;
        node.fy = 0;

        node.velocity = {
                x: 0,
                y: 0
        };
    }

},


resetVelocities: function() {
    for ( var i = 0; i < this.graph.nodeArray.length; ++i) {
        var node = this.graph.nodeArray[i];

        node.velocity = {
                x: 0,
                y: 0
        };
    }

},


iterate: function(iterations) {
    var SQRT        = Math.sqrt;
    var RAND        = Math.random;
    var maxRFQ      = this.maxRepulsiveForceDistanceQ;
    var l_k2        = this.k2;


    var it = iterations-1,
        i, j, node1, node2;

    var L_GRAPH     = this.graph;
    var L_EDGES     = L_GRAPH.edges;
    var nodeArray   = L_GRAPH.nodeArray;
    var L_NLEN      = nodeArray.length;

    /* 
     * addition: update midnodes position
     */
    for (e in L_GRAPH.edges) {
        var edge = L_GRAPH.edges[e];
        var s = edge.source;
        var t = edge.target;
        if (s != t) {
            var id = s.id+"#"+t.id;
            var midNode = L_GRAPH.nodes[id];
            if (midNode) {
                var dx = s.layoutPosX - t.layoutPosX;
                var dy = s.layoutPosY - t.layoutPosY;
                midNode.layoutPosX = s.layoutPosX - dx/2;
                midNode.layoutPosY = s.layoutPosY - dy/2;
            }
        }
    }


    /*
     * repulsive
     */
    do {
        for (i = 0; i < L_NLEN; ++i) {
            node1 = nodeArray[i];

            for (j = i+1; j < L_NLEN; ++j) {
                node2 = nodeArray[j];

                // per cappio
                if (node1 === node2)
                    continue;

                var dx = node2.layoutPosX - node1.layoutPosX;
                var dy = node2.layoutPosY - node1.layoutPosY;
                var d2 = dx * dx + dy * dy;
                if (d2 < 0.001) {
                    dx = 0.1 * RAND() + 0.1;
                    dy = 0.1 * RAND() + 0.1;
                    d2 = dx * dx + dy * dy;
                }


                if (d2 < maxRFQ) {
                    var d = SQRT(d2);
                    var f = 2*(l_k2 / d2);

                    var xx = f * dx / d;
                    var yy = f * dy / d;

                    node2.fx += xx;
                    node2.fy += yy;
                    node1.fx -= xx;
                    node1.fy -= yy;
                }


            } // for j
        } // for i



        /*
         * Attractive
         */
        i = (L_EDGES.length)-1;
        if (i >= 0) {
            do {
                var edge = L_EDGES[i];
                var node1 = edge.source;
                var node2 = edge.target;

                // evita self-force, che cmq andrebbe a zero
                if (node1 === node2)
                    continue;

                var dx = node2.layoutPosX - node1.layoutPosX;
                var dy = node2.layoutPosY - node1.layoutPosY;
                var d2 = dx * dx + dy * dy;
                if (d2 < 0.01) {
                    dx = 0.1 * RAND() + 0.1;
                    dy = 0.1 * RAND() + 0.1;
                    d2 = dx * dx + dy * dy;
                }

                d = SQRT(d2);
                var f = (l_k2-d2)/l_k2;

                var n2d = node2.edges.length;
                if (n2d > 2) {
                    n2d = 2;
                } 
                var n1d = node1.edges.length;
                if (n1d > 2) {
                    n1d = 2;
                } 

                var xcomp = f * dx/d;
                var ycomp = f * dy/d;

                node2.fx += xcomp / n2d;
                node2.fy += ycomp / n2d;
                node1.fx -= xcomp / n1d;
                node1.fy -= ycomp / n1d;    
            } while (i--);
        } // if i>=0



        /*
         * Move by the given force
         */
        var max = this.maxVertexMovement;
        var d = this.damping;
        var c = this.c;
        var i = L_NLEN-1;
        do {
            var node = nodeArray[i];

            var xmove,
                ymove;

            var v = node.velocity;

            v.x = v.x * d + node.fx * c; 
            v.y = v.y * d + node.fy * c;

            xmove = v.x;
            ymove = v.y;

            if (xmove > max)
                xmove = max;
            else if (xmove < -max)
                xmove = -max;

            if (ymove > max)
                ymove = max;
            else if (ymove < -max)
                ymove = -max;

            if (node.isNailed !== undefined) {
                v.x = 0;
                v.y = 0;
            } else {
                v.x = xmove;
                v.y = ymove;

                node.layoutPosX += xmove;
                node.layoutPosY += ymove;
            }


            node.fx = 0;
            node.fy = 0;
        } while (i--);

    } while (it--); 
},
Graph.Layout.Spring=函数(){
这是最大斥力距离=10;
this.maxExcepriveForceDistanceQ=this.maxExcepriveForceDistance*this.maxExcepriveForceDistance;
该系数k=2.5;
this.k2=this.k*this.k;
该系数c=0.01;
此参数为.maxVertexMovement=0.2;
该阻尼=0.7;
};
Graph.Layout.Spring.prototype={
resetForUpdate:function(){
这个.addDummies();
此.currentIteration=0;
这个;
},
重置:函数(){
此参数为0;
此.currentIteration=0;
这个.layoutpready();
这是resetForUpdate();
},
isStable:函数(){
var nARR=this.graph.noderray;
var i=平均长度-1;
做{
var-vel=nARR[i].速度;
var vx=等级x;
var vy=y级;
var v=vx*vx+vy*vy;
如果(v>0.0002){
返回false;
}
}而(我--),;
返回true;
},
addDummies:function(){
对于(本图中的e.边){
var-edge=this.graph.edges[e];
var s=edge.source;
var t=edge.target;
var id=s.id+“#”+t.id;
console.log(“添加”,id);
如果(!this.graph.nodes[id]){
如果(s.id!=t.id){
this.graph.addNode(id为“”);
var node=this.graph.nodes[id];
node.dummy=true;
node.fx=0;
node.fy=0;
node.next1id=s.id;
node.next2id=t.id;
节点速度={
x:0,,
y:0
};
}
}
}
},
布局准备:函数(){
对于(var i=0;i=0){
做{
physics: {
enabled: { boolean: bool },
barnesHut: {
  gravitationalConstant: { number },
  centralGravity: { number },
  springLength: { number },
  springConstant: { number },
  damping: { number },
  avoidOverlap: { number },
  __type__: { object }
},
forceAtlas2Based: {
  gravitationalConstant: { number },
  centralGravity: { number },
  springLength: { number },
  springConstant: { number },
  damping: { number },
  avoidOverlap: { number },
  __type__: { object }
},
repulsion: {
  centralGravity: { number },
  springLength: { number },
  springConstant: { number },
  nodeDistance: { number },
  damping: { number },
  __type__: { object }
},
hierarchicalRepulsion: {
  centralGravity: { number },
  springLength: { number },
  springConstant: { number },
  nodeDistance: { number },
  damping: { number },
  avoidOverlap: { number },
  __type__: { object }
},
maxVelocity: { number },
minVelocity: { number },    // px/s
solver: { string: ['barnesHut', 'repulsion', 'hierarchicalRepulsion', 'forceAtlas2Based'] },
stabilization: {
  enabled: { boolean: bool },
  iterations: { number },   // maximum number of iteration to stabilize
  updateInterval: { number },
  onlyDynamicEdges: { boolean: bool },
  fit: { boolean: bool },
  __type__: { object, boolean: bool }
},
timestep: { number },
adaptiveTimestep: { boolean: bool },
__type__: { object, boolean: bool }