```
computePositionStep: function(property, opt) {
var graph = this.graph, GUtil = Graph.Util;
var min = Math.min, max = Math.max;
var dpos = $C(0, 0);
//calculate repulsive forces
GUtil.eachNode(graph, function(v) {
//initialize disp
$each(property, function(p) {
v.disp[p].x = 0; v.disp[p].y = 0;
});
GUtil.eachNode(graph, function(u) {
if(u.id != v.id) {
$each(property, function(p) {
var vp = v.getPos(p), up = u.getPos(p);
dpos.x = vp.x - up.x;
dpos.y = vp.y - up.y;
var norm = dpos.norm() || 1;
v.disp[p].$add(dpos
.$scale(opt.nodef(norm) / norm));
});
}
});
});
//calculate attractive forces
var T = !!graph.getNode(this.root).visited;
GUtil.eachNode(graph, function(node) {
GUtil.eachAdjacency(node, function(adj) {
var nodeTo = adj.nodeTo;
if(!!nodeTo.visited === T) {
$each(property, function(p) {
var vp = node.getPos(p), up = nodeTo.getPos(p);
dpos.x = vp.x - up.x;
dpos.y = vp.y - up.y;
var norm = dpos.norm() || 1;
node.disp[p].$add(dpos.$scale(-opt.edgef(norm) / norm));
nodeTo.disp[p].$add(dpos.$scale(-1));
});
}
});
node.visited = !T;
});
//arrange positions to fit the canvas
var t = opt.t, w2 = opt.width / 2, h2 = opt.height / 2;
GUtil.eachNode(graph, function(u) {
$each(property, function(p) {
var disp = u.disp[p];
var norm = disp.norm() || 1;
var p = u.getPos(p);
p.$add($C(disp.x * min(Math.abs(disp.x), t) / norm,
disp.y * min(Math.abs(disp.y), t) / norm));
p.x = min(w2, max(-w2, p.x));
p.y = min(h2, max(-h2, p.y));
});
});
}
```

```
for(var i=0; i < times; i++) {
opt.t = opt.tstart * (1 - i/(times -1));
this.computePositionStep(property, opt);
}
```

```
computePositions: function(property, opt, incremental) {
var times = this.config.iterations, i = 0, that = this;
if(incremental) {
(function iter() {
for(var total=incremental.iter, j=0; j<total; j++) {
opt.t = opt.tstart * (1 - i++/(times -1));
that.computePositionStep(property, opt);
if(i >= times) {
incremental.onComplete();
return;
}
}
incremental.onStep(Math.round(i / (times -1) * 100));
setTimeout(iter, 1);
})();
} else {
for(; i < times; i++) {
opt.t = opt.tstart * (1 - i/(times -1));
this.computePositionStep(property, opt);
}
}
}
```

```
//compute positions incrementally and animate.
fd.computePositions(property, opt, {
iter: 20,
onStep: function(perc) {
Log.write(perc + '% loaded...');
},
onComplete: function() {
Log.write('done');
fd.animate();
}
});
```