Separate a Link Force with optimization
This commit is contained in:
99
src/link.js
99
src/link.js
@@ -1,100 +1,53 @@
|
||||
import constant from "./constant";
|
||||
import jiggle from "./jiggle";
|
||||
import {map} from "d3-collection";
|
||||
import {getStress} from "./stress";
|
||||
|
||||
/**
|
||||
* Extended link force algorithm to include the stress metric for
|
||||
* comparisons between the different algorithms.
|
||||
* Everything else is the same as in D3 force module.
|
||||
* Modified link force algorithm
|
||||
* - ignore alpha
|
||||
* - removed location prediction, and bias
|
||||
* - modified strength calculation
|
||||
* - removed other unused functions
|
||||
* Making it more suitable for the spring model.
|
||||
*/
|
||||
|
||||
function index(d, i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
function find(nodeById, nodeId) {
|
||||
var node = nodeById.get(nodeId);
|
||||
if (!node) throw new Error("missing: " + nodeId);
|
||||
return node;
|
||||
}
|
||||
|
||||
export default function(links) {
|
||||
var id = index,
|
||||
strength = defaultStrength,
|
||||
strengths,
|
||||
var dataSizeFactor,
|
||||
distance = constant(30),
|
||||
distances,
|
||||
distances = [],
|
||||
nodes,
|
||||
count,
|
||||
bias,
|
||||
iterations = 1;
|
||||
|
||||
if (links == null) links = [];
|
||||
|
||||
function defaultStrength(link) {
|
||||
return 1 / Math.min(count[link.source.index], count[link.target.index]);
|
||||
}
|
||||
|
||||
function force(alpha) {
|
||||
function force() {
|
||||
for (var k = 0, n = links.length; k < iterations; ++k) { // Each iteration in a tick
|
||||
for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) { //For each link
|
||||
for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) { // For each link
|
||||
link = links[i];
|
||||
// jiggle so it wont divide / multiply by zero after this
|
||||
source = link.source;
|
||||
target = link.target;
|
||||
x = target.x + target.vx - source.x - source.vx || jiggle();
|
||||
y = target.y + target.vy - source.y - source.vy || jiggle();
|
||||
x = target.x - source.x || jiggle();
|
||||
y = target.y - source.y || jiggle();
|
||||
l = Math.sqrt(x * x + y * y);
|
||||
l = (l - distances[i]) / l * alpha * strengths[i];
|
||||
l = (l - distances[i]) / l * dataSizeFactor;
|
||||
x *= l, y *= l;
|
||||
target.vx -= x * (b = bias[i]);
|
||||
target.vy -= y * b;
|
||||
source.vx += x * (b = 1 - b);
|
||||
source.vy += y * b;
|
||||
target.vx -= x;
|
||||
target.vy -= y;
|
||||
source.vx += x;
|
||||
source.vy += y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
if (!nodes) return;
|
||||
|
||||
var i,
|
||||
n = nodes.length,
|
||||
m = links.length,
|
||||
nodeById = map(nodes, id),
|
||||
link;
|
||||
|
||||
for (i = 0, count = new Array(n); i < n; ++i) {
|
||||
count[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < m; ++i) {
|
||||
link = links[i];
|
||||
link.index = i;
|
||||
//if (typeof link.source !== "object") link.source = find(nodeById, link.source);
|
||||
//if (typeof link.target !== "object") link.target = find(nodeById, link.target);
|
||||
++count[link.source.index];
|
||||
++count[link.target.index];
|
||||
}
|
||||
|
||||
for (i = 0, bias = new Array(m); i < m; ++i) {
|
||||
link = links[i];
|
||||
bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
|
||||
}
|
||||
|
||||
strengths = new Array(m), initializeStrength();
|
||||
distances = new Array(m), initializeDistance();
|
||||
}
|
||||
|
||||
function initializeStrength() {
|
||||
if (!nodes) return;
|
||||
|
||||
for (var i = 0, n = links.length; i < n; ++i) {
|
||||
strengths[i] = +strength(links[i], i, links);
|
||||
}
|
||||
console.log("CUSTOM LINK FORCE");
|
||||
dataSizeFactor = 0.5/(nodes.length-1);
|
||||
initializeDistance();
|
||||
}
|
||||
|
||||
function initializeDistance() {
|
||||
console.log("INIT DISTANCE", links.length);
|
||||
if (!nodes) return;
|
||||
|
||||
for (var i = 0, n = links.length; i < n; ++i) {
|
||||
@@ -119,17 +72,9 @@ export default function(links) {
|
||||
return arguments.length ? (iterations = +_, force) : iterations;
|
||||
};
|
||||
|
||||
force.strength = function(_) {
|
||||
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initializeStrength(), force) : strength;
|
||||
};
|
||||
|
||||
force.distance = function(_) {
|
||||
return arguments.length ? (distance = typeof _ === "function" ? _ : constant(+_), initializeDistance(), force) : distance;
|
||||
};
|
||||
|
||||
force.stress = function() {
|
||||
return getStress(nodes, function(s,t){return distance({source: s, target: t});});
|
||||
}
|
||||
|
||||
return force;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user