0 | module Web.MVC.Canvas.Shape
2 | import Control.Monad.Either.Extra
5 | import Web.MVC.Canvas.Angle
15 | data PathType = Fill | Stroke
18 | data Segment : Type where
19 | Move : (x,y : Double) -> Segment
20 | Line : (x,y : Double) -> Segment
21 | Arc : (x,y,radius : Double)
22 | -> (start,stop : Angle)
23 | -> (counterclockwise : Bool)
25 | ArcTo : (x1,y1,x2,y2,radius : Double) -> Segment
29 | data RectType = Fill | Stroke | Clear
32 | data Shape : Type where
33 | Rect : (x,y,w,h : Double) -> RectType -> Shape
34 | Path : List Segment -> PathType -> Shape
35 | Shapes : List Shape -> Shape
36 | Text : String -> (x,y : Double) -> Optional Double -> Shape
37 | Text' : String -> (x,y : Double) -> Shape
40 | circle : (x,y,radius : Double) -> PathType -> Shape
41 | circle x y r = Path [Arc x y r (rad 0) (rad $
2 * pi) False]
44 | polyLine : List (Double,Double) -> Shape
45 | polyLine [] = Path [] Stroke
46 | polyLine ((x,y) :: t) = Path (Move x y :: map (uncurry Line) t) Stroke
49 | Semigroup Shape where
52 | Shapes xs <+> Shapes ys = Shapes $
xs ++ ys
53 | x <+> Shapes ys = Shapes $
x :: ys
54 | x <+> y = Shapes [x,y]
64 | applySegment : CanvasRenderingContext2D -> Segment -> JSIO ()
65 | applySegment ctxt (Move x y) = moveTo ctxt x y
66 | applySegment ctxt (Line x y) = lineTo ctxt x y
67 | applySegment ctxt (Arc x y r start stop ccw) = do
68 | arc' ctxt x y r (toRadians start) (toRadians stop) (Def ccw)
69 | applySegment ctxt (ArcTo x1 y1 x2 y2 radius) =
70 | arcTo ctxt x1 y1 x2 y2 radius
73 | applyAll : CanvasRenderingContext2D -> List Shape -> JSIO ()
76 | apply : CanvasRenderingContext2D -> Shape -> JSIO ()
78 | applyAll ctxt = assert_total $
traverseList_ (apply ctxt)
80 | apply ctxt (Rect x y w h Fill) = fillRect ctxt x y w h
81 | apply ctxt (Rect x y w h Stroke) = strokeRect ctxt x y w h
82 | apply ctxt (Rect x y w h Clear) = clearRect ctxt x y w h
83 | apply ctxt (Path ss st) = do
85 | traverseList_ (applySegment ctxt) ss
88 | Stroke => stroke ctxt
89 | apply ctxt (Text str x y max) = fillText' ctxt str x y max
90 | apply ctxt (Text' str x y) = fillText ctxt str x y
91 | apply ctxt (Shapes xs) = applyAll ctxt xs