0 | module Rhone.Canvas.Shape
2 | import Control.Monad.Either.Extra
3 | import Rhone.JS.Reactimate
5 | import Rhone.Canvas.Angle
16 | data PathType = Fill | Stroke
19 | data Segment : Type where
20 | Move : (x,y : Double) -> Segment
21 | Line : (x,y : Double) -> Segment
22 | Arc : (x,y,radius : Double)
23 | -> (start,stop : Angle)
24 | -> (counterclockwise : Bool)
26 | ArcTo : (x1,y1,x2,y2,radius : Double) -> Segment
30 | data RectType = Fill | Stroke | Clear
33 | data Shape : Type where
34 | Rect : (x,y,w,h : Double) -> RectType -> Shape
35 | Path : List Segment -> PathType -> Shape
36 | Shapes : List Shape -> Shape
37 | Text : String -> (x,y : Double) -> Optional Double -> Shape
38 | Text' : String -> (x,y : Double) -> Shape
41 | circle : (x,y,radius : Double) -> PathType -> Shape
42 | circle x y r = Path [Arc x y r (rad 0) (rad $
2 * pi) False]
45 | polyLine : List (Double,Double) -> Shape
46 | polyLine [] = Path [] Stroke
47 | polyLine ((x,y) :: t) = Path (Move x y :: map (uncurry Line) t) Stroke
50 | Semigroup Shape where
53 | Shapes xs <+> Shapes ys = Shapes $
xs ++ ys
54 | x <+> Shapes ys = Shapes $
x :: ys
55 | x <+> y = Shapes [x,y]
65 | applySegment : CanvasRenderingContext2D -> Segment -> JSIO ()
66 | applySegment ctxt (Move x y) = moveTo ctxt x y
67 | applySegment ctxt (Line x y) = lineTo ctxt x y
68 | applySegment ctxt (Arc x y r start stop ccw) = do
69 | arc' ctxt x y r (toRadians start) (toRadians stop) (Def ccw)
70 | applySegment ctxt (ArcTo x1 y1 x2 y2 radius) =
71 | arcTo ctxt x1 y1 x2 y2 radius
74 | applyAll : CanvasRenderingContext2D -> List Shape -> JSIO ()
77 | apply : CanvasRenderingContext2D -> Shape -> JSIO ()
79 | applyAll ctxt = assert_total $
traverseList_ (apply ctxt)
81 | apply ctxt (Rect x y w h Fill) = fillRect ctxt x y w h
82 | apply ctxt (Rect x y w h Stroke) = strokeRect ctxt x y w h
83 | apply ctxt (Rect x y w h Clear) = clearRect ctxt x y w h
84 | apply ctxt (Path ss st) = do
86 | traverseList_ (applySegment ctxt) ss
89 | Stroke => stroke ctxt
90 | apply ctxt (Text str x y max) = fillText' ctxt str x y max
91 | apply ctxt (Text' str x y) = fillText ctxt str x y
92 | apply ctxt (Shapes xs) = applyAll ctxt xs