blob: 7187be213850d6623e381b214defebcb38ed3ce7 [file] [log] [blame]
import * as vec2 from 'zrender/src/core/vector';
var scaleAndAdd = vec2.scaleAndAdd; // function adjacentNode(n, e) {
// return e.n1 === n ? e.n2 : e.n1;
// }
export function forceLayout(nodes, edges, opts) {
var rect = opts.rect;
var width = rect.width;
var height = rect.height;
var center = [rect.x + width / 2, rect.y + height / 2]; // var scale = opts.scale || 1;
var gravity = opts.gravity == null ? 0.1 : opts.gravity; // for (var i = 0; i < edges.length; i++) {
// var e = edges[i];
// var n1 = e.n1;
// var n2 = e.n2;
// n1.edges = n1.edges || [];
// n2.edges = n2.edges || [];
// n1.edges.push(e);
// n2.edges.push(e);
// }
// Init position
for (var i = 0; i < nodes.length; i++) {
var n = nodes[i];
if (!n.p) {
// Use the position from first adjecent node with defined position
// Or use a random position
// From d3
// if (n.edges) {
// var j = -1;
// while (++j < n.edges.length) {
// var e = n.edges[j];
// var other = adjacentNode(n, e);
// if (other.p) {
// n.p = vec2.clone(other.p);
// break;
// }
// }
// }
// if (!n.p) {
n.p = vec2.create(width * (Math.random() - 0.5) + center[0], height * (Math.random() - 0.5) + center[1]); // }
}
n.pp = vec2.clone(n.p);
n.edges = null;
} // Formula in 'Graph Drawing by Force-directed Placement'
// var k = scale * Math.sqrt(width * height / nodes.length);
// var k2 = k * k;
var friction = 0.6;
return {
warmUp: function () {
friction = 0.5;
},
setFixed: function (idx) {
nodes[idx].fixed = true;
},
setUnfixed: function (idx) {
nodes[idx].fixed = false;
},
step: function (cb) {
var v12 = [];
var nLen = nodes.length;
for (var i = 0; i < edges.length; i++) {
var e = edges[i];
var n1 = e.n1;
var n2 = e.n2;
vec2.sub(v12, n2.p, n1.p);
var d = vec2.len(v12) - e.d;
var w = n2.w / (n1.w + n2.w);
if (isNaN(w)) {
w = 0;
}
vec2.normalize(v12, v12);
!n1.fixed && scaleAndAdd(n1.p, n1.p, v12, w * d * friction);
!n2.fixed && scaleAndAdd(n2.p, n2.p, v12, -(1 - w) * d * friction);
} // Gravity
for (var i = 0; i < nLen; i++) {
var n = nodes[i];
if (!n.fixed) {
vec2.sub(v12, center, n.p); // var d = vec2.len(v12);
// vec2.scale(v12, v12, 1 / d);
// var gravityFactor = gravity;
scaleAndAdd(n.p, n.p, v12, gravity * friction);
}
} // Repulsive
// PENDING
for (var i = 0; i < nLen; i++) {
var n1 = nodes[i];
for (var j = i + 1; j < nLen; j++) {
var n2 = nodes[j];
vec2.sub(v12, n2.p, n1.p);
var d = vec2.len(v12);
if (d === 0) {
// Random repulse
vec2.set(v12, Math.random() - 0.5, Math.random() - 0.5);
d = 1;
}
var repFact = (n1.rep + n2.rep) / d / d;
!n1.fixed && scaleAndAdd(n1.pp, n1.pp, v12, repFact);
!n2.fixed && scaleAndAdd(n2.pp, n2.pp, v12, -repFact);
}
}
var v = [];
for (var i = 0; i < nLen; i++) {
var n = nodes[i];
if (!n.fixed) {
vec2.sub(v, n.p, n.pp);
scaleAndAdd(n.p, n.p, v, friction);
vec2.copy(n.pp, n.p);
}
}
friction = friction * 0.992;
cb && cb(nodes, edges, friction < 0.01);
}
};
}