elm/libraries/Graphics/Collage.elm

262 lines
7.2 KiB
Elm
Raw Normal View History

module Graphics.Collage where
2013-09-12 20:07:38 +00:00
{-| The collage API is for freeform graphics. You can move, rotate, scale, etc.
all sorts of forms including lines, shapes, images, and elements.
# Unstructured Graphics
@docs collage
# Creating Forms
@docs toForm, filled, textured, gradient, outlined, traced
# Transforming Forms
@docs move, moveX, moveY, scale, rotate, alpha
# Grouping Forms
Grouping forms makes it easier to write modular graphics code. You can create
a form that is a composite of many subforms. From there it is easy to transform
it as a single unit.
@docs group, groupTransform
# Shapes
@docs rect, oval, square, circle, ngon, polygon
# Paths
@docs segment, path
# Line Styles
@docs solid, dashed, dotted, LineStyle, LineCap, LineJoin, defaultLine
-}
2013-07-27 11:06:22 +00:00
import open Basics
import List
2013-07-27 11:06:22 +00:00
import Either (Either, Left, Right)
import Transform2D (Transform2D, identity)
import Native.Graphics.Collage
2013-08-22 02:10:26 +00:00
import Graphics.Element (Element)
2013-07-27 11:06:22 +00:00
import Color (Color, black, Gradient)
import Maybe (Maybe)
import JavaScript (JSString)
type Form = {
theta : Float,
scale : Float,
x : Float,
y : Float,
2013-06-13 19:00:17 +00:00
alpha : Float,
form : BasicForm
}
data FillStyle
= Solid Color
| Texture String
| Grad Gradient
2013-09-12 20:07:38 +00:00
{-| The shape of the ends of a line. -}
data LineCap = Flat | Round | Padded
2013-03-27 01:50:18 +00:00
2013-09-12 20:07:38 +00:00
{-| The shape of the “joints” of a line, where each line segment
meets. `Sharp` takes an argument to limit the length of the joint. This
defaults to 10.
-}
data LineJoin = Smooth | Sharp Float | Clipped
2013-09-12 20:07:38 +00:00
{-| All of the attributes of a line style. This lets you build up a line style
however you want. You can also update existing line styles with record updates.
-}
2013-03-27 01:50:18 +00:00
type LineStyle = {
color : Color,
width : Float,
cap : LineCap,
join : LineJoin,
dashing : [Int],
dashOffset : Int
}
2013-09-12 20:07:38 +00:00
{-| The default line style, which is solid black with flat caps and sharp joints.
You can use record updates to build the line style you
want. For example, to make a thicker line, you could say:
{ defaultLine | width <- 10 }
-}
defaultLine : LineStyle
2013-03-27 01:50:18 +00:00
defaultLine = {
2013-07-27 11:06:22 +00:00
color = black,
2013-03-27 01:50:18 +00:00
width = 1,
cap = Flat,
join = Sharp 10,
2013-03-27 01:50:18 +00:00
dashing = [],
2013-05-21 08:03:51 +00:00
dashOffset = 0
2013-03-27 01:50:18 +00:00
}
2013-09-12 20:07:38 +00:00
{-| Create a solid line style with a given color. -}
solid : Color -> LineStyle
2013-03-27 16:52:16 +00:00
solid clr = { defaultLine | color <- clr }
2013-09-12 20:07:38 +00:00
{-| Create a dashed line style with a given color. Dashing equals `[8,4]`. -}
dashed : Color -> LineStyle
2013-03-27 16:52:16 +00:00
dashed clr = { defaultLine | color <- clr, dashing <- [8,4] }
2013-09-12 20:07:38 +00:00
{-| Create a dotted line style with a given color. Dashing equals `[3,3]`. -}
dotted : Color -> LineStyle
2013-03-27 16:52:16 +00:00
dotted clr = { defaultLine | color <- clr, dashing <- [3,3] }
2013-03-27 01:50:18 +00:00
data BasicForm
= FPath LineStyle Path
| FShape (Either LineStyle FillStyle) Shape
| FImage Int Int (Int,Int) String
| FElement Element
| FGroup Transform2D [Form]
2013-06-13 19:00:17 +00:00
form : BasicForm -> Form
form f = { theta=0, scale=1, x=0, y=0, alpha=1, form=f }
2013-03-16 20:00:59 +00:00
2013-07-27 11:06:22 +00:00
fill style shape = form (FShape (Right style) shape)
2013-09-12 20:07:38 +00:00
{-| Create a filled in shape. -}
filled : Color -> Shape -> Form
filled color shape = fill (Solid color) shape
2013-09-12 20:07:38 +00:00
{-| Create a textured shape. The texture is described by some url and is
tiled to fill the entire shape.
-}
textured : String -> Shape -> Form
textured src shape = fill (Texture src) shape
2013-09-12 20:07:38 +00:00
{-| Fill a shape with a [gradient](/docs/Color.elm#linear). -}
gradient : Gradient -> Shape -> Form
gradient grad shape = fill (Grad grad) shape
2013-09-12 20:07:38 +00:00
{-| Outline a shape with a given line style. -}
outlined : LineStyle -> Shape -> Form
2013-07-27 11:06:22 +00:00
outlined style shape = form (FShape (Left style) shape)
2013-09-12 20:07:38 +00:00
{-| Trace a path with a given line style. -}
traced : LineStyle -> Path -> Form
traced style path = form (FPath style path)
2013-09-12 20:07:38 +00:00
{-| Create a sprite from a sprite sheet. It cuts out a rectangle
at a given position.
-}
sprite : Int -> Int -> (Int,Int) -> String -> Form
sprite w h pos src = form (FImage w h pos src)
2013-09-12 20:07:38 +00:00
{-| Turn any `Element` into a `Form`. This lets you use text, gifs, and video
in your collage. This means you can move, rotate, and scale
an `Element` however you want.
-}
toForm : Element -> Form
toForm e = form (FElement e)
2013-09-12 20:07:38 +00:00
{-| Flatten many forms into a single `Form`. This lets you move and rotate them
as a single unit, making it possible to build small, modular components.
-}
group : [Form] -> Form
2013-07-27 11:06:22 +00:00
group fs = form (FGroup identity fs)
2013-09-12 20:07:38 +00:00
{-| Flatten many forms into a single `Form` and then apply a matrix
transformation.
-}
groupTransform : Transform2D -> [Form] -> Form
groupTransform matrix fs = form (FGroup matrix fs)
2013-09-12 20:07:38 +00:00
{-| Rotate a form by a given angle. Rotate takes standard Elm angles (radians)
and turns things counterclockwise. So to turn `form` 30&deg; to the left
you would say, `(rotate (degrees 30) form)`.
-}
rotate : number -> Form -> Form
rotate t f = { f | theta <- f.theta + t }
2013-09-12 20:07:38 +00:00
{-| Scale a form by a given factor. Scaling by 2 doubles the size.
-}
scale : number -> Form -> Form
scale s f = { f | scale <- f.scale * s }
2013-09-12 20:07:38 +00:00
{-| Move a form by the given amount. This is a relative translation so
`(move (10,10) form)` would move `form` ten pixels up and ten pixels to the
right.
-}
move : (number,number) -> Form -> Form
move (x,y) f = { f | x <- f.x + x, y <- f.y + y }
2013-09-12 20:07:38 +00:00
{-| Move a shape in the x direction. This is relative so `(moveX 10 form)` moves
`form` 10 pixels to the right.
-}
moveX : number -> Form -> Form
moveX x f = { f | x <- f.x + x }
2013-09-12 20:07:38 +00:00
{-| Move a shape in the y direction. This is relative so `(moveY 10 form)` moves
`form` upwards by 10 pixels.
-}
moveY : number -> Form -> Form
moveY y f = { f | y <- f.y + y }
2013-09-12 20:07:38 +00:00
{-| Set the alpha of a `Form`. The default is 1, and 0 is totally transparent. -}
alpha : Float -> Form -> Form
alpha a f = { f | alpha <- a }
2013-06-13 19:00:17 +00:00
2013-09-12 20:07:38 +00:00
{-| A collage is a collection of 2D forms. There are no strict positioning
relationships between forms, so you are free to do all kinds of 2D graphics.
-}
collage : Int -> Int -> [Form] -> Element
collage = Native.Graphics.Collage.collage
type Path = [(Float,Float)]
2013-09-12 20:07:38 +00:00
{-| Create a path that follows a sequence of points. -}
path : [(Float,Float)] -> Path
path ps = ps
2013-09-12 20:07:38 +00:00
{-| Create a path along a given line segment. -}
segment : (Float,Float) -> (Float,Float) -> Path
segment p1 p2 = [p1,p2]
type Shape = [(Float,Float)]
2013-09-12 20:07:38 +00:00
{-| Create an arbitrary polygon by specifying its corners in order.
`polygon` will automatically close all shapes, so the given list
of points does not need to start and end with the same position.
-}
polygon : [(Float,Float)] -> Shape
polygon points = points
2013-09-12 20:07:38 +00:00
{-| A rectangle with a given width and height. -}
rect : Float -> Float -> Shape
2013-05-24 07:50:18 +00:00
rect w h = let hw = w/2
hh = h/2
in [ (0-hw,0-hh), (0-hw,hh), (hw,hh), (hw,0-hh) ]
2013-09-12 20:07:38 +00:00
{-| A square with a given edge length. -}
square : Float -> Shape
2013-05-24 07:50:18 +00:00
square n = rect n n
2013-09-12 20:07:38 +00:00
{-| An oval with a given width and height. -}
oval : Float -> Float -> Shape
oval w h =
let n = 50
2013-07-27 11:06:22 +00:00
t = 2 * pi / n
hw = w/2
hh = h/2
2013-07-27 11:06:22 +00:00
f i = (hw * cos (t*i), hh * sin (t*i))
2013-05-21 08:03:51 +00:00
in List.map f [0..n-1]
2013-09-12 20:07:38 +00:00
{-| A circle with a given radius. -}
circle : Float -> Shape
circle r = oval (2*r) (2*r)
2013-09-12 20:07:38 +00:00
{-| A regular polygon with N sides. The first argument specifies the number
of sides and the second is the radius. So to create a pentagon with radius
30 you would say:
ngon 5 30
-}
ngon : Int -> Float -> Shape
ngon n r =
let m = toFloat n
2013-07-27 11:06:22 +00:00
t = 2 * pi / m
f i = ( r * cos (t*i), r * sin (t*i) )
in List.map f [0..m-1]