Hylograph.Kernel.D3.Setup
- Package
- purescript-hylograph-d3-kernel
- Repository
- afcondon/purescript-hylograph-d3-kernel
Declarative Force Setup
Unified system for declaratively configuring force simulations. Replaces the older ForceSpec (too simple) and Config.* modules (wrong abstraction layer).
Key features:
- Static or dynamic (per-node) parameter values
- Optional filters to apply forces selectively
- Idempotent
applySetupthat works for both initial setup and updates
Example:
mySetup = setup "physics"
[ manyBody "charge" # withStrength (-30.0)
, collide "collision" # withRadius (dynamic _.r)
, positionX "gridX" # withX (dynamic _.gridX) # withStrength 0.1
, positionY "gridY" # withY (dynamic _.gridY) # withStrength 0.1
]
-- Apply to simulation (idempotent - can call repeatedly)
applySetup mySetup sim
-- Update: just call applySetup with new config
applySetup (mySetup # removeForce "charge") sim
#valueToNumber Source
valueToNumber :: forall node. Value node Number -> NumberExtract a number from a Value (for static values only, dynamic returns default) Used internally; prefer the accessor pattern for dynamic values
#ForceConfig Source
type ForceConfig node = { distance :: Value node Number, distanceMax :: Number, distanceMin :: Number, filter :: Maybe (node -> Boolean), forceType :: ForceType, iterations :: Int, name :: String, radius :: Value node Number, strength :: Value node Number, theta :: Number, x :: Value node Number, y :: Value node Number }Configuration for a single force Parameterized by node type for dynamic values and filters
#forceName Source
forceName :: forall node. ForceConfig node -> StringGet the name of a force config
#manyBody Source
manyBody :: forall node. String -> ForceConfig nodeCreate a many-body (charge) force Default: repulsive with strength -30
#collide Source
collide :: forall node. String -> ForceConfig nodeCreate a collision force Default: radius 1, strength 1
#link Source
link :: forall node. String -> ForceConfig nodeCreate a link (spring) force Default: distance 30, strength 1
#center Source
center :: forall node. String -> ForceConfig nodeCreate a centering force Default: center at (0, 0), strength 1
#positionX Source
positionX :: forall node. String -> ForceConfig nodeCreate an X-positioning force Default: x = 0, strength 0.1
#positionY Source
positionY :: forall node. String -> ForceConfig nodeCreate a Y-positioning force Default: y = 0, strength 0.1
#radial Source
radial :: forall node. String -> ForceConfig nodeCreate a radial force Default: radius 100, center (0,0), strength 0.1
#withStrength Source
withStrength :: forall node. Value node Number -> ForceConfig node -> ForceConfig nodeSet strength (works for all force types)
#withRadius Source
withRadius :: forall node. Value node Number -> ForceConfig node -> ForceConfig nodeSet radius (for Collide, Radial)
#withX Source
withX :: forall node. Value node Number -> ForceConfig node -> ForceConfig nodeSet X position/target (for Center, PositionX, Radial)
#withY Source
withY :: forall node. Value node Number -> ForceConfig node -> ForceConfig nodeSet Y position/target (for Center, PositionY, Radial)
#withDistance Source
withDistance :: forall node. Value node Number -> ForceConfig node -> ForceConfig nodeSet distance (for Link)
#withTheta Source
withTheta :: forall node. Number -> ForceConfig node -> ForceConfig nodeSet theta (Barnes-Hut approximation, for ManyBody)
#withIterations Source
withIterations :: forall node. Int -> ForceConfig node -> ForceConfig nodeSet iterations (for Collide, Link)
#withFilter Source
withFilter :: forall node. (node -> Boolean) -> ForceConfig node -> ForceConfig nodeAdd a filter predicate (force only applies to matching nodes)
#withDistanceMin Source
withDistanceMin :: forall node. Number -> ForceConfig node -> ForceConfig nodeSet distance min (for ManyBody)
#withDistanceMax Source
withDistanceMax :: forall node. Number -> ForceConfig node -> ForceConfig nodeSet distance max (for ManyBody)
#Setup Source
type Setup node = { forces :: Array (ForceConfig node), name :: String, params :: SetupParams }Complete setup: forces + simulation params
#defaultParams Source
defaultParams :: SetupParamsDefault simulation parameters
#setup Source
setup :: forall node. String -> Array (ForceConfig node) -> Setup nodeCreate a setup with default params
#setupWithParams Source
setupWithParams :: forall node. String -> Array (ForceConfig node) -> SetupParams -> Setup nodeCreate a setup with custom params
#getForces Source
getForces :: forall node. Setup node -> Array (ForceConfig node)Get forces from setup
#getParams Source
getParams :: forall node. Setup node -> SetupParamsGet params from setup
#addForce Source
addForce :: forall node. ForceConfig node -> Setup node -> Setup nodeAdd a force to the setup
#removeForce Source
removeForce :: forall node. String -> Setup node -> Setup nodeRemove a force by name
#updateForce Source
updateForce :: forall node. ForceConfig node -> Setup node -> Setup nodeUpdate a force by name (replace if exists)
#withAlphaDecay Source
withAlphaDecay :: forall node. Number -> Setup node -> Setup nodeSet alpha decay
#withAlphaTarget Source
withAlphaTarget :: forall node. Number -> Setup node -> Setup nodeSet alpha target
#withVelocityDecay Source
withVelocityDecay :: forall node. Number -> Setup node -> Setup nodeSet velocity decay
#applySetup Source
applySetup :: forall row linkRow. Setup (SimulationNode row) -> Simulation row linkRow -> Effect UnitApply a setup to a simulation.
This is idempotent - calling with the same setup does minimal work:
- Forces in setup but not simulation: create and add
- Forces in simulation but not setup: remove
After applying, forces are re-initialized with current nodes.
#GUPLinkResult Source
type GUPLinkResult :: Row Type -> Typetype GUPLinkResult linkRow = { entered :: Array { source :: NodeID, target :: NodeID | linkRow }, exited :: Array { source :: NodeID, target :: NodeID | linkRow }, updated :: Array { source :: NodeID, target :: NodeID | linkRow } }
Result of a link data update with enter/update/exit categorization
#applySetupWithData Source
applySetupWithData :: forall row linkRow. Setup (SimulationNode row) -> Array (SimulationNode row) -> Array { source :: NodeID, target :: NodeID | linkRow } -> Simulation row linkRow -> Effect { links :: GUPLinkResult linkRow, nodes :: GUPResult (SimulationNode row) }Apply setup with new nodes and links, using GUP semantics.
#addForceToSim Source
addForceToSim :: forall row linkRow. ForceConfig (SimulationNode row) -> Simulation row linkRow -> Effect UnitAdd a single force to simulation (without full setup)
#removeForceFromSim Source
removeForceFromSim :: forall row linkRow. String -> Simulation row linkRow -> Effect UnitRemove a single force from simulation by name