@graphty/layout
Version:
graph layout algorithms based on networkx
67 lines • 2.12 kB
JavaScript
/**
* Shell layout algorithm
*/
import { _processParams } from '../../utils/params';
import { getNodesFromGraph } from '../../utils/graph';
import { np } from '../../utils/numpy';
/**
* Position nodes in concentric circles.
*
* @param G - Graph or list of nodes
* @param nlist - List of node lists for each shell
* @param scale - Scale factor for positions
* @param center - Coordinate pair around which to center the layout
* @param dim - Dimension of layout (currently only supports dim=2)
* @returns Positions dictionary keyed by node
*/
export function shellLayout(G, nlist = null, scale = 1, center = null, dim = 2) {
if (dim !== 2) {
throw new Error("can only handle 2 dimensions");
}
const processed = _processParams(G, center, 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;
}
// If no nlist is specified, put all nodes in a single shell
if (!nlist) {
nlist = [nodes];
}
const radiusBump = scale / nlist.length;
let radius;
if (nlist[0].length === 1) {
// Single node at center
radius = 0;
pos[nlist[0][0]] = [...center];
radius += radiusBump;
}
else {
// Start at radius 1
radius = radiusBump;
}
for (let i = 0; i < nlist.length; i++) {
const shell = nlist[i];
if (shell.length === 0)
continue;
if (shell.length === 1 && i === 0) {
// Already handled the case of a single center node
continue;
}
// Calculate positions on a circle
const theta = np.linspace(0, 2 * Math.PI, shell.length + 1).slice(0, -1);
shell.forEach((node, j) => {
const x = Math.cos(theta[j]) * radius + center[0];
const y = Math.sin(theta[j]) * radius + center[1];
pos[node] = [x, y];
});
radius += radiusBump;
}
return pos;
}
//# sourceMappingURL=shell.js.map