forceAngle = function(angleFn) {
var nodes,
links = [],
strength = _ => {
return 0.1;
},
distance = _ => {
return 10;
};
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
let node = nodes[i];
node.vx += (node.target.x - node.x) * strength(node) * alpha;
node.vy += (node.target.y - node.y) * strength(node) * alpha;
}
}
function initialize() {
if (!nodes) return;
let getId = d => {
return typeof d.id === "string"
? d.id
: typeof d.index === "number"
? d.index
: d;
};
var linkCache = [];
for (var i = 0; i < links.length; ++i) {
linkCache[`${getId(links[i].source)}|${getId(links[i].target)}`] = true;
}
nodes.forEach((d, i) => {
var p1, p2, p3;
// default target to current position
d.target = { x: d.x, y: d.y };
// position of the first node/link in chain is fixed
if (i == 0 || d.chainIndex == 0) {
return;
}
// angle of the first two nodes is relative to a point x-1 from the first point
if (i == 1 || d.chainIndex == 1) {
// copy so we don't modify existing
p1 = JSON.parse(JSON.stringify(nodes[i - 1]));
p1.target.x = -1;
} else {
p1 = nodes[i - 2];
}
p2 = nodes[i - 1];
p3 = nodes[i];
// only calculate angle for linked nodes if links are specified
if (links.length != 0) {
if (
(linkCache[`${getId(p1)}|${getId(p2)}`] != true ||
linkCache[`${getId(p2)}|${getId(p3)}`] != true) &&
i != 1 &&
d.chainIndex != 1
) {
return;
}
}
var angle = typeof angleFn === "function" ? angleFn(d, i) : angleFn;
var radAngle = (angle / 180) * Math.PI;
// reverse p2/p3 because canvas origin is at top left the unit circle origin is bottom left
// TODO remove this and override in canvas drawing?
// TODO negative angles are in the wrong direction
radAngle -= Math.atan2(
p1.target.y - p2.target.y,
p2.target.x - p1.target.x
);
// generate the exact destination position for current node
var dist = distance(d);
var x = p2.target.x + dist * Math.cos(radAngle);
var y = p2.target.y + dist * Math.sin(radAngle);
d.target = { x: x, y: y };
});
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
arguments.length
? (strength =
typeof _ === "function"
? _
: () => {
return _;
})
: strength;
return force;
};
force.distance = function(_) {
arguments.length
? (distance =
typeof _ === "function"
? _
: () => {
return _;
})
: distance;
initialize();
return force;
};
force.links = function(_) {
return arguments.length ? ((links = _), initialize(), force) : links;
};
return force;
}