### Start Development Server Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/demo/README.md Runs the development server with hot-reloading. Useful for interactive development and testing. ```bash npm start ``` -------------------------------- ### Install via npm Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Install the ngraph.forcelayout library using npm for Node.js projects. ```bash npm install ngraph.forcelayout ``` -------------------------------- ### Initialize and Iterate Force Layout Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Basic setup for ngraph.forcelayout. Requires an ngraph.graph instance. Perform multiple iterations using `layout.step()` before querying node positions. ```js // graph is an instance of `ngraph.graph` object. var createLayout = require('ngraph.forcelayout'); var layout = createLayout(graph); for (var i = 0; i < ITERATIONS_COUNT; ++i) { layout.step(); } // now we can ask layout where each node/link is best positioned: graph.forEachNode(function(node) { console.log(layout.getNodePosition(node.id)); // Node position is pair of x,y coordinates: // {x: ... , y: ... } }); graph.forEachLink(function(link) { console.log(layout.getLinkPosition(link.id)); // link position is a pair of two positions: // { // from: {x: ..., y: ...}, // to: {x: ..., y: ...} // } }) ``` -------------------------------- ### Set Initial Node Positions Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Demonstrates using `setNodePosition` to manually set initial positions for nodes before the simulation starts. This can be used for seeding or implementing drag interactions. ```js var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); var layout = createLayout(graph); // Place node 1 at a fixed screen position before simulation starts layout.setNodePosition(1, 0, 0); layout.setNodePosition(2, 100, 0); layout.setNodePosition(3, 50, 86); // equilateral triangle seed for (var i = 0; i < 50; i++) layout.step(); console.log(layout.getNodePosition(1)); // shifted from seed due to forces ``` -------------------------------- ### Get Graph Bounding Box with ngraph.forcelayout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Calculates and returns the minimum and maximum coordinates (x, y, and potentially z) that encompass all nodes in the graph. This is recomputed on every call. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); for (var i = 0; i < 20; i++) graph.addLink(i, (i + 1) % 20); var layout = createLayout(graph); for (var i = 0; i < 300; i++) layout.step(); var rect = layout.getGraphRect(); console.log('Width: ', rect.max_x - rect.min_x); console.log('Height: ', rect.max_y - rect.min_y); console.log('Center: ', (rect.max_x + rect.min_x) / 2, (rect.max_y + rect.min_y) / 2); ``` -------------------------------- ### Get Graph Bounding Box Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Use `getGraphRect()` to obtain the bounding box of the graph, which includes the minimum and maximum x and y coordinates. ```javascript var rect = layout.getGraphRect(); // rect.min_x, rect.min_y - left top coordinates of the bounding box // rect.max_x, rect.max_y - right bottom coordinates of the bounding box ``` -------------------------------- ### Get Link Endpoint Positions with ngraph.forcelayout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Retrieves the current positions of a link's source and target nodes. The returned position objects are the same references as those from `getNodePosition`, ensuring referential equality. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); var link = graph.addLink('src', 'dst'); var layout = createLayout(graph); for (var i = 0; i < 100; i++) layout.step(); var lp = layout.getLinkPosition(link.id); console.log('from:', lp.from.x, lp.from.y); console.log('to: ', lp.to.x, lp.to.y); // Verify referential equality with getNodePosition console.log(lp.from === layout.getNodePosition('src')); // true console.log(lp.to === layout.getNodePosition('dst')); // true ``` -------------------------------- ### Get Specific Body by Node ID Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Retrieve a specific body object using its node ID. This allows direct manipulation of its physical attributes like position and mass. ```javascript var graph = createGraph(); graph.addLink(1, 2); // Get body that represents node 1: var body = layout.getBody(1); assert( typeof body.pos.x === 'number' && typeof body.pos.y === 'number', 'Body has position'); assert(body.mass, 'Body has mass'); ``` -------------------------------- ### Get Node Position and Verify Object Identity Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Retrieves the position of a node using `getNodePosition`. It highlights that the returned position object is mutated in place and object identity is preserved across calls for the same node. ```js var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink('alice', 'bob'); graph.addLink('bob', 'carol'); var layout = createLayout(graph); for (var i = 0; i < 100; i++) layout.step(); // 2D var pos = layout.getNodePosition('alice'); console.log(pos.x, pos.y); // e.g. -8.3 2.1 // Object identity is preserved — no allocation on repeated calls console.log(layout.getNodePosition('alice') === layout.getNodePosition('alice')); // true ``` -------------------------------- ### Basic Initialization and Iteration Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Demonstrates how to create a force layout instance and run iterations to position nodes and links. ```APIDOC ## Basic Initialization and Iteration ### Description Initializes the force layout and performs multiple iterations to calculate node and link positions. ### Usage ```javascript // graph is an instance of `ngraph.graph` object. var createLayout = require('ngraph.forcelayout'); var layout = createLayout(graph); // Perform multiple iterations for layout convergence for (var i = 0; i < ITERATIONS_COUNT; ++i) { layout.step(); } // Access node and link positions after iterations graph.forEachNode(function(node) { console.log(layout.getNodePosition(node.id)); // Node position is pair of x,y coordinates: {x: ... , y: ... } }); graph.forEachLink(function(link) { console.log(layout.getLinkPosition(link.id)); // link position is a pair of two positions: // { // from: {x: ..., y: ...}, // to: {x: ..., y: ...} // } ``` ``` -------------------------------- ### Create and Run Force-Directed Layout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Demonstrates creating a graph, initializing a 2D layout with custom physics settings, running the simulation for a fixed number of steps, and retrieving final node positions. ```js var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); // Build a small graph var graph = createGraph(); graph.addLink('a', 'b'); graph.addLink('b', 'c'); graph.addLink('c', 'a'); // Create a 2D layout with custom physics var layout = createLayout(graph, { gravity: -12, springLength: 30, springCoefficient: 0.8, dragCoefficient: 0.9, theta: 0.8, timeStep: 0.5, }); // Run 300 iterations until stable (or forced) for (var i = 0; i < 300; i++) { var stable = layout.step(); if (stable) { console.log('Converged after', i, 'steps'); break; } } // Read final positions graph.forEachNode(function (node) { var pos = layout.getNodePosition(node.id); console.log(node.id, '->', pos); // { x: -12.4, y: 7.8 } }); ``` -------------------------------- ### Build for Production Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/demo/README.md Compiles and minifies the application for production deployment. ```bash npm run build ``` -------------------------------- ### Basic CSS for ngraph.forcelayout Demo Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/demo/public/index.html Essential CSS for the ngraph.forcelayout demo, including box-sizing, font styles, and canvas positioning. ```css box-sizing: border-box; } body { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #EEE; margin: 0; background: rgb(12, 41, 82); overflow: hidden; } canvas { position: absolute; width: 100%; height: 100%; left: 0; right: 0; top: 0; bottom: 0; ``` -------------------------------- ### Initialize Force Layout with Physics Settings Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Customize the physics simulation by providing a `physicsSettings` object during layout initialization. This allows tuning parameters like time step, gravity, spring length, and drag. ```js // Configure var physicsSettings = { timeStep: 0.5, dimensions: 2, gravity: -12, theta: 0.8, springLength: 10, springCoefficient: 0.8, dragCoefficient: 0.9, }; // pass it as second argument to layout: var layout = require('ngraph.forcelayout')(graph, physicsSettings); ``` -------------------------------- ### Animate Layout with Stability Events Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Shows how to set up an animation loop using `layout.step()` and listen for `'stable'` events to detect when the layout has converged. Requires `requestAnimationFrame` for animation. ```js var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); var layout = createLayout(graph); // Listen for stability change layout.on('stable', function (isStable) { console.log('Stable:', isStable); }); // Animate loop (e.g. in a browser requestAnimationFrame) function animate() { var done = layout.step(); console.log('last move:', layout.lastMove); // total movement magnitude if (!done) requestAnimationFrame(animate); } animate(); ``` -------------------------------- ### Physics Simulator Configuration Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Details how to configure the physics simulation parameters. ```APIDOC ## Physics Simulator Configuration ### Description Allows customization of the physics simulation parameters that govern node interactions and movement. ### Parameters - `timeStep` (number): The time step for the simulation. - `dimensions` (number): The number of dimensions for the layout (e.g., 2 for 2D, 3 for 3D). - `gravity` (number): The gravitational force applied to nodes. - `theta` (number): The theta parameter for the Barnes-Hut algorithm. - `springLength` (number): The ideal length of the springs connecting nodes. - `springCoefficient` (number): The stiffness of the springs. - `dragCoefficient` (number): The coefficient of drag, which slows down the simulation. ### Usage ```javascript var physicsSettings = { timeStep: 0.5, dimensions: 2, gravity: -12, theta: 0.8, springLength: 10, springCoefficient: 0.8, dragCoefficient: 0.9, }; var layout = require('ngraph.forcelayout')(graph, physicsSettings); // Access the simulator (read-only): var simulator = layout.simulator; ``` ``` -------------------------------- ### createLayout(graph, physicsSettings?) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Creates a force-directed layout for an ngraph.graph instance. Accepts an optional settings object to tune the physics simulator. Returns a Layout object augmented with ngraph.events so callers can listen to 'step' and 'stable' events. ```APIDOC ## createLayout(graph, physicsSettings?) ### Description Creates a force-directed layout for an `ngraph.graph` instance. Accepts an optional settings object to tune the physics simulator. Returns a `Layout` object augmented with `ngraph.events` so callers can listen to `step` and `stable` events. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); // Build a small graph var graph = createGraph(); graph.addLink('a', 'b'); graph.addLink('b', 'c'); graph.addLink('c', 'a'); // Create a 2D layout with custom physics var layout = createLayout(graph, { gravity: -12, springLength: 30, springCoefficient: 0.8, dragCoefficient: 0.9, theta: 0.8, timeStep: 0.5, }); // Run 300 iterations until stable (or forced) for (var i = 0; i < 300; i++) { var stable = layout.step(); if (stable) { console.log('Converged after', i, 'steps'); break; } } // Read final positions graph.forEachNode(function (node) { var pos = layout.getNodePosition(node.id); console.log(node.id, '->', pos); // { x: -12.4, y: 7.8 } }); ``` ### Response #### Success Response (200) Layout object with event listeners. #### Response Example None provided. ``` -------------------------------- ### layout.step() Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Performs one iteration of force integration. Returns `true` when the system is considered stable (average per-body movement ≤ 0.01), `false` otherwise. Also fires the 'step' event after each call and 'stable' when stability status changes. ```APIDOC ## layout.step() ### Description Performs one iteration of force integration. Returns `true` when the system is considered stable (average per-body movement ≤ 0.01), `false` otherwise. Also fires the `'step'` event after each call and `'stable'` when stability status changes. ### Method `step()` ### Parameters None ### Request Example ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); var layout = createLayout(graph); // Listen for stability change layout.on('stable', function (isStable) { console.log('Stable:', isStable); }); // Animate loop (e.g. in a browser requestAnimationFrame) function animate() { var done = layout.step(); console.log('last move:', layout.lastMove); // total movement magnitude if (!done) requestAnimationFrame(animate); } animate(); ``` ### Response #### Success Response (200) `true` if the system is stable, `false` otherwise. #### Response Example None provided. ``` -------------------------------- ### Node Pinning and Position Setting Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Explains how to pin nodes to prevent them from moving and how to set their positions manually. ```APIDOC ## Node Pinning and Position Setting ### Description Allows pinning nodes to fix their positions and manually setting node positions. ### Methods - `pinNode(node, shouldPin)`: Pins or unpins a node. - `isNodePinned(node)`: Checks if a node is currently pinned. - `setNodePosition(nodeId, x, y)`: Manually sets the position of a node. ### Usage ```javascript var nodeToPin = graph.getNode(nodeId); // Pin a node: layout.pinNode(nodeToPin, true); // Toggle node pinning: layout.pinNode(node, !layout.isNodePinned(node)); // Set a specific node position: layout.setNodePosition(nodeId, x, y); ``` ``` -------------------------------- ### Include via CDN Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Include the ngraph.forcelayout library in your HTML file using a CDN link. The library will be available globally as `ngraphCreateLayout`. ```html ``` -------------------------------- ### Configure Multi-dimensional Layouts (3D and N-D) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Set the `dimensions` option to N to run the simulation in N-dimensional space. For dimensions beyond 3, positions are exposed as `c4`, `c5`, etc. The code generation for dimensions is cached. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); graph.addLink(3, 1); // 3D layout var layout3d = createLayout(graph, { dimensions: 3 }); for (var i = 0; i < 100; i++) layout3d.step(); var p = layout3d.getNodePosition(1); console.log('3D pos:', p.x, p.y, p.z); // 6D layout — positions get c4, c5, c6 var graph6 = createGraph(); graph6.addLink('a', 'b'); var layout6d = createLayout(graph6, { dimensions: 6 }); layout6d.step(); var q = layout6d.getNodePosition('a'); console.log('6D pos:', q.x, q.y, q.z, q.c4, q.c5, q.c6); // Bounding box for 3D var rect = layout3d.getGraphRect(); console.log(rect.min_x, rect.max_x, rect.min_y, rect.max_y, rect.min_z, rect.max_z); ``` -------------------------------- ### Physics simulator access Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Gain direct access to the underlying `PhysicsSimulator` via `layout.simulator`. This allows for runtime tuning of physics parameters like gravity, drag, spring settings, and adding/removing custom forces. ```APIDOC ## Physics simulator — Direct access via `layout.simulator` ### Description `layout.simulator` exposes the underlying `PhysicsSimulator` for runtime physics tuning: changing gravity, drag, spring settings, adding/removing custom force functions, and reading the bounding box independent of the layout API. ### Properties - `simulator` (PhysicsSimulator): An instance of the physics simulator. ### Methods on `simulator` - `gravity(value)`: Get or set the gravity force. - `theta(value)`: Get or set the Barnes-Hut approximation parameter. - `springLength(value)`: Get or set the ideal spring length. - `springCoefficient(value)`: Get or set the spring coefficient. - `addForce(name, forceFn)`: Adds a custom force function. - `removeForce(name)`: Removes a custom force function. - `getForces()`: Returns a map of active force names. - `getBBox()`: Returns the bounding box of the simulation. ``` -------------------------------- ### Multi-dimensional Layout Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Shows how to configure the layout for 2D, 3D, and higher dimensions. ```APIDOC ## Multi-dimensional Layout ### Description Configures the force layout to operate in specified dimensions (2D, 3D, or higher). ### Usage ```javascript // For 3D layout: let layout3D = createLayout(graph, {dimensions: 3}); let nodePosition3D = layout3D.getNodePosition(nodeId); // has {x, y, z} attributes // For 6D layout: let layout6D = createLayout(graph, {dimensions: 6}); let nodePosition6D = layout6D.getNodePosition(nodeId); // has {x, y, z, c4, c5, c6} attributes ``` ``` -------------------------------- ### Configure Multi-Dimensional Layout Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md To create layouts in dimensions higher than 2D, specify the 'dimensions' option during initialization. Node positions will include additional attributes (e.g., z, c4, c5) for dimensions beyond 3D. ```js let layout = createLayout(graph, {dimensions: 3}); // 3D layout let nodePosition = layout.getNodePosition(nodeId); // has {x, y, z} attributes ``` ```js let layout = createLayout(graph, {dimensions: 6}); // 6D layout // Every layout with more than 3 dimensions, say N, gets additional attributes: // c4, c5, ... cN let nodePosition = layout.getNodePosition(nodeId); // has {x, y, z, c4, c5, c6} ``` -------------------------------- ### Initialize Google Analytics Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/demo/public/index.html Standard JavaScript snippet for initializing Google Analytics. Ensure this is included on your page to track analytics. ```javascript window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-TXT6313TGG'); ``` -------------------------------- ### Access and Tune Physics Simulator Directly Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Interact with the underlying `PhysicsSimulator` via `layout.simulator` to tune physics parameters like gravity and drag, add custom forces, or read the bounding box at runtime. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); var layout = createLayout(graph, { gravity: -5 }); var sim = layout.simulator; // Read / change settings at runtime using fluent accessor pattern console.log('gravity:', sim.gravity()); // -5 sim.gravity(-20); // apply stronger repulsion console.log('theta:', sim.theta()); // 0.8 (default) sim.springLength(50).springCoefficient(0.5); // chained setters // Add a custom wind force that nudges all bodies rightward sim.addForce('wind', function (iterationNumber) { sim.bodies.forEach(function (body) { if (!body.isPinned) body.force.x += 0.1; }); }); for (var i = 0; i < 100; i++) layout.step(); // Remove the custom force sim.removeForce('wind'); // List active forces sim.getForces().forEach(function (fn, name) { console.log('force:', name); // 'nbody', 'spring' (wind was removed) }); // Bounding box var bbox = sim.getBBox(); console.log('bbox:', bbox.min_x, bbox.max_x, bbox.min_y, bbox.max_y); ``` -------------------------------- ### Render Static Force-Directed Layout in SVG Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/demo-static/index.html Initializes a grid graph, computes a static layout, and renders nodes and edges as SVG elements. Ensure the 'graph-container' element exists in your HTML and has appropriate CSS for positioning. ```javascript const graph = generators.grid(5, 5); const layout = ngraphCreate2dLayout(graph); for (let i = 0; i < 300; ++i) { layout.step(); } const rect = layout.getGraphRect() const w = rect.max_x - rect.min_x; const h = rect.max_y - rect.min_y; const dw = w * 0.2; const dh = h * 0.2; const container = document.querySelector('.graph-container'); // make it centered: container.setAttribute('viewBox', `${rect.min_x - dw} ${rect.min_y - dh} ${w + 2 * dw} ${h + 2 * dh}`); // render edges: graph.forEachLink(link => { const from = layout.getNodePosition(link.fromId); const to = layout.getNodePosition(link.toId); const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', from.x); line.setAttribute('y1', from.y); line.setAttribute('x2', to.x); line.setAttribute('y2', to.y); line.setAttribute('stroke', 'black'); container.appendChild(line); }) // render nodes: graph.forEachNode(node => { const pos = layout.getNodePosition(node.id); console.log(pos); const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); rect.setAttribute('x', pos.x - 1); rect.setAttribute('y', pos.y - 1); rect.setAttribute('width', 2); rect.setAttribute('height', 2); rect.setAttribute('fill', 'orange'); container.appendChild(rect); }) ``` -------------------------------- ### Standalone Physics Simulator Usage Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt This snippet shows how to use the physics simulator independently of the graph layout API for pure physics simulations. It demonstrates adding bodies, springs, running the simulation, and removing springs. ```javascript var createSimulator = require('ngraph.forcelayout').simulator; var sim = createSimulator({ gravity: -10, springCoefficient: 0.5, dragCoefficient: 0.9, timeStep: 0.5, dimensions: 2, }); var b1 = sim.addBodyAt({ x: -50, y: 0 }); var b2 = sim.addBodyAt({ x: 50, y: 0 }); // Connect them with a spring of rest length 20 var spring = sim.addSpring(b1, b2, 20); console.log('spring:', spring.from.pos, '->', spring.to.pos); for (var i = 0; i < 200; i++) sim.step(); console.log('b1 final pos:', b1.pos.x.toFixed(2), b1.pos.y.toFixed(2)); console.log('b2 final pos:', b2.pos.x.toFixed(2), b2.pos.y.toFixed(2)); // Remove spring to let bodies repel sim.removeSpring(spring); for (var i = 0; i < 50; i++) sim.step(); console.log('b1 after spring removal:', b1.pos.x.toFixed(2)); ``` -------------------------------- ### layout.getBody(nodeId) / layout.forEachBody(cb) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Provides access to the underlying physics bodies. `getBody` returns the raw `Body` object for a specific node, allowing direct manipulation of its physical properties. `forEachBody` iterates over all bodies in the simulation. ```APIDOC ## `layout.getBody(nodeId)` / `layout.forEachBody(cb)` — Access physical bodies ### Description `getBody` returns the raw `Body` object (`{ pos, force, velocity, mass, isPinned }`) for direct physics manipulation. `forEachBody` iterates all bodies, passing `(body, nodeId)` to the callback. ### Parameters #### `getBody` - **nodeId** (string | number) - Required - The ID of the node whose body to retrieve. #### `forEachBody` - **cb** (function) - Required - A callback function that will be executed for each body. It receives `(body, nodeId)` as arguments. ### Response #### `getBody` Success Response (200) - **pos** (object) - The current position of the body (`{x, y}`). - **force** (object) - The current force applied to the body (`{x, y}`). - **velocity** (object) - The current velocity of the body (`{x, y}`). - **mass** (number) - The mass of the body. - **isPinned** (boolean) - Indicates if the body is pinned. ### Request Example ```js // Inspect a single body var body = layout.getBody(1); console.log('pos:', body.pos); console.log('velocity:', body.velocity); // Compute total kinetic energy across all bodies var totalKE = 0; layout.forEachBody(function (b) { totalKE += b.velocity.x * b.velocity.x + b.velocity.y * b.velocity.y; }); console.log('Total KE:', totalKE); ``` ### Response Example ```json { "pos": {"x": 15.3, "y": -22.7}, "force": {"x": 0.1, "y": -0.2}, "velocity": {"x": 0.5, "y": -0.8}, "mass": 1.0, "isPinned": false } ``` ``` -------------------------------- ### Multi-dimensional layout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Configure the layout to operate in N-dimensional space (e.g., 3D, 6D) by specifying the `dimensions` option. Higher dimensions beyond 3 will have their positions exposed as `c4`, `c5`, etc. ```APIDOC ## Multi-dimensional layout ### Description Pass `dimensions: N` in the settings to run the simulation in any number of dimensions. Positions for dimensions 4+ are exposed as `c4`, `c5`, … `cN` properties on the vector. Code generation happens once per unique dimension count and is cached. ### Configuration - `dimensions` (number): The number of dimensions for the layout simulation. ``` -------------------------------- ### Access Physics Bodies with ngraph.forcelayout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Provides direct access to the physical `Body` objects, which contain properties like position, force, velocity, mass, and pinned status. `forEachBody` allows iteration over all bodies for aggregate calculations. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); var layout = createLayout(graph); layout.step(); // Inspect a single body var body = layout.getBody(1); console.log('pos:', body.pos); // { x: ..., y: ... } console.log('velocity:', body.velocity); // { x: ..., y: ... } console.log('mass:', body.mass); // e.g. 1.33 console.log('pinned:', body.isPinned); // false // Compute total kinetic energy across all bodies var totalKE = 0; layout.forEachBody(function (b) { totalKE += b.velocity.x * b.velocity.x + b.velocity.y * b.velocity.y; }); console.log('Total KE:', totalKE); ``` -------------------------------- ### layout.getSpring(linkIdOrFromId, toId?) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Retrieves the `Spring` object associated with a link. The link can be identified by its ID, the link object itself, or by providing the IDs of its source and destination nodes. ```APIDOC ## `layout.getSpring(linkIdOrFromId, toId?)` — Access a spring ### Description Returns the `Spring` object (`{ from: Body, to: Body, length, coefficient }`) for an edge identified by link id, link object, or a `(fromId, toId)` pair. ### Parameters #### Path Parameters - **linkIdOrFromId** (string | object) - Required - The ID of the link, or the ID/object of the source node. - **toId** (string | number) - Optional - The ID of the destination node (required if `linkIdOrFromId` is a node ID). ### Response #### Success Response (200) - **from** (Body) - The source `Body` object of the spring. - **to** (Body) - The destination `Body` object of the spring. - **length** (number) - The ideal length of the spring. A value of -1 indicates the global default is used. - **coefficient** (number) - The spring coefficient (stiffness). A value of -1 indicates the global default is used. ### Request Example ```js // Three equivalent ways to get the same spring: var s1 = layout.getSpring(link); // pass link object var s2 = layout.getSpring(link.id); // pass link id var s3 = layout.getSpring('A', 'B'); // pass from/to node ids console.log('spring length:', s1.length); console.log('spring coefficient:', s1.coefficient); ``` ### Response Example ```json { "from": {"pos": {"x": 10.5, "y": 20.2}, "mass": 1.0, ...}, "to": {"pos": {"x": 30.1, "y": 40.8}, "mass": 1.0, ...}, "length": 50, "coefficient": 0.1 } ``` ``` -------------------------------- ### Dynamic Graph Updates with Reactive Layout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt This snippet demonstrates how the layout automatically updates when nodes and links are added or removed from the graph. No extra calls are needed to update the physics simulation. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); var layout = createLayout(graph); // start with empty graph // Add nodes/links dynamically — layout tracks changes automatically graph.addLink(1, 2); graph.addLink(2, 3); layout.step(); console.log('bodies after 2 links:', layout.simulator.bodies.length); // 3 graph.addLink(3, 4); layout.step(); console.log('bodies after 3 links:', layout.simulator.bodies.length); // 4 // Remove a node — its body is removed from the simulator graph.removeNode(4); layout.step(); console.log('bodies after node removal:', layout.simulator.bodies.length); // 3 ``` -------------------------------- ### Measure Simulation Stability with getForceVectorLength Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Use `getForceVectorLength()` to check the Euclidean norm of all force vectors. A value near zero indicates convergence, meaning the simulation has stabilized. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); for (var i = 0; i < 10; i++) graph.addLink(i, (i + 3) % 10); var layout = createLayout(graph); var step = 0; while (layout.getForceVectorLength() > 0.1 && step < 1000) { layout.step(); step++; } console.log('Converged in', step, 'steps, force length:', layout.getForceVectorLength().toFixed(4)); ``` -------------------------------- ### layout.setNodePosition(nodeId, x, y, z?, ...c) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Teleports the physical body of `nodeId` to the given coordinates without affecting its velocity or pinned state. Useful for seeding initial positions or implementing drag interactions. ```APIDOC ## layout.setNodePosition(nodeId, x, y, z?, ...c) ### Description Teleports the physical body of `nodeId` to the given coordinates without affecting its velocity or pinned state. Useful for seeding initial positions or implementing drag interactions. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); var layout = createLayout(graph); // Place node 1 at a fixed screen position before simulation starts layout.setNodePosition(1, 0, 0); layout.setNodePosition(2, 100, 0); layout.setNodePosition(3, 50, 86); // equilateral triangle seed for (var i = 0; i < 50; i++) layout.step(); console.log(layout.getNodePosition(1)); // shifted from seed due to forces ``` ### Response #### Success Response (200) None #### Response Example None provided. ``` -------------------------------- ### layout.getNodePosition(nodeId) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Returns the live position object (`{x, y}` in 2D; `{x, y, z}` in 3D; `{x, y, z, c4, …}` in higher dimensions) for the body corresponding to `nodeId`. The same object reference is returned on every call for the same node — it is mutated in place on each `step()`. ```APIDOC ## layout.getNodePosition(nodeId) ### Description Returns the live position object (`{x, y}` in 2D; `{x, y, z}` in 3D; `{x, y, z, c4, …}` in higher dimensions) for the body corresponding to `nodeId`. The same object reference is returned on every call for the same node — it is mutated in place on each `step()`. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink('alice', 'bob'); graph.addLink('bob', 'carol'); var layout = createLayout(graph); for (var i = 0; i < 100; i++) layout.step(); // 2D var pos = layout.getNodePosition('alice'); console.log(pos.x, pos.y); // e.g. -8.3 2.1 // Object identity is preserved — no allocation on repeated calls console.log(layout.getNodePosition('alice') === layout.getNodePosition('alice')); // true ``` ### Response #### Success Response (200) An object representing the node's position (e.g., `{x: number, y: number}`). #### Response Example None provided. ``` -------------------------------- ### Pin and Unpin Nodes with ngraph.forcelayout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Allows pinning nodes to fix their positions during layout calculation or unpinning them to allow movement. Nodes can be pinned initially via their data object (`isPinned: true`) or programmatically using `pinNode`. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addLink(1, 2); graph.addLink(2, 3); // Pin via node data at creation time graph.addNode(4, { isPinned: true }); graph.addLink(3, 4); var layout = createLayout(graph); // Pin node 1 programmatically and fix its position layout.pinNode(graph.getNode(1), true); layout.setNodePosition(1, 0, 0); for (var i = 0; i < 200; i++) layout.step(); var pos1 = layout.getNodePosition(1); console.log(pos1.x, pos1.y); // still 0, 0 // Toggle pin var node2 = graph.getNode(2); layout.pinNode(node2, !layout.isNodePinned(node2)); console.log(layout.isNodePinned(node2)); // false — now free to move ``` -------------------------------- ### layout.getForceVectorLength() Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Measures the stability of the current simulation by returning the Euclidean norm of the sum of all force vectors. A value close to zero indicates that the system has converged. ```APIDOC ## layout.getForceVectorLength() ### Description Returns the Euclidean norm of the sum of all force vectors. A value close to zero indicates the system has converged and further steps will produce minimal movement. ### Method `getForceVectorLength()` ### Returns - `number`: The Euclidean norm of the sum of all force vectors. ``` -------------------------------- ### layout.pinNode(node, isPinned) / layout.isNodePinned(node) Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Allows pinning or unpinning a node. Pinned nodes are excluded from physics simulation, maintaining their current position while other nodes move around them. The `isNodePinned` method checks the pinned status of a node. ```APIDOC ## `layout.pinNode(node, isPinned)` / `layout.isNodePinned(node)` — Pin or unpin a node ### Description Pinned nodes are excluded from force integration — they remain at their current position while all other nodes move around them. Accepts the full node object (from `graph.getNode()`). Setting `node.data.isPinned = true` before layout creation also pins a node automatically. ### Parameters #### `pinNode` - **node** (object) - Required - The node object to pin or unpin. - **isPinned** (boolean) - Required - `true` to pin the node, `false` to unpin it. #### `isNodePinned` - **node** (object) - Required - The node object to check. ### Response #### `isNodePinned` Success Response (200) - **return value** (boolean) - `true` if the node is pinned, `false` otherwise. ### Request Example ```js // Pin node 1 programmatically and fix its position layout.pinNode(graph.getNode(1), true); layout.setNodePosition(1, 0, 0); // Toggle pin var node2 = graph.getNode(2); layout.pinNode(node2, !layout.isNodePinned(node2)); console.log(layout.isNodePinned(node2)); // false — now free to move ``` ### Response Example ```js console.log(layout.isNodePinned(graph.getNode(1))); // true ``` ``` -------------------------------- ### Pinning and Setting Node Positions Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Use `pinNode(node, true)` to prevent a node from moving during layout iterations. `isNodePinned(node)` checks the pinned status. `setNodePosition(nodeId, x, y)` allows manual position updates. ```js var nodeToPin = graph.getNode(nodeId); layout.pinNode(nodeToPin, true); // now layout will not move this node ``` ```js var node = graph.getNode(nodeId); layout.pinNode(node, !layout.isNodePinned(node)); // toggle it ``` ```js layout.setNodePosition(nodeId, x, y); ``` -------------------------------- ### layout.dispose() Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Stops the layout simulation by detaching it from graph events. After calling dispose(), changes to the graph will not affect the physics simulation. ```APIDOC ## layout.dispose() ### Description Detaches the layout from the graph's `changed` events and fires a `disposed` event. After `dispose()`, dynamically adding or removing nodes/links will no longer update the physics simulation. ### Method `dispose()` ``` -------------------------------- ### Access Springs with ngraph.forcelayout Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Retrieves the `Spring` object associated with a link, allowing inspection of its length and coefficient. The spring can be accessed using the link object, link ID, or a pair of source and target node IDs. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); var link = graph.addLink('A', 'B'); var layout = createLayout(graph); // Three equivalent ways to get the same spring: var s1 = layout.getSpring(link); // pass link object var s2 = layout.getSpring(link.id); // pass link id var s3 = layout.getSpring('A', 'B'); // pass from/to node ids console.log(s1 === s2 && s2 === s3); // true console.log('spring length:', s1.length); // -1 means "use global default" console.log('spring coefficient:', s1.coefficient); // -1 means "use global default" console.log('from body pos:', s1.from.pos); console.log('to body pos:', s1.to.pos); ``` -------------------------------- ### Iterate Over All Bodies Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Use `forEachBody` to iterate through all bodies in the layout. This method provides access to each body's properties and its corresponding node ID from the graph. ```javascript layout.forEachBody(function(body, nodeId) { assert( typeof body.pos.x === 'number' && typeof body.pos.y === 'number', 'Body has position'); assert(graph.getNode(nodeId), 'NodeId is coming from the graph'); }); ``` -------------------------------- ### Node Position Object Reuse Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md The `getNodePosition()` and `getLinkPosition()` methods return the same object reference for a given node/link across calls. This is for performance reasons. If you need to store positions, copy the returned object. ```js layout.getNodePosition(1) === layout.getNodePosition(1); ``` -------------------------------- ### Disposing Layout Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Describes how to stop the layout from monitoring graph changes. ```APIDOC ## Disposing Layout ### Description Stops the force layout from monitoring graph events and releases resources. ### Method `dispose()` ### Usage ```javascript layout.dispose(); ``` ``` -------------------------------- ### Customize Node Mass with nodeMass Function Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Override the default node mass calculation (which scales with degree) by providing a `nodeMass` function in the settings. This allows for custom mass assignments based on node properties. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); graph.addNode('heavy', { weight: 100 }); graph.addNode('light', { weight: 1 }); graph.addLink('heavy', 'light'); var layout = createLayout(graph, { nodeMass: function (nodeId) { var node = graph.getNode(nodeId); return node && node.data ? node.data.weight : 1; } }); var heavyBody = layout.getBody('heavy'); var lightBody = layout.getBody('light'); console.log('heavy mass:', heavyBody.mass); // 100 console.log('light mass:', lightBody.mass); // 1 for (var i = 0; i < 200; i++) layout.step(); ``` -------------------------------- ### Dispose Layout Listener Source: https://github.com/anvaka/ngraph.forcelayout/blob/main/README.md Call `layout.dispose()` to stop the layout from monitoring graph events and prevent memory leaks when the layout is no longer needed. ```js layout.dispose(); ``` -------------------------------- ### Custom nodeMass function Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Override the default node mass calculation by providing a custom `nodeMass` function in the layout settings. This allows for dynamic control over how node mass affects the simulation. ```APIDOC ## Custom `nodeMass` function ### Description By default, node mass scales with degree (number of links / 3 + 1). Provide a `nodeMass` function in settings to override this for every node. ### Configuration - `nodeMass` (function): A function that takes a `nodeId` and returns the mass for that node. ``` -------------------------------- ### Stop Layout Updates with dispose() Source: https://context7.com/anvaka/ngraph.forcelayout/llms.txt Call `dispose()` to detach the layout from graph events. After disposal, changes to the graph (adding/removing nodes/links) will not update the physics simulation. ```javascript var createGraph = require('ngraph.graph'); var createLayout = require('ngraph.forcelayout'); var graph = createGraph(); var layout = createLayout(graph); graph.addLink(1, 2); layout.step(); // Stop the layout; subsequent graph mutations won't be tracked layout.dispose(); graph.addLink(3, 4); // layout is unaware of this change console.log(layout.simulator.bodies.length); // still 2 ```