I'm learning how to use Threepenny GUI, I've hooked up to a click event stream from a canvas, mapped that event stream to a stream of Point and applied accumB
to []
and that Event Point
to get a Behaviour [Point]
where Point
:
data Point = Point {
x :: Int,
y :: Int
}
And the code to map the click Event
stream to the Behaviour [Point]
:
let pointStream = uncurry Point <$> UI.mousedown canvas
let pointsStream = fmap (:) pointStream
let pointsAccumB = accumB [] pointsStream
pointsBehaviour <- pointsAccumB
I would then like to draw these points to a canvas element which I have added to the body of the HTML in the setup
method.
I've managed to draw the points from the behaviour like so:
on UI.click drawButton $ const $ do
UI.clearCanvas canvas
points <- currentValue pointsBehaviour
-- Draw the points here
But the problem is I would like to have the points be drawn to the canvas each time the user clicks the canvas, without requiring the user to go and click a button. Or, in other words, I would like to combine a draw point function into the point stream.
From my research, it looks like sink
may be the function that I need to use to tie together the behaviour and the mutation of the UI in an FRP style.
But, I'm struggling to understand how to piece this together (i.e. what would the sink
application look like for this given use case?). Is it even possible to do this with Threepenny currently?
Wrap your point-drawing code in a WriteAttr
and pass it to sink
. The attribute might be defined like this:
drawnPoints :: WriteAttr Canvas [Point]
drawnPoints = mkWriteAttr $ \canvas point -> do
UI.clearCanvas canvas
-- Draw the points here
You can then connect your actual points and canvas using sink
:
element canvas # sink drawnPoints pointsBehaviour