packages feed

blank-canvas 0.4.0 → 0.5

raw patch · 12 files changed

+1651/−361 lines, 12 filesdep +base64-bytestringdep +colourdep +data-default-classdep −networkdep ~aesondep ~scottydep ~textPVP ok

version bump matches the API change (PVP)

Dependencies added: base64-bytestring, colour, data-default-class

Dependencies removed: network

Dependency ranges changed: aeson, scotty, text, wai-extra

API changes (from Hackage documentation)

- Graphics.Blank: static :: Options -> [String]
+ Graphics.Blank: AlphabeticBaseline :: TextBaselineAlignment
+ Graphics.Blank: BevelCorner :: LineJoinCorner
+ Graphics.Blank: BottomBaseline :: TextBaselineAlignment
+ Graphics.Blank: ButtCap :: LineEndCap
+ Graphics.Blank: CenterAnchor :: TextAnchorAlignment
+ Graphics.Blank: EndAnchor :: TextAnchorAlignment
+ Graphics.Blank: HangingBaseline :: TextBaselineAlignment
+ Graphics.Blank: IdeographicBaseline :: TextBaselineAlignment
+ Graphics.Blank: LeftAnchor :: TextAnchorAlignment
+ Graphics.Blank: MiddleBaseline :: TextBaselineAlignment
+ Graphics.Blank: MiterCorner :: LineJoinCorner
+ Graphics.Blank: NoRepeat :: RepeatDirection
+ Graphics.Blank: Repeat :: RepeatDirection
+ Graphics.Blank: RepeatX :: RepeatDirection
+ Graphics.Blank: RepeatY :: RepeatDirection
+ Graphics.Blank: RightAnchor :: TextAnchorAlignment
+ Graphics.Blank: RoundCap :: LineEndCap
+ Graphics.Blank: RoundCorner :: LineJoinCorner
+ Graphics.Blank: SquareCap :: LineEndCap
+ Graphics.Blank: StartAnchor :: TextAnchorAlignment
+ Graphics.Blank: TopBaseline :: TextBaselineAlignment
+ Graphics.Blank: data LineEndCap
+ Graphics.Blank: data LineJoinCorner
+ Graphics.Blank: data RepeatDirection
+ Graphics.Blank: data TextAnchorAlignment
+ Graphics.Blank: data TextBaselineAlignment
+ Graphics.Blank: dataURLMimeType :: Text -> Text
+ Graphics.Blank: drawImageAt :: Image image => (image, Double, Double) -> Canvas ()
+ Graphics.Blank: drawImageCrop :: Image image => (image, Double, Double, Double, Double, Double, Double, Double, Double) -> Canvas ()
+ Graphics.Blank: drawImageSize :: Image image => (image, Double, Double, Double, Double) -> Canvas ()
+ Graphics.Blank: putImageDataAt :: (ImageData, Double, Double) -> Canvas ()
+ Graphics.Blank: putImageDataDirty :: (ImageData, Double, Double, Double, Double, Double, Double) -> Canvas ()
+ Graphics.Blank: readDataURL :: Text -> FilePath -> IO Text
+ Graphics.Blank: sync :: Canvas ()
+ Graphics.Blank: writeDataURL :: FilePath -> Text -> IO ()
+ Graphics.Blank.Style: addColorStop :: CanvasColor color => (Double, color) -> CanvasGradient -> Canvas ()
+ Graphics.Blank.Style: aliceblue :: Colour Double
+ Graphics.Blank.Style: antiquewhite :: Colour Double
+ Graphics.Blank.Style: aqua :: Colour Double
+ Graphics.Blank.Style: aquamarine :: Colour Double
+ Graphics.Blank.Style: azure :: Colour Double
+ Graphics.Blank.Style: beige :: Colour Double
+ Graphics.Blank.Style: bisque :: Colour Double
+ Graphics.Blank.Style: black :: Colour Double
+ Graphics.Blank.Style: blanchedalmond :: Colour Double
+ Graphics.Blank.Style: blue :: Colour Double
+ Graphics.Blank.Style: blueviolet :: Colour Double
+ Graphics.Blank.Style: brown :: Colour Double
+ Graphics.Blank.Style: burlywood :: Colour Double
+ Graphics.Blank.Style: cadetblue :: Colour Double
+ Graphics.Blank.Style: chartreuse :: Colour Double
+ Graphics.Blank.Style: chocolate :: Colour Double
+ Graphics.Blank.Style: class Style a => CanvasColor a
+ Graphics.Blank.Style: coral :: Colour Double
+ Graphics.Blank.Style: cornflowerblue :: Colour Double
+ Graphics.Blank.Style: cornsilk :: Colour Double
+ Graphics.Blank.Style: crimson :: Colour Double
+ Graphics.Blank.Style: cyan :: Colour Double
+ Graphics.Blank.Style: darkblue :: Colour Double
+ Graphics.Blank.Style: darkcyan :: Colour Double
+ Graphics.Blank.Style: darkgoldenrod :: Colour Double
+ Graphics.Blank.Style: darkgray :: Colour Double
+ Graphics.Blank.Style: darkgreen :: Colour Double
+ Graphics.Blank.Style: darkgrey :: Colour Double
+ Graphics.Blank.Style: darkkhaki :: Colour Double
+ Graphics.Blank.Style: darkmagenta :: Colour Double
+ Graphics.Blank.Style: darkolivegreen :: Colour Double
+ Graphics.Blank.Style: darkorange :: Colour Double
+ Graphics.Blank.Style: darkorchid :: Colour Double
+ Graphics.Blank.Style: darkred :: Colour Double
+ Graphics.Blank.Style: darksalmon :: Colour Double
+ Graphics.Blank.Style: darkseagreen :: Colour Double
+ Graphics.Blank.Style: darkslateblue :: Colour Double
+ Graphics.Blank.Style: darkslategray :: Colour Double
+ Graphics.Blank.Style: darkslategrey :: Colour Double
+ Graphics.Blank.Style: darkturquoise :: Colour Double
+ Graphics.Blank.Style: darkviolet :: Colour Double
+ Graphics.Blank.Style: deeppink :: Colour Double
+ Graphics.Blank.Style: deepskyblue :: Colour Double
+ Graphics.Blank.Style: dimgray :: Colour Double
+ Graphics.Blank.Style: dimgrey :: Colour Double
+ Graphics.Blank.Style: dodgerblue :: Colour Double
+ Graphics.Blank.Style: firebrick :: Colour Double
+ Graphics.Blank.Style: floralwhite :: Colour Double
+ Graphics.Blank.Style: forestgreen :: Colour Double
+ Graphics.Blank.Style: fuchsia :: Colour Double
+ Graphics.Blank.Style: gainsboro :: Colour Double
+ Graphics.Blank.Style: ghostwhite :: Colour Double
+ Graphics.Blank.Style: gold :: Colour Double
+ Graphics.Blank.Style: goldenrod :: Colour Double
+ Graphics.Blank.Style: gray :: Colour Double
+ Graphics.Blank.Style: green :: Colour Double
+ Graphics.Blank.Style: greenyellow :: Colour Double
+ Graphics.Blank.Style: grey :: Colour Double
+ Graphics.Blank.Style: honeydew :: Colour Double
+ Graphics.Blank.Style: hotpink :: Colour Double
+ Graphics.Blank.Style: hsl :: Int -> Percentage -> Percentage -> Colour Double
+ Graphics.Blank.Style: hsla :: Int -> Percentage -> Percentage -> Alpha -> AlphaColour Double
+ Graphics.Blank.Style: indianred :: Colour Double
+ Graphics.Blank.Style: indigo :: Colour Double
+ Graphics.Blank.Style: ivory :: Colour Double
+ Graphics.Blank.Style: jsStyle :: Style a => a -> String
+ Graphics.Blank.Style: khaki :: Colour Double
+ Graphics.Blank.Style: lavender :: Colour Double
+ Graphics.Blank.Style: lavenderblush :: Colour Double
+ Graphics.Blank.Style: lawngreen :: Colour Double
+ Graphics.Blank.Style: lemonchiffon :: Colour Double
+ Graphics.Blank.Style: lightblue :: Colour Double
+ Graphics.Blank.Style: lightcoral :: Colour Double
+ Graphics.Blank.Style: lightcyan :: Colour Double
+ Graphics.Blank.Style: lightgoldenrodyellow :: Colour Double
+ Graphics.Blank.Style: lightgray :: Colour Double
+ Graphics.Blank.Style: lightgreen :: Colour Double
+ Graphics.Blank.Style: lightgrey :: Colour Double
+ Graphics.Blank.Style: lightpink :: Colour Double
+ Graphics.Blank.Style: lightsalmon :: Colour Double
+ Graphics.Blank.Style: lightseagreen :: Colour Double
+ Graphics.Blank.Style: lightskyblue :: Colour Double
+ Graphics.Blank.Style: lightslategray :: Colour Double
+ Graphics.Blank.Style: lightslategrey :: Colour Double
+ Graphics.Blank.Style: lightsteelblue :: Colour Double
+ Graphics.Blank.Style: lightyellow :: Colour Double
+ Graphics.Blank.Style: lime :: Colour Double
+ Graphics.Blank.Style: limegreen :: Colour Double
+ Graphics.Blank.Style: linen :: Colour Double
+ Graphics.Blank.Style: magenta :: Colour Double
+ Graphics.Blank.Style: maroon :: Colour Double
+ Graphics.Blank.Style: mediumaquamarine :: Colour Double
+ Graphics.Blank.Style: mediumblue :: Colour Double
+ Graphics.Blank.Style: mediumorchid :: Colour Double
+ Graphics.Blank.Style: mediumpurple :: Colour Double
+ Graphics.Blank.Style: mediumseagreen :: Colour Double
+ Graphics.Blank.Style: mediumslateblue :: Colour Double
+ Graphics.Blank.Style: mediumspringgreen :: Colour Double
+ Graphics.Blank.Style: mediumturquoise :: Colour Double
+ Graphics.Blank.Style: mediumvioletred :: Colour Double
+ Graphics.Blank.Style: midnightblue :: Colour Double
+ Graphics.Blank.Style: mintcream :: Colour Double
+ Graphics.Blank.Style: mistyrose :: Colour Double
+ Graphics.Blank.Style: moccasin :: Colour Double
+ Graphics.Blank.Style: navajowhite :: Colour Double
+ Graphics.Blank.Style: navy :: Colour Double
+ Graphics.Blank.Style: oldlace :: Colour Double
+ Graphics.Blank.Style: olive :: Colour Double
+ Graphics.Blank.Style: olivedrab :: Colour Double
+ Graphics.Blank.Style: orange :: Colour Double
+ Graphics.Blank.Style: orangered :: Colour Double
+ Graphics.Blank.Style: orchid :: Colour Double
+ Graphics.Blank.Style: palegoldenrod :: Colour Double
+ Graphics.Blank.Style: palegreen :: Colour Double
+ Graphics.Blank.Style: paleturquoise :: Colour Double
+ Graphics.Blank.Style: palevioletred :: Colour Double
+ Graphics.Blank.Style: papayawhip :: Colour Double
+ Graphics.Blank.Style: peachpuff :: Colour Double
+ Graphics.Blank.Style: peru :: Colour Double
+ Graphics.Blank.Style: pink :: Colour Double
+ Graphics.Blank.Style: plum :: Colour Double
+ Graphics.Blank.Style: powderblue :: Colour Double
+ Graphics.Blank.Style: purple :: Colour Double
+ Graphics.Blank.Style: readColourName :: Monad m => String -> m (Colour Double)
+ Graphics.Blank.Style: rebeccapurple :: Colour Double
+ Graphics.Blank.Style: red :: Colour Double
+ Graphics.Blank.Style: rgb :: Word8 -> Word8 -> Word8 -> Colour Double
+ Graphics.Blank.Style: rgbPercent :: Percentage -> Percentage -> Percentage -> Colour Double
+ Graphics.Blank.Style: rgba :: Word8 -> Word8 -> Word8 -> Alpha -> AlphaColour Double
+ Graphics.Blank.Style: rgbaPercent :: Percentage -> Percentage -> Percentage -> Alpha -> AlphaColour Double
+ Graphics.Blank.Style: rosybrown :: Colour Double
+ Graphics.Blank.Style: royalblue :: Colour Double
+ Graphics.Blank.Style: saddlebrown :: Colour Double
+ Graphics.Blank.Style: salmon :: Colour Double
+ Graphics.Blank.Style: sandybrown :: Colour Double
+ Graphics.Blank.Style: seagreen :: Colour Double
+ Graphics.Blank.Style: seashell :: Colour Double
+ Graphics.Blank.Style: shadowColor :: CanvasColor canvasColor => canvasColor -> Canvas ()
+ Graphics.Blank.Style: sienna :: Colour Double
+ Graphics.Blank.Style: silver :: Colour Double
+ Graphics.Blank.Style: skyblue :: Colour Double
+ Graphics.Blank.Style: slateblue :: Colour Double
+ Graphics.Blank.Style: slategray :: Colour Double
+ Graphics.Blank.Style: slategrey :: Colour Double
+ Graphics.Blank.Style: snow :: Colour Double
+ Graphics.Blank.Style: springgreen :: Colour Double
+ Graphics.Blank.Style: steelblue :: Colour Double
+ Graphics.Blank.Style: tan :: Colour Double
+ Graphics.Blank.Style: teal :: Colour Double
+ Graphics.Blank.Style: thistle :: Colour Double
+ Graphics.Blank.Style: tomato :: Colour Double
+ Graphics.Blank.Style: transparent :: AlphaColour Double
+ Graphics.Blank.Style: turquoise :: Colour Double
+ Graphics.Blank.Style: type Alpha = Double
+ Graphics.Blank.Style: type Percentage = Double
+ Graphics.Blank.Style: violet :: Colour Double
+ Graphics.Blank.Style: wheat :: Colour Double
+ Graphics.Blank.Style: white :: Colour Double
+ Graphics.Blank.Style: whitesmoke :: Colour Double
+ Graphics.Blank.Style: yellow :: Colour Double
+ Graphics.Blank.Style: yellowgreen :: Colour Double
- Graphics.Blank: Event :: Bool -> Maybe (Float, Float) -> EventName -> Maybe Int -> Event
+ Graphics.Blank: Event :: Bool -> Maybe (Double, Double) -> EventName -> Maybe Int -> Event
- Graphics.Blank: Options :: Int -> [EventName] -> Bool -> [String] -> String -> [Middleware] -> Options
+ Graphics.Blank: Options :: Int -> [EventName] -> Bool -> String -> [Middleware] -> Options
- Graphics.Blank: TextMetrics :: Float -> TextMetrics
+ Graphics.Blank: TextMetrics :: Double -> TextMetrics
- Graphics.Blank: addColorStop :: (Float, Text) -> CanvasGradient -> Canvas ()
+ Graphics.Blank: addColorStop :: (Double, Text) -> CanvasGradient -> Canvas ()
- Graphics.Blank: arc :: (Float, Float, Float, Float, Float, Bool) -> Canvas ()
+ Graphics.Blank: arc :: (Double, Double, Double, Double, Double, Bool) -> Canvas ()
- Graphics.Blank: arcTo :: (Float, Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: arcTo :: (Double, Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: bezierCurveTo :: (Float, Float, Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: bezierCurveTo :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: clearRect :: (Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: clearRect :: (Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: createLinearGradient :: (Float, Float, Float, Float) -> Canvas CanvasGradient
+ Graphics.Blank: createLinearGradient :: (Double, Double, Double, Double) -> Canvas CanvasGradient
- Graphics.Blank: createPattern :: (CanvasImage, Text) -> Canvas CanvasPattern
+ Graphics.Blank: createPattern :: (CanvasImage, RepeatDirection) -> Canvas CanvasPattern
- Graphics.Blank: createRadialGradient :: (Float, Float, Float, Float, Float, Float) -> Canvas CanvasGradient
+ Graphics.Blank: createRadialGradient :: (Double, Double, Double, Double, Double, Double) -> Canvas CanvasGradient
- Graphics.Blank: devicePixelRatio :: DeviceContext -> Float
+ Graphics.Blank: devicePixelRatio :: DeviceContext -> Double
- Graphics.Blank: drawImage :: Image image => (image, [Float]) -> Canvas ()
+ Graphics.Blank: drawImage :: Image image => (image, [Double]) -> Canvas ()
- Graphics.Blank: ePageXY :: Event -> Maybe (Float, Float)
+ Graphics.Blank: ePageXY :: Event -> Maybe (Double, Double)
- Graphics.Blank: fillRect :: (Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: fillRect :: (Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: fillText :: (Text, Float, Float) -> Canvas ()
+ Graphics.Blank: fillText :: (Text, Double, Double) -> Canvas ()
- Graphics.Blank: getImageData :: (Float, Float, Float, Float) -> Canvas ImageData
+ Graphics.Blank: getImageData :: (Double, Double, Double, Double) -> Canvas ImageData
- Graphics.Blank: globalAlpha :: Float -> Canvas ()
+ Graphics.Blank: globalAlpha :: Double -> Canvas ()
- Graphics.Blank: isPointInPath :: (Float, Float) -> Canvas Bool
+ Graphics.Blank: isPointInPath :: (Double, Double) -> Canvas Bool
- Graphics.Blank: lineCap :: Text -> Canvas ()
+ Graphics.Blank: lineCap :: LineEndCap -> Canvas ()
- Graphics.Blank: lineJoin :: Text -> Canvas ()
+ Graphics.Blank: lineJoin :: LineJoinCorner -> Canvas ()
- Graphics.Blank: lineTo :: (Float, Float) -> Canvas ()
+ Graphics.Blank: lineTo :: (Double, Double) -> Canvas ()
- Graphics.Blank: lineWidth :: Float -> Canvas ()
+ Graphics.Blank: lineWidth :: Double -> Canvas ()
- Graphics.Blank: miterLimit :: Float -> Canvas ()
+ Graphics.Blank: miterLimit :: Double -> Canvas ()
- Graphics.Blank: moveTo :: (Float, Float) -> Canvas ()
+ Graphics.Blank: moveTo :: (Double, Double) -> Canvas ()
- Graphics.Blank: putImageData :: (ImageData, [Float]) -> Canvas ()
+ Graphics.Blank: putImageData :: (ImageData, [Double]) -> Canvas ()
- Graphics.Blank: quadraticCurveTo :: (Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: quadraticCurveTo :: (Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: rect :: (Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: rect :: (Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: rotate :: Float -> Canvas ()
+ Graphics.Blank: rotate :: Double -> Canvas ()
- Graphics.Blank: saveRestore :: Canvas () -> Canvas ()
+ Graphics.Blank: saveRestore :: Canvas a -> Canvas a
- Graphics.Blank: scale :: (Float, Float) -> Canvas ()
+ Graphics.Blank: scale :: (Double, Double) -> Canvas ()
- Graphics.Blank: setTransform :: (Float, Float, Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: setTransform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: shadowBlur :: Float -> Canvas ()
+ Graphics.Blank: shadowBlur :: Double -> Canvas ()
- Graphics.Blank: shadowOffsetX :: Float -> Canvas ()
+ Graphics.Blank: shadowOffsetX :: Double -> Canvas ()
- Graphics.Blank: shadowOffsetY :: Float -> Canvas ()
+ Graphics.Blank: shadowOffsetY :: Double -> Canvas ()
- Graphics.Blank: strokeRect :: (Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: strokeRect :: (Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: strokeText :: (Text, Float, Float) -> Canvas ()
+ Graphics.Blank: strokeText :: (Text, Double, Double) -> Canvas ()
- Graphics.Blank: textAlign :: Text -> Canvas ()
+ Graphics.Blank: textAlign :: TextAnchorAlignment -> Canvas ()
- Graphics.Blank: textBaseline :: Text -> Canvas ()
+ Graphics.Blank: textBaseline :: TextBaselineAlignment -> Canvas ()
- Graphics.Blank: transform :: (Float, Float, Float, Float, Float, Float) -> Canvas ()
+ Graphics.Blank: transform :: (Double, Double, Double, Double, Double, Double) -> Canvas ()
- Graphics.Blank: translate :: (Float, Float) -> Canvas ()
+ Graphics.Blank: translate :: (Double, Double) -> Canvas ()

Files

+ Changelog.md view
@@ -0,0 +1,18 @@+## 0.5++API changes+ * Using Double rather than Float+ * Generalized saveRestore to be polymorphic++API additions+ * Added sync for forcing synchronization between the server and client+ * Added argument specific variants of drawImage and putImageData.+ * Added ADTs for RepeatDirection, Alignment, Baseline, LineEnds, Corner (previous used Text)+ * Use of the colour(sic) package (Text is still allowed)++Bug fixes:+ * Fixed unicode escapes in strings++Additions:+ * Allow Images to access client-side filesystem+
Graphics/Blank.hs view
@@ -15,7 +15,7 @@         , DeviceContext       -- abstact         , send           -- * HTML5 Canvas API-          -- | See <http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.pdf> for the JavaScript +          -- | See <http://www.nihilogic.dk/labs/canvas_sheet/HTML5_Canvas_Cheat_Sheet.pdf> for the JavaScript           --   version of this API.         , Canvas        -- abstact           -- ** Canvas element@@ -42,6 +42,8 @@         , lineCap         , lineJoin         , miterLimit+        , LineEndCap(..)+        , LineJoinCorner(..)           -- ** Colors, styles and shadows         , strokeStyle         , fillStyle@@ -53,6 +55,7 @@         , createRadialGradient         , createPattern         , addColorStop+        , RepeatDirection(..)         , CanvasGradient         , CanvasPattern           -- ** Paths@@ -70,12 +73,14 @@         , rect         , isPointInPath           -- ** Text-        , font +        , font         , textAlign         , textBaseline         , fillText         , strokeText         , measureText+        , TextAnchorAlignment(..)+        , TextBaselineAlignment(..)         , TextMetrics(..)           -- ** Rectangles         , clearRect@@ -97,6 +102,8 @@         , with         , myCanvasContext         , deviceCanvasContext+         -- ** Syncing+        , sync          -- ** Debugging         , console_log         , eval@@ -104,7 +111,7 @@          -- ** Drawing Utilities         , module Graphics.Blank.Utils          -- ** Events-        , trigger +        , trigger         , eventQueue         , wait         , flush@@ -115,38 +122,48 @@         , local_only         ) where -import Control.Concurrent-import Control.Concurrent.STM-import Control.Monad-import Control.Exception-import Network.Wai.Handler.Warp (run)-import Network.Wai (Middleware,remoteHost, responseLBS)-import qualified Network.HTTP.Types as H-import Network.Socket (SockAddr(..))-import System.IO.Unsafe (unsafePerformIO)---import System.Mem.StableName-import Web.Scotty (scottyApp, get, file)-import qualified Web.Scotty as Scotty---import Network.Wai.Middleware.RequestLogger -- Used when debugging---import Network.Wai.Middleware.Static-import qualified Web.Scotty.Comet as KC-import Data.Aeson-import Data.Aeson.Types (parse)-import Data.String+import           Control.Concurrent+import           Control.Concurrent.STM+import           Control.Exception+import           Control.Monad+import           Control.Monad.IO.Class++import           Data.Aeson+import           Data.Aeson.Types (parse)+import           Data.List as L+import           Data.Monoid ((<>))+import qualified Data.Set as S+import           Data.String import qualified Data.Text as T-import Data.Text (Text)-import Data.Monoid((<>))+import           Data.Text (Text)+import qualified Data.Text.Lazy as LT -import Graphics.Blank.Events-import Graphics.Blank.DeviceContext-import Graphics.Blank.Canvas-import Graphics.Blank.Generated hiding (fillStyle,strokeStyle)+import qualified Graphics.Blank.Canvas as Canvas+import           Graphics.Blank.Canvas hiding (addColorStop)+import           Graphics.Blank.DeviceContext+import           Graphics.Blank.Events import qualified Graphics.Blank.Generated as Generated+import           Graphics.Blank.Generated hiding (fillStyle, strokeStyle, shadowColor) import qualified Graphics.Blank.JavaScript as JavaScript-import Graphics.Blank.JavaScript hiding (width, height)-import Graphics.Blank.Utils-import Paths_blank_canvas+import           Graphics.Blank.JavaScript hiding (width, height)+import           Graphics.Blank.Utils +import qualified Network.HTTP.Types as H+import           Network.Wai (Middleware, responseLBS)+import           Network.Wai.Middleware.Local+import           Network.Wai.Handler.Warp+-- import           Network.Wai.Middleware.RequestLogger -- Used when debugging+-- import           Network.Wai.Middleware.Static++import           Paths_blank_canvas++import           System.IO.Unsafe (unsafePerformIO)+-- import           System.Mem.StableName++import qualified Web.Scotty as Scotty+import           Web.Scotty (scottyApp, get, file)+import qualified Web.Scotty.Comet as KC+ -- | blankCanvas is the main entry point into blank-canvas. -- A typical invocation would be --@@ -172,17 +189,21 @@    kComet <- KC.kCometPlugin  +   locals :: TVar (S.Set Text) <- atomically $ newTVar S.empty+ --   print dataDir     app <- scottyApp $ do --        middleware logStdoutDev-        sequence_ [ Scotty.middleware ware -                  | ware <- middleware opts +        sequence_ [ Scotty.middleware ware+                  | ware <- middleware opts                   ]         -- use the comet         let kc_opts :: KC.Options             kc_opts = KC.Options { KC.prefix = "/blank", KC.verbose = if debug opts then 3 else 0 } ++         KC.connect kc_opts $ \ kc_doc -> do                 -- register the events we want to watch for                 KC.send kc_doc $ T.unlines@@ -198,18 +219,19 @@                                    atomically $ writeTChan queue event                            _ -> return () -                let cxt0 = DeviceContext kc_doc queue 300 300 1-                -                -- A bit of bootstrapping ++                let cxt0 = DeviceContext kc_doc queue 300 300 1 locals++                -- A bit of bootstrapping                 DeviceAttributes w h dpr <- send cxt0 device                 -- print (DeviceAttributes w h dpr) -                let cxt1 = cxt0 +                let cxt1 = cxt0                          { ctx_width = w                          , ctx_height = h                          , ctx_devicePixelRatio = dpr                          }-                +                 (actions $ cxt1) `catch` \ (e :: SomeException) -> do                         print ("Exception in blank-canvas application:"  :: String)                         print e@@ -219,57 +241,78 @@         get "/jquery.js"        $ file $ dataDir ++ "/static/jquery.js"         get "/jquery-json.js"   $ file $ dataDir ++ "/static/jquery-json.js"         get "/kansas-comet.js"  $ file $ kComet-        sequence_ [ get (fromString ("/" ++ nm)) $ file $ (root opts ++ "/" ++ nm) | nm <- static opts ]++        -- There has to be a better way of doing this, using function, perhaps?+        get (Scotty.regex "^/(.*)$") $ do+          fileName :: Text <- Scotty.param "1"+          db <- liftIO $ atomically $ readTVar $ locals+          if fileName `S.member` db+          then do+            mime <- mimeTypes (T.unpack fileName)+            Scotty.setHeader "Content-Type" $ LT.fromStrict $ mime+            file $ (root opts ++ "/" ++ T.unpack fileName)+          else do+            Scotty.next+         return () -   run (port opts) app ++   runSettings (setPort (port opts)+               $ setTimeout 5+               $ defaultSettings+               ) app+ -- | Sends a set of Canvas commands to the canvas. Attempts -- to common up as many commands as possible. Should not crash.  send :: DeviceContext -> Canvas a -> IO a-send cxt commands = -      send' (deviceCanvasContext cxt) commands id +send cxt commands =+      send' (deviceCanvasContext cxt) commands id   where-      send' :: CanvasContext -> Canvas a -> (String -> String) -> IO a-      send' c (Bind (Return a) k)    cmds = send' c (k a) cmds-      send' c (Bind (Bind m k1) k2)  cmds = send' c (Bind m (\ r -> Bind (k1 r) k2)) cmds-      send' c (Bind (Method cmd) k) cmds = send' c (k ()) (cmds . ((showJS c ++ ".") ++) . shows cmd . (";" ++))-      send' c (Bind (Command cmd) k) cmds = send' c (k ()) (cmds . shows cmd . (";" ++))-      send' c (Bind (Query query) k) cmds = do-              -- send the com-              uq <- atomically $ getUniq-              -- The query function returns a function takes the unique port number of the reply.-              sendToCanvas cxt (cmds . ((show query ++ "(" ++ show uq ++ "," ++ showJS c ++ ");") ++))-              v <- KC.getReply (theComet cxt) uq-              case parse (parseQueryResult query) v of-                Error msg -> fail msg-                Success a -> do-                        send' c (k a) id-      send' c (Bind (With c' m) k) cmds = send' c' (Bind m (With c . k)) cmds-      send' c (Bind MyContext k)   cmds = send' c (k c) cmds+      sendBind :: CanvasContext -> Canvas a -> (a -> Canvas b) -> (String -> String) -> IO b+      sendBind c (Return a) k    cmds = send' c (k a) cmds+      sendBind c (Bind m k1) k2 cmds = sendBind c m (\ r -> Bind (k1 r) k2) cmds+      sendBind c (Method cmd) k cmds = send' c (k ()) (cmds . ((showJS c ++ ".") ++) . shows cmd . (";" ++))+      sendBind c (Command cmd) k cmds = send' c (k ()) (cmds . shows cmd . (";" ++))+      sendBind c (Query query) k cmds = sendQuery c query k cmds+      sendBind c (With c' m) k  cmds = send' c' (Bind m (With c . k)) cmds+      sendBind c MyContext k    cmds = send' c (k c) cmds -      send' _ (With c m)           cmds = send' c m cmds-      send' c MyContext            cmds = send' c (Return c) cmds-      send' _ (Return a)           cmds = do+      sendQuery :: CanvasContext -> Query a -> (a -> Canvas b) -> (String -> String) -> IO b+      sendQuery c query k cmds = do+          case query of+            NewImage url -> do+              let url' = if "/" `T.isPrefixOf` url then T.tail url else url+              atomically $ do+                  db <- readTVar (localFiles cxt)+                  writeTVar (localFiles cxt) $ S.insert url' $ db+            _ -> return ()++          -- send the com+          uq <- atomically $ getUniq+          -- The query function returns a function takes the unique port number of the reply.+          sendToCanvas cxt (cmds . ((show query ++ "(" ++ show uq ++ "," ++ showJS c ++ ");") ++))+          v <- KC.getReply (theComet cxt) uq+          case parse (parseQueryResult query) v of+            Error msg -> fail msg+            Success a -> do+                    send' c (k a) id++++      send' :: CanvasContext -> Canvas a -> (String -> String) -> IO a+-- Most of these can be factored out, except return+      send' c (Bind m k)            cmds = sendBind c m k cmds+      send' _ (With c m)            cmds = send' c m cmds  -- This is a bit of a hack+      send' _ (Return a)            cmds = do               sendToCanvas cxt cmds               return a-      send' c cmd                  cmds = send' c (Bind cmd Return) cmds+      send' c cmd                   cmds = sendBind c cmd Return cmds   local_only :: Middleware-local_only f r k = case remoteHost r of-                   SockAddrInet _  h | h == fromIntegral home-                                    -> f r k-#if !defined(mingw32_HOST_OS) && !defined(_WIN32)-                   SockAddrUnix _   -> f r k-#endif-                   _                ->  k $ responseLBS H.status403-                                                        [("Content-Type", "text/plain")]-							 "local access only"- where-        home :: Integer-        home = 127 + (256 * 256 * 256) * 1+local_only = local $ responseLBS H.status403 [("Content-Type", "text/plain")] "local access only"   {-# NOINLINE uniqVar #-}@@ -282,17 +325,26 @@     writeTVar uniqVar (u + 1)     return u +mimeTypes :: Monad m => FilePath -> m Text+mimeTypes filePath+  | ".jpg" `L.isSuffixOf` filePath = return "image/jpeg"+  | ".png" `L.isSuffixOf` filePath = return "image/png"+  | ".gif" `L.isSuffixOf` filePath = return "image/gif"+  | otherwise = fail $ "do not understand mime type for : " ++ show filePath+ ------------------------------------------------- -data Options = Options +-- TODO: add extra mime types+++data Options = Options         { port   :: Int              -- ^ which port do we issue the blank canvas using         , events :: [EventName]      -- ^ which events does the canvas listen to         , debug  :: Bool             -- ^ turn on debugging (default False)-        , static :: [String]         -- ^ path to images, and other static artifacts         , root   :: String           -- ^ location of the static files (default .)         , middleware :: [Middleware] -- ^ extra middleware(s) to be executed. (default [local_only])         }-        + instance Num Options where     (+) = error "no arithmetic for Blank Canvas Options"     (-) = error "no arithmetic for Blank Canvas Options"@@ -302,7 +354,6 @@     fromInteger n = Options { port = fromInteger n                             , events = []                             , debug = False-                            , static = []                             , root = "."                             , middleware = [local_only]                             }@@ -317,9 +368,14 @@ strokeStyle :: Text -> Canvas () strokeStyle = Generated.strokeStyle +shadowColor :: Text -> Canvas ()+shadowColor = Generated.shadowColor++addColorStop :: (Double, Text) -> CanvasGradient -> Canvas ()+addColorStop = Canvas.addColorStop+ height :: (Image image, Num a) => image -> a height = JavaScript.height  width :: (Image image, Num a) => image -> a width = JavaScript.width-
Graphics/Blank/Canvas.hs view
@@ -2,28 +2,30 @@  module Graphics.Blank.Canvas where -import Graphics.Blank.Events-import Graphics.Blank.JavaScript+import           Control.Applicative+import           Control.Monad (ap, liftM2) -import Data.Aeson (FromJSON(..),Value(..),encode)-import Data.Aeson.Types (Parser, (.:))-import Data.Char (chr)-import Control.Monad (ap, liftM2)-import Control.Applicative-import Data.Monoid+import           Graphics.Blank.Events+import           Graphics.Blank.JavaScript++import           Data.Aeson (FromJSON(..),Value(..),encode)+import           Data.Aeson.Types (Parser, (.:))+import           Data.Char (chr)+ import qualified Data.ByteString.Lazy as DBL+import           Data.Monoid import qualified Data.Text as Text-import Data.Text (Text)+import           Data.Text (Text)   data Canvas :: * -> * where-        Method  :: Method                              -> Canvas ()     -- <context>.<method>-        Command :: Command                             -> Canvas ()     -- <command>-        Query   :: (Show a) => Query a                 -> Canvas a-        With    :: CanvasContext -> Canvas a           -> Canvas a-        MyContext ::                                      Canvas CanvasContext-        Bind    :: Canvas a -> (a -> Canvas b)         -> Canvas b-        Return  :: a                                   -> Canvas a+        Method    :: Method                      -> Canvas ()     -- <context>.<method>+        Command   :: Command                     -> Canvas ()     -- <command>+        Query     :: (Show a) => Query a         -> Canvas a+        With      :: CanvasContext -> Canvas a   -> Canvas a+        MyContext ::                                Canvas CanvasContext+        Bind      :: Canvas a -> (a -> Canvas b) -> Canvas b+        Return    :: a                           -> Canvas a  instance Monad Canvas where         return = Return@@ -40,62 +42,63 @@   mappend = liftM2 mappend   mempty  = return mempty + -- HTML5 Canvas assignments: FillStyle, Font, GlobalAlpha, GlobalCompositeOperation, LineCap, LineJoin, LineWidth, MiterLimit, ShadowBlur, ShadowColor, ShadowOffsetX, ShadowOffsetY, StrokeStyle, TextAlign, TextBaseline data Method         -- regular HTML5 canvas commands-        = Arc (Float,Float,Float,Float,Float,Bool)-        | ArcTo (Float,Float,Float,Float,Float)+        = Arc (Double, Double, Double, Double, Double, Bool)+        | ArcTo (Double, Double, Double, Double, Double)         | BeginPath-        | BezierCurveTo (Float,Float,Float,Float,Float,Float)-        | forall image . Image image => DrawImage (image,[Float]) -- 'drawImage' takes 2, 4 or 8 floats arguments-        | ClearRect (Float,Float,Float,Float)+        | BezierCurveTo (Double, Double, Double, Double, Double, Double)+        | ClearRect (Double, Double, Double, Double)         | Clip         | ClosePath+        | forall image . Image image => DrawImage (image,[Double]) -- drawImage' takes 2, 4, or 8 'Double' arguments. See 'drawImageAt', 'drawImageSize', and 'drawImageCrop' for variants with exact numbers of arguments.         | Fill-        | FillRect (Float,Float,Float,Float)+        | FillRect (Double, Double, Double, Double)         | forall style . Style style => FillStyle style-        | FillText (Text,Float,Float)+        | FillText (Text, Double, Double)         | Font Text-        | GlobalAlpha Float+        | GlobalAlpha Double         | GlobalCompositeOperation Text-        | LineCap Text-        | LineJoin Text-        | LineTo (Float,Float)-        | LineWidth Float-        | MiterLimit Float-        | MoveTo (Float,Float)-        | PutImageData (ImageData,[Float])-        | QuadraticCurveTo (Float,Float,Float,Float)-        | Rect (Float,Float,Float,Float)+        | LineCap LineEndCap+        | LineJoin LineJoinCorner+        | LineTo (Double, Double)+        | LineWidth Double+        | MiterLimit Double+        | MoveTo (Double, Double)+        | PutImageData (ImageData, [Double]) -- 'putImageData' takes 2 or 6 'Double' arguments. See `putImageDataAt' and `putImageDataDirty' for variants with exact numbers of arguments.+        | QuadraticCurveTo (Double, Double, Double, Double)+        | Rect (Double, Double, Double, Double)         | Restore-        | Rotate Float-        | Scale (Float,Float)+        | Rotate Double         | Save-        | SetTransform (Float,Float,Float,Float,Float,Float)+        | Scale (Double, Double)+        | SetTransform (Double, Double, Double, Double, Double, Double)+        | ShadowBlur Double+        | forall canvasColor . CanvasColor canvasColor => ShadowColor canvasColor+        | ShadowOffsetX Double+        | ShadowOffsetY Double         | Stroke-        | StrokeRect (Float,Float,Float,Float)-        | StrokeText (Text,Float,Float)+        | StrokeRect (Double, Double, Double, Double)         | forall style . Style style => StrokeStyle style-        | ShadowBlur Float-        | ShadowColor Text-        | ShadowOffsetX Float-        | ShadowOffsetY Float-        | TextAlign Text-        | TextBaseline Text-        | Transform (Float,Float,Float,Float,Float,Float)-        | Translate (Float,Float)+        | StrokeText (Text,Double, Double)+        | TextAlign TextAnchorAlignment+        | TextBaseline TextBaselineAlignment+        | Transform (Double, Double, Double, Double, Double, Double)+        | Translate (Double, Double)  data Command   = Trigger Event-  | AddColorStop (Float,Text) CanvasGradient+  | forall color . CanvasColor color => AddColorStop (Double, color) CanvasGradient   | forall msg . JSArg msg => Log msg   | Eval Text  instance Show Command where   show (Trigger e) = "Trigger(" ++ map (chr . fromEnum) (DBL.unpack (encode e)) ++ ")"   show (AddColorStop (off,rep) g)-     = showJS g ++ ".addColorStop(" ++ showJS off ++ "," ++ showJS rep ++ ")"-  show (Log msg) = "console.log(" ++ showJS msg ++ ")" +     = showJS g ++ ".addColorStop(" ++ showJS off ++ "," ++ jsStyle rep ++ ")"+  show (Log msg) = "console.log(" ++ showJS msg ++ ")"   show (Eval cmd) = Text.unpack cmd -- no escaping or interpretation  -----------------------------------------------------------------------------@@ -116,7 +119,7 @@ trigger = Command . Trigger  -- | add a Color stop to a Canvas Gradient.-addColorStop :: (Float,Text) -> CanvasGradient -> Canvas ()+addColorStop :: CanvasColor color => (Double, color) -> CanvasGradient -> Canvas () addColorStop (off,rep) = Command . AddColorStop (off,rep)  -- | 'console_log' aids debugging by sending the argument to the browser console.log.@@ -129,22 +132,23 @@  ----------------------------------------------------------------------------- data Query :: * -> * where-        Device                                            :: Query DeviceAttributes-        ToDataURL                                         :: Query Text-        MeasureText          :: Text                      -> Query TextMetrics-        IsPointInPath        :: (Float,Float)             -> Query Bool-        NewImage             :: Text                      -> Query CanvasImage-        CreateLinearGradient :: (Float,Float,Float,Float)             -> Query CanvasGradient-        CreateRadialGradient :: (Float,Float,Float,Float,Float,Float) -> Query CanvasGradient-        CreatePattern        :: Image image => (image,Text) -> Query CanvasPattern-        NewCanvas            :: (Int,Int)                 -> Query CanvasContext-        GetImageData         :: (Float,Float,Float,Float) -> Query ImageData+        Device               ::                                                     Query DeviceAttributes+        ToDataURL            ::                                                     Query Text+        MeasureText          :: Text                                             -> Query TextMetrics+        IsPointInPath        :: (Double, Double)                                 -> Query Bool+        NewImage             :: Text                                             -> Query CanvasImage+        CreateLinearGradient :: (Double, Double, Double, Double)                 -> Query CanvasGradient+        CreateRadialGradient :: (Double, Double, Double, Double, Double, Double) -> Query CanvasGradient+        CreatePattern        :: Image image => (image, RepeatDirection)          -> Query CanvasPattern+        NewCanvas            :: (Int, Int)                                       -> Query CanvasContext+        GetImageData         :: (Double, Double, Double, Double)                 -> Query ImageData+        Sync                 ::                                                     Query () -data DeviceAttributes = DeviceAttributes Int Int Float +data DeviceAttributes = DeviceAttributes Int Int Double         deriving Show-        + -- | The 'width' argument of 'TextMetrics' can trivially be projected out.-data TextMetrics = TextMetrics Float+data TextMetrics = TextMetrics Double         deriving Show  instance Show (Query a) where@@ -155,10 +159,11 @@   show (NewImage url)           = "NewImage(" ++ showJS url ++ ")"   show (CreateLinearGradient (x0,y0,x1,y1)) = "CreateLinearGradient(" ++ showJS x0 ++ "," ++ showJS y0 ++ "," ++ showJS x1 ++ "," ++ showJS y1 ++ ")"   show (CreateRadialGradient (x0,y0,r0,x1,y1,r1)) = "CreateRadialGradient(" ++ showJS x0 ++ "," ++ showJS y0 ++ "," ++ showJS r0 ++ "," ++ showJS x1 ++ "," ++ showJS y1 ++ "," ++ showJS r1 ++ ")"-  show (CreatePattern (img,str)) = "CreatePattern(" ++ jsImage img ++ "," ++ showJS str ++ ")"+  show (CreatePattern (img,dir)) = "CreatePattern(" ++ jsImage img ++ "," ++ jsRepeatDirection dir ++ ")"   show (NewCanvas (x,y))         = "NewCanvas(" ++ showJS x ++ "," ++ showJS y ++ ")"-  show (GetImageData (sx,sy,sw,sh)) +  show (GetImageData (sx,sy,sw,sh))                                  = "GetImageData(" ++ showJS sx ++ "," ++ showJS sy ++ "," ++ showJS sw ++ "," ++ showJS sh ++ ")"+  show Sync                      = "Sync"  -- This is how we take our value to bits parseQueryResult :: Query a -> Value -> Parser a@@ -171,20 +176,21 @@ parseQueryResult (CreateRadialGradient {}) o = CanvasGradient <$> parseJSON o parseQueryResult (CreatePattern {}) o = CanvasPattern <$> parseJSON o parseQueryResult (NewCanvas {}) o = uncurry3 CanvasContext <$> parseJSON o-parseQueryResult (GetImageData {}) (Object o) = ImageData +parseQueryResult (GetImageData {}) (Object o) = ImageData                                          <$> (o .: "width")                                          <*> (o .: "height")                                          <*> (o .: "data")+parseQueryResult (Sync {}) _ = return () -- we just accept anything; empty list sent parseQueryResult _ _ = fail "no parse in blank-canvas server (internal error)"  uncurry3 :: (t0 -> t1 -> t2 -> t3) -> (t0, t1, t2) -> t3-uncurry3 f (a,b,c) = f a b c +uncurry3 f (a,b,c) = f a b c  device :: Canvas DeviceAttributes device = Query Device  -- | Turn the canvas into a png data stream / data URL.--- +-- -- > "data:image/png;base64,iVBORw0KGgo.." -- toDataURL :: () -> Canvas Text@@ -193,29 +199,32 @@ measureText :: Text -> Canvas TextMetrics measureText = Query . MeasureText -isPointInPath :: (Float,Float) -> Canvas Bool+isPointInPath :: (Double, Double) -> Canvas Bool isPointInPath = Query . IsPointInPath --- | 'image' takes a URL (perhaps a data URL), and returns the 'CanvasImage' handle, +-- | 'image' takes a URL (perhaps a data URL), and returns the 'CanvasImage' handle, -- _after_ loading. -- The assumption is you are using local images, so loading should be near instant. newImage :: Text -> Canvas CanvasImage-newImage = Query . NewImage +newImage = Query . NewImage -createLinearGradient :: (Float,Float,Float,Float) -> Canvas CanvasGradient+createLinearGradient :: (Double, Double, Double, Double) -> Canvas CanvasGradient createLinearGradient = Query . CreateLinearGradient -createRadialGradient :: (Float,Float,Float,Float,Float,Float) -> Canvas CanvasGradient+createRadialGradient :: (Double, Double, Double, Double, Double, Double) -> Canvas CanvasGradient createRadialGradient = Query . CreateRadialGradient -createPattern :: (CanvasImage, Text) -> Canvas CanvasPattern+createPattern :: (CanvasImage, RepeatDirection) -> Canvas CanvasPattern createPattern = Query . CreatePattern  -- | Create a new, off-screen canvas buffer. Takes width and height.-newCanvas :: (Int,Int) -> Canvas CanvasContext+newCanvas :: (Int, Int) -> Canvas CanvasContext newCanvas = Query . NewCanvas  -- | Capture ImageDate from the Canvas.-getImageData :: (Float,Float,Float,Float) -> Canvas ImageData-getImageData = Query . GetImageData        +getImageData :: (Double, Double, Double, Double) -> Canvas ImageData+getImageData = Query . GetImageData +-- | Send all commands to the browser, wait for the browser to ack, then continue.+sync :: Canvas ()+sync = Query $ Sync
Graphics/Blank/DeviceContext.hs view
@@ -1,29 +1,33 @@ {-# LANGUAGE OverloadedStrings #-} module Graphics.Blank.DeviceContext where -import Graphics.Blank.JavaScript-import Control.Concurrent.STM--import qualified Web.Scotty.Comet as KC+import           Control.Concurrent.STM -import Graphics.Blank.Events-import Data.Monoid((<>))+import           Data.Set (Set)+import           Data.Monoid ((<>))+import           Data.Text (Text) import qualified Data.Text as T +import           Graphics.Blank.Events+import           Graphics.Blank.JavaScript++import qualified Web.Scotty.Comet as KC+ -- | 'Context' is our abstact handle into a specific 2d-context inside a browser. -- Note that the JavaScript API concepts of 2D-Context and Canvas -- are conflated in blank-canvas. Therefore, there is no 'getContext' method, -- rather 'getContext' is implied (when using 'send').  data DeviceContext = DeviceContext-        { theComet    :: KC.Document                -- ^ The mechansims for sending commands-        , eventQueue  :: EventQueue                 -- ^ A single (typed) event queue-        , ctx_width   :: !Int-        , ctx_height  :: !Int-        , ctx_devicePixelRatio :: !Float+        { theComet             :: KC.Document     -- ^ The mechansims for sending commands+        , eventQueue           :: EventQueue      -- ^ A single (typed) event queue+        , ctx_width            :: !Int+        , ctx_height           :: !Int+        , ctx_devicePixelRatio :: !Double+        , localFiles           :: TVar (Set Text) -- ^ approved local files         } -instance Image DeviceContext where +instance Image DeviceContext where   jsImage = jsImage . deviceCanvasContext   width  = fromIntegral . ctx_width   height = fromIntegral . ctx_height@@ -36,7 +40,7 @@ --   to use the native devicePixelRatio, and if successful, 'devicePixelRatio' will return a number other than 1. --   You can think of devicePixelRatio as the line width to use to make lines look one pixel wide. -devicePixelRatio ::  DeviceContext -> Float+devicePixelRatio ::  DeviceContext -> Double devicePixelRatio = ctx_devicePixelRatio  -- | internal command to send a message to the canvas.@@ -51,7 +55,7 @@ -- | 'flush' all the current events, returning them all to the user. Never blocks. flush :: DeviceContext -> IO [Event] flush cxt = atomically $ loop-  where loop = do +  where loop = do           b <- isEmptyTChan (eventQueue cxt)           if b then return [] else do                  e <- readTChan (eventQueue cxt)
Graphics/Blank/Events.hs view
@@ -1,16 +1,17 @@ {-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-} module Graphics.Blank.Events where +import Control.Applicative ((<|>), (<$>), (<*>))+import Control.Concurrent.STM+ import Data.Aeson (FromJSON(..), Value(..), ToJSON(..)) import Data.Aeson.Types ((.:), (.=), object)-import Control.Applicative((<|>),(<$>),(<*>))-import Control.Concurrent.STM import Data.Text (Text) --- | Basic Event from Browser; see <http://api.jquery.com/category/events/event-object/> for details.+-- | Basic Event from Browser; see <http://api.jquery.com/category/events/> for details. data Event = Event         { eMetaKey :: Bool-        , ePageXY  :: Maybe (Float,Float)+        , ePageXY  :: Maybe (Double, Double)         , eType    :: EventName          -- "Describes the nature of the event." jquery         , eWhich   :: Maybe Int          -- magic code for key presses         }@@ -18,22 +19,22 @@   instance FromJSON Event where-   parseJSON (Object v) = Event <$> ((v .: "eMetaKey")              <|> return False)-                                <*> (Just <$> (v .: "ePageXY")      <|> return Nothing)-                                <*> (v .: "eType")-                                <*> (Just <$> (v .: "eWhich")       <|> return Nothing)+   parseJSON (Object v) = Event <$> ((v .: "metaKey")              <|> return False)+                                <*> (Just <$> (v .: "pageXY")      <|> return Nothing)+                                <*> (v .: "type")+                                <*> (Just <$> (v .: "which")       <|> return Nothing)    parseJSON _ = fail "no parse of Event"      instance ToJSON Event where    toJSON e = object -            $ ((:) ("eMetaKey" .=  eMetaKey e))+            $ ((:) ("metaKey" .=  eMetaKey e))             $ (case ePageXY e of                  Nothing -> id-                 Just (x,y) -> (:) ("ePageXY" .= (x,y)))-            $ ((:) ("eType" .= eType e))+                 Just (x,y) -> (:) ("pageXY" .= (x,y)))+            $ ((:) ("type" .= eType e))             $ (case eWhich e of                  Nothing -> id-                 Just w -> (:) ("eWhich" .= w))+                 Just w -> (:) ("which" .= w))             $ []  -- | 'EventName' mirrors event names from jquery, and use lower case.
Graphics/Blank/GHCi.hs view
@@ -3,10 +3,11 @@ import Control.Concurrent import Control.Concurrent.STM import Control.Monad-import System.IO.Unsafe (unsafePerformIO)  import Graphics.Blank (Options(..),port,send, Canvas, blankCanvas) +import System.IO.Unsafe (unsafePerformIO)+ -- | splitCanvas is the GHCi entry point into blank-canvas. -- A typical invocation would be --@@ -39,6 +40,6 @@  -- common TVar for all ports in use. {-# NOINLINE usedPorts #-}-usedPorts :: TVar [(Int,TMVar (Canvas ()))]+usedPorts :: TVar [(Int, TMVar (Canvas ()))] usedPorts = unsafePerformIO $ newTVarIO [] 
Graphics/Blank/Generated.hs view
@@ -6,67 +6,63 @@ import Data.Text (Text)  instance Show Method where-  show (Arc (a1,a2,a3,a4,a5,a6)) = "arc(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ "," ++ jsFloat a5 ++ "," ++ jsBool a6 ++ ")"-  show (ArcTo (a1,a2,a3,a4,a5)) = "arcTo(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ "," ++ jsFloat a5 ++ ")"+  show (Arc (a1,a2,a3,a4,a5,a6)) = "arc(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ "," ++ jsDouble a5 ++ "," ++ jsBool a6 ++ ")"+  show (ArcTo (a1,a2,a3,a4,a5)) = "arcTo(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ "," ++ jsDouble a5 ++ ")"   show BeginPath = "beginPath()"-  show (BezierCurveTo (a1,a2,a3,a4,a5,a6)) = "bezierCurveTo(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ "," ++ jsFloat a5 ++ "," ++ jsFloat a6 ++ ")"-  show (DrawImage (a1,a2)) = "drawImage(" ++ jsImage a1 ++ "," ++ jsList jsFloat a2 ++ ")"-  show (ClearRect (a1,a2,a3,a4)) = "clearRect(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ ")"+  show (BezierCurveTo (a1,a2,a3,a4,a5,a6)) = "bezierCurveTo(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ "," ++ jsDouble a5 ++ "," ++ jsDouble a6 ++ ")"+  show (ClearRect (a1,a2,a3,a4)) = "clearRect(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ ")"   show Clip = "clip()"   show ClosePath = "closePath()"+  show (DrawImage (a1,a2)) = "drawImage(" ++ jsImage a1 ++ "," ++ jsList jsDouble a2 ++ ")"   show Fill = "fill()"-  show (FillRect (a1,a2,a3,a4)) = "fillRect(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ ")"+  show (FillRect (a1,a2,a3,a4)) = "fillRect(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ ")"   show (FillStyle (a1)) = "fillStyle = (" ++ jsStyle a1 ++ ")"-  show (FillText (a1,a2,a3)) = "fillText(" ++ jsText a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ ")"+  show (FillText (a1,a2,a3)) = "fillText(" ++ jsText a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ ")"   show (Font (a1)) = "font = (" ++ jsText a1 ++ ")"-  show (GlobalAlpha (a1)) = "globalAlpha = (" ++ jsFloat a1 ++ ")"+  show (GlobalAlpha (a1)) = "globalAlpha = (" ++ jsDouble a1 ++ ")"   show (GlobalCompositeOperation (a1)) = "globalCompositeOperation = (" ++ jsText a1 ++ ")"-  show (LineCap (a1)) = "lineCap = (" ++ jsText a1 ++ ")"-  show (LineJoin (a1)) = "lineJoin = (" ++ jsText a1 ++ ")"-  show (LineTo (a1,a2)) = "lineTo(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ ")"-  show (LineWidth (a1)) = "lineWidth = (" ++ jsFloat a1 ++ ")"-  show (MiterLimit (a1)) = "miterLimit = (" ++ jsFloat a1 ++ ")"-  show (MoveTo (a1,a2)) = "moveTo(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ ")"-  show (PutImageData (a1,a2)) = "putImageData(" ++ jsImageData a1 ++ "," ++ jsList jsFloat a2 ++ ")"-  show (QuadraticCurveTo (a1,a2,a3,a4)) = "quadraticCurveTo(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ ")"-  show (Rect (a1,a2,a3,a4)) = "rect(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ ")"+  show (LineCap (a1)) = "lineCap = (" ++ jsLineEndCap a1 ++ ")"+  show (LineJoin (a1)) = "lineJoin = (" ++ jsLineJoinCorner a1 ++ ")"+  show (LineTo (a1,a2)) = "lineTo(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ ")"+  show (LineWidth (a1)) = "lineWidth = (" ++ jsDouble a1 ++ ")"+  show (MiterLimit (a1)) = "miterLimit = (" ++ jsDouble a1 ++ ")"+  show (MoveTo (a1,a2)) = "moveTo(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ ")"+  show (PutImageData (a1,a2)) = "putImageData(" ++ jsImageData a1 ++ "," ++ jsList jsDouble a2 ++ ")"+  show (QuadraticCurveTo (a1,a2,a3,a4)) = "quadraticCurveTo(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ ")"+  show (Rect (a1,a2,a3,a4)) = "rect(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ ")"   show Restore = "restore()"-  show (Rotate (a1)) = "rotate(" ++ jsFloat a1 ++ ")"-  show (Scale (a1,a2)) = "scale(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ ")"+  show (Rotate (a1)) = "rotate(" ++ jsDouble a1 ++ ")"   show Save = "save()"-  show (SetTransform (a1,a2,a3,a4,a5,a6)) = "setTransform(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ "," ++ jsFloat a5 ++ "," ++ jsFloat a6 ++ ")"+  show (Scale (a1,a2)) = "scale(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ ")"+  show (SetTransform (a1,a2,a3,a4,a5,a6)) = "setTransform(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ "," ++ jsDouble a5 ++ "," ++ jsDouble a6 ++ ")"+  show (ShadowBlur (a1)) = "shadowBlur = (" ++ jsDouble a1 ++ ")"+  show (ShadowColor (a1)) = "shadowColor = (" ++ jsCanvasColor a1 ++ ")"+  show (ShadowOffsetX (a1)) = "shadowOffsetX = (" ++ jsDouble a1 ++ ")"+  show (ShadowOffsetY (a1)) = "shadowOffsetY = (" ++ jsDouble a1 ++ ")"   show Stroke = "stroke()"-  show (StrokeRect (a1,a2,a3,a4)) = "strokeRect(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ ")"-  show (StrokeText (a1,a2,a3)) = "strokeText(" ++ jsText a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ ")"+  show (StrokeRect (a1,a2,a3,a4)) = "strokeRect(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ ")"   show (StrokeStyle (a1)) = "strokeStyle = (" ++ jsStyle a1 ++ ")"-  show (ShadowBlur (a1)) = "shadowBlur = (" ++ jsFloat a1 ++ ")"-  show (ShadowColor (a1)) = "shadowColor = (" ++ jsText a1 ++ ")"-  show (ShadowOffsetX (a1)) = "shadowOffsetX = (" ++ jsFloat a1 ++ ")"-  show (ShadowOffsetY (a1)) = "shadowOffsetY = (" ++ jsFloat a1 ++ ")"-  show (TextAlign (a1)) = "textAlign = (" ++ jsText a1 ++ ")"-  show (TextBaseline (a1)) = "textBaseline = (" ++ jsText a1 ++ ")"-  show (Transform (a1,a2,a3,a4,a5,a6)) = "transform(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ "," ++ jsFloat a3 ++ "," ++ jsFloat a4 ++ "," ++ jsFloat a5 ++ "," ++ jsFloat a6 ++ ")"-  show (Translate (a1,a2)) = "translate(" ++ jsFloat a1 ++ "," ++ jsFloat a2 ++ ")"+  show (StrokeText (a1,a2,a3)) = "strokeText(" ++ jsText a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ ")"+  show (TextAlign (a1)) = "textAlign = (" ++ jsTextAnchorAlignment a1 ++ ")"+  show (TextBaseline (a1)) = "textBaseline = (" ++ jsTextBaselineAlignment a1 ++ ")"+  show (Transform (a1,a2,a3,a4,a5,a6)) = "transform(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ "," ++ jsDouble a3 ++ "," ++ jsDouble a4 ++ "," ++ jsDouble a5 ++ "," ++ jsDouble a6 ++ ")"+  show (Translate (a1,a2)) = "translate(" ++ jsDouble a1 ++ "," ++ jsDouble a2 ++ ")"  -- DSL -arc :: (Float,Float,Float,Float,Float,Bool) -> Canvas ()+arc :: (Double, Double, Double, Double, Double, Bool) -> Canvas () arc = Method . Arc -arcTo :: (Float,Float,Float,Float,Float) -> Canvas ()+arcTo :: (Double, Double, Double, Double, Double) -> Canvas () arcTo = Method . ArcTo  beginPath :: () -> Canvas () beginPath () = Method BeginPath -bezierCurveTo :: (Float,Float,Float,Float,Float,Float) -> Canvas ()+bezierCurveTo :: (Double, Double, Double, Double, Double, Double) -> Canvas () bezierCurveTo = Method . BezierCurveTo --- | 'drawImage' takes 2, 4 or 8 floats arguments-drawImage :: Image image => (image,[Float]) -> Canvas ()-drawImage = Method . DrawImage--clearRect :: (Float,Float,Float,Float) -> Canvas ()+clearRect :: (Double, Double, Double, Double) -> Canvas () clearRect = Method . ClearRect  clip :: () -> Canvas ()@@ -75,102 +71,107 @@ closePath :: () -> Canvas () closePath () = Method ClosePath +-- | drawImage' takes 2, 4, or 8 'Double' arguments. See 'drawImageAt', 'drawImageSize', and 'drawImageCrop' for variants with exact numbers of arguments.+drawImage :: Image image => (image,[Double]) -> Canvas ()+drawImage = Method . DrawImage+ fill :: () -> Canvas () fill () = Method Fill -fillRect :: (Float,Float,Float,Float) -> Canvas ()+fillRect :: (Double, Double, Double, Double) -> Canvas () fillRect = Method . FillRect  fillStyle :: Style style => style -> Canvas () fillStyle = Method . FillStyle -fillText :: (Text,Float,Float) -> Canvas ()+fillText :: (Text, Double, Double) -> Canvas () fillText = Method . FillText  font :: Text -> Canvas () font = Method . Font -globalAlpha :: Float -> Canvas ()+globalAlpha :: Double -> Canvas () globalAlpha = Method . GlobalAlpha  globalCompositeOperation :: Text -> Canvas () globalCompositeOperation = Method . GlobalCompositeOperation -lineCap :: Text -> Canvas ()+lineCap :: LineEndCap -> Canvas () lineCap = Method . LineCap -lineJoin :: Text -> Canvas ()+lineJoin :: LineJoinCorner -> Canvas () lineJoin = Method . LineJoin -lineTo :: (Float,Float) -> Canvas ()+lineTo :: (Double, Double) -> Canvas () lineTo = Method . LineTo -lineWidth :: Float -> Canvas ()+lineWidth :: Double -> Canvas () lineWidth = Method . LineWidth -miterLimit :: Float -> Canvas ()+miterLimit :: Double -> Canvas () miterLimit = Method . MiterLimit -moveTo :: (Float,Float) -> Canvas ()+moveTo :: (Double, Double) -> Canvas () moveTo = Method . MoveTo -putImageData :: (ImageData,[Float]) -> Canvas ()+-- | 'putImageData' takes 2 or 6 'Double' arguments. See `putImageDataAt' and `putImageDataDirty' for variants with exact numbers of arguments.+putImageData :: (ImageData, [Double]) -> Canvas () putImageData = Method . PutImageData -quadraticCurveTo :: (Float,Float,Float,Float) -> Canvas ()+quadraticCurveTo :: (Double, Double, Double, Double) -> Canvas () quadraticCurveTo = Method . QuadraticCurveTo -rect :: (Float,Float,Float,Float) -> Canvas ()+rect :: (Double, Double, Double, Double) -> Canvas () rect = Method . Rect  restore :: () -> Canvas () restore () = Method Restore -rotate :: Float -> Canvas ()+rotate :: Double -> Canvas () rotate = Method . Rotate -scale :: (Float,Float) -> Canvas ()-scale = Method . Scale- save :: () -> Canvas () save () = Method Save -setTransform :: (Float,Float,Float,Float,Float,Float) -> Canvas ()+scale :: (Double, Double) -> Canvas ()+scale = Method . Scale++setTransform :: (Double, Double, Double, Double, Double, Double) -> Canvas () setTransform = Method . SetTransform +shadowBlur :: Double -> Canvas ()+shadowBlur = Method . ShadowBlur++shadowColor :: CanvasColor canvasColor => canvasColor -> Canvas ()+shadowColor = Method . ShadowColor++shadowOffsetX :: Double -> Canvas ()+shadowOffsetX = Method . ShadowOffsetX++shadowOffsetY :: Double -> Canvas ()+shadowOffsetY = Method . ShadowOffsetY+ stroke :: () -> Canvas () stroke () = Method Stroke -strokeRect :: (Float,Float,Float,Float) -> Canvas ()+strokeRect :: (Double, Double, Double, Double) -> Canvas () strokeRect = Method . StrokeRect -strokeText :: (Text,Float,Float) -> Canvas ()-strokeText = Method . StrokeText- strokeStyle :: Style style => style -> Canvas () strokeStyle = Method . StrokeStyle -shadowBlur :: Float -> Canvas ()-shadowBlur = Method . ShadowBlur--shadowColor :: Text -> Canvas ()-shadowColor = Method . ShadowColor--shadowOffsetX :: Float -> Canvas ()-shadowOffsetX = Method . ShadowOffsetX--shadowOffsetY :: Float -> Canvas ()-shadowOffsetY = Method . ShadowOffsetY+strokeText :: (Text,Double, Double) -> Canvas ()+strokeText = Method . StrokeText -textAlign :: Text -> Canvas ()+textAlign :: TextAnchorAlignment -> Canvas () textAlign = Method . TextAlign -textBaseline :: Text -> Canvas ()+textBaseline :: TextBaselineAlignment -> Canvas () textBaseline = Method . TextBaseline -transform :: (Float,Float,Float,Float,Float,Float) -> Canvas ()+transform :: (Double, Double, Double, Double, Double, Double) -> Canvas () transform = Method . Transform -translate :: (Float,Float) -> Canvas ()+translate :: (Double, Double) -> Canvas () translate = Method . Translate 
Graphics/Blank/JavaScript.hs view
@@ -2,51 +2,75 @@  module Graphics.Blank.JavaScript where -import Data.List-import Data.Word (Word8)-import Numeric-import Data.Text (Text)+import           Control.Applicative +import           Data.Char (isControl, isAscii, ord)+import           Data.Colour+import           Data.Colour.SRGB+import           Data.Default.Class+import           Data.Ix+import           Data.List+import           Data.String+import           Data.Text (Text, unpack)+import           Data.Word (Word8)+ import qualified Data.Vector.Unboxed as V-import Data.Vector.Unboxed (Vector)+import           Data.Vector.Unboxed (Vector) +import           Numeric++import           Text.ParserCombinators.ReadP (skipSpaces, string)+import           Text.ParserCombinators.ReadPrec+import           Text.Read+ ------------------------------------------------------------- --- TODO: close off +-- TODO: close off class Image a where   jsImage :: a -> String   width  :: Num b => a -> b   height :: Num b => a -> b -instance Image CanvasImage where +instance Image CanvasImage where   jsImage = jsCanvasImage-  width  (CanvasImage _ w _) = fromIntegral w +  width  (CanvasImage _ w _) = fromIntegral w   height (CanvasImage _ _ h) = fromIntegral h-  + -- The Image of a canvas is the the canvas context, not the DOM entry, so -- you need to indirect back to the DOM here. instance Image CanvasContext where   jsImage = (++ ".canvas") . jsCanvasContext-  width  (CanvasContext _ w _) = fromIntegral w +  width  (CanvasContext _ w _) = fromIntegral w   height (CanvasContext _ _ h) = fromIntegral h  -- instance Element Video  -- Not supported  ----------------------------------------------------------------------------- --- TODO: close off +-- TODO: close off class Style a where   jsStyle :: a -> String -instance Style Text           where { jsStyle = jsText }-instance Style CanvasGradient where { jsStyle = jsCanvasGradient }-instance Style CanvasPattern  where { jsStyle = jsCanvasPattern }+instance Style Text                 where { jsStyle = jsText }+instance Style CanvasGradient       where { jsStyle = jsCanvasGradient }+instance Style CanvasPattern        where { jsStyle = jsCanvasPattern }+instance Style (Colour Double)      where { jsStyle = jsColour }+instance Style (AlphaColour Double) where { jsStyle = jsAlphaColour } +class Style a => CanvasColor a++jsCanvasColor :: CanvasColor color => color -> String+jsCanvasColor = jsStyle++instance CanvasColor Text+instance CanvasColor (Colour Double)+instance CanvasColor (AlphaColour Double)+ -------------------------------------------------------------  -- | A handle to an offscreen canvas. CanvasContext can not be destroyed. data CanvasContext = CanvasContext Int Int Int- deriving (Show,Eq,Ord)                + deriving (Show,Eq,Ord)  -- | A handle to the Image. CanvasImages can not be destroyed. data CanvasImage = CanvasImage Int Int Int deriving (Show,Eq,Ord)@@ -59,11 +83,173 @@  ------------------------------------------------------------- +-- | The direction in which a 'CanvasPattern' repeats.+data RepeatDirection = Repeat   -- ^ The pattern repeats both horizontally+                                --   and vertically.+                     | RepeatX  -- ^ The pattern repeats only horizontally.+                     | RepeatY  -- ^ The pattern repeats only vertically.+                     | NoRepeat -- ^ The pattern displays only once and+                                --   does not repeat.+  deriving Eq++instance Default RepeatDirection where+  def = Repeat++instance IsString RepeatDirection where+  fromString = read++instance Read RepeatDirection where+  readPrec = parens . lift $ do+      skipSpaces+      (string "repeat"          >> return Repeat)+        <|> (string "repeat-x"  >> return RepeatX)+        <|> (string "repeat-y"  >> return RepeatY)+        <|> (string "no-repeat" >> return NoRepeat)++instance Show RepeatDirection where+  showsPrec _ rd = showString $ case rd of+      Repeat   -> "repeat"+      RepeatX  -> "repeat-x"+      RepeatY  -> "repeat-y"+      NoRepeat -> "no-repeat"++-- | The style of the caps on the endpoints of a line.+data LineEndCap = ButtCap   -- ^ Flat edges+                | RoundCap  -- ^ Semicircular end caps+                | SquareCap -- ^ Square end caps+  deriving Eq++instance Default LineEndCap where+  def = ButtCap++instance IsString LineEndCap where+  fromString = read++instance Read LineEndCap where+  readPrec = parens $ do+      Ident s <- lexP+      case s of+          "butt"   -> return ButtCap  +          "round"  -> return RoundCap +          "square" -> return SquareCap+          _        -> pfail++instance Show LineEndCap where+  showsPrec _ le = showString $ case le of+      ButtCap   -> "butt"+      RoundCap  -> "round"+      SquareCap -> "square"++-- | The style of corner that is created when two lines join.+data LineJoinCorner = BevelCorner -- ^ A filled triangle with a beveled edge+                                  --   connects two lines.+                    | RoundCorner -- ^ A filled arc connects two lines.+                    | MiterCorner -- ^ A filled triangle with a sharp edge+                                  --   connects two lines.+  deriving Eq++instance Default LineJoinCorner where+  def = MiterCorner++instance IsString LineJoinCorner where+  fromString = read++instance Read LineJoinCorner where+  readPrec = parens $ do+      Ident s <- lexP+      case s of+          "bevel" -> return BevelCorner+          "round" -> return RoundCorner+          "miter" -> return MiterCorner+          _       -> pfail++instance Show LineJoinCorner where+  showsPrec _ corner = showString $ case corner of+      BevelCorner -> "bevel"+      RoundCorner -> "round"+      MiterCorner -> "miter"++-- | The anchor point for text in the current 'DeviceContext'.+data TextAnchorAlignment = StartAnchor  -- ^ The text is anchored at either its left edge+                                        --   (if the canvas is left-to-right) or its right+                                        --   edge (if the canvas is right-to-left).+                         | EndAnchor    -- ^ The text is anchored at either its right edge+                                        --   (if the canvas is left-to-right) or its left+                                        --   edge (if the canvas is right-to-left).+                         | CenterAnchor -- ^ The text is anchored in its center.+                         | LeftAnchor   -- ^ The text is anchored at its left edge.+                         | RightAnchor  -- ^ the text is anchored at its right edge.+  deriving Eq++instance Default TextAnchorAlignment where+  def = StartAnchor++instance IsString TextAnchorAlignment where+  fromString = read++instance Read TextAnchorAlignment where+  readPrec = parens $ do+      Ident s <- lexP+      case s of+          "start"  -> return StartAnchor+          "end"    -> return EndAnchor+          "center" -> return CenterAnchor+          "left"   -> return LeftAnchor+          "right"  -> return RightAnchor+          _        -> pfail++instance Show TextAnchorAlignment where+  showsPrec _ align = showString $ case align of+      StartAnchor  -> "start"+      EndAnchor    -> "end"+      CenterAnchor -> "center"+      LeftAnchor   -> "left"+      RightAnchor  -> "right"++-- | The baseline alignment used when drawing text in the current 'DeviceContext'.+--   The baselines are ordered from highest ('Top') to lowest ('Bottom').+data TextBaselineAlignment = TopBaseline+                           | HangingBaseline+                           | MiddleBaseline+                           | AlphabeticBaseline+                           | IdeographicBaseline+                           | BottomBaseline+  deriving (Bounded, Eq, Ix, Ord)++instance Default TextBaselineAlignment where+  def = AlphabeticBaseline++instance IsString TextBaselineAlignment where+  fromString = read++instance Read TextBaselineAlignment where+  readPrec = parens $ do+      Ident s <- lexP+      case s of+          "top"         -> return TopBaseline+          "hanging"     -> return HangingBaseline+          "middle"      -> return MiddleBaseline+          "alphabetic"  -> return AlphabeticBaseline+          "ideographic" -> return IdeographicBaseline+          "bottom"      -> return BottomBaseline+          _             -> pfail++instance Show TextBaselineAlignment where+  showsPrec _ bl = showString $ case bl of+      TopBaseline         -> "top"+      HangingBaseline     -> "hanging"+      MiddleBaseline      -> "middle"+      AlphabeticBaseline  -> "alphabetic"+      IdeographicBaseline -> "ideographic"+      BottomBaseline      -> "bottom"++-------------------------------------------------------------+ -- | 'ImageData' is a transliteration of the JavaScript ImageData, --   There are two 'Int's, and one (unboxed) 'Vector' of 'Word8's. --  width, height, data can be projected from 'ImageData', --  'Vector.length' can be used to find the length.--- +-- --   Note: 'ImageData' lives on the server, not the client.  data ImageData = ImageData !Int !Int !(Vector Word8) deriving (Show, Eq, Ord)@@ -73,32 +259,47 @@ class JSArg a where   showJS :: a -> String -instance JSArg Float where-  showJS a = showFFloat (Just 3) a ""        +instance JSArg (AlphaColour Double) where+  showJS aCol+      | a >= 1    = jsColour rgbCol+      | a <= 0    = jsLiteralString "rgba(0,0,0,0)"+      | otherwise = jsLiteralString $ "rgba("+          ++ show r     ++ ","+          ++ show g     ++ ","+          ++ show b     ++ ","+          ++ jsDouble a ++ ")"+    where+      a         = alphaChannel aCol+      rgbCol    = darken (recip a) $ aCol `over` black+      RGB r g b = toSRGB24 rgbCol -jsFloat :: Float -> String-jsFloat = showJS +jsAlphaColour :: AlphaColour Double -> String+jsAlphaColour = showJS -instance JSArg Int where-  showJS a = show a+instance JSArg Bool where+  showJS True  = "true"+  showJS False = "false" +jsBool :: Bool -> String+jsBool = showJS+ instance JSArg CanvasContext where   showJS (CanvasContext n _ _) = "canvasbuffers[" ++ show n ++ "]"  jsCanvasContext :: CanvasContext -> String-jsCanvasContext = showJS +jsCanvasContext = showJS  instance JSArg CanvasImage where   showJS (CanvasImage n _ _) = "images[" ++ show n ++ "]"  jsCanvasImage :: CanvasImage -> String-jsCanvasImage = showJS +jsCanvasImage = showJS  instance JSArg CanvasGradient where   showJS (CanvasGradient n) = "gradients[" ++ show n ++ "]"  jsCanvasGradient :: CanvasGradient -> String-jsCanvasGradient = showJS +jsCanvasGradient = showJS  instance JSArg CanvasPattern where   showJS (CanvasPattern n) = "patterns[" ++ show n ++ "]"@@ -106,6 +307,18 @@ jsCanvasPattern :: CanvasPattern -> String jsCanvasPattern = showJS +instance JSArg (Colour Double) where+  showJS = jsLiteralString . sRGB24show++jsColour :: Colour Double -> String+jsColour = showJS++instance JSArg Double where+  showJS a = showFFloat (Just 3) a ""++jsDouble :: Double -> String+jsDouble = showJS+ instance JSArg ImageData where   showJS (ImageData w h d) = "ImageData(" ++ show w ++ "," ++ show h ++ ",[" ++ vs ++ "])"      where@@ -114,18 +327,86 @@ jsImageData :: ImageData -> String jsImageData = showJS -instance JSArg Bool where-  showJS True  = "true"-  showJS False = "false"+instance JSArg Int where+  showJS a = show a -jsBool :: Bool -> String-jsBool = showJS+instance JSArg LineEndCap where+  showJS = jsLiteralString . show -instance JSArg Text where -  showJS str = show str+jsLineEndCap :: LineEndCap -> String+jsLineEndCap = showJS +instance JSArg LineJoinCorner where+  showJS = jsLiteralString . show++jsLineJoinCorner :: LineJoinCorner -> String+jsLineJoinCorner = showJS++jsList :: (a -> String) -> [a] -> String+jsList js = concat . intersperse "," . map js++instance JSArg RepeatDirection where+  showJS = jsLiteralString . show++jsRepeatDirection :: RepeatDirection -> String+jsRepeatDirection = showJS++instance JSArg Text where+  showJS = jsLiteralString . unpack+ jsText :: Text -> String jsText = showJS -jsList :: (a -> String) -> [a] -> String-jsList js = concat . intersperse "," . map js +instance JSArg TextAnchorAlignment where+  showJS = jsLiteralString . show++jsTextAnchorAlignment :: TextAnchorAlignment -> String+jsTextAnchorAlignment = showJS++instance JSArg TextBaselineAlignment where+  showJS = jsLiteralString . show++jsTextBaselineAlignment :: TextBaselineAlignment -> String+jsTextBaselineAlignment = showJS++-- The following was from our Sunroof compiler.+-- -------------------------------------------------------------+-- String Conversion Utilities: Haskell -> JS+-- -------------------------------------------------------------++-- | Transform a Haskell string into a string representing a JS string literal.+jsLiteralString :: String -> String+jsLiteralString = jsQuoteString . jsEscapeString++-- | Add quotes to a string.+jsQuoteString :: String -> String+jsQuoteString s = "\"" ++ s ++ "\""++-- | Transform a character to a string that represents its JS+--   unicode escape sequence.+jsUnicodeChar :: Char -> String+jsUnicodeChar c =+  let hex = showHex (ord c) ""+  in ('\\':'u': replicate (4 - length hex) '0') ++ hex++-- | Correctly replace Haskell characters by the JS escape sequences.+jsEscapeString :: String -> String+jsEscapeString [] = []+jsEscapeString (c:cs) = case c of+  -- Backslash has to remain backslash in JS.+  '\\' -> '\\' : '\\' : jsEscapeString cs+  -- Special control sequences.+  '\0' -> jsUnicodeChar '\0' ++ jsEscapeString cs -- Ambigous with numbers+  '\a' -> jsUnicodeChar '\a' ++ jsEscapeString cs -- Non JS+  '\b' -> '\\' : 'b' : jsEscapeString cs+  '\f' -> '\\' : 'f' : jsEscapeString cs+  '\n' -> '\\' : 'n' : jsEscapeString cs+  '\r' -> '\\' : 'r' : jsEscapeString cs+  '\t' -> '\\' : 't' : jsEscapeString cs+  '\v' -> '\\' : 'v' : jsEscapeString cs+  '\"' -> '\\' : '\"' : jsEscapeString cs+  '\'' -> '\\' : '\'' : jsEscapeString cs+  -- Non-control ASCII characters can remain as they are.+  c' | not (isControl c') && isAscii c' -> c' : jsEscapeString cs+  -- All other non ASCII signs are escaped to unicode.+  c' -> jsUnicodeChar c' ++ jsEscapeString cs
Graphics/Blank/Style.hs view
@@ -1,13 +1,841 @@--- | These are overloaded versions of 'strokeStyle' and 'fillStyle'.- module Graphics.Blank.Style -        ( strokeStyle+        ( -- * Overloaded versions of 'Canvas' functions+          strokeStyle         , fillStyle-        , Style+        , shadowColor+        , addColorStop+        , Style(..)+        , CanvasColor+          -- * 'CanvasColor' creation+        , Alpha+        , Percentage+        , rgb+        , rgbPercent+        , rgba+        , rgbaPercent+        , hsl+        , hsla+          -- * @colour@ reexports+        , readColourName+        , aliceblue+        , antiquewhite+        , aqua+        , aquamarine+        , azure+        , beige+        , bisque+        , black+        , blanchedalmond+        , blue+        , blueviolet+        , brown+        , burlywood+        , cadetblue+        , chartreuse+        , chocolate+        , coral+        , cornflowerblue+        , cornsilk+        , crimson+        , cyan+        , darkblue+        , darkcyan+        , darkgoldenrod+        , darkgray+        , darkgreen+        , darkgrey+        , darkkhaki+        , darkmagenta+        , darkolivegreen+        , darkorange+        , darkorchid+        , darkred+        , darksalmon+        , darkseagreen+        , darkslateblue+        , darkslategray+        , darkslategrey+        , darkturquoise+        , darkviolet+        , deeppink+        , deepskyblue+        , dimgray+        , dimgrey+        , dodgerblue+        , firebrick+        , floralwhite+        , forestgreen+        , fuchsia+        , gainsboro+        , ghostwhite+        , gold+        , goldenrod+        , gray+        , green+        , grey+        , greenyellow+        , honeydew+        , hotpink+        , indianred+        , indigo+        , ivory+        , khaki+        , lavender+        , lavenderblush+        , lawngreen+        , lemonchiffon+        , lightblue+        , lightcoral+        , lightcyan+        , lightgoldenrodyellow+        , lightgray+        , lightgreen+        , lightgrey+        , lightpink+        , lightsalmon+        , lightseagreen+        , lightskyblue+        , lightslategray+        , lightslategrey+        , lightsteelblue+        , lightyellow+        , lime+        , limegreen+        , linen+        , magenta+        , maroon+        , mediumaquamarine+        , mediumblue+        , mediumorchid+        , mediumpurple+        , mediumseagreen+        , mediumslateblue+        , mediumspringgreen+        , mediumturquoise+        , mediumvioletred+        , midnightblue+        , mintcream+        , mistyrose+        , moccasin+        , navajowhite+        , navy+        , oldlace+        , olive+        , olivedrab+        , orange+        , orangered+        , orchid+        , palegoldenrod+        , palegreen+        , paleturquoise+        , palevioletred+        , papayawhip+        , peachpuff+        , peru+        , pink+        , plum+        , powderblue+        , purple+        , red+        , rosybrown+        , royalblue+        , saddlebrown+        , salmon+        , sandybrown+        , seagreen+        , seashell+        , sienna+        , silver+        , skyblue+        , slateblue+        , slategray+        , slategrey+        , snow+        , springgreen+        , steelblue+        , tan+        , teal+        , thistle+        , tomato+        , turquoise+        , violet+        , wheat+        , white+        , whitesmoke+        , yellow+        , yellowgreen+        , rebeccapurple+        , transparent         ) where -import Graphics.Blank.Generated-import Graphics.Blank.JavaScript+import qualified Data.Colour as Colour+import           Data.Colour hiding (black, transparent)+import qualified Data.Colour.Names as Names+import           Data.Colour.RGBSpace+import qualified Data.Colour.RGBSpace.HSL as HSL+import           Data.Colour.SRGB+import           Data.Word +import           Graphics.Blank.Canvas+import           Graphics.Blank.Generated+import           Graphics.Blank.JavaScript +import           Prelude hiding (tan) +-- |+-- A value ranging from 0.0 to 1.0. A color with an alpha value of 0.0 is 'transparent',+-- and a color with an alpha value of 1.0 is opaque.+type Alpha = Double++-- | A value ranging from 0.0 to 100.0.+type Percentage = Double++-- |+-- Specifies a 'Colour' by its red, green, and blue components, where each component+-- is an integer between 0 and 255.+rgb :: Word8 -> Word8 -> Word8 -> Colour Double+rgb = sRGB24++-- |+-- Specifies a 'Colour' by its red, green, and blue components, where each component+-- is given by a percentage of 255.+rgbPercent :: Percentage -> Percentage -> Percentage -> Colour Double+rgbPercent r g b = sRGB (r/100) (g/100) (b/100)++-- |+-- Specifies an 'AlphaColour' by its RGB components and an alpha value.+-- +-- @+-- 'rgba' r g b 0.0 = 'transparent'+-- @+rgba :: Word8 -> Word8 -> Word8 -> Alpha -> AlphaColour Double+rgba r g b = withOpacity $ rgb r g b++-- |+-- Specifies an 'AlphaColour' by its RGB component percentages and an alpha value.+-- +-- @+-- 'rgbaPercent' r g b 0.0 = 'transparent'+-- @+rgbaPercent :: Percentage -> Percentage -> Percentage -> Alpha -> AlphaColour Double+rgbaPercent r g b = withOpacity $ rgbPercent r g b++-- |+-- Specifies a 'Colour' by its hue (which ranges from 0° to 360°), saturation, and+-- value.+hsl :: Int -> Percentage -> Percentage -> Colour Double+hsl h s l = uncurryRGB sRGB $ HSL.hsl (realToFrac h) (s/100) (l/100)++-- |+-- Specifies an 'AlphaColour' by its HSV values and an alpha value.+-- +-- @+-- 'hsla' h s v 0.0 = 'transparent'+-- @+hsla :: Int -> Percentage -> Percentage -> Alpha -> AlphaColour Double+hsla h s l = withOpacity $ hsl h s l++-- |+-- Takes a string naming a 'Colour' (must be all lowercase) and returns it. Fails if+-- the name is not recognized.+readColourName :: Monad m => String -> m (Colour Double)+readColourName "rebeccapurple" = return rebeccapurple+readColourName name            = Names.readColourName name++-- | @#F0F8FF@, @rgb(240, 248, 255)@, @hsl(208, 100%, 97%)@+aliceblue :: Colour Double+aliceblue = Names.aliceblue++-- | @#FAEBD7@, @rgb(250, 235, 215)@, @hsl(34, 78%, 91%)@+antiquewhite :: Colour Double+antiquewhite = Names.antiquewhite++-- | @#00FFFF@, @rgb(0, 255, 255)@, @hsl(180, 100%, 50%)@. Same as 'cyan'.+aqua :: Colour Double+aqua = Names.aqua++-- | @#7FFFD4@, @rgb(127, 255, 212)@, @hsl(160, 100%, 75%)@+aquamarine :: Colour Double+aquamarine = Names.aquamarine++-- | @#F0FFFF@, @rgb(240, 255, 255)@, @hsl(180, 100%, 97%)@+azure :: Colour Double+azure = Names.azure++-- | @#F5F5DC@, @rgb(245, 245, 220)@, @hsl(60, 56%, 91%)@+beige :: Colour Double+beige = Names.beige++-- | @#FFE4C4@, @rgb(255, 228, 196)@, @hsl(33, 100%, 88%)@+bisque :: Colour Double+bisque = Names.bisque++-- | @#000000@, @rgb(0, 0, 0)@, @hsl(0, 0%, 0%)@+black :: Colour Double+black = Colour.black++-- | @#FFEBCD@, @rgb(255, 235, 205)@, @hsl(36, 100%, 90%)@+blanchedalmond :: Colour Double+blanchedalmond = Names.blanchedalmond++-- | @#0000FF@, @rgb(0, 0, 255)@, @hsl(240, 100%, 50%)@+blue :: Colour Double+blue = Names.blue++-- | @#8A2BE2@, @rgb(138, 43, 226)@, @hsl(271, 76%, 53%)@+blueviolet :: Colour Double+blueviolet = Names.blueviolet++-- | @#A52A2A@, @rgb(165, 42, 42)@, @hsl(0, 59%, 41%)@+brown :: Colour Double+brown = Names.brown++-- | @#DEB887@, @rgb(222, 184, 135)@, @hsl(34, 57%, 70%)@+burlywood :: Colour Double+burlywood = Names.burlywood++-- | @#5F9EA0@, @rgb(95, 158, 160)@, @hsl(182, 25%, 50%)@+cadetblue :: Colour Double+cadetblue = Names.cadetblue++-- | @#7FFF00@, @rgb(127, 255, 0)@, @hsl(90, 100%, 50%)@+chartreuse :: Colour Double+chartreuse = Names.chartreuse++-- | @#D2691E@, @rgb(210, 105, 30)@, @hsl(25, 75%, 47%)@+chocolate :: Colour Double+chocolate = Names.chocolate++-- | @#FF7F50@, @rgb(255, 127, 80)@, @hsl(16, 100%, 66%)@+coral :: Colour Double+coral = Names.coral++-- | @#6495ED@, @rgb(100, 149, 237)@, @hsl(219, 79%, 66%)@+cornflowerblue :: Colour Double+cornflowerblue = Names.cornflowerblue++-- | @#FFF8DC@, @rgb(255, 248, 220)@, @hsl(48, 100%, 93%)@+cornsilk :: Colour Double+cornsilk = Names.cornsilk++-- | @#DC143C@, @rgb(220, 20, 60)@, @hsl(348, 83%, 58%)@+crimson :: Colour Double+crimson = Names.crimson++-- | @#00FFFF@, @rgb(0, 255, 255)@, @hsl(180, 100%, 50%)@. Same as 'aqua'.+cyan :: Colour Double+cyan = Names.cyan++-- | @#00008B@, @rgb(0, 0, 139)@, @hsl(240, 100%, 27%)@+darkblue :: Colour Double+darkblue = Names.darkblue++-- | @#008B8B@, @rgb(0, 139, 139)@, @hsl(180, 100%, 27%)@+darkcyan :: Colour Double+darkcyan = Names.darkcyan++-- | @#B8860B@, @rgb(184, 134, 11)@, @hsl(43, 89%, 38%)@+darkgoldenrod :: Colour Double+darkgoldenrod = Names.darkgoldenrod++-- | @#A9A9A9@, @rgb(169, 169, 169)@, @hsl(0, 0%, 66%)@. Same as 'darkgrey'.+darkgray :: Colour Double+darkgray = Names.darkgray++-- | @#006400@, @rgb(0, 100, 0)@, @hsl(120, 100%, 20%)@+darkgreen :: Colour Double+darkgreen = Names.darkgreen++-- | @#A9A9A9@, @rgb(169, 169, 169)@, @hsl(0, 0%, 66%)@. Same as 'darkgray'.+darkgrey :: Colour Double+darkgrey = Names.darkgrey++-- | @#BDB76B@, @rgb(189, 183, 107)@, @hsl(56, 38%, 58%)@+darkkhaki :: Colour Double+darkkhaki = Names.darkkhaki++-- | @#8B008B@, @rgb(139, 0, 139)@, @hsl(300, 100%, 27%)@+darkmagenta :: Colour Double+darkmagenta = Names.darkmagenta++-- | @#556B2F@, @rgb(85, 107, 47)@, @hsl(82, 39%, 30%)@+darkolivegreen :: Colour Double+darkolivegreen = Names.darkolivegreen++-- | @#FF8C00@, @rgb(255, 140, 0)@, @hsl(33, 100%, 50%)@+darkorange :: Colour Double+darkorange = Names.darkorange++-- | @#9932CC@, @rgb(153, 50, 204)@, @hsl(280, 61%, 50%)@+darkorchid :: Colour Double+darkorchid = Names.darkorchid++-- | @#8B0000@, @rgb(139, 0, 0)@, @hsl(0, 100%, 27%)@+darkred :: Colour Double+darkred = Names.darkred++-- | @#E9967A@, @rgb(233, 150, 122)@, @hsl(15, 72%, 70%)@+darksalmon :: Colour Double+darksalmon = Names.darksalmon++-- | @#8FBC8F@, @rgb(143, 188, 143)@, @hsl(120, 25%, 65%)@+darkseagreen :: Colour Double+darkseagreen = Names.darkseagreen++-- | @#483D8B@, @rgb(72, 61, 139)@, @hsl(248, 39%, 39%)@+darkslateblue :: Colour Double+darkslateblue = Names.darkslateblue++-- | @#2F4F4F@, @rgb(47, 79, 79)@, @hsl(180, 25%, 25%)@. Same as 'darkslategrey'.+darkslategray :: Colour Double+darkslategray = Names.darkslategray++-- | @#2F4F4F@, @rgb(47, 79, 79)@, @hsl(180, 25%, 25%)@. Same as 'darkslategray'.+darkslategrey :: Colour Double+darkslategrey = Names.darkslategrey++-- | @#00CED1@, @rgb(0, 206, 209)@, @hsl(181, 100%, 41%)@+darkturquoise :: Colour Double+darkturquoise = Names.darkturquoise++-- | @#9400D3@, @rgb(148, 0, 211)@, @hsl(282, 100%, 41%)@+darkviolet :: Colour Double+darkviolet = Names.darkviolet++-- | @#FF1493@, @rgb(255, 20, 147)@, @hsl(328, 100%, 54%)@+deeppink :: Colour Double+deeppink = Names.deeppink++-- | @#00BFFF@, @rgb(0, 191, 255)@, @hsl(195, 100%, 50%)@+deepskyblue :: Colour Double+deepskyblue = Names.deepskyblue++-- | @#696969@, @rgb(105, 105, 105)@, @hsl(0, 0%, 41%)@. Same as 'darkgrey'.+dimgray :: Colour Double+dimgray = Names.dimgray++-- | @#696969@, @rgb(105, 105, 105)@, @hsl(0, 0%, 41%)@. Same as 'darkgray'.+dimgrey :: Colour Double+dimgrey = Names.dimgrey++-- | @#1E90FF@, @rgb(30, 144, 255)@, @hsl(210, 100%, 56%)@+dodgerblue :: Colour Double+dodgerblue = Names.dodgerblue++-- | @#B22222@, @rgb(178, 34, 34)@, @hsl(0, 68%, 42%)@+firebrick :: Colour Double+firebrick = Names.firebrick++-- | @#FFFAF0@, @rgb(255, 250, 240)@, @hsl(40, 100%, 97%)@+floralwhite :: Colour Double+floralwhite = Names.floralwhite++-- | @#228B22@, @rgb(34, 139, 34)@, @hsl(120, 61%, 34%)@+forestgreen :: Colour Double+forestgreen = Names.forestgreen++-- | @#FF00FF@, @rgb(255, 0, 255)@, @hsl(300, 100%, 50%)@. Same as 'magenta'.+fuchsia :: Colour Double+fuchsia = Names.fuchsia++-- | @#DCDCDC@, @rgb(220, 220, 220)@, @hsl(0, 0%, 86%)@+gainsboro :: Colour Double+gainsboro = Names.gainsboro++-- | @#F8F8FF@, @rgb(248, 248, 255)@, @hsl(240, 100%, 99%)@+ghostwhite :: Colour Double+ghostwhite = Names.ghostwhite++-- | @#FFD700@, @rgb(255, 215, 0)@, @hsl(51, 100%, 50%)@+gold :: Colour Double+gold = Names.gold++-- | @#DAA520@, @rgb(218, 165, 32)@, @hsl(43, 74%, 49%)@+goldenrod :: Colour Double+goldenrod = Names.goldenrod++-- | @#808080@, @rgb(128, 128, 128)@, @hsl(0, 0%, 50%)@. Same as 'grey'.+gray :: Colour Double+gray = Names.gray++-- | @#008000@, @rgb(0, 128, 0)@, @hsl(120, 100%, 25%)@+green :: Colour Double+green = Names.green++-- | @#808080@, @rgb(128, 128, 128)@, @hsl(0, 0%, 50%)@. Same as 'gray'.+grey :: Colour Double+grey = Names.grey++-- | @#ADFF2F@, @rgb(173, 255, 47)@, @hsl(84, 100%, 59%)@+greenyellow :: Colour Double+greenyellow = Names.greenyellow++-- | @#F0FFF0@, @rgb(240, 255, 240)@, @hsl(120, 100%, 97%)@+honeydew :: Colour Double+honeydew = Names.honeydew++-- | @#FF69B4@, @rgb(255, 105, 180)@, @hsl(330, 100%, 71%)@+hotpink :: Colour Double+hotpink = Names.hotpink++-- | @#CD5C5C@, @rgb(205, 92, 92)@, @hsl(0, 53%, 58%)@+indianred :: Colour Double+indianred = Names.indianred++-- | @#4B0082@, @rgb(75, 0, 130)@, @hsl(275, 100%, 25%)@+indigo :: Colour Double+indigo = Names.indigo++-- | @#FFFFF0@, @rgb(255, 255, 240)@, @hsl(60, 100%, 97%)@+ivory :: Colour Double+ivory = Names.ivory++-- | @#F0E68C@, @rgb(240, 230, 140)@, @hsl(54, 77%, 75%)@+khaki :: Colour Double+khaki = Names.khaki++-- | @#E6E6FA@, @rgb(230, 230, 250)@, @hsl(240, 67%, 94%)@+lavender :: Colour Double+lavender = Names.lavender++-- | @#FFF0F5@, @rgb(255, 240, 245)@, @hsl(340, 100%, 97%)@+lavenderblush :: Colour Double+lavenderblush = Names.lavenderblush++-- | @#7CFC00@, @rgb(124, 252, 0)@, @hsl(90, 100%, 49%)@+lawngreen :: Colour Double+lawngreen = Names.lawngreen++-- | @#FFFACD@, @rgb(255, 250, 205)@, @hsl(54, 100%, 90%)@+lemonchiffon :: Colour Double+lemonchiffon = Names.lemonchiffon++-- | @#ADD8E6@, @rgb(173, 216, 230)@, @hsl(195, 53%, 79%)@+lightblue :: Colour Double+lightblue = Names.lightblue++-- | @#F08080@, @rgb(240, 128, 128)@, @hsl(0, 79%, 72%)@+lightcoral :: Colour Double+lightcoral = Names.lightcoral++-- | @#E0FFFF@, @rgb(224, 255, 255)@, @hsl(180, 100%, 94%)@+lightcyan :: Colour Double+lightcyan = Names.lightcyan++-- | @#FAFAD2@, @rgb(250, 250, 210)@, @hsl(60, 80%, 90%)@+lightgoldenrodyellow :: Colour Double+lightgoldenrodyellow = Names.lightgoldenrodyellow++-- | @#D3D3D3@, @rgb(211, 211, 211)@, @hsl(0, 0%, 83%)@. Same as 'lightgrey'.+lightgray :: Colour Double+lightgray = Names.lightgray++-- | @#90EE90@, @rgb(144, 238, 144)@, @hsl(120, 73%, 75%)@+lightgreen :: Colour Double+lightgreen = Names.lightgreen++-- | @#D3D3D3@, @rgb(211, 211, 211)@, @hsl(0, 0%, 83%)@. Same as 'lightgrey'.+lightgrey :: Colour Double+lightgrey = Names.lightgrey++-- | @#FFB6C1@, @rgb(255, 182, 193)@, @hsl(351, 100%, 86%)@+lightpink :: Colour Double+lightpink = Names.lightpink++-- | @#FFA07A@, @rgb(255, 160, 122)@, @hsl(17, 100%, 74%)@+lightsalmon :: Colour Double+lightsalmon = Names.lightsalmon++-- | @#20B2AA@, @rgb(32, 178, 170)@, @hsl(177, 70%, 41%)@+lightseagreen :: Colour Double+lightseagreen = Names.lightseagreen++-- | @#87CEFA@, @rgb(135, 206, 250)@, @hsl(203, 92%, 75%)@+lightskyblue :: Colour Double+lightskyblue = Names.lightskyblue++-- | @#778899@, @rgb(119, 136, 153)@, @hsl(210, 14%, 53%)@. Same as 'lightslategrey'.+lightslategray :: Colour Double+lightslategray = Names.lightslategray++-- | @#778899@, @rgb(119, 136, 153)@, @hsl(210, 14%, 53%)@. Same as 'lightslategray'.+lightslategrey :: Colour Double+lightslategrey = Names.lightslategrey++-- | @#B0C4DE@, @rgb(176, 196, 222)@, @hsl(214, 41%, 78%)@+lightsteelblue :: Colour Double+lightsteelblue = Names.lightsteelblue++-- | @#FFFFE0@, @rgb(255, 255, 224)@, @hsl(60, 100%, 94%)@+lightyellow :: Colour Double+lightyellow = Names.lightyellow++-- | @#00FF00@, @rgb(0, 255, 0)@, @hsl(120, 100%, 50%)@+lime :: Colour Double+lime = Names.lime++-- | @#32CD32@, @rgb(50, 205, 50)@, @hsl(120, 61%, 50%)@+limegreen :: Colour Double+limegreen = Names.limegreen++-- | @#FAF0E6@, @rgb(250, 240, 230)@, @hsl(30, 67%, 94%)@+linen :: Colour Double+linen = Names.linen++-- | @#FF00FF@, @rgb(255, 0, 255)@, @hsl(300, 100%, 50%)@. Same as 'fuchsia'.+magenta :: Colour Double+magenta = Names.magenta++-- | @#800000@, @rgb(128, 0, 0)@, @hsl(0, 100%, 25%)@+maroon :: Colour Double+maroon = Names.maroon++-- | @#66CDAA@, @rgb(102, 205, 170)@, @hsl(160, 51%, 60%)@+mediumaquamarine :: Colour Double+mediumaquamarine = Names.mediumaquamarine++-- | @#0000CD@, @rgb(0, 0, 205)@, @hsl(240, 100%, 40%)@+mediumblue :: Colour Double+mediumblue = Names.mediumblue++-- | @#BA55D3@, @rgb(186, 85, 211)@, @hsl(288, 59%, 58%)@+mediumorchid :: Colour Double+mediumorchid = Names.mediumorchid++-- | @#9370DB@, @rgb(147, 112, 219)@, @hsl(260, 60%, 65%)@+mediumpurple :: Colour Double+mediumpurple = Names.mediumpurple++-- | @#3CB371@, @rgb(60, 179, 113)@, @hsl(147, 50%, 47%)@+mediumseagreen :: Colour Double+mediumseagreen = Names.mediumseagreen++-- | @#7B68EE@, @rgb(123, 104, 238)@, @hsl(249, 80%, 67%)@+mediumslateblue :: Colour Double+mediumslateblue = Names.mediumslateblue++-- | @#00FA9A@, @rgb(0, 250, 154)@, @hsl(157, 100%, 49%)@+mediumspringgreen :: Colour Double+mediumspringgreen = Names.mediumspringgreen++-- | @#48D1CC@, @rgb(72, 209, 204)@, @hsl(178, 60%, 55%)@+mediumturquoise :: Colour Double+mediumturquoise = Names.turquoise++-- | @#C71585@, @rgb(199, 21, 133)@, @hsl(322, 81%, 43%)@+mediumvioletred :: Colour Double+mediumvioletred = Names.mediumvioletred++-- | @#191970@, @rgb(25, 25, 112)@, @hsl(240, 64%, 27%)@+midnightblue :: Colour Double+midnightblue = Names.midnightblue++-- | @#F5FFFA@, @rgb(245, 255, 250)@, @hsl(150, 100%, 98%)@+mintcream :: Colour Double+mintcream = Names.mintcream++-- | @#FFE4E1@, @rgb(255, 228, 225)@, @hsl(6, 100%, 94%)@+mistyrose :: Colour Double+mistyrose = Names.mistyrose++-- | @#FFE4B5@, @rgb(255, 228, 181)@, @hsl(38, 100%, 85%)@+moccasin :: Colour Double+moccasin = Names.moccasin++-- | @#FFDEAD@, @rgb(255, 222, 173)@, @hsl(36, 100%, 84%)@+navajowhite :: Colour Double+navajowhite = Names.navajowhite++-- | @#000080@, @rgb(0, 0, 128)@, @hsl(240, 100%, 25%)@+navy :: Colour Double+navy = Names.navy++-- | @#FDF5E6@, @rgb(253, 245, 230)@, @hsl(39, 85%, 95%)@+oldlace :: Colour Double+oldlace = Names.oldlace++-- | @#808000@, @rgb(128, 128, 0)@, @hsl(60, 100%, 25%)@+olive :: Colour Double+olive = Names.olive++-- | @#6B8E23@, @rgb(107, 142, 35)@, @hsl(80, 60%, 35%)@+olivedrab :: Colour Double+olivedrab = Names.olivedrab++-- | @#FFA500@, @rgb(255, 165, 0)@, @hsl(39, 100%, 50%)@+orange :: Colour Double+orange = Names.orange++-- | @#FF4500@, @rgb(255, 69, 0)@, @hsl(16, 100%, 50%)@+orangered :: Colour Double+orangered = Names.orangered++-- | @#DA70D6@, @rgb(218, 112, 214)@, @hsl(302, 59%, 65%)@+orchid :: Colour Double+orchid = Names.orchid++-- | @#EEE8AA@, @rgb(238, 232, 170)@, @hsl(55, 67%, 80%)@+palegoldenrod :: Colour Double+palegoldenrod = Names.palegoldenrod++-- | @#98FB98@, @rgb(152, 251, 152)@, @hsl(120, 93%, 79%)@+palegreen :: Colour Double+palegreen = Names.palegreen++-- | @#AFEEEE@, @rgb(175, 238, 238)@, @hsl(180, 65%, 81%)@+paleturquoise :: Colour Double+paleturquoise = Names.paleturquoise++-- | @#DB7093@, @rgb(219, 112, 147)@, @hsl(340, 60%, 65%)@+palevioletred :: Colour Double+palevioletred = Names.palevioletred++-- | @#FFEFD5@, @rgb(255, 239, 213)@, @hsl(37, 100%, 92%)@+papayawhip :: Colour Double+papayawhip = Names.papayawhip++-- | @#FFDAB9@, @rgb(255, 218, 185)@, @hsl(28, 100%, 86%)@+peachpuff :: Colour Double+peachpuff = Names.peachpuff++-- | @#CD853F@, @rgb(205, 133, 63)@, @hsl(30, 59%, 53%)@+peru :: Colour Double+peru = Names.peru++-- | @#FFC0CB@, @rgb(255, 192, 203)@, @hsl(350, 100%, 88%)@+pink :: Colour Double+pink = Names.pink++-- | @#DDA0DD@, @rgb(221, 160, 221)@, @hsl(300, 47%, 75%)@+plum :: Colour Double+plum = Names.plum++-- | @#B0E0E6@, @rgb(176, 224, 230)@, @hsl(187, 52%, 80%)@+powderblue :: Colour Double+powderblue = Names.powderblue++-- | @#800080@, @rgb(128, 0, 128)@, @hsl(300, 100%, 25%)@+purple :: Colour Double+purple = Names.purple++-- | @#FF0000@, @rgb(255, 0, 0)@, @hsl(0, 100%, 50%)@+red :: Colour Double+red = Names.red++-- | @#BC8F8F@, @rgb(188, 143, 143)@, @hsl(0, 25%, 65%)@+rosybrown :: Colour Double+rosybrown = Names.rosybrown++-- | @#4169E1@, @rgb(65, 105, 225)@, @hsl(225, 73%, 57%)@+royalblue :: Colour Double+royalblue = Names.royalblue++-- | @#8B4513@, @rgb(139, 69, 19)@, @hsl(25, 76%, 31%)@+saddlebrown :: Colour Double+saddlebrown = Names.saddlebrown++-- | @#FA8072@, @rgb(250, 128, 114)@, @hsl(6, 93%, 71%)@+salmon :: Colour Double+salmon = Names.salmon++-- | @#F4A460@, @rgb(244, 164, 96)@, @hsl(28, 87%, 67%)@+sandybrown :: Colour Double+sandybrown = Names.sandybrown++-- | @#2E8B57@, @rgb(46, 139, 87)@, @hsl(146, 50%, 36%)@+seagreen :: Colour Double+seagreen = Names.seagreen++-- | @#FFF5EE@, @rgb(255, 245, 238)@, @hsl(25, 100%, 97%)@+seashell :: Colour Double+seashell = Names.seashell++-- | @#A0522D@, @rgb(160, 82, 45)@, @hsl(19, 56%, 40%)@+sienna :: Colour Double+sienna = Names.sienna++-- | @#C0C0C0@, @rgb(192, 192, 192)@, @hsl(0, 0%, 75%)@+silver :: Colour Double+silver = Names.silver++-- | @#87CEEB@, @rgb(135, 206, 235)@, @hsl(197, 71%, 73%)@+skyblue :: Colour Double+skyblue = Names.skyblue++-- | @#6A5ACD@, @rgb(106, 90, 205)@, @hsl(248, 53%, 58%)@+slateblue :: Colour Double+slateblue = Names.slateblue++-- | @#708090@, @rgb(112, 128, 144)@, @hsl(210, 13%, 50%)@. Same as 'slategrey'.+slategray :: Colour Double+slategray = Names.slategray++-- | @#708090@, @rgb(112, 128, 144)@, @hsl(210, 13%, 50%)@. Same as 'slategray'.+slategrey :: Colour Double+slategrey = Names.slategrey++-- | @#FFFAFA@, @rgb(255, 250, 250)@, @hsl(0, 100%, 99%)@+snow :: Colour Double+snow = Names.snow++-- | @#00FF7F@, @rgb(0, 255, 127)@, @hsl(150, 100%, 50%)@+springgreen :: Colour Double+springgreen = Names.springgreen++-- | @#4682B4@, @rgb(70, 130, 180)@, @hsl(207, 44%, 49%)@+steelblue :: Colour Double+steelblue = Names.steelblue++-- | @#D2B48C@, @rgb(210, 180, 140)@, @hsl(34, 44%, 69%)@+tan :: Colour Double+tan = Names.tan++-- | @#008080@, @rgb(0, 128, 128)@, @hsl(180, 100%, 25%)@+teal :: Colour Double+teal = Names.teal++-- | @#D8BFD8@, @rgb(216, 191, 216)@, @hsl(300, 24%, 80%)@+thistle :: Colour Double+thistle = Names.thistle++-- | @#FF6347@, @rgb(255, 99, 71)@, @hsl(9, 100%, 64%)@+tomato :: Colour Double+tomato = Names.tomato++-- | @#40E0D0@, @rgb(64, 224, 208)@, @hsl(174, 72%, 56%)@+turquoise :: Colour Double+turquoise = Names.turquoise++-- | @#EE82EE@, @rgb(238, 130, 238)@, @hsl(300, 76%, 72%)@+violet :: Colour Double+violet = Names.violet++-- | @#F5DEB3@, @rgb(245, 222, 179)@, @hsl(39, 77%, 83%)@+wheat :: Colour Double+wheat = Names.wheat++-- | @#FFFFFF@, @rgb(255, 255, 255)@, @hsl(0, 100%, 100%)@+white :: Colour Double+white = Names.white++-- | @#F5F5F5@, @rgb(245, 245, 245)@, @hsl(0, 0%, 96%)@+whitesmoke :: Colour Double+whitesmoke = Names.whitesmoke++-- | @#FFFF00@, @rgb(255, 255, 0)@, @hsl(60, 100%, 50%)@+yellow :: Colour Double+yellow = Names.yellow++-- | @#9ACD32@, @rgb(154, 205, 50)@, @hsl(80, 61%, 50%)@+yellowgreen :: Colour Double+yellowgreen = Names.yellowgreen++-- | @#663399@, @rgb(102, 51, 153)@, @hsl(270, 50%, 40%)@+rebeccapurple :: Colour Double+rebeccapurple = sRGB24 102 51 153++-- |+-- This 'AlphaColour' is entirely transparent and has no associated+-- color channel (i.e., @rgba(0, 0, 0, 0.0)@ or @hsla(0, 0%, 0%, 0.0)@).+transparent :: AlphaColour Double+transparent = Colour.transparent
Graphics/Blank/Utils.hs view
@@ -1,9 +1,18 @@+{-# LANGUAGE OverloadedStrings #-} module Graphics.Blank.Utils where +import Data.ByteString.Base64  -- Not sure why to use this, vs this *.URL version. This one works, though.+import qualified Data.ByteString as B+import Data.Monoid+import Data.Text(Text)+import qualified Data.Text as Text+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+ import Graphics.Blank.Canvas import Graphics.Blank.Generated import Graphics.Blank.JavaScript + -- | Clear the screen. Restores the default transformation matrix. clearCanvas :: Canvas () clearCanvas = do@@ -12,13 +21,13 @@   clearRect (0,0,width me,height me)  -- | Wrap a canvas computation in 'save' / 'restore'.-saveRestore :: Canvas () -> Canvas ()+saveRestore :: Canvas a -> Canvas a saveRestore m = do     save ()-    m+    r <- m     restore ()-    -    +    return r+ infixr 0 #  -- | The @#@-operator is the Haskell analog to the @.@-operator@@ -26,6 +35,78 @@ -- -- > grd # addColorStop(0, "#8ED6FF"); -----   This can be seen as equivalent of @document.addColorStop(0, "#8ED6FF")@.+--   This can be seen as equivalent of @grd.addColorStop(0, "#8ED6FF")@. (#) :: a -> (a -> Canvas b) -> Canvas b (#) obj act = act obj++-- | Read a file, and generate a data URL.+--+-- >  url <- readDataURL "image/png" "image/foo.png"+--+readDataURL :: Text -> FilePath -> IO Text+readDataURL mime_type filePath = do+	    dat <- B.readFile filePath+	    return $ "data:" <> mime_type <> ";base64," <> decodeUtf8 (encode dat)++-- | Find the mime type for a data URL.+--+-- > > dataURLMimeType "data:image/png;base64,iVBORw..."+-- > "image/png"+--+dataURLMimeType :: Text -> Text+dataURLMimeType txt+    | dat /= "data" = error "dataURLMimeType: no 'data:'"+    | not (Text.null rest0) && not (Text.null rest2) = mime_type+    | otherwise = error "dataURLMimeType: bad parse"+ where+   (dat,rest0)       = Text.span (/= ':') txt+   Just (_,rest1)    = Text.uncons rest0+   (mime_type,rest2) = Text.span (/= ';') rest1++-- | Write a data URL to a given file.++writeDataURL :: FilePath -> Text -> IO ()+writeDataURL fileName+             = B.writeFile fileName+             . decodeLenient+             . encodeUtf8+             . Text.tail+             . Text.dropWhile (/= ',')++-- | Draws an image onto the canvas at the given x- and y-coordinates.+drawImageAt :: Image image => (image, Double, Double) -> Canvas ()+drawImageAt (img, dx, dy) = Method $ DrawImage (img, [dx, dy])++-- | Acts like 'drawImageAt', but with two extra 'Double' arguments. The third and fourth+--   'Double's specify the width and height of the image, respectively.+drawImageSize :: Image image => (image, Double, Double, Double, Double) -> Canvas ()+drawImageSize (img, dx, dy, dw, dh) = Method $ DrawImage (img, [dx, dy, dw, dh])++-- | Acts like 'drawImageSize', but with four extra 'Double' arguments before the arguments+--   of 'drawImageSize'. The first and second 'Double's specify the x- and y-coordinates at+--   which the image begins to crop. The third and fourth 'Double's specify the width and+--   height of the cropped image.+-- +-- @+-- 'drawImageCrop' img 0 0 dw dh dx dy dw dh = 'drawImageSize' = dx dy dw dh+-- @+drawImageCrop :: Image image => (image, Double, Double, Double, Double, Double, Double, Double, Double) -> Canvas ()+drawImageCrop (img, sx, sy, sw, sh, dx, dy, dw, dh)+  = Method $ DrawImage (img, [sx, sy, sw, sh, dx, dy, dw, dh])++-- | Writes 'ImageData' to the canvas at the given x- and y-coordinates.+putImageDataAt :: (ImageData, Double, Double) -> Canvas ()+putImageDataAt (imgData, dx, dy) = Method $ PutImageData (imgData, [dx, dy])++-- | Acts like 'putImageDataDirty', but with four extra 'Double' arguments that specify+--   which region of the 'ImageData' (the dirty rectangle) should be drawn. The third+--   and fourth 'Double's specify the dirty rectangle's x- and y- coordinates, and the+--   fifth and sixth 'Double's specify the dirty rectangle's width and height.+--   +-- @+-- 'putImageDataDirty' imgData dx dy 0 0 w h = 'putImageDataAt' imgData dx dy+--   where (w, h) = case imgData of ImageData w' h' _ -> (w', h')+-- @+putImageDataDirty :: (ImageData, Double, Double, Double, Double, Double, Double) -> Canvas ()+putImageDataDirty (imgData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)+  = Method $ PutImageData (imgData, [dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight])
blank-canvas.cabal view
@@ -1,5 +1,5 @@ Name:                blank-canvas-Version:             0.4.0+Version:             0.5 Synopsis:            HTML5 Canvas Graphics Library  Description:      blank-canvas is a Haskell binding to the complete@@ -11,7 +11,7 @@                   images.                   .                   @-                     &#123;-# LANGUAGE OverloadedStrings #-&#125;+		     &#123;-&#35; LANGUAGE OverloadedStrings &#35;-&#125;                      module Main where                      import Graphics.Blank                     -- import the blank canvas                      .@@ -30,7 +30,7 @@ 		  . License:             BSD3 License-file:        LICENSE-Author:              Andy Gill+Author:              Andy Gill and Ryan Scott Maintainer:          andygill@ku.edu Copyright:           Copyright (c) 2014 The University of Kansas Homepage:            https://github.com/ku-fpg/blank-canvas/wiki@@ -39,14 +39,16 @@ Build-type:          Simple Stability:           beta Extra-source-files:  README.md+            	     Changelog.md Cabal-version:       >= 1.10 data-files:     static/index.html     static/jquery.js     static/jquery-json.js + Library-  Exposed-modules:     Graphics.Blank, +  Exposed-modules:     Graphics.Blank,                        Graphics.Blank.GHCi,                        Graphics.Blank.Style   other-modules:       Graphics.Blank.Canvas,@@ -58,25 +60,27 @@                        Paths_blank_canvas    default-language:    Haskell2010-  build-depends:       base             >= 4.3.1        && < 4.8,-                       bytestring       == 0.10.*,-                       aeson            == 0.7.*,-                       containers       == 0.5.*,-                       kansas-comet     == 0.3.*,-                       scotty           == 0.8.*,-                       http-types       == 0.8.*,-                       text             >= 1.1          && < 1.2,-                       network          >= 2.4          && < 2.6,-                       transformers     >= 0.3          && < 0.5,-                       wai              == 3.*,-                       wai-extra        == 3.*,-                       warp             == 3.*,-                       stm              >= 2.2          && < 2.5,-                       vector           >= 0.10         && < 0.11+  build-depends:       aeson              >= 0.7   && < 0.9,+                       base64-bytestring  == 1.0.*,+                       base               >= 4.3.1 && < 4.8,+                       bytestring         == 0.10.*,+                       colour             >= 2.2   && < 3.0,+                       containers         == 0.5.*,+                       data-default-class == 0.0.*,+                       http-types         == 0.8.*,+                       kansas-comet       == 0.3.*,+                       scotty             >= 0.8   && < 0.10,+                       stm                >= 2.2   && < 2.5,+                       text               >= 1.1   && < 1.3,+                       transformers       >= 0.3   && < 0.5,+                       wai                == 3.*,+                       wai-extra          >= 3.0.1 && < 3.1,+                       warp               == 3.*,+                       vector             >= 0.10  && < 0.11    GHC-options:  -Wall -fno-warn-orphans -fno-warn-warnings-deprecations+  GHC-prof-options:  -Wall -fno-warn-orphans -fno-warn-warnings-deprecations -auto-all -fsimpl-tick-factor=100000  source-repository head   type:     git   location: git://github.com/ku-fpg/blank-canvas.git-
static/index.html view
@@ -43,9 +43,9 @@             }             function ToDataURL(u,c) {                 $.kc.reply(u,c.canvas.toDataURL());-                            +             }-            function NewImage(src) { +            function NewImage(src) {                 return function (u,c) {                     var img = new Image();                     var count = images.push(img);@@ -54,52 +54,52 @@                     };                     img.onerror = function() { alert("Image " + src + " not found.\nAdd as a static file to fix this."); };                     img.src = src;-                }        +                }             } -            function CreateLinearGradient(x0,y0,x1,y1) { +            function CreateLinearGradient(x0,y0,x1,y1) {                 return function (u,c) {                     var count = gradients.push(c.createLinearGradient(x0,y0,x1,y1));                     $.kc.reply(u,count - 1);-                }        +                }             } -            function CreateRadialGradient(x0,y0,r0,x1,y1,r1) { +            function CreateRadialGradient(x0,y0,r0,x1,y1,r1) {                 return function (u,c) {                     var count = gradients.push(c.createRadialGradient(x0,y0,r0,x1,y1,r1));                     $.kc.reply(u,count - 1);-                }        +                }             } -            function CreatePattern(img,src) { +            function CreatePattern(img,src) {                 return function (u,c) {                     var count = patterns.push(c.createPattern(img,src));                     $.kc.reply(u,count - 1);-                }        +                }             } -            function MeasureText(txt) { +            function MeasureText(txt) {                 return function (u,c) {-                    $.kc.reply(u,c.measureText(txt));-                }        +                    $.kc.reply(u,{ width: c.measureText(txt).width });+                }             }-            function IsPointInPath(x,y) { +            function IsPointInPath(x,y) {                 return function (u,c) {                     $.kc.reply(u,c.isPointInPath(x,y));-                }        +                }             } -            function NewCanvas(w,h) { +            function NewCanvas(w,h) {                 return function (u,c) {                     var canvas = document.createElement('canvas');                     canvas.width = w;                     canvas.height = h;                     var count = canvasbuffers.push(canvas.getContext("2d"));-                    $.kc.reply(u,[count - 1,w,h]);              -                }        +                    $.kc.reply(u,[count - 1,w,h]);+                }             } -            function GetImageData(sx,sy,sw,sh) { +            function GetImageData(sx,sy,sw,sh) {                 return function (u,c) {                     var img = c.getImageData(sx,sy,sw,sh);                     var arr = [];@@ -110,25 +110,31 @@                                  , height: img.height                                  , data: arr                                  });-                }        +                }             } -            function Trigger(e) { -                $.kc.event({ eMetaKey: e.eMetaKey,-                             ePageXY : e.ePageXY,-                             eType   : e.eType,-                             eWhich  : e.eWhich-                            });+            function Sync(u,c) {+                $.kc.reply(u,[]);             }++            function Trigger(e) {+		var o = {};+		o.metaKey = e.metaKey;+                o.type    = e.type;+		if (e.pageXY != undefined) { +	            o.pageXY = e.pageXY; +  	        }+		if (e.pageX != undefined && e.pageY != undefined) {+		    o.pageXY = [e.pageX,e.pageY];+                }+                if (e.which != undefined) { +                    o.which = e.which; +                }+                $.kc.event(o);+            }             function register(name) {-                $(document).bind(name,function (e){-                        $.kc.event({ eMetaKey: e.metaKey,-                                     ePageXY : [e.pageX,e.pageY],-                                     eType   : e.type,-                                     eWhich  : e.which-                                    });-                });-            }  +                $(document).bind(name,Trigger);+            }             function redraw() {                 $.ajax({ url: "/canvas/" + session,                          type: "GET",@@ -136,10 +142,10 @@                          success: function success() {                                  redraw();                          }-                         }); +                         });              }-             -             function ImageData(w,h,dat) { ++             function ImageData(w,h,dat) {                 var imgData = canvasbuffers[0].createImageData(w,h);                 for(var i = 0;i < dat.length;i ++) {                    imgData.data[i] = dat[i];@@ -169,8 +175,8 @@                 $("#canvas").replaceWith(                             '<canvas id="canvas" width="' + (w * myDevicePixelRatio) + '" height="' + (h * myDevicePixelRatio) +                             '" style="border: black solid ' + b + 'px; padding: 0px; margin: 0px"></canvas>');-                $("#canvas").css("width",w + "px");            -                $("#canvas").css("height",h + "px");            +                $("#canvas").css("width",w + "px");+                $("#canvas").css("height",h + "px");                 c = getContext("2d");                 canvasbuffers.push(c);                 $.kc.connect("/blank");