This module exposes a nice drawing API that works on top of the the DOM canvas.
See instructions in the main page of the package for installation, as it
requires the elm-canvas
web component to work.
{ label : String
, valuetype : String
, value : Json.Encode.Value
}
The data type for return values needed from main elm code.
label is for identify the target, every time you use a js function with return value or store some data, you need a label to get it in next frame.
valuetype is the data type of the return value.
Note: the valuetype of a stored data is storeValue
value is the value you need.
toHtml : ( Basics.Int, Basics.Int ) -> ( List CanvasValue, CanvasValue -> msg ) -> List (Html.Attribute msg) -> List Renderable -> Html msg
Create a Html element that you can use in your view.
Canvas.toHtml ( width, height )
( model.canvasReturnValue, Canvas )
[ style "display" "block", onClick CanvasClick ]
[ shapes [ fill Color.white ] [ rect ( 0, 0 ) w h ]
, text
[ font { style = "", size = 48, family = "sans-serif" }, align Center ]
( 50, 50 )
"Hello world"
]
toHtml
is almost like creating other Html elements. We need to pass (width,
height)
in pixels, the CanvasValue
list that receive from canvas which might be stored
in your model, the way you change the canvas value to a msg which you defined
in the Msg part, a list of Html.Attribute
, and finally instead of a list
of html elements, we pass a List Renderable
. A Renderable
is a thing that
the canvas knows how to render. Read on for more information 👇.
Note: Remember to include the elm-canvas
web component from npm in your page for
this to work!
Note: This element has display: inline
by default, so their width or
height will have no effect. You can change it to block
for example. See MDN:
display for possible
display values.
toHtmlWith : { width : Basics.Int, height : Basics.Int, textures : List (Texture.Source msg), returnValues : ( List CanvasValue, CanvasValue -> msg ) } -> List (Html.Attribute msg) -> List Renderable -> Html msg
Similar to toHtml
but with more explicit options and the ability to load
textures.
Canvas.toHtmlWith
{ width = 500
, height = 500
, textures = [ Texture.loadImageUrl "./assets/sprite.png" TextureLoaded ]
, returnValues = ( model.canvasReturnValue, Canvas )
}
[ style "display" "block", onClick CanvasClick ]
[ shapes [ fill Color.white ] [ rect ( 0, 0 ) w h ]
, text
[ font { style = "", size = 48, family = "sans-serif" }, align Center ]
( 50, 50 )
"Hello world"
]
Note: Remember to include the elm-canvas
web component from npm in your page for
this to work!
Note: This element has display: inline
by default, so their width or
height will have no effect. You can change it to block
for example. See MDN:
display for possible
display values.
See toHtml
above and the Canvas.Texture
module for more details.
Internal.Renderable
A Renderable
is a thing that the canvas knows how to render, similar to
Html
elements.
We can make Renderable
s to use with Canvas.toHtml
with functions like
shapes
and text
.
( Basics.Float, Basics.Float )
A small alias to reference points on some of the functions on the package.
The first argument of the tuple is the x
position, and the second is the y
position.
-- Making a point with x = 15 and y = 55
point : Point
point =
( 15, 55 )
clear : Point -> Basics.Float -> Basics.Float -> Renderable
We use clear
to remove the contents of a rectangle in the screen and make
them transparent.
import Canvas exposing (..)
Canvas.toHtml ( width, height )
[]
[ clear ( 0, 0 ) width height
, shapes [ fill Color.red ] [ rect ( 10, 10 ) 20 20 ]
]
shapes : List Internal.Setting -> List Shape -> Renderable
We use shapes
to render different shapes like rectangles, circles, and
lines of different kinds that we can connect together.
You can draw many shapes with the same Setting
s, which makes for very
efficient rendering.
import Canvas exposing (..)
import Color -- elm install avh4/elm-color
Canvas.toHtml ( width, height )
[]
[ shapes [ fill Color.white ] [ rect ( 0, 0 ) width height ] ]
You can read more about the different kinds of Shape
in the Drawing shapes
section.
text : List Internal.Setting -> Point -> String -> Renderable
We use text
to render text on the canvas. We need to pass the list of
settings to style it, the point with the coordinates where we want to render,
and the text to render.
Keep in mind that align
and other settings can change where the text is
positioned with regards to the coordinates provided.
Canvas.toHtml ( width, height )
[]
[ text
[ font { style = "", size = 48, family = "sans-serif" }, align Center ]
( 50, 50 )
"Hello world"
]
You can learn more about drawing text and its settings in the Drawing text section.
texture : List Internal.Setting -> Point -> Texture -> Renderable
Draw a texture into your canvas.
Textures can be loaded by using toHtmlWith
and passing in a Texture.Source
.
Once the texture is loaded, and you have an actual Texture
, you can use it
with this method to draw it.
You can also make different types of textures from the same texture, in case you have a big sprite sheet and want to create smaller textures that are a viewport into a bigger sheet.
See the Canvas.Texture
module and the sprite
function in it.
group : List Internal.Setting -> List Renderable -> Renderable
Groups many renderables into one, and provides the opportunity to apply settings for the whole group.
Canvas.toHtml ( width, height )
[]
[ group [ fill Color.red ]
[ shapes [] [ rect ( 0, 0 ) w h ]
, text
[ font { style = "", size = 48, family = "sans-serif" }, align Center ]
( 50, 50 )
"Hello world"
]
]
empty : Renderable
Empty renderable. Useful for creating an empty renderable instead of writing group [] []
Shapes can be rectangles, circles, and different types of lines. By composing
shapes, you can draw complex figures! There are many functions that produce
a Shape
, which you can feed to shapes
to get something on the screen.
Internal.Shape
A Shape
represents a shape or lines to be drawn. Giving them to shapes
we get a Renderable
for the canvas.
shapes []
[ path ( 20, 10 )
[ lineTo ( 10, 30 )
, lineTo ( 30, 30 )
, lineTo ( 20, 10 )
]
, circle ( 50, 50 ) 10
, rect ( 100, 150 ) 40 50
, circle ( 100, 100 ) 80
]
rect : Point -> Basics.Float -> Basics.Float -> Shape
Creates the shape of a rectangle. It needs the position of the top left corner, the width, and the height.
rect pos width height
roundRect : Point -> Basics.Float -> Basics.Float -> List Basics.Float -> Shape
Creates the shape of a rounded rectangle. It takes the position of the top left corner, the width, the height and a list specifying the radii of the circular arc to be used for the corners of the rectangle. The list must contain between 1 and 4 positive numbers. You can find more info on this page.
circle : Point -> Basics.Float -> Shape
Creates a circle. It takes the position of the center of the circle, and the radius of it.
circle pos radius
arc : Point -> Basics.Float -> { startAngle : Basics.Float, endAngle : Basics.Float, clockwise : Basics.Bool } -> Shape
Creates an arc, a partial circle. It takes:
Note: If you want to give the angles in degrees, you can use the degrees
function from elm/core.
arc ( 10, 10 ) 40 { startAngle = degrees 15, endAngle = degrees 85, clockwise = True }
Note: If you want to make a partial circle (like a pizza slice), combine
with path
to make a triangle, and then the arc. See the pie chart example.
path : Point -> List PathSegment -> Shape
Creates a complex path as a shape from a list of PathSegment
instructions.
It is mandatory to pass in the starting point for the path, since the path
starts with an implicit moveTo
the starting point to avoid undesirable
behavior and implicit state.
path startingPoint segments
In order to make a complex path, we need to put together a list of PathSegment
Internal.PathSegment
In order to draw a path, you need to give the function path
a list of
PathSegment
arcTo : Point -> Point -> Basics.Float -> PathSegment
Adds an arc to the path with the given control points and radius.
The arc drawn will be a part of a circle, never elliptical. Typical use could be making a rounded corner.
One way to think about the arc drawn is to imagine two straight segments, from
the starting point (latest point in current path) to the first control point,
and then from the first control point to the second control point. These two
segments form a sharp corner with the first control point being in the corner.
Using arcTo
, the corner will instead be an arc with the given radius.
The arc is tangential to both segments, which can sometimes produce surprising results, e.g. if the radius given is larger than the distance between the starting point and the first control point.
If the radius specified doesn't make the arc meet the starting point (latest point in the current path), the starting point is connected to the arc with a straight line segment.
arcTo ( x1, y1 ) ( x2, y2 ) radius
You can see more examples and docs in this page
bezierCurveTo : Point -> Point -> Point -> PathSegment
Adds a cubic Bézier curve to the path. It requires three points. The first
two points are control points and the third one is the end point. The starting
point is the last point in the current path, which can be changed using moveTo
before creating the Bézier curve. You can learn more about this curve in the
MDN docs.
bezierCurveTo controlPoint1 controlPoint2 point
bezierCurveTo ( cp1x, cp1y ) ( cp2x, cp2y ) ( x, y )
cp1x
cp1y
cp2x
cp2y
x
y
lineTo : Point -> PathSegment
Connects the last point in the previous shape to the x, y coordinates with a straight line.
lineTo ( x, y )
If you want to make a line independently of where the previous shape ended, you
can use moveTo
before using lineTo.
moveTo : Point -> PathSegment
moveTo
doesn't necessarily produce any shape, but it moves the starting
point somewhere so that you can use this with other lines.
moveTo point
quadraticCurveTo : Point -> Point -> PathSegment
Adds a quadratic Bézier curve to the path. It requires two points. The
first point is a control point and the second one is the end point. The starting
point is the last point in the current path, which can be changed using moveTo
before creating the quadratic Bézier curve. Learn more about quadratic bezier
curves in the MDN docs
quadraticCurveTo controlPoint point
quadraticCurveTo ( cpx, cpy ) ( x, y )
cpx
cpy
x
y