@graphty/layout
Version:
graph layout algorithms based on networkx
73 lines • 2.58 kB
JavaScript
/**
* Spiral layout algorithm
*/
import { _processParams } from '../../utils/params';
import { getNodesFromGraph } from '../../utils/graph';
import { rescaleLayout } from '../../utils/rescale';
/**
* Position nodes in a spiral layout.
*
* @param G - Graph or list of nodes
* @param scale - Scale factor for positions
* @param center - Coordinate pair around which to center the layout
* @param dim - Dimension of layout
* @param resolution - Controls the spacing between spiral elements
* @param equidistant - Whether to place nodes equidistant from each other
* @returns Positions dictionary keyed by node
*/
export function spiralLayout(G, scale = 1, center = null, dim = 2, resolution = 0.35, equidistant = false) {
if (dim !== 2) {
throw new Error("can only handle 2 dimensions");
}
const processed = _processParams(G, center || [0, 0], dim);
const nodes = getNodesFromGraph(processed.G);
center = processed.center;
const pos = {};
if (nodes.length === 0) {
return pos;
}
if (nodes.length === 1) {
pos[nodes[0]] = [...center];
return pos;
}
let positions = [];
if (equidistant) {
// Create equidistant points along the spiral
// This matches the Python implementation logic
const chord = 1;
const step = 0.5;
let theta = resolution;
theta += chord / (step * theta);
for (let i = 0; i < nodes.length; i++) {
const r = step * theta;
theta += chord / r;
positions.push([Math.cos(theta) * r, Math.sin(theta) * r]);
}
}
else {
// Create points with equal angle but increasing distance
const dist = Array.from({ length: nodes.length }, (_, i) => parseFloat(String(i)));
const angle = dist.map(d => resolution * d);
positions = dist.map((d, i) => [
Math.cos(angle[i]) * d,
Math.sin(angle[i]) * d
]);
}
// Convert position array to position matrix for rescaling
const posArray = [];
for (let i = 0; i < positions.length; i++) {
posArray.push(positions[i]);
}
// Rescale positions and add center offset
const scaledPositions = rescaleLayout(posArray, scale);
for (let i = 0; i < scaledPositions.length; i++) {
scaledPositions[i][0] += center[0];
scaledPositions[i][1] += center[1];
}
// Create position dictionary
for (let i = 0; i < nodes.length; i++) {
pos[nodes[i]] = scaledPositions[i];
}
return pos;
}
//# sourceMappingURL=spiral.js.map