d3-force-3d

repository·master·Indexed 19 days ago

https://github.com/vasturiano/d3-force-3d

A multi-dimensional extension of the d3-force library (v3.0.6) that enables physical simulations in 1D, 2D, or 3D spaces. Designed as a drop-in replacement for d3-force, it uses a velocity Verlet numerical integrator to simulate forces on particles. It supports various force types including centering, collision, and links, and allows for configurable dimensionality via the numDimensions method.

Tokens
6.6K
Snippets
24
Records
39
Agent score
58%

What's inside d3-force-3d

  1. Overview of d3-force-3d

    master

    d3-force-3d is an extended version of d3-force that supports multi-dimensional simulations (1D, 2D, or 3D) via the numDimensions method. It is fully backwards compatible with d3-force (v3.0.0) and acts as a drop-in replacement.

    The module uses a velocity Verlet numerical integrator to simulate physical forces on particles. It assumes a constant unit time step (Δt = 1) and constant unit mass (m = 1) for all particles. This makes force equivalent to constant acceleration, which is applied to velocity and then to position.

    Common use cases include:

    • Force-directed graphs and trees (networks and hierarchies).
    • Collision detection for bubble charts or beeswarm plots.
    • Rudimentary physics engines (e.g., simulating cloth/lattices).
    • Multi-dimensional spatial simulations.
  2. Understand the concept of Forces

    master

    A force is a function that modifies nodes' positions or velocities. Forces can represent physical phenomena (like gravity or charge) or geometric constraints (like keeping nodes within a box or at a fixed distance).

    How Forces Work:

    • They typically read a node's current position $\langle x, y, z \rangle$ and modify its velocity $\langle vx, vy, vz \rangle$.
    • Some forces "peek ahead" to the anticipated next position $\langle x + vx, y + vy, z + vz \rangle$ to resolve constraints via iterative relaxation.
    • Some forces modify position directly to avoid adding energy (e.g., recentering).

    Force Lifecycle:

    • force(alpha): Applies the force, optionally observing the simulation's alpha.
    • force.initialize(nodes, random, numDimensions): A method forces can implement to receive the simulation's nodes, random source, and dimensions. This is called when a force is bound to a simulation or when nodes change.
  3. How to use d3-force-3d simulations

    master

    To run a simulation, follow these steps:

    1. Create a simulation: Initialize a simulation instance using forceSimulation(nodes), where nodes is an array of objects representing your particles.
    2. Compose forces: Add various forces (e.g., charge, collision, centering) to the simulation instance.
    3. Listen for ticks: Use the .on("tick", ...) listener to react to every step of the simulation. Inside the tick handler, update your rendering system (Canvas, SVG, or WebGL) with the updated node positions.
    4. Set dimensions (Optional): Use .numDimensions(n) to specify the dimensionality (1, 2, or 3). Defaults to 2.
  4. Install d3-force-3d

    master

    You can install d3-force-3d using npm, load it via Skypack for modern ESM environments, or use a UMD bundle via CDN for legacy environments.

    Using npm

    npm install d3-force-3d

    Using Skypack (ESM)

    For modern browsers using <script type="module">:

    <script type="module">
    import {forceSimulation} from "https://cdn.skypack.dev/d3-force-3d";
    
    const simulation = forceSimulation(nodes);
    </script>

    Using CDN (UMD/Legacy)

    For legacy environments, load the required dependencies and the d3-force-3d bundle. This will export a d3 global:

    <script src="https://cdn.jsdelivr.net/npm/d3-dispatch@3"></script>
    <script src="https://cdn.jsdelivr.net/npm/d3-quadtree@3"></script>
    <script src="https://cdn.jsdelivr.net/npm/d3-timer@3"></script>
    <script src="https://cdn.jsdelivr.net/npm/d3-binarytree"></script>
    <script src="https://cdn.jsdelivr.net/npm/d3-octree"></script>
    <script src="https://cdn.jsdelivr.net/npm/d3-force-3d"></script>
    <script>
    const simulation = d3.forceSimulation(nodes);
    </script>
    npm install d3-force-3d
  5. Optimize many-body force with theta and distance limits

    master

    To improve performance and stability of the forceManyBody, you can configure the following:

    • manyBody.theta([theta]): Sets the Barnes–Hut approximation criterion. A lower value increases accuracy but decreases performance. Default is 0.9.
    • manyBody.distanceMin([distanceMin]): Sets the minimum distance between nodes for this force. This prevents infinitely strong forces when nodes are coincident. Default is 1.
    • manyBody.distanceMax([distanceMax]): Sets the maximum distance for this force. Specifying a finite value improves performance and creates more localized layouts. Default is Infinity.
  6. Position nodes along axes with forceX, forceY, and forceZ

    master

    The positioning forces push nodes towards a target position along a specific dimension. These are intended for global forces applied to all nodes.

    • d3.forceX([x]): Pushes nodes towards a target x position.
    • d3.forceY([y]): Pushes nodes towards a target y position.
    • d3.forceZ([z]): Pushes nodes towards a target z position.

    Each force can be configured with a strength([strength]) accessor. The strength determines how much the node's velocity is incremented: (target - current) * strength. A value of 0.1 moves the node 10% of the way toward the target per application. Values should typically be in the range [0, 1].

  7. Configure simulation cooling with alpha and decay

    master

    The simulation uses an alpha value (analogous to temperature) that decreases over time until it reaches alphaMin, at which point the simulation stops.

    • simulation.alpha(alpha): Sets the current alpha (range [0, 1]).
    • simulation.alphaMin(min): Sets the minimum alpha threshold (default 0.001).
    • simulation.alphaDecay(decay): Sets the decay rate (range [0, 1]). Higher decay makes the simulation stabilize faster but risks local minima; lower decay allows for better convergence.
    • simulation.alphaTarget(target): Sets the target alpha (default 0). Setting a target greater than alphaMin allows the simulation to run indefinitely.
  8. Create a radial positioning force with d3.forceRadial

    master

    Creates a positioning force that pulls nodes towards the surface of a circle or sphere of a specified radius. The sphere is centered at a given ⟨x, y, z⟩ coordinate (defaults to ⟨0, 0, 0⟩).

    API

    • d3.forceRadial(radius[, x][, y][, z]): Creates the force. radius can be a number or an accessor function (node, index) => number.
    • force.radius([radius]): Sets the radius accessor. The target radius is recomputed only when this is called.
    • force.strength([strength]): Sets the strength accessor. Determines how much to increment the node's x, y, and z velocity.
      • A value of 0.1 moves the node 10% of the way to the closest point on the sphere perimeter per application.
      • Recommended range is [0, 1].
      • Default strength is 0.1.
    • force.x([x]): Sets the x-coordinate of the sphere center. Defaults to 0.
    • force.y([y]): Sets the y-coordinate of the sphere center. Defaults to 0.
    • force.z([z]): Sets the z-coordinate of the sphere center. Defaults to 0.
    // Pull nodes toward a sphere of radius 200 centered at the origin
    const force = d3.forceRadial(200);
    
    // Pull nodes toward a sphere of radius 100 centered at (50, 50, 50)
    const forceCustom = d3.forceRadial(100, 50, 50, 50);
  9. Configure simulation dimensions

    master

    Use simulation.numDimensions(numDimensions) to set the number of dimensions (1, 2, or 3).

    • 1D: Manipulates x and vx.
    • 2D: Manipulates x, y, vx, and vy.
    • 3D: Manipulates x, y, z, vx, vy, and vz.

    Calling this method re-initializes any bound forces. If no argument is provided, it returns the current number of dimensions (default is 2).

  10. Use the many-body force for gravity or repulsion

    master

    The d3.forceManyBody() creates a force that applies to all nodes in the simulation. It can simulate:

    • Gravity (Attraction): Use a positive strength.
    • Electrostatic Charge (Repulsion): Use a negative strength (default is -30).

    Unlike links, this force is global; every node affects every other node.

    const force = d3.forceManyBody().strength(-30);
  11. Find the closest node to a position

    master
    Use simulation.find(x[, y[, z]][, radius]) to find the node closest to the coordinates ⟨x, y, z⟩ within a given radius. If radius is not specified, it defaults to infinity. Returns undefined if no node is found within the search area.
  12. Use the Links force

    master

    The link force acts like a spring, pushing linked nodes together or apart based on a target distance.

    API:

    • d3.forceLink([links]): Creates a new link force. If no links are provided, it defaults to an empty array.
    • link.links([links]): Sets or gets the array of links. Setting links triggers a recomputation of distance and strength parameters for each link.

    Link Object Structure: Each link in the array is an object. (Note: The specific properties of the link object were cut off in the source segment, but it is used to define connections between nodes).

    const links = [{ source: 0, target: 1 }];
    const force = d3.forceLink(links);