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.
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.
Similar to Html.Attribute, settings control the presentation and other
style options for the Renderables.
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.
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 [ size 48, align Center ] ( 50, 50 ) "Hello world" ]You can learn more about drawing text and its settings in the Drawing text section.
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 )The two main style settings are fill color and stroke color, which are documented here.
By default, renderables are drawn with black color. If you want to specify
a different color to draw, use this Setting on your renderable.
The type Color comes from the package avh4/elm-color. To use it explicitly,
run:
elm install avh4 / elm - colorand then import it in.
import Color
-- ...
shapes
[ fill Color.green ]
[ rect ( 10, 30 ) 50 50 ]By default, renderables are drawn with no visible stroke. If you want to
specify a stroke color to draw an outline over your renderable, use this
Setting on it.
The type Color comes from the package avh4/elm-color. To use it explicitly,
run:
elm install avh4 / elm - colorand then import it in.
import Color
-- ...
shapes
[ stroke Color.red ]
[ rect ( 10, 30 ) 50 50 ]There are other style settings in the documentation (if you search for things
that return a Setting you can see). More specifically:
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.
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.
Creates the shape of a rectangle. It needs the position of the top left corner, the width, and the height.
rect pos width heightCreates a circle. It takes the position of the center of the circle, and the radius of it.
circle pos radiusCreates an arc, a partial circle. It takes the position of the center of the circle, the radius of it, the start angle where the arc will start, the end angle where the arc will end, and if it should draw in clockwise or anti-clockwise direction.
arc ( 10, 10 ) 40 { startAngle = 15, endAngle = 85, clockwise = True }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 segmentsIn order to make a complex path, we need to put together a list of PathSegment
In order to draw a path, you need to give the function path a list of
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 ) radiusYou can see more examples and docs in this page
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 )cp1xcp1ycp2xcp2yxyConnects 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 doesn't necessarily produce any shape, but it moves the starting
point somewhere so that you can use this with other lines.
moveTo pointAdds 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 )cpxcpyxyTo draw text we use the function text documented above:
text
[ font { size = 48, family = "serif" }
, align Center
]
( 50, 50 )
"Hello world"You can apply the following styling settings to text specifically. They will do
nothing if you apply them to other renderables, like shapes.
Specify the font size and family to use when rendering text.
size: What is the size of the text in pixels. Similar to the font-size
property in CSS.family: Font family name to use when drawing the text. For example, you can
use "monospace", "serif" or "sans-serif" to use the user configured
default fonts in the browser. You can also specify other font names like
"Consolas".Specifies the text alignment to use when drawing text. Beware
that the alignment is based on the x value of position passed to text. So if
textAlign is Center, then the text would be drawn at x - (width / 2).
The default value is Start. MDN docs
Type of text alignment
LeftRightCenterStartEndSpecifies the current text baseline being used when drawing text.
The default value is Alphabetic.
See MDN docs for examples and rendering of the different modes.
Type of text baseline.
TopHangingMiddleAlphabeticIdeographicBottomThe following are settings that you can apply, to create very specific and custom effects.
Line style settings apply to paths, and the stroke of shapes and text (if any).
Specify the thickness of lines in space units. When passing zero, negative, Infinity and NaN values are ignored. More information and examples in the MDN docs
Determines how the end points of every line are drawn. See LineCap for the
possible types. By default ButtCap is used. See the MDN docs
for examples.
Type of end points for line drawn.
ButtCapRoundCapSquareCapSpecify how two connecting segments (of lines, arcs or curves) with
non-zero lengths in a shape are joined together (degenerate segments with zero
lengths, whose specified endpoints and control points are exactly at the same
position, are skipped). See the type LineJoin.
By default this property is set to MiterJoin. Note that the lineJoin setting
has no effect if the two connected segments have the same direction, because no
joining area will be added in this case.
More information and examples in the MDN docs
Determines how two connecting segments with non-zero lengths in a shape are joined together.
RoundBevelMiterYou can see examples and pictures on the MDN docs
Specify the line dash pattern used when stroking lines, using a list of values which specify alternating lengths of lines and gaps which describe the pattern.
lineDash segmentssegments[5,
15, 25] will become [5, 15, 25, 5, 15, 25]. If the list is empty, the line
dash list is clear and line strokes are solid.You can see examples and more information in the MDN docs
Specify the line dash pattern offset or "phase".
There are visual examples and more information in the MDN docs
Specify the miter limit ratio in space units. When passing zero, negative, Infinity and NaN values are ignored. It defaults to 10.
More information and live example in the MDN docs
The shadow setting allows you to create a shadow for a renderable, similar to
what the box-shadow CSS does to HTML elements.
Specify a shadow to be rendered. See the Shadow type alias to know what
parameters to pass.
Record with the settings for a shadow.
blur: Amount of blur for the shadowcolor: Color of the shadow (from avh4/elm-color)offset: ( xOffset, yOffset )Transforms are very useful as they allow you to manipulate the rendering via a transformation matrix, allowing you to translate, scale, rotate and skew the rendering context easily. They can be a bit of an advanced topic, but they are powerful and can be very useful.
Specify the transform matrix to apply when drawing. You do so by applying
transforms in order, like translate, rotate, or scale, but you can also
use applyMatrix and set the matrix yourself manually if you know what you are
doing.
shapes
[ transform [ rotate (degrees 50) ] ]
[ rect ( 40, 40 ) 20 20 ]Type of transform to apply to the matrix, to be used in transform. See the
functions below to learn how to create transforms.
Adds a translation transformation by moving the canvas and its origin x
units horizontally and y units vertically on the grid.
More information and examples on the MDN docs
translate x yAdds a rotation to the transformation matrix. The angle argument
represents a clockwise rotation angle and is expressed in radians. Use the core
function degrees to make it easier to represent the rotation.
rotate (degrees 90)The rotation center point is always the canvas origin. To change the center
point, we will need to move the canvas by using the translate transform before
rotating. For example, a very common use case to rotate from a specific point in
the canvas, maybe the center of your renderable, would be done by translating to
that point, rotating, and then translating back, if you want to apply more
transformations. Like this:
transform
[ translate x y
, rotate rotation
, translate -x -y
{- Other transforms -}
]See the MDN docs for more information and examples.
Adds a scaling transformation to the canvas units by x horizontally and by
y vertically.
By default, one unit on the canvas is exactly one pixel. If we apply, for instance, a scaling factor of 0.5, the resulting unit would become 0.5 pixels and so shapes would be drawn at half size. In a similar way setting the scaling factor to 2.0 would increase the unit size and one unit now becomes two pixels. This results in shapes being drawn twice as large.
scale x yxyNote: You can use scale -1 1 to flip the context horizontally and scale 1
-1 to flip it vertically.
More information and examples in the MDN docs
Multiplies the current transformation with the matrix described by the arguments of this method. You are able to scale, rotate, move and skew the context.
m11m12m21m22dxdyFinally, there are a couple of other settings that you can use to create interesting visual effects:
Specifies the alpha value that is applied before renderables are drawn onto
the canvas. The value is in the range from 0.0 (fully transparent) to 1.0 (fully
opaque). The default value is 1.0. Values outside the range, including
Infinity and NaN will not be set and alpha will remain default.
Specify the type of compositing operation to apply when drawing new
entities, where type is a GlobalCompositeOperationMode identifying which of
the compositing or blending mode operations to use.
See GlobalCompositeOperationMode below for more information.
compositeOperationMode ScreenType of compositing operation, identifying which of the compositing or blending mode operations to use. See the chapter Compositing from the Canvas Tutorial.
For more information and pictures of what each mode does, see the MDN docs.
Create a Html element that you can use in your view.
toHtmlis almost like creating other Html elements. We need to pass(width, height)in pixels, a list ofHtml.Attribute, and finally instead of a list of html elements, we pass aList Renderable. ARenderableis a thing that the canvas knows how to render. Read on for more information 👇.Note: Remember to include the
elm-canvasweb component from npm in your page for this to work!