@antv/layout
Version:
graph layout algorithm
62 lines (50 loc) • 1.69 kB
text/typescript
import type { NodeData, Point } from '../../types';
import type { GraphLib } from '../../model/data';
import { AccMap } from './types';
/**
* Gravity force toward center
* Pulls all nodes toward a specified center point
*/
export function forceGravity(center: Point = [0, 0, 0], gravity: number = 10) {
let getCenter: ((node?: NodeData, degree?: number) => number[]) | undefined;
function force(model: GraphLib, accMap: AccMap) {
const nodes = model.nodes();
if (!nodes) return;
model.forEachNode((node) => {
const { id, mass, x, y, z = 0 } = node;
let vecX = 0;
let vecY = 0;
let vecZ = 0;
let currentGravity = gravity;
const degree = model.degree(id);
const forceCenter = getCenter?.(node, degree);
if (forceCenter) {
const [centerX, centerY, strength] = forceCenter;
vecX = x - centerX;
vecY = y - centerY;
currentGravity = strength;
} else {
vecX = x - center[0];
vecY = y - center[1];
vecZ = z - (center[2] || 0);
}
if (currentGravity) {
accMap[id].x -= (currentGravity * vecX) / mass;
accMap[id].y -= (currentGravity * vecY) / mass;
accMap[id].z -= (currentGravity * vecZ) / mass;
}
});
}
force.center = function (_?: Point) {
return arguments.length ? ((center = _!), force) : center;
};
force.gravity = function (_?: number) {
return arguments.length ? ((gravity = _!), force) : gravity;
};
force.getCenter = function (
_?: (node?: NodeData, degree?: number) => number[],
) {
return arguments.length ? ((getCenter = _), force) : getCenter;
};
return force;
}