Module

Hylograph.Expr.Friendly

Package
purescript-hylograph-selection
Repository
afcondon/purescript-hylograph-selection

Friendly DSL for Data-Driven Attributes

A more approachable API for the finally-tagless expression system. Designed for D3.js developers learning PureScript.

Quick Start

import Hylograph.Expr.Friendly

-- Define field accessors for your data type
_x = field @"x"
_y = field @"y"
_name = field @"name"

-- Build expressions with readable arithmetic
xPosition = _x `times` 40.0 `plus` 50.0
yPosition = _y `times` 30.0

-- Create attributes
myAttrs =
  [ computed "cx" xPosition
  , computed "cy" yPosition
  , staticStr "fill" "steelblue"
  ]

Value Constructors

  • num 42.0 - numeric value
  • text "hello" - string value
  • bool true - boolean value

Arithmetic (use with backticks for infix)

  • plus, minus, times, dividedBy - binary operations
  • negated - unary negation

Attribute Constructors

  • computed - data-driven numeric/showable attribute
  • computedStr - data-driven string attribute
  • static - constant numeric/showable attribute
  • staticStr - constant string attribute
  • from - escape hatch using plain PureScript function

#num Source

num :: forall repr. NumExpr repr => Number -> repr Number

Create a numeric value

radius = num 5.0
scaled = _x `times` num 20.0  -- or use `timesN` to skip the `num`

#text Source

text :: forall repr. StringExpr repr => String -> repr String

Create a text (string) value

fill = text "steelblue"
label = _name `append` text " (selected)"

#bool Source

bool :: forall repr. BoolExpr repr => Boolean -> repr Boolean

Create a boolean value

visible = bool true

#plus Source

plus :: forall repr. NumExpr repr => repr Number -> repr Number -> repr Number

Add two expressions

total = _x `plus` _y
offset = _index `times` num 40.0 `plus` num 50.0

#minus Source

minus :: forall repr. NumExpr repr => repr Number -> repr Number -> repr Number

Subtract expressions

#times Source

times :: forall repr. NumExpr repr => repr Number -> repr Number -> repr Number

Multiply expressions

scaled = _value `times` num 2.0

#dividedBy Source

dividedBy :: forall repr. NumExpr repr => repr Number -> repr Number -> repr Number

Divide expressions

#negated Source

negated :: forall repr. NumExpr repr => repr Number -> repr Number

Negate an expression

#plusN Source

plusN :: forall repr. NumExpr repr => repr Number -> Number -> repr Number

Add a literal number: _xplusN50.0

#minusN Source

minusN :: forall repr. NumExpr repr => repr Number -> Number -> repr Number

Subtract a literal number

#timesN Source

timesN :: forall repr. NumExpr repr => repr Number -> Number -> repr Number

Multiply by a literal number: _indextimesN40.0

#dividedByN Source

dividedByN :: forall repr. NumExpr repr => repr Number -> Number -> repr Number

Divide by a literal number

#lessThan Source

lessThan :: forall repr. CompareExpr repr => repr Number -> repr Number -> repr Boolean

Less than comparison

#lessOrEqual Source

lessOrEqual :: forall repr. CompareExpr repr => repr Number -> repr Number -> repr Boolean

Less than or equal

#greaterThan Source

greaterThan :: forall repr. CompareExpr repr => repr Number -> repr Number -> repr Boolean

Greater than comparison

#greaterOrEqual Source

greaterOrEqual :: forall repr. CompareExpr repr => repr Number -> repr Number -> repr Boolean

Greater than or equal

#equals Source

equals :: forall repr. CompareExpr repr => repr Number -> repr Number -> repr Boolean

Numeric equality

#textEquals Source

textEquals :: forall repr. StringCompareExpr repr => repr String -> repr String -> repr Boolean

String equality

#textNotEquals Source

textNotEquals :: forall repr. StringCompareExpr repr => repr String -> repr String -> repr Boolean

String inequality

#and_ Source

and_ :: forall repr. BoolExpr repr => repr Boolean -> repr Boolean -> repr Boolean

Boolean AND (use underscore to avoid keyword conflict)

#or_ Source

or_ :: forall repr. BoolExpr repr => repr Boolean -> repr Boolean -> repr Boolean

Boolean OR

#not_ Source

not_ :: forall repr. BoolExpr repr => repr Boolean -> repr Boolean

Boolean NOT

#ifThen Source

ifThen :: forall repr a. BoolExpr repr => repr Boolean -> repr a -> repr a -> repr a

Conditional expression

fillColor = ifThen (_value `greaterThan` num 50.0)
              (text "red")
              (text "blue")

#sin Source

sin :: forall repr. TrigExpr repr => repr Number -> repr Number

#cos Source

cos :: forall repr. TrigExpr repr => repr Number -> repr Number

#tan Source

tan :: forall repr. TrigExpr repr => repr Number -> repr Number

#asin Source

asin :: forall repr. TrigExpr repr => repr Number -> repr Number

#acos Source

acos :: forall repr. TrigExpr repr => repr Number -> repr Number

#atan Source

atan :: forall repr. TrigExpr repr => repr Number -> repr Number

#atan2 Source

atan2 :: forall repr. TrigExpr repr => repr Number -> repr Number -> repr Number

#pi Source

pi :: forall repr. TrigExpr repr => repr Number

#append Source

append :: forall repr. StringExpr repr => repr String -> repr String -> repr String

Concatenate strings

label = _name `append` text ": " `append` _value

#field Source

field :: forall @sym repr datumRow a r. IsSymbol sym => Cons sym a r datumRow => DatumExpr repr datumRow => repr a

Access a field from the datum

Define field accessors for your data type:

type MyDataRow = (x :: Number, y :: Number, name :: String)

_x :: forall repr. DatumExpr repr MyDataRow => repr Number
_x = field @"x"

_y :: forall repr. DatumExpr repr MyDataRow => repr Number
_y = field @"y"

_name :: forall repr. DatumExpr repr MyDataRow => repr String
_name = field @"name"

#index Source

index :: forall repr datumRow. DatumExpr repr datumRow => repr Int

Access the element index (for staggered animations, positioning by index)

#attr Source

attr :: forall datum a. ToAttributeValue a => String -> EvalD datum a -> Attribute datum

Create a data-driven attribute from an expression. Works for both numeric and string expressions - no need for separate functions!

attr "cx" $ _x `timesN` 20.0 `plusN` 50.0
attr "r" $ num 5.0
attr "fill" $ text "steelblue"
attr "fill" $ ifThen condition (text "red") (text "blue")

#attrWithIndex Source

attrWithIndex :: forall datum a. ToAttributeValue a => String -> EvalD datum a -> Attribute datum

Create a data-driven attribute that also uses the element index

attrWithIndex "x" $ index `timesN` 50.0

#static Source

static :: forall datum a. Show a => String -> a -> Attribute datum

Create a static (constant) attribute

static "stroke-width" 2.0
static "opacity" 0.8

#staticStr Source

staticStr :: forall datum. String -> String -> Attribute datum

Create a static string attribute (no quotes)

staticStr "fill" "steelblue"
staticStr "stroke" "none"

#from Source

from :: forall datum a. Show a => String -> (datum -> a) -> Attribute datum

Create an attribute from a plain PureScript function (escape hatch)

Use when computations are complex or use libraries not in the DSL.

from "cx" (_.x * 20.0 + 50.0)
from "r" (\d -> sqrt d.area / pi)

#fromStr Source

fromStr :: forall datum. String -> (datum -> String) -> Attribute datum

Create a string attribute from a plain function

fromStr "class" _.category
fromStr "fill" (\d -> if d.active then "green" else "gray")

#fromWithIndex Source

fromWithIndex :: forall datum a. Show a => String -> (datum -> Int -> a) -> Attribute datum

Create an indexed attribute from a function taking datum and index

fromWithIndex "x" (\d i -> toNumber i * 50.0)

#fromStrWithIndex Source

fromStrWithIndex :: forall datum. String -> (datum -> Int -> String) -> Attribute datum

Create an indexed string attribute from a function

#viewBox Source

viewBox :: forall datum. Number -> Number -> Number -> Number -> Attribute datum

Create a viewBox attribute with structured parameters

viewBox 0.0 0.0 800.0 600.0  -- instead of staticStr "viewBox" "0 0 800 600"

#x Source

x :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#y Source

y :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#cx Source

cx :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#cy Source

cy :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#x1 Source

x1 :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#y1 Source

y1 :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#x2 Source

x2 :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#y2 Source

y2 :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#dx Source

dx :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#dy Source

dy :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#width Source

width :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#height Source

height :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#r Source

r :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#fill Source

fill :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#stroke Source

stroke :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#strokeWidth Source

strokeWidth :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#opacity Source

opacity :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#class_ Source

class_ :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

CSS class attribute (underscore suffix since class is a reserved word)

class_ $ text "my-element highlighted"

#textAnchor Source

textAnchor :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#dominantBaseline Source

dominantBaseline :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#fontSize Source

fontSize :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#fontFamily Source

fontFamily :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#textContent Source

textContent :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#path Source

path :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#transform Source

transform :: forall datum a. ToAttributeValue a => EvalD datum a -> Attribute datum

#Color Source

type Color = Color

Re-export Color type for type-safe fills and strokes

Instances

#color Source

color :: forall repr. StringExpr repr => Color -> repr String

Create a color expression from a Color value

fill $ color steelblue

#hex Source

hex :: forall repr. StringExpr repr => String -> repr String

Parse a hex color string

fill $ hex "#2c3e50"

#rgb_ Source

rgb_ :: forall repr. StringExpr repr => Int -> Int -> Int -> repr String

Create a color from RGB values (0-255)

fill $ rgb_ 44 62 80

#hsl_ Source

hsl_ :: forall repr. StringExpr repr => Number -> Number -> Number -> repr String

Create a color from HSL values (hue 0-360, saturation/lightness 0.0-1.0)

fill $ hsl_ 210.0 0.5 0.3

#black Source

black :: forall repr. StringExpr repr => repr String

Pure black color

#white Source

white :: forall repr. StringExpr repr => repr String

Pure white color

#lighten Source

lighten :: Number -> Color -> Color

Lighten a color by a factor (0.0 to 1.0)

fill $ lighten 0.2 (hex "#3498db")

#darken Source

darken :: Number -> Color -> Color

Darken a color by a factor (0.0 to 1.0)

#saturate Source

saturate :: Number -> Color -> Color

Increase saturation by a factor

#desaturate Source

desaturate :: Number -> Color -> Color

Decrease saturation by a factor

#Px Source

newtype Px

Pixels

Constructors

Instances

#px Source

px :: forall repr. StringExpr repr => Number -> repr String

Create a pixel value

fontSize $ px 16.0

#Pt Source

newtype Pt

Points (1pt = 1/72 inch)

Constructors

Instances

#pt Source

pt :: forall repr. StringExpr repr => Number -> repr String

Create a point value

fontSize $ pt 12.0

#Em Source

newtype Em

Em units (relative to parent font size)

Constructors

Instances

#em_ Source

em_ :: forall repr. StringExpr repr => Number -> repr String

Create an em value (note: em_ to avoid conflict with Prelude's em)

fontSize $ em_ 1.5

#Rem Source

newtype Rem

Rem units (relative to root font size)

Constructors

Instances

#rem_ Source

rem_ :: forall repr. StringExpr repr => Number -> repr String

Create a rem value

fontSize $ rem_ 1.0

#Percent Source

newtype Percent

Percentage

Constructors

Instances

#pct Source

pct :: forall repr. StringExpr repr => Number -> repr String

Create a percentage value

width $ pct 100.0

#eval Source

eval :: forall datum a. EvalD datum a -> datum -> a

Evaluate an expression with a datum (index defaults to 0)

x = eval scaleX datum  -- instead of runEvalD scaleX datum 0

#evalAt Source

evalAt :: forall datum a. EvalD datum a -> datum -> Int -> a

Evaluate an expression with datum and explicit index

x = evalAt scaleX datum 5

#computed Source

computed :: forall datum a. Show a => String -> EvalD datum a -> Attribute datum

Create a data-driven attribute from an expression

computed "cx" (_x `timesN` 20.0 `plusN` 50.0)
computed "r" (num 5.0)

#computedStr Source

computedStr :: forall datum. String -> EvalD datum String -> Attribute datum

Create a data-driven string attribute (no quotes added)

computedStr "fill" (ifThen condition (text "red") (text "blue"))
computedStr "class" _category

#computedWithIndex Source

computedWithIndex :: forall datum a. Show a => String -> EvalD datum a -> Attribute datum

Create a data-driven attribute that also uses the element index

computedWithIndex "x" (index `timesN` 50.0)

#computedStrWithIndex Source

computedStrWithIndex :: forall datum. String -> EvalD datum String -> Attribute datum

Create a data-driven string attribute that also uses the element index

#ToAttributeValue Source

class ToAttributeValue a  where

Typeclass for converting values to attribute strings. String values pass through unchanged, other types use Show. This allows attr to work for both numeric and string expressions.

Members

Instances

Re-exports from Hylograph.Expr.Animation

#AnimatedBuilder Source

type AnimatedBuilder datum = { config :: AnimationConfig, fromValue :: Maybe (AnimatedValue datum), name :: String, toValue :: AnimatedValue datum }

Builder for animated attributes

Accumulates the animation specification before converting to Attribute. Use animatedTo to create, config modifiers to adjust, and animated to finalize.

#withStagger Source

withStagger :: forall datum. Number -> AnimatedBuilder datum -> AnimatedBuilder datum

Set staggered delay based on element index

Creates an indexed animation where each element's delay is: baseDelay + (index * staggerDelay)

animated $ animatedTo (num 1.0)
  # withStagger 50.0  -- Each element starts 50ms after the previous

#withEasing Source

withEasing :: forall datum. EasingType -> AnimatedBuilder datum -> AnimatedBuilder datum

Set the easing function

animated $ animatedTo (num 1.0)
  # withEasing ElasticOut

#withDuration Source

withDuration :: forall datum. Number -> AnimatedBuilder datum -> AnimatedBuilder datum

Set the animation duration in milliseconds

animated $ animatedTo (num 1.0) # withDuration 500.0

#withDelay Source

withDelay :: forall datum. Number -> AnimatedBuilder datum -> AnimatedBuilder datum

Set the delay before animation starts (in milliseconds)

animated $ animatedTo (num 1.0)
  # withDelay 200.0  -- Wait 200ms before starting

#shrinkTo Source

shrinkTo :: forall datum. Number -> Attribute datum

Shrink to a target radius (for exit animations)

exitAttrs = [ shrinkTo 0.0 # withDuration 300.0 ]

#growFrom Source

growFrom :: forall datum. Number -> Attribute datum

Grow from a starting radius to the datum's radius

enterAttrs = [ growFrom 0.0 # withDuration 300.0 ]

#fadeOut Source

fadeOut :: forall datum. Attribute datum

Fade out from current opacity to 0

exitAttrs = [ fadeOut # withDuration 300.0 ]

#fadeIn Source

fadeIn :: forall datum. Attribute datum

Fade in from 0 to 1 opacity

enterAttrs = [ fadeIn # withDuration 300.0 ]

#animatedToIndexed Source

animatedToIndexed :: forall datum. String -> (datum -> Int -> Number) -> AnimatedBuilder datum

Create an indexed animated attribute builder (uses datum and element index for target)

animated $ animatedToIndexed "cx" (\d i -> d.x + toNumber i * spacing)

#animatedTo Source

animatedTo :: forall datum. String -> EvalD datum Number -> AnimatedBuilder datum

Create an animated attribute builder targeting a value

The attribute name is required. The target value can be:

  • A constant: animatedTo "opacity" (num 1.0)
  • A field: animatedTo "cx" (field @"x")
  • An expression: animatedTo "cx" (field @"x"timesN20.0)
opacity $ animated $ animatedTo (num 1.0)
  # withDuration 500.0

#animatedFromStatic Source

animatedFromStatic :: forall datum. Number -> AnimatedBuilder datum -> AnimatedBuilder datum

Set a static starting value for an animation

animated $ animatedFromStatic 0.0 $ animatedTo "opacity" (num 1.0)

#animatedFromIndexed Source

animatedFromIndexed :: forall datum. (datum -> Int -> Number) -> AnimatedBuilder datum -> AnimatedBuilder datum

Set an indexed starting value for an animation (uses datum and element index)

animated $ animatedFromIndexed (\d i -> d.baseX + toNumber i * 10.0) $ animatedTo "cx" (field @"x")

#animatedFrom Source

animatedFrom :: forall datum. EvalD datum Number -> AnimatedBuilder datum -> AnimatedBuilder datum

Set the starting value for an animation

Without animatedFrom, the animation reads the current DOM value as start. With animatedFrom, the animation uses the specified value.

-- Animate from 0 to 1
opacity $ animated $ animatedFrom (num 0.0) $ animatedTo (num 1.0)

-- Animate from current DOM value to target (no animatedFrom)
opacity $ animated $ animatedTo (field @"targetOpacity")

#animatedAttr Source

animatedAttr :: forall datum. String -> AnimatedBuilder datum -> Attribute datum

Create an animated attribute with explicit name (alternative syntax)

animatedAttr "opacity" $ animatedFrom (num 0.0) $ animatedTo (num 1.0)

#animated Source

animated :: forall datum. AnimatedBuilder datum -> Attribute datum

Convert an AnimatedBuilder to an Attribute

This is the final step after building the animation specification.

myAttr = animated $ animatedFrom (num 0.0) $ animatedTo (num 1.0)
  # withDuration 500.0
  # withEasing QuadOut

Re-exports from Hylograph.Expr.Datum

#DatumExpr Source

class DatumExpr :: (Type -> Type) -> Row Type -> Constraintclass DatumExpr (repr :: Type -> Type) (datumRow :: Row Type) | repr -> datumRow

Datum field access with compile-time safety

The datumRow parameter is a Row kind (not Type), representing the fields available in the datum record. The constraint Row.Cons sym a r datumRow ensures:

  • datumRow contains a field named sym
  • The field has type a
  • Compiler error if field doesn't exist

The interpreter works with Record datumRow at runtime.

Re-exports from Hylograph.Expr.Expr

#BoolExpr Source

class BoolExpr :: (Type -> Type) -> Constraintclass BoolExpr repr 

Boolean expressions

#NumExpr Source

class NumExpr :: (Type -> Type) -> Constraintclass NumExpr repr 

Numeric expressions

#StringExpr Source

class StringExpr :: (Type -> Type) -> Constraintclass StringExpr repr 

String expressions

Re-exports from Hylograph.Expr.Interpreter.Eval

#EvalD Source

newtype EvalD datum a

Evaluator with datum access - a function from datum (and index) to value

Instances

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