Hylograph.Internal.Selection.Operations
- Package
- purescript-hylograph-selection
- Repository
- afcondon/purescript-hylograph-selection
Internal: Implementation of selection operations using web-dom.
Provides the concrete implementations for SelectionM operations:
- Selecting:
select,selectAll,selectElement - Appending:
append,appendChild,appendChildInheriting - Data binding:
joinData,joinDataWithKey,renderData - Attributes:
setAttrs,setAttrsExit - Lifecycle:
remove,clear,merge - HATS rendering:
renderTree,renderTreeKeyed
Uses web-dom for DOM manipulation, not D3's selection API.
Internal module - use Hylograph.Selection for the public API.
SAFETY: Phantom Type Guards for unsafePartial
This module uses unsafePartial extensively to pattern-match on Selection
constructors. These are safe because the phantom type parameter (SEmpty,
SPending, SBoundOwns, SBoundInherits, SExiting) is set at construction time
and enforced by the type system:
SEmptyguaranteesEmptySelectionconstructorSPendingguaranteesPendingSelectionconstructorSBoundOwnsguaranteesBoundSelectionwith owned dataSBoundInheritsguaranteesBoundSelectionwith inherited dataSExitingguaranteesExitingSelectionconstructor
The phantom types make illegal states unrepresentable at compile time.
A function taking Selection SPending elem datum can only receive a
PendingSelection, so the partial match is actually total for that type.
Similarly, Array.unsafeIndex is used where indices come from internal
bookkeeping (e.g., join algorithms) that maintains valid bounds.
#select Source
select :: forall m datum. MonadEffect m => String -> m (Selection SEmpty Element datum)Select a single element matching the CSS selector
Returns an empty selection (no data bound). The datum type is polymorphic and will be inferred from usage. This is typically the starting point for data binding.
Example:
svg <- select "svg"
circles <- renderData Circle [1, 2, 3] "circle" svg ...
#selectElement Source
selectElement :: forall m datum. MonadEffect m => Element -> m (Selection SEmpty Element datum)Select from a DOM element directly
This is useful for framework integration (React, Vue, etc.) where you have a reference to a DOM element rather than a CSS selector.
Example:
selectElement element >>= renderTree myVisualization
#selectAll Source
selectAll :: forall state parent parentDatum datum m. MonadEffect m => String -> Selection state parent parentDatum -> m (Selection SEmpty Element datum)Select all elements matching the CSS selector within a parent selection
Returns an empty selection (no data bound yet). The datum type is polymorphic and will be inferred from usage. Use this for nested selections.
Example:
svg <- select "svg"
groups <- selectAll "g" svg
#selectAllWithData Source
selectAllWithData :: forall state parent parentDatum datum m. MonadEffect m => String -> Selection state parent parentDatum -> m (Selection SBoundOwns Element datum)Select all elements matching selector and extract their bound data
Use this when selecting child elements that have inherited data from their parent. This is necessary when you want to use the selection with transitions that need access to the bound data (like withTransitionStaggered).
Example:
-- After creating nodes with appendChildInheriting
groups <- selectSimulationGroups
circles <- selectAllWithData "circle" groups.nodes
withTransitionStaggered config delayFn circles [fill colorByDepth]
#selectChildInheriting Source
selectChildInheriting :: forall parent datum m. MonadEffect m => String -> Selection SBoundOwns parent datum -> m (Selection SBoundOwns Element datum)Select child elements, inheriting parent's data
Like D3's selection.select(): for each parent element, selects the first
child matching the selector and copies the parent's __data__ to the child.
Use when you have groups with bound data and want to update their children.
Example:
groups <- selectAllWithData ".treemap-package" container
circles <- selectChildInheriting "circle" groups
setAttrs [ fill (colorByData _.topoLayer) ] circles
#append Source
append :: forall parent datum m. MonadEffect m => ElementType -> Array (Attribute datum) -> Selection SPending parent datum -> m (Selection SBoundOwns Element datum)Append new elements to a pending (enter) selection
This materializes the data into DOM elements. Returns a bound selection that can be further modified.
Example:
enterSelection <- append Circle
[ fill "green"
, radius 10.0
, cx (\d -> d.x)
]
pendingSelection
#appendChild Source
appendChild :: forall parent datum datumOut m. MonadEffect m => ElementType -> Array (Attribute datumOut) -> Selection SEmpty parent datum -> m (Selection SEmpty Element datumOut)Append a single child element to a parent selection
Creates one new element and appends it to each parent in the selection. Returns an empty selection of the newly created element(s).
This is different from append which creates elements for each datum
in a pending (enter) selection. appendChild is for structural elements
like creating an SVG container.
Example:
container <- select "#viz"
svg <- appendChild SVG [width 400.0, height 150.0] container
circles <- renderData Circle [1, 2, 3] "circle" svg ...
#appendChildInheriting Source
appendChildInheriting :: forall parent datum m. MonadEffect m => ElementType -> Array (Attribute datum) -> Selection SBoundOwns parent datum -> m (Selection SBoundInherits Element datum)Append child elements to a data-bound selection, inheriting parent's data
This is the key function for creating nested SVG structures where children need access to their parent's bound data. The children don't own the data binding - they inherit it from their parent.
Semantics: Each parent element gets one child. The child inherits the parent's data by copying the data reference (a performance optimization vs. traversing the DOM tree on every attribute access).
Type signature documents the data flow:
- Parent must be SBoundOwns (owns the data to inherit from)
- Child is SBoundInherits (borrows parent's data)
- Both parent and child have same datum type
Example:
-- Create groups with data
groups <- append Group [] enterSelection -- SBoundOwns
-- Add circles that inherit group's data
circles <- appendChildInheriting Circle [radius 5.0] groups -- SBoundInherits
-- Add text that also inherits group's data
labels <- appendChildInheriting Text [textContent _.name] groups -- SBoundInherits
#setAttrs Source
setAttrs :: forall datum m. MonadEffect m => Array (Attribute datum) -> Selection SBoundOwns Element datum -> m (Selection SBoundOwns Element datum)Set attributes on a bound selection
Updates existing elements with new attribute values. This is used for the "update" part of enter-update-exit.
Example:
updated <- setAttrs
[ fill "orange"
, cx (\d -> d.x)
]
boundSelection
#setAttrsExit Source
setAttrsExit :: forall datum m. MonadEffect m => Array (Attribute datum) -> Selection SExiting Element datum -> m (Selection SExiting Element datum)Set attributes on an exiting selection
Similar to setAttrs but for selections in the exit phase. Useful for styling elements before they are removed.
Example:
setAttrsExit [fill "brown", class_ "exiting"] exitSelection
#clear Source
clear :: forall m. MonadEffect m => String -> m UnitClear all children from an element
Selects the element and removes all its children. Useful for clearing a container before rendering new content.
Example:
clear "#viz"
svg <- appendChild SVG [...] container
#syncDOMToData Source
syncDOMToData :: forall m. MonadEffect m => String -> m UnitSync DOM transform positions back to data.x and data.y
Reads the current transform attribute from each element matching the selector and updates the bound data's x/y coordinates. Essential for transitioning from CSS animations to force simulation - ensures simulation sees current positions.
Example:
-- After tree reveal animation completes:
syncDOMToData "g.nodes > g" -- Sync group positions to node data
start -- Simulation continues from current positions
#merge Source
merge :: forall datum m. MonadEffect m => Selection SBoundOwns Element datum -> Selection SBoundOwns Element datum -> m (Selection SBoundOwns Element datum)Merge two bound selections
Follows D3 semantics: concatenates in document order. Useful for combining enter and update selections.
Example:
allCircles <- merge enterSelection updateSelection
#joinData Source
joinData :: forall f parent parentDatum datum m. MonadEffect m => Foldable f => Ord datum => f datum -> String -> Selection SEmpty parent parentDatum -> m (JoinResult Selection parent datum)Low-level data join for power users
Explicitly returns enter, update, and exit selections. Users must handle each set manually.
Example:
JoinResult { enter, update, exit } <- joinData [1, 2, 3] "circle" svg
enterEls <- append Circle [...] enter
updateEls <- setAttrs [...] update
remove exit
#joinDataWithKey Source
joinDataWithKey :: forall f parent parentDatum datum key m. MonadEffect m => Foldable f => Eq key => f datum -> (datum -> key) -> String -> Selection SEmpty parent parentDatum -> m (JoinResult Selection parent datum)Low-level data join with custom key function
Like joinData, but uses a key function to extract comparable keys instead of requiring Ord on the data itself.
This is essential for data types that don't have lawful Ord instances (e.g., opaque foreign types like D3Link_Swizzled).
Example:
JoinResult { enter, update, exit } <- joinDataWithKey links (\l -> l.id) "line" svg
enterEls <- append Line [...] enter
updateEls <- setAttrs [...] update
remove exit
#renderData Source
renderData :: forall f parent datum m. MonadEffect m => Foldable f => Ord datum => ElementType -> f datum -> String -> Selection SEmpty parent datum -> Maybe (datum -> Array (Attribute datum)) -> Maybe (datum -> Array (Attribute datum)) -> Maybe (datum -> Array (Attribute datum)) -> m (Selection SBoundOwns Element datum)High-level data rendering for most users
Manages the entire enter-update-exit cycle automatically. Users provide Maybe callbacks for each phase.
This is the recommended API for 90% of use cases.
Example:
circles <- renderData Circle [1, 2, 3] "circle" svg
(Just \d -> [fill "green", cx (\_ -> d * 100.0)]) -- Enter
(Just \d -> [fill "orange"]) -- Update
Nothing -- Exit (just remove)
#appendData Source
appendData :: forall f parent parentDatum datum m. MonadEffect m => Foldable f => ElementType -> f datum -> Array (Attribute datum) -> Selection SEmpty parent parentDatum -> m (Selection SBoundOwns Element datum)Simple data append for initial renders
A simplified variant of renderData for when you just want to create elements from data without worrying about enter/update/exit cycles.
This is perfect for initial renders where you know there are no existing elements to update or remove.
Example:
svg <- select "svg"
circles <- appendData Circle [1, 2, 3]
[radius 10.0, fill "steelblue", cx (\d _ -> d * 100.0)]
svg
#on Source
on :: forall state elem datum. Behavior datum -> Selection state elem datum -> Effect (Selection state elem datum)Attach a behavior (zoom, drag, etc.) to a selection
Works with any selection type - extracts elements and applies D3 behavior. Returns the selection unchanged to allow chaining.
Example:
svg <- appendChild SVG [...] container
zoomGroup <- appendChild Group [...] svg
_ <- on (Drag defaultDrag) zoomGroup
_ <- on (Zoom $ defaultZoom (ScaleExtent 0.5 4.0) ".zoom-group") svg
#renderTree Source
renderTree :: forall parent parentDatum datum. Ord datum => Selection SEmpty parent parentDatum -> Tree datum -> Effect (Map String (Selection SBoundOwns Element datum))Render a declarative tree structure
Walks the tree, creates DOM elements, and returns a map of named selections. This is the core implementation of the declarative API.
#renderTreeKeyed Source
renderTreeKeyed :: forall parent parentDatum datum. Selection SEmpty parent parentDatum -> Tree datum -> Effect (Map String (Selection SBoundOwns Element datum))Render a tree using key functions from UpdateJoin instead of Ord constraint
This is for cases where the datum type doesn't have Ord, but UpdateJoin provides a keyFn for identity matching. The keyFn in the AST handles keying.
Note: Uses unsafeCoerce to bypass the Ord constraint. This is safe when the tree uses UpdateJoin with a keyFn, as that's what determines identity.
#reselect Source
reselect :: forall datum datumOut. String -> Map String (Selection SBoundOwns Element datum) -> Effect (Selection SEmpty Element datumOut)Extract a named selection from a renderTree result and convert to SEmpty
This is useful for the two-tree pattern where you need to render different datum types in sequence:
axesSelections <- renderTree container axesTree
chartGroup <- reselect "chartGroup" axesSelections
barsSelections <- renderTree chartGroup barsTree
If the named selection is not found, returns an empty selection.
#createElementWithNS Source
createElementWithNS :: ElementType -> Document -> Effect ElementCreate an element with the appropriate namespace Uses the element's rendering context to determine namespace
#getDocument Source
getDocument :: forall parent datum. SelectionImpl parent datum -> Effect Document- Modules
- Data.
DependencyGraph - Hylograph.
AST - Hylograph.
Axis. Axis - Hylograph.
Brush - Hylograph.
Brush. FFI - Hylograph.
Brush. Types - Hylograph.
Classify - Hylograph.
Data. Graph - Hylograph.
Data. Graph. Algorithms - Hylograph.
Data. Node - Hylograph.
Data. Tree - Hylograph.
Expr. Animation - Hylograph.
Expr. Attr - Hylograph.
Expr. Datum - Hylograph.
Expr. Expr - Hylograph.
Expr. Friendly - Hylograph.
Expr. Integration - Hylograph.
Expr. Interpreter. CodeGen - Hylograph.
Expr. Interpreter. Eval - Hylograph.
Expr. Interpreter. Meta - Hylograph.
Expr. Interpreter. PureSVG - Hylograph.
Expr. Interpreter. SVG - Hylograph.
Expr. Path - Hylograph.
Expr. Path. Generators - Hylograph.
Expr. Sugar - Hylograph.
Expr. Units - Hylograph.
HATS - Hylograph.
HATS. Friendly - Hylograph.
HATS. InterpreterTick - Hylograph.
HATS. Transitions - Hylograph.
Interaction. Brush - Hylograph.
Interaction. Coordinated - Hylograph.
Interaction. Pointer - Hylograph.
Interaction. Zoom - Hylograph.
Internal. Attribute - Hylograph.
Internal. Behavior. FFI - Hylograph.
Internal. Behavior. Types - Hylograph.
Internal. Capabilities. Selection - Hylograph.
Internal. Capabilities. Transition - Hylograph.
Internal. FFI - Hylograph.
Internal. Selection. Join - Hylograph.
Internal. Selection. Operations - Hylograph.
Internal. Selection. Operations. Conversions - Hylograph.
Internal. Selection. Operations. Helpers - Hylograph.
Internal. Selection. Operations. Selection - Hylograph.
Internal. Selection. Query - Hylograph.
Internal. Selection. Types - Hylograph.
Internal. Transition. FFI - Hylograph.
Internal. Transition. Manager - Hylograph.
Internal. Transition. Scene - Hylograph.
Internal. Transition. Types - Hylograph.
Internal. Types - Hylograph.
Interpreter. D3 - Hylograph.
Interpreter. English - Hylograph.
Interpreter. Mermaid - Hylograph.
Interpreter. MetaAST - Hylograph.
Interpreter. SemiQuine - Hylograph.
Interpreter. SemiQuine. TreeToCode - Hylograph.
Interpreter. SemiQuine. Types - Hylograph.
Render - Hylograph.
Scale - Hylograph.
Scale. FP - Hylograph.
Shape. Arc - Hylograph.
Shape. Pie - Hylograph.
Shape. Polygon - Hylograph.
Tooltip - Hylograph.
Transform - Hylograph.
TreeDSL - Hylograph.
TreeDSL. ShapeTree - Hylograph.
Unified - Hylograph.
Unified. Attribute - Hylograph.
Unified. DataDSL - Hylograph.
Unified. Display - Hylograph.
Unified. Examples - Hylograph.
Unified. Join - Hylograph.
Unified. Sugar