Module

Hylograph.Scene.Handle

Package
purescript-hylograph-simulation
Repository
afcondon/purescript-hylograph-simulation

Scene Handle

Opaque handle for scene-based visualizations. Wraps simulation + scene engine + transition state. User never sees Refs - just pure-looking Effect operations.

This is the high-level API for sophisticated visualizations with:

  • Choreographed scene transitions (Init → Interpolate → Finalize)
  • Node filtering (for focus/neighborhood views)
  • GUP-style enter/exit animations

Example usage:

-- Create handle with callbacks
handle <- Scene.create config callbacks nodes links renderFn

-- Transition to a scene
Scene.transitionTo treeFormScene handle

-- In your animation loop
continuing <- Scene.onTick handle
when continuing $ requestAnimationFrame (const $ ...)

-- Clean up
Scene.destroy handle

#SceneHandle Source

newtype SceneHandle :: Row Type -> Row Type -> Typenewtype SceneHandle nodeRow linkRow

Opaque handle to a scene-based visualization.

User cannot access internal state directly. All operations go through the module's exported functions.

#HandleConfig Source

type HandleConfig = { containerSelector :: String, linksGroupId :: Maybe GroupId, nodesGroupId :: GroupId }

Configuration for creating a handle

#Callbacks Source

type Callbacks :: Row Type -> Typetype Callbacks nodeRow = { onNodeClick :: SimulationNode nodeRow -> Effect Unit, onNodeHover :: SimulationNode nodeRow -> Effect Unit, onNodeLeave :: Effect Unit, onTransitionComplete :: Effect Unit }

Callbacks for events (D3 → User code)

These are called when D3 events fire. Use them to notify your UI framework (Halogen, React, etc.) of user interactions.

#create Source

create :: forall nodeRow linkRow. HandleConfig -> Callbacks nodeRow -> Array (SimulationNode nodeRow) -> Array { source :: Int, target :: Int | linkRow } -> (Array (SimulationNode nodeRow) -> Effect Unit) -> Effect (SceneHandle nodeRow linkRow)

Create a new scene handle.

Sets up:

  • D3 force simulation with the provided nodes/links
  • Scene engine for managing transitions
  • Event binding via callbacks

The render function is called on every tick with current node positions.

#destroy Source

destroy :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect Unit

Clean up resources.

Stops the simulation and releases references.

#transitionTo Source

transitionTo :: forall nodeRow linkRow. SceneConfig (SimulationNode nodeRow) -> SceneHandle nodeRow linkRow -> Effect Unit

Transition to a new scene.

Triggers the three-phase lifecycle:

  1. Init rules - prepare starting state (e.g., move nodes to root)
  2. Interpolation - animate positions from start to target
  3. Final rules - set up stable state (e.g., pin/unpin nodes)

The transition is driven by onTick calls.

#isTransitioning Source

isTransitioning :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect Boolean

Check if a transition is currently in progress.

#getTransitionProgress Source

getTransitionProgress :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect (Maybe Number)

Get transition progress (0.0 to 1.0).

Returns Nothing if no transition is in progress.

#getCurrentScene Source

getCurrentScene :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect (Maybe (SceneConfig (SimulationNode nodeRow)))

Get the current scene configuration (if any).

#getAllNodes Source

getAllNodes :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect (Array (SimulationNode nodeRow))

Get all nodes (with current positions).

#filterNodes Source

filterNodes :: forall nodeRow linkRow. (SimulationNode nodeRow -> Boolean) -> SceneHandle nodeRow linkRow -> Effect Unit

Filter visible nodes by predicate.

Nodes that don't match are hidden (but kept in simulation). Use showAllNodes to restore.

This is useful for neighborhood/focus views.

#showAllNodes Source

showAllNodes :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect Unit

Show all nodes (restore from filter).

#transformNodes Source

transformNodes :: forall nodeRow linkRow. (SimulationNode nodeRow -> SimulationNode nodeRow) -> SceneHandle nodeRow linkRow -> Effect Unit

Transform nodes in place.

Applies a function to all nodes, mutating them directly. Useful for setting fx/fy (pinning) or updating positions.

After transformation, forces are re-initialized and simulation reheated.

#onTick Source

onTick :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect Boolean

Tick handler - call this from your animation loop.

Advances interpolation during transitions, then calls the render function. Returns true if animation should continue, false if stable.

Typical usage:

let loop = do
      continuing <- Scene.onTick handle
      when continuing $ requestAnimationFrame (const loop)
loop

#getSimulation Source

getSimulation :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect (Simulation nodeRow linkRow)

Get the underlying simulation (for advanced use cases).

Use with caution - direct manipulation may interfere with scene transitions.

#reheat Source

reheat :: forall nodeRow linkRow. SceneHandle nodeRow linkRow -> Effect Unit

Reheat the simulation manually.

Useful when you've made changes outside the normal transition flow.

Re-exports from Hylograph.Scene.Types

#SceneConfig Source

type SceneConfig node = { finalRules :: Array node -> Array (NodeRule node), initRules :: Array (NodeRule node), layout :: Array node -> PositionMap, name :: String, stableMode :: EngineMode }

Scene configuration with three-phase lifecycle.

Phase 1: Initialize (initRules) Applied before transition starts. Use this to set up starting positions, e.g., moving tree nodes to the root for a "grow from root" animation.

Phase 2: Transition (layout) The interpolation engine smoothly moves nodes from their current positions to the target positions computed by the layout function.

Phase 3: Finalize (finalRules) Applied after transition completes. Use this to set up the stable state, e.g., unpinning nodes so forces can take over, or setting gridX/gridY.

Example:

treeFormScene :: SceneConfig MyNode
treeFormScene =
  { name: "TreeForm"
  , initRules: [ moveToRootRule ]
  , layout: \nodes -> computeTreePositions nodes
  , finalRules: \_ -> [ pinAtTreePositionsRule ]
  , stableMode: Static
  }

#PositionMap Source

type PositionMap = Object Position

Position map: node ID (as string) -> position Used for capturing current positions and specifying targets

#NodeRule Source

type NodeRule node = { apply :: node -> node, name :: String, select :: node -> Boolean }

A rule that selects nodes and applies a transform.

Rules are applied with first-match-wins semantics (like CSS cascade). If multiple rules match a node, only the first one applies.

Example:

pinPackages :: NodeRule MyNode
pinPackages =
  { name: "pinPackages"
  , select: \n -> n.nodeType == Package
  , apply: \n -> n { fx = notNull n.x, fy = notNull n.y }
  }

#EngineMode Source

data EngineMode

Engine mode determines what happens after a transition completes.

  • Physics: D3 force simulation runs, nodes settle via forces
  • Static: Nodes stay pinned at their final positions

Constructors

Instances