on 577fc17 help sign in
elk/libraries/Graphics/Collage.elm
260 lines 7.4 kB history raw
1module Graphics.Collage where
3{-| The collage API is for freeform graphics. You can move, rotate, scale, etc.
4all sorts of forms including lines, shapes, images, and elements.
6# Unstructured Graphics
7@docs collage
8
9# Creating Forms
10@docs toForm, filled, textured, gradient, outlined, traced
12# Transforming Forms
13@docs move, moveX, moveY, scale, rotate, alpha
15# Grouping Forms
16Grouping forms makes it easier to write modular graphics code. You can create
17a form that is a composite of many subforms. From there it is easy to transform
18it as a single unit.
20@docs group, groupTransform
22# Shapes
23@docs rect, oval, square, circle, ngon, polygon
25# Paths
26@docs segment, path
28# Line Styles
29@docs solid, dashed, dotted, LineStyle, LineCap, LineJoin, defaultLine
31-}
33import Basics (..)
34import List
35import Either (Either(Left, Right))
36import Transform2D (Transform2D, identity)
37import Native.Graphics.Collage
38import Graphics.Element (Element)
39import Color (Color, black, Gradient)
40import Maybe (Maybe)
42type Form = {
43 theta : Float,
44 scale : Float,
45 x : Float,
46 y : Float,
47 alpha : Float,
48 form : BasicForm
49 }
51data FillStyle
52 = Solid Color
53 | Texture String
54 | Grad Gradient
56{-| The shape of the ends of a line. -}
57data LineCap = Flat | Round | Padded
59{-| The shape of the “joints” of a line, where each line segment
60meets. `Sharp` takes an argument to limit the length of the joint. This
61defaults to 10.
62-}
63data LineJoin = Smooth | Sharp Float | Clipped
65{-| All of the attributes of a line style. This lets you build up a line style
66however you want. You can also update existing line styles with record updates.
67-}
68type LineStyle = {
69 color : Color,
70 width : Float,
71 cap : LineCap,
72 join : LineJoin,
73 dashing : [Int],
74 dashOffset : Int
75 }
77{-| The default line style, which is solid black with flat caps and sharp joints.
78You can use record updates to build the line style you
79want. For example, to make a thicker line, you could say:
81 { defaultLine | width <- 10 }
82-}
83defaultLine : LineStyle
84defaultLine = {
85 color = black,
86 width = 1,
87 cap = Flat,
88 join = Sharp 10,
89 dashing = [],
90 dashOffset = 0
91 }
93{-| Create a solid line style with a given color. -}
94solid : Color -> LineStyle
95solid clr = { defaultLine | color <- clr }
97{-| Create a dashed line style with a given color. Dashing equals `[8,4]`. -}
98dashed : Color -> LineStyle
99dashed clr = { defaultLine | color <- clr, dashing <- [8,4] }
101{-| Create a dotted line style with a given color. Dashing equals `[3,3]`. -}
102dotted : Color -> LineStyle
103dotted clr = { defaultLine | color <- clr, dashing <- [3,3] }
105data BasicForm
106 = FPath LineStyle Path
107 | FShape (Either LineStyle FillStyle) Shape
108 | FImage Int Int (Int,Int) String
109 | FElement Element
110 | FGroup Transform2D [Form]
112form : BasicForm -> Form
113form f = { theta=0, scale=1, x=0, y=0, alpha=1, form=f }
115fill style shape = form (FShape (Right style) shape)
117{-| Create a filled in shape. -}
118filled : Color -> Shape -> Form
119filled color shape = fill (Solid color) shape
121{-| Create a textured shape. The texture is described by some url and is
122tiled to fill the entire shape.
123-}
124textured : String -> Shape -> Form
125textured src shape = fill (Texture src) shape
127{-| Fill a shape with a [gradient](/library/Color.elm#linear). -}
128gradient : Gradient -> Shape -> Form
129gradient grad shape = fill (Grad grad) shape
131{-| Outline a shape with a given line style. -}
132outlined : LineStyle -> Shape -> Form
133outlined style shape = form (FShape (Left style) shape)
135{-| Trace a path with a given line style. -}
136traced : LineStyle -> Path -> Form
137traced style path = form (FPath style path)
139{-| Create a sprite from a sprite sheet. It cuts out a rectangle
140at a given position.
141-}
142sprite : Int -> Int -> (Int,Int) -> String -> Form
143sprite w h pos src = form (FImage w h pos src)
145{-| Turn any `Element` into a `Form`. This lets you use text, gifs, and video
146in your collage. This means you can move, rotate, and scale
147an `Element` however you want.
148-}
149toForm : Element -> Form
150toForm e = form (FElement e)
152{-| Flatten many forms into a single `Form`. This lets you move and rotate them
153as a single unit, making it possible to build small, modular components.
154-}
155group : [Form] -> Form
156group fs = form (FGroup identity fs)
158{-| Flatten many forms into a single `Form` and then apply a matrix
159transformation.
160-}
161groupTransform : Transform2D -> [Form] -> Form
162groupTransform matrix fs = form (FGroup matrix fs)
164{-| Move a form by the given amount. This is a relative translation so
165`(move (10,10) form)` would move `form` ten pixels up and ten pixels to the
166right.
167-}
168move : (Float,Float) -> Form -> Form
169move (x,y) f = { f | x <- f.x + x, y <- f.y + y }
171{-| Move a shape in the x direction. This is relative so `(moveX 10 form)` moves
172`form` 10 pixels to the right.
173-}
174moveX : Float -> Form -> Form
175moveX x f = { f | x <- f.x + x }
177{-| Move a shape in the y direction. This is relative so `(moveY 10 form)` moves
178`form` upwards by 10 pixels.
179-}
180moveY : Float -> Form -> Form
181moveY y f = { f | y <- f.y + y }
183{-| Scale a form by a given factor. Scaling by 2 doubles the size.
184-}
185scale : Float -> Form -> Form
186scale s f = { f | scale <- f.scale * s }
188{-| Rotate a form by a given angle. Rotate takes standard Elm angles (radians)
189and turns things counterclockwise. So to turn `form` 30&deg; to the left
190you would say, `(rotate (degrees 30) form)`.
191-}
192rotate : Float -> Form -> Form
193rotate t f = { f | theta <- f.theta + t }
195{-| Set the alpha of a `Form`. The default is 1, and 0 is totally transparent. -}
196alpha : Float -> Form -> Form
197alpha a f = { f | alpha <- a }
199{-| A collage is a collection of 2D forms. There are no strict positioning
200relationships between forms, so you are free to do all kinds of 2D graphics.
201-}
202collage : Int -> Int -> [Form] -> Element
203collage = Native.Graphics.Collage.collage
206type Path = [(Float,Float)]
208{-| Create a path that follows a sequence of points. -}
209path : [(Float,Float)] -> Path
210path ps = ps
212{-| Create a path along a given line segment. -}
213segment : (Float,Float) -> (Float,Float) -> Path
214segment p1 p2 = [p1,p2]
216type Shape = [(Float,Float)]
218{-| Create an arbitrary polygon by specifying its corners in order.
219`polygon` will automatically close all shapes, so the given list
220of points does not need to start and end with the same position.
221-}
222polygon : [(Float,Float)] -> Shape
223polygon points = points
225{-| A rectangle with a given width and height. -}
226rect : Float -> Float -> Shape
227rect w h = let hw = w/2
228 hh = h/2
229 in [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ]
231{-| A square with a given edge length. -}
232square : Float -> Shape
233square n = rect n n
235{-| An oval with a given width and height. -}
236oval : Float -> Float -> Shape
237oval w h =
238 let n = 50
239 t = 2 * pi / n
240 hw = w/2
241 hh = h/2
242 f i = (hw * cos (t*i), hh * sin (t*i))
243 in List.map f [0..n-1]
245{-| A circle with a given radius. -}
246circle : Float -> Shape
247circle r = oval (2*r) (2*r)
249{-| A regular polygon with N sides. The first argument specifies the number
250of sides and the second is the radius. So to create a pentagon with radius
25130 you would say:
253 ngon 5 30
254-}
255ngon : Int -> Float -> Shape
256ngon n r =
257 let m = toFloat n
258 t = 2 * pi / m
259 f i = ( r * cos (t*i), r * sin (t*i) )
260 in List.map f [0..m-1]