Force-directed graph simulation with unified D3 and WASM engine support.
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
import Data.Nullable (null) as Nullable
import Hylograph.Simulation
( runSimulation, Engine(..), SimulationEvent(..), subscribe
, setup, manyBody, center, withStrength, withX, withY, static
)
import Hylograph.AST as A
import Hylograph.Unified.Attribute as Attr
import Hylograph.Unified.Display (showNumD)
import Hylograph.Internal.Selection.Types (ElementType(..))
main :: Effect Unit
main = do
-- Run simulation with D3 engine (or use WASM for same API)
{ handle, events } <- runSimulation
{ engine: D3
, setup: setup "physics"
[ manyBody "charge" # withStrength (static (-50.0))
, center "center" # withX (static 200.0) # withY (static 150.0)
]
, nodes:
[ { id: 0, x: 190.0, y: 140.0, vx: 0.0, vy: 0.0, fx: Nullable.null, fy: Nullable.null }
, { id: 1, x: 200.0, y: 150.0, vx: 0.0, vy: 0.0, fx: Nullable.null, fy: Nullable.null }
, { id: 2, x: 210.0, y: 160.0, vx: 0.0, vy: 0.0, fx: Nullable.null, fy: Nullable.null }
]
, links: []
, container: "#visualization"
, nodeTemplate: \_ -> A.elem Circle
[ Attr.attr "cx" _.x showNumD
, Attr.attr "cy" _.y showNumD
, Attr.attrStatic "r" "8"
, Attr.attrStatic "fill" "#4a9eff"
]
, alphaMin: 0.001
}
-- Subscribe to simulation events
_ <- subscribe events \event -> case event of
Tick { alpha } -> log $ "Alpha: " <> show alpha
Completed -> log "Simulation converged!"
_ -> pure unit
log "Simulation running!"spago install hylograph-simulation- Dual Engine Support - Same API for D3.js and Rust/WASM physics
- Framework Agnostic - Works with Halogen, React, or vanilla JS
- Declarative Forces - Compose forces with a fluent builder API
- Event Subscription - React to Tick, Started, Stopped, Completed events
- GUP Semantics - Enter/update/exit tracking when data changes
import Hylograph.ForceEngine.Halogen (toHalogenEmitter)
handleAction Initialize = do
{ handle, events } <- liftEffect $ runSimulation config
halogenEmitter <- liftEffect $ toHalogenEmitter events
void $ H.subscribe $ halogenEmitter <#> SimEvent
handleAction (SimEvent (Tick { alpha })) =
H.modify_ _ { alpha = alpha }
handleAction (SimEvent Completed) =
liftEffect $ log "Done!"useEffect(() => {
const { handle, events } = runSimulation(config)();
const unsubscribe = subscribe(events)(event => {
if (event.tag === 'Completed') {
console.log('Simulation converged!');
}
})();
return () => unsubscribe();
}, []);| Force | Description |
|---|---|
manyBody |
N-body charge simulation (attract/repel) |
center |
Pulls nodes toward a center point |
link |
Spring forces between connected nodes |
collide |
Prevents node overlap |
positionX |
Pulls nodes toward an X position |
positionY |
Pulls nodes toward a Y position |
radial |
Pulls nodes toward a circle |
Hylograph.Simulation- High-level API (recommended)Hylograph.Simulation.Emitter- Framework-agnostic event systemHylograph.ForceEngine.Setup- Declarative force configurationHylograph.ForceEngine.Simulation- Low-level D3 simulation controlHylograph.ForceEngine.WASM- WASM engine integration
This package is part of the Hylograph visualization ecosystem:
- hylograph-selection - D3 selection and rendering
- hylograph-simulation - Force simulation (this package)
- hylograph-simulation-halogen - Halogen integration
- hylograph-graph - Graph data structures
- hylograph-layout - Layout algorithms
MIT
