-- | Compile with: dist/build/fay/fay -autorun examples/canvaswater.hs {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE NoImplicitPrelude #-} -- | A demonstration of Fay using the canvas element to display a -- simple effect. module CanvasWater (main) where import Language.Fay.FFI import Language.Fay.Prelude -- | Main entry point. main :: Fay () main = do img <- newImage addEventListener img "load" (start img) False setSrc img "haskell.png" -- | Start the animation. start :: Image -> Fay () start img = do canvas <- getElementById "can" context <- getContext canvas "2d" drawImage context img 0 0 step <- newRef (0 :: Double) setInterval (animate context img step) 30 -- | Animate the water effect. animate :: Context -> Image -> Ref Double -> Fay () animate context img step = do stepn <- readRef step setFillStyle context "rgb(255,255,255)" forM_ [0..imgHeight] $ \i -> drawImageSpecific context img 0 0 imgWidth imgHeight (sin(3*(stepn+i/20.0))*(i/2.0)) (140+i) imgWidth imgHeight writeRef step (stepn + 0.05) imgHeight = 140 imgWidth = 200 -------------------------------------------------------------------------------- -- Elements class Eventable a -- | A DOM element. data Element instance Foreign Element instance Eventable Element -- | Add an event listener to an element. addEventListener :: (Foreign a,Eventable a) => a -> String -> Fay () -> Bool -> Fay () addEventListener = ffi "%1['addEventListener'](%2,%3,%4)" FayNone -- | Get an element by its ID. getElementById :: String -> Fay Element getElementById = ffi "document['getElementById'](%1)" FayNone -------------------------------------------------------------------------------- -- Images data Image instance Foreign Image instance Eventable Image -- | Make a new image. newImage :: Fay Image newImage = ffi "new Image()" FayNone -- | Make a new image. setSrc :: Image -> String -> Fay () setSrc = ffi "%1['src'] = %2" FayNone -------------------------------------------------------------------------------- -- Canvas -- | A canvas context. data Context instance Foreign Context -- | Get an element by its ID. getContext :: Element -> String -> Fay Context getContext = ffi "%1['getContext'](%2)" FayNone -- | Draw an image onto a canvas rendering context. drawImage :: Context -> Image -> Double -> Double -> Fay () drawImage = ffi "%1['drawImage'](%2,%3,%4)" FayNone -- | Draw an image onto a canvas rendering context. -- -- Nine arguments: the element, source (x,y) coordinates, source width and -- height (for cropping), destination (x,y) coordinates, and destination width -- and height (resize). -- -- context.drawImage(img_elem, sx, sy, sw, sh, dx, dy, dw, dh); drawImageSpecific :: Context -> Image -> Double -> Double -> Double -> Double -> Double -> Double -> Double -> Double -> Fay () drawImageSpecific = ffi "%1['drawImage'](%2,%3,%4,%5,%6,%7,%8,%9,%10)" FayNone -- | Set the fill style. setFillStyle :: Context -> String -> Fay () setFillStyle = ffi "%1['fillStyle']=%2" FayNone -- | Set the fill style. setFillRect :: Context -> Double -> Double -> Double -> Double -> Fay () setFillRect = ffi "%1['fillRect'](%2,%3,%4,%5)" FayNone -------------------------------------------------------------------------------- -- Ref -- | A mutable reference like IORef. data Ref a instance Foreign a => Foreign (Ref a) -- | Make a new mutable reference. newRef :: Foreign a => a -> Fay (Ref a) newRef = ffi "new Fay$$Ref(%1)" FayNone -- | Replace the value in the mutable reference. writeRef :: Foreign a => Ref a -> a -> Fay () writeRef = ffi "Fay$$writeRef(%1,%2)" FayNone -- | Get the referred value from the mutable value. readRef :: Foreign a => Ref a -> Fay a readRef = ffi "Fay$$readRef(%1)" FayNone -------------------------------------------------------------------------------- -- Misc -- | Alert using window.alert. alert :: Foreign a => a -> Fay () alert = ffi "window['alert'](%1)" FayNone -- | Alert using window.alert. print :: Double -> Fay () print = ffi "console['log'](%1)" FayNone -- | Alert using window.alert. log :: String -> Fay () log = ffi "console['log'](%1)" FayNone -- | Alert using window.alert. sin :: Double -> Double sin = ffi "window.Math['sin'](%1)" FayNone -- | Alert using window.alert. setInterval :: Fay () -> Double -> Fay () setInterval = ffi "window['setInterval'](%1,%2)" FayNone