Timing
This example demonstrates the difference between the timing of per-frame and fixed-rate updates using a graph of the frequency (Hz/frames per second) that the delta
time value corresponds to.
It begins on the left and moves to the right, and when it reaches the right edge of the view box it restarts from the left, overwriting the old chart.
Update function
The two update types share a function in this example:
behavior: defaultBehavior
{ render = render
, update = saveDelta @"reg"
, fixed =
{ interval: hz 60.0
, function: saveDelta @"fixed"
}
}
saveDelta :: forall @l t r. IsSymbol l => Cons l Number t r =>
Delta -> Scaler -> { | r } -> Effect (Maybe { | r })
saveDelta { delta } _ = pure <<< Just <<< set (Proxy @l) delta
This uses a Proxy
representing a key of the state record to set that key’s value to the delta
from the Delta
record.
TextMetrics
This example uses custom definitions for TextMetrics
and measureText
to clear the canvas behind the text (most of the canvas is not refreshed each frame, but text gets messy if it’s drawn on top of other text).
Most of the TextMetrics
attributes are relative to the text alignment and baseline of the canvas, so toRelativeBoundingRect
converts them into a rectangle:
toRelativeBoundingRect :: TextMetrics -> Rect
toRelativeBoundingRect
{ actualBoundingBoxLeft
, actualBoundingBoxRight
, actualBoundingBoxAscent
, actualBoundingBoxDescent
} =
{ x: -actualBoundingBoxLeft
, y: -actualBoundingBoxAscent
, width: actualBoundingBoxRight + actualBoundingBoxLeft
, height: actualBoundingBoxDescent + actualBoundingBoxAscent
}
This rectangle is in canvas coordinates and relative to the coordinates of the text, so it needs to be shifted by the position of the text after scaling to the canvas:
let { x, y } = position *~> canvas
relative@{ width, height } <- toRelativeBoundingRect <$> measureText ctx text
clearRect ctx { width, height, x: x + relative.x, y: y + relative.y }
fillText ctx text x y