Published
Edited
Jul 6, 2020
Fork of forceAngular
1 fork
Importers
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
forceRadial = forcePolar
Insert cell
forceAngular = (angle, x, y) => forcePolar(null, x, y, angle, )
Insert cell
forcePolar = function(radius, x, y, angle) {
var nodes,
strength = constant(0.1),
strengths,
radii,
angles;

if (angle !== undefined && angle !== null && typeof angle !== "function")
angle = constant(+angle);
if (radius !== undefined && radius !== null && typeof radius !== "function")
radius = constant(+radius);
if (x == null) x = 0;
if (y == null) y = 0;

function force(alpha) {
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i],
dx = node.x - x || 1e-6,
dy = node.y - y || 1e-6,
r = Math.hypot(dy, dx);

if (radius) {
var k = ((radii[i] - r) * strengths[i] * alpha) / r;
node.vx += dx * k;
node.vy += dy * k;
}

if (angle) {
var a = Math.atan2(dy, dx),
diff = angles[i] - a,
k = r * Math.sin(diff) * (strengths[i] * alpha);

// the factor below augments the "unease" for points that are opposite the correct direction:
// in that case, though sin(diff) is small, tan(diff/2) is very high
k *= Math.hypot(1, Math.tan(diff / 2));

node.vx += -k * Math.sin(a);
node.vy += k * Math.cos(a);
}
}
}

function initialize() {
if (!nodes) return;
var i,
n = nodes.length;
strengths = new Array(n);
angles = new Array(n);
radii = new Array(n);
for (i = 0; i < n; ++i) {
if (angle) angles[i] = +angle(nodes[i], i, nodes) * (Math.PI / 180);
if (radius) radii[i] = +radius(nodes[i], i, nodes);
strengths[i] =
(angle && isNaN(angles[i])) || (radius && isNaN(radii[i]))
? 0
: +strength(nodes[i], i, nodes);
}
}

force.initialize = function(_) {
(nodes = _), initialize();
};

force.strength = function(_) {
return arguments.length
? ((strength = typeof _ === "function" ? _ : constant(+_)),
initialize(),
force)
: strength;
};

force.angle = function(_) {
return arguments.length
? ((angle = typeof _ === "function" ? _ : constant(+_)),
initialize(),
force)
: angle;
};

force.radius = function(_) {
return arguments.length
? ((radius = typeof _ === "function" ? _ : constant(+_)),
initialize(),
force)
: radius;
};

force.x = function(_) {
return arguments.length ? ((x = +_), force) : x;
};

force.y = function(_) {
return arguments.length ? ((y = +_), force) : y;
};

return force;
}
Insert cell
Insert cell
nodes = {
replay;

const angle = d3.randomUniform(0, 360),
radius = d3.randomUniform(1, 10);

return Array.from({ length: 400 }, () => ({
angle: angle(),
r: radius()
}));
}
Insert cell
constant = x => _ => x
Insert cell
height = Math.min(500, width * 0.7)
Insert cell
d3 = require("d3@5")
Insert cell
import { slider } from "@jashkenas/inputs"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more