Prelude. I'm new to Haskell and functional programming at all, but I can't help coding in Haskell, because it' so exiciting! Thus, my question could be very simple and/or trivial. I'm still reading "Learn You a Haskell for Great Good", and Monads are still in the way.
Consider following behaviour:
- Create a stack of events (simply array)
- Listen for
mousemove
events, when event fired, push them into stack
- Listen for
- Run render loop:
- use
requestAnimationFrame
to start loop - every time check if there are any events stacked
- get last event from stack, make some stuff with it and render
- empty stack
- request next frame
- use
What I can't realize is how to get interested value from event, e.g. pageX or clientX, it's looks like I have to do something with data definitions, and I'm stuck with it. Please help.
P.S. I also can't understand how to check result of foreign function, e.g. when I try to get DOM element the result may be element or null
, thus, say, getElById
is impure, and I need to check what I've got in result. How to realize it? Seems I can use something like: data Element = Null | Element ...
and then pattern match the result, but how to make foreign function to be aware of expected result?
UPDATE
Here working example of desired logics:
module MouseTracker where
import FFI
import Prelude
data Element
data Event
type EventStack = [Event]
data Frame
consLog :: a -> Fay ()
consLog = ffi "console.log(%1)"
reqFrame :: (Frame -> Fay ()) -> Fay ()
reqFrame = ffi "requestAnimationFrame(%1)"
getDoc :: Fay Element
getDoc = ffi "document"
createEl :: String -> Fay Element
createEl = ffi "document.createElement(%1)"
elById :: String -> Fay Element
elById = ffi "document.getElementById(%1)"
elSetId :: Element -> String -> Fay ()
elSetId = ffi "%1.setAttribute('id',%2)"
elSetHtml :: Element -> String -> Fay ()
elSetHtml = ffi "%1.innerHTML = %2"
docBodyAppend :: Element -> Fay ()
docBodyAppend = ffi "document.body.appendChild(%1)"
elListenWith :: Element -> String -> (Event -> Fay ()) -> Fay ()
elListenWith = ffi "%1.addEventListener(%2, %3)"
winListenWith :: String -> (Event -> Fay ()) -> Fay ()
winListenWith = ffi "window.addEventListener(%1,%2)"
docListener :: String -> (Event -> Fay ()) -> Fay ()
docListener evtType fn = do
doc <- getDoc
elListenWith doc evtType fn
createTrace :: Fay ()
createTrace = do
div <- createEl "div"
docBodyAppend div
elSetId div "trace"
createStack :: Fay ()
createStack = ffi "window._eventStack = []"
getStack :: Fay EventStack
getStack = ffi "window._eventStack"
updateStack :: EventStack -> Fay ()
updateStack = ffi "window._eventStack = %1"
emptyStack :: Fay ()
emptyStack = createStack
listenMice :: Fay()
listenMice = docListener "mousemove" trackMouse
where trackMouse :: Event -> Fay ()
trackMouse evt = do
stk <- getStack
updateStack (evt:stk)
renderFrame :: Frame -> Fay ()
renderFrame frame = do
stack <- getStack
if length stack > 0
then (do
let e = head stack
traceEventCoord e)
else (do return ())
reqFrame renderFrame
emptyStack
where traceEventCoord :: Event -> Fay ()
traceEventCoord e = do
eX <- pageX e
eY <- pageY e
let str = show eX ++ " x " ++ show eY
trace <- elById "trace"
elSetHtml trace str
pageX :: Event -> Fay Int
pageX = ffi "%1['pageX']"
pageY :: Event -> Fay Int
pageY = ffi "%1['pageY']"
main = do
docListener "DOMContentLoaded" $ \ _ -> do
putStrLn "DOM ready"
createTrace
createStack
listenMice
reqFrame renderFrame