joakin/elm-canvas/4.1.0

NOTE: the latest version is 5.0.0

Canvas

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.

Usage in HTML

toHtml : ( Int, Int ) -> List (Attribute msg) -> List Renderable -> Html msg

Create a Html element that you can use in your view.

Canvas.toHtml ( width, height )
    [ style "display" "block", onClick CanvasClick ]
    [ shapes [ fill Color.white ] [ rect ( 0, 0 ) w h ]
    , text
        [ font { 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, 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.

{ width : Int
, height : Int
, textures : List (Source msg)
}
-> List (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 ]
    }
    [ style "display" "block", onClick CanvasClick ]
    [ shapes [ fill Color.white ] [ rect ( 0, 0 ) w h ]
    , text
        [ font { 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.

Drawing things

A Renderable is a thing that the canvas knows how to render, similar to Html elements.

We can make Renderables to use with Canvas.toHtml with functions like shapes and text.

type alias Point =
( Float, 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 -> Float -> 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 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 Settings, 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 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 { 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 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.

Drawing shapes

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.

type alias Shape =
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
    ]

Here are the different functions that produce shapes that we can draw.

rect : Point -> Float -> 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
circle : Point -> 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
-> Float
-> { startAngle : Float
, endAngle : Float
, clockwise : Bool
}
-> Shape

Creates an arc, a partial circle. It takes:

  • The position of the center of the circle
  • The radius of the circle
  • The start angle (in radians) where the arc will start
    • 0 is center right, 90 is bottom center
  • The end angle (in radians) where the arc will end
  • If it should draw in clockwise or anti-clockwise direction

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

Paths

In order to make a complex path, we need to put together a list of PathSegment

type alias PathSegment =
PathSegment

In order to draw a path, you need to give the function path a list of PathSegment

arcTo : Point -> Point -> 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
    • The x axis of the coordinate for the first control point.
  • cp1y
    • The y axis of the coordinate for the first control point.
  • cp2x
    • The x axis of the coordinate for the second control point.
  • cp2y
    • The y axis of the coordinate for the second control point.
  • x
    • The x axis of the coordinate for the end point.
  • y
    • The y axis of the coordinate for the end point.
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
    • The x axis of the coordinate for the control point.
  • cpy
    • The y axis of the coordinate for the control point.
  • x
    • The x axis of the coordinate for the end point.
  • y
    • The y axis of the coordinate for the end point.