on cb154ac help sign in
elk/libraries/Graphics/Element.elm
263 lines 9.2 kB history raw
2module Graphics.Element (widthOf, heightOf, sizeOf,
3 width, height, size, opacity, color, tag, link,
4 image, fittedImage, croppedImage, tiledImage,
5 flow, up, down, left, right, inward, outward,
6 above, below, beside, layers,
7 container, absolute, relative,
8 middle, topLeft, topRight, bottomLeft, bottomRight,
9 midLeft, midRight, midTop, midBottom, middleAt,
10 topLeftAt, topRightAt, bottomLeftAt, bottomRightAt,
11 midLeftAt, midRightAt, midTopAt, midBottomAt,
12 spacer, newElement
13 ) where
15import Native.Utils (guid, max, htmlHeight)
16import JavaScript as JS
17import List as List
18import Color
19import Maybe (Just, Nothing)
21type Properties = {
22 id : Int,
23 width : Int,
24 height : Int,
25 opacity : Float,
26 color : Maybe Color,
27 href : JSString,
28 tag : JSString
29 }
31type Element = { props : Properties, element : ElementPrim }
33-- Get the width of an Element
34widthOf : Element -> Int
35widthOf e = e.props.width
37-- Get the height of an Element
38heightOf : Element -> Int
39heightOf e = e.props.height
41-- Get the width and height of an Element
42sizeOf : Element -> (Int,Int)
43sizeOf e = (e.props.width, e.props.height)
45-- Create an `Element` with a given width.
46width : Int -> Element -> Element
47width nw e = let p = e.props
48 props = case e.element of
49 Image _ w h _ -> {p| height <- h/w*nw }
50 RawHtml html -> {p| height <- let (w,h) = htmlHeight nw html in h}
51 _ -> p
52 in { element=e.element, props={props| width <- nw} }
54-- Create an `Element` with a given height.
55height : Int -> Element -> Element
56height nh e = let p = e.props
57 props = case e.element of
58 Image _ w h _ -> {p| width <- w/h*nh }
59 _ -> p
60 in { element=e.element, props={p| height <- nh} }
62-- Create an `Element` with a new width and height.
63size : Int -> Int -> Element -> Element
64size w h e = height h (width w e)
66-- Create an `Element` with a given opacity. Opacity is a number between 0 and 1
67-- where 0 means totally clear.
68opacity : Float -> Element -> Element
69opacity o e = let p = e.props in { element=e.element, props={p| opacity <- o} }
71-- Create an `Element` with a given background color.
72color : Color -> Element -> Element
73color c e = let p = e.props in
74 { element=e.element, props={p| color <- Just c} }
76-- Create an `Element` with a tag. This lets you link directly to it.
77-- The element `(tag "all-about-badgers" thirdParagraph)` can be reached
78-- with a link lik this: `/facts-about-animals.elm#all-about-badgers`
79tag : String -> Element -> Element
80tag name e = let p = e.props in
81 { element=e.element, props={p| tag <- JS.fromString name} }
83-- Create an `Element` that is a hyper-link.
84link : String -> Element -> Element
85link href e = let p = e.props in
86 { element=e.element, props={p| href <- JS.fromString href} }
88emptyStr = JS.fromString ""
89newElement w h e =
90 { props = Properties (guid ()) w h 1 Nothing emptyStr emptyStr, element = e }
92data ElementPrim
93 = Image ImageStyle Int Int JSString
94 | Container Position Element
95 | Flow Direction [Element]
96 | Spacer
97 | RawHtml JSString
98 | Custom -- for custom Elements implemented in JS, see collage for example
100data ImageStyle = Plain | Fitted | Cropped (Int,Int) | Tiled
102-- Create an image given a width, height, and image source.
103image : Int -> Int -> String -> Element
104image w h src = newElement w h (Image Plain w h (JS.fromString src))
106-- Create a fitted image given a width, height, and image source.
107-- This will crop the picture to best fill the given dimensions.
108fittedImage : Int -> Int -> String -> Element
109fittedImage w h src = newElement w h (Image Fitted w h (JS.fromString src))
111-- Create a cropped image. Take a rectangle out of the picture starting
112-- at the given top left coordinate. If you have a 140-by-140 image,
113-- the following will cut a 100-by-100 square out of the middle of it.
114--
115-- croppedImage (20,20) 100 100 "yogi.jpg"
116croppedImage : (Int,Int) -> Int -> Int -> String -> Element
117croppedImage pos w h src =
118 newElement w h (Image (Cropped pos) w h (JS.fromString src))
120tiledImage : Int -> Int -> String -> Element
121tiledImage w h src =
122 newElement w h (Image Tiled w h (JS.fromString src))
124data Three = P | Z | N
125data Pos = Absolute Int | Relative Float
126type Position = { horizontal : Three, vertical : Three, x : Pos, y : Pos }
128-- Put an element in a container. This lets you position the element really
129-- easily, and there are tons of ways to set the `Position`.
130-- To center `element` exactly in a 300-by-300 square you would say:
131--
132-- container 300 300 middle element
133--
134-- By setting the color of the container, you can create borders.
135container : Int -> Int -> Position -> Element -> Element
136container w h pos e = newElement w h (Container pos e)
138-- Create an empty box. This is useful for getting your spacing right and
139-- for making borders.
140spacer : Int -> Int -> Element
141spacer w h = newElement w h Spacer
143data Direction = DUp | DDown | DLeft | DRight | DIn | DOut
145-- Have a list of elements flow in a particular direction.
146-- The `Direction` starts from the first element in the list.
147--
148-- flow right [a,b,c]
149--
150-- +---+---+---+
151-- | a | b | c |
152-- +---+---+---+
153flow : Direction -> [Element] -> Element
154flow dir es =
155 let ws = List.map widthOf es
156 hs = List.map heightOf es
157 newFlow w h = newElement w h (Flow dir es)
158 in
159 if es == [] then spacer 0 0 else
160 case dir of
161 DUp -> newFlow (List.maximum ws) (List.sum hs)
162 DDown -> newFlow (List.maximum ws) (List.sum hs)
163 DLeft -> newFlow (List.sum ws) (List.maximum hs)
164 DRight -> newFlow (List.sum ws) (List.maximum hs)
165 DIn -> newFlow (List.maximum ws) (List.maximum hs)
166 DOut -> newFlow (List.maximum ws) (List.maximum hs)
168-- Stack elements vertically. To put `a` above `b` you would say:
169--
170-- a `above` b
171above : Element -> Element -> Element
172above hi lo =
173 newElement (max (widthOf hi) (widthOf lo))
174 (heightOf hi + heightOf lo)
175 (Flow DDown [hi,lo])
177-- Stack elements vertically. To put `a` below `b` you would say:
178--
179-- a `below` b
180below : Element -> Element -> Element
181below lo hi =
182 newElement (max (widthOf hi) (widthOf lo))
183 (heightOf hi + heightOf lo)
184 (Flow DDown [hi,lo])
186-- Put elements beside each other horizontally.
187beside : Element -> Element -> Element
188beside lft rht =
189 newElement (widthOf lft + widthOf rht)
190 (max (heightOf lft) (heightOf rht))
191 (Flow right [lft,rht])
193-- Layer elements on top of each other, starting from the bottom.
194-- `(layers == flow outward)`
195layers : [Element] -> Element
196layers es =
197 let ws = List.map widthOf es
198 hs = List.map heightOf es
199 in newElement (List.maximum ws) (List.maximum hs) (Flow DOut es)
202-- Repetitive things --
204absolute : Int -> Pos
205absolute = Absolute
206relative : Float -> Pos
207relative = Relative
209middle : Position
210middle = { horizontal=Z, vertical=Z, x=Relative 0.5, y=Relative 0.5 }
211topLeft : Position
212topLeft = { horizontal=N, vertical=P, x=Absolute 0, y=Absolute 0 }
213topRight : Position
214topRight = { topLeft | horizontal <- P }
215bottomLeft : Position
216bottomLeft = { topLeft | vertical <- N }
217bottomRight : Position
218bottomRight = { bottomLeft | horizontal <- P }
219midLeft : Position
220midLeft = { middle | horizontal <- N, x <- Absolute 0 }
221midRight : Position
222midRight = { midLeft | horizontal <- P }
223midTop : Position
224midTop = { middle | vertical <- P, y <- Absolute 0 }
225midBottom : Position
226midBottom = { midTop | vertical <- N }
228middleAt : Pos -> Pos -> Position
229middleAt x y = { horizontal = Z, vertical = Z, x = x, y = y }
230topLeftAt : Pos -> Pos -> Position
231topLeftAt x y = { horizontal = N, vertical = P, x = x, y = y }
232topRightAt : Pos -> Pos -> Position
233topRightAt x y = { horizontal = P, vertical = P, x = x, y = y }
234bottomLeftAt : Pos -> Pos -> Position
235bottomLeftAt x y = { horizontal = N, vertical = N, x = x, y = y }
236bottomRightAt : Pos -> Pos -> Position
237bottomRightAt x y = { horizontal = P, vertical = N, x = x, y = y }
238midLeftAt : Pos -> Pos -> Position
239midLeftAt x y = { horizontal = N, vertical = Z, x = x, y = y }
240midRightAt : Pos -> Pos -> Position
241midRightAt x y = { horizontal = P, vertical = Z, x = x, y = y }
242midTopAt : Pos -> Pos -> Position
243midTopAt x y = { horizontal = Z, vertical = P, x = x, y = y }
244midBottomAt : Pos -> Pos -> Position
245midBottomAt x y = { horizontal = Z, vertical = N, x = x, y = y }
247up : Direction
248up = DUp
250down : Direction
251down = DDown
253left : Direction
254left = DLeft
256right : Direction
257right = DRight
259inward : Direction
260inward = DIn
262outward : Direction
263outward = DOut