Its distinctive quality is that it is a low-level, procedural model. This means that rendering happens on the fly through method calls. The context object that operates on the canvas stores particular state/settings that define the drawing patterns.
Having completed the abstract view on the canvas tag through this short theoretical introduction it is time to get our hands dirty.
To start we need a simple HTML page with a defined canvas element:
The first thing to do is get the drawing context that executes the drawing methods on the canvas. In order to do this, simply use the getContext method of the canvas element providing the name of the respective implementation – 2d, 3d, WebGL, etc. Check http://www.webgl.com/ for more information on an implementation of a 3D context based on OpenGL.
Once we have the context it’s time to do the first drawing. We will start by drawing rectangles. There are two methods for that – strokeRect and fillRect that both accept 4 parameters – startX, startY, endX, endY. The positions specified here (and in any canvas drawing method) are in pixels and are relative to the top-left corner of the canvas element.
Check the way the third rectangle appears to be drawn over the others, thanks to the clearRect method call.
The 2d context of the canvas tag offers great capabilities for drawing any form of paths – will it be straight lines or curves of any kind. The drawing should be defined between beginPath and closePath calls. For straight lines one can use the moveTo(x,y) and lineTo(x,y) methods. When using these two methods the drawing is done in the following fashion – moveTo lifts the brush and positions it at the specified location, whereas lineTo uses the brush to draw a line to the specified position:
The code above will produce an equilateral triangle, where the side will be 130px-10px=120px.
There are different methods for drawing curves, but for the sake of brevity, we will focus on bezierCurveTo (drawing Bézier Curves) and arc (drawing circles or sectors):
This code snippet will produce the following raster:
In there you can see the Bézier Curve as the slope. The circle above it is the result of the arc method call closing the path at 360deg.
Being able to draw text is essential and very useful. In the 2d context of the canvas there are the two methods to do this – fillText(text, x, y) that draws a solid text and strokeText(text, x, y) that draws the borders of the letters without filling them. Of course, the canvas provides settings to change the font and text position. Here is a short example:
Drawing shadows is part of the API as well. Almost all basic characteristics of shadows are covered by the canvas context – the shadow offset, color, blur (Gaussian Blur):
The code above will result in the following canvas rendering, where the green neon shadow is clearly visible.
Along with the ability to draw geometries through the graphics API, the context offers a way to manipulate each pixel individually. The canvas is represented by a one dimensional array of values (vector) between 0-255, where each pixel is represented by a 4-tuple of neighboring elements in the combination RGBA(red, green, blue, alpha). This array can be accessed through the getImageData method and after the manipulations put back in the canvas through setImageData.
Here is an example that creates the negative of the rendered image. This is done by subtracting the color components of the pixel from 255, thus leaving only the negative color value for the pixel.
It is common for any graphics API to support linear transformations and the 2D canvas context is no different. Along with short-hand functions such as translate, rotate, scale, etc. that cover the basic linear transformations, there are the more complex methods transform(m00,m10, m01, m11, m02, m12) and setTransform(m00,m10, m01, m11, m02, m12). The last two methods provide directly a matrix to the transformation engine. The transform method just adds another transformation in the queue, while setTransform defines the new transformation matrix, thus resetting the previously defined transformations. The transformation matrix(3x3) definition is the following:
In that matrix m02 and m12 define the translation of the objects, whereas the m00 – m11 define the linear transformation itself in 2D space. To be more precise this matrix describes affine transformations – linear transformations followed by a translation.
Here is a simple example of rotating the rectangles from the first example:
The translation is needed so that no part of the rectangles in clipped on the canvas edges.
Being able to transform objects in the canvas, putting this to animation seems like the next natural step. In order to make it work, we need to call an animation handler repeatedly over a specific period of time. Since the introduction of the requestAnimationFrame, setting up the animation has become even easier. Here is a simple example of making the rectangles rotate:
One important aspect of doing transformation in canvas is the way they are stacked. The most recent definitions are applied first, which resembles the behavior of a LIFO queue. When building animations one should keep this in mind.
When we were first building the Telerik’s ASP.NET Image Editor control we had the idea that sooner or later we will integrate the canvas tag support in it and that day is coming pretty close. Being impressed by the productivity and capabilities of the canvas tag in modern browsers and being able to edit the image without the unnecessary going back and forth to the server we hope that the ImageEditor will become ever better at what it does. Furthermore it will provide more features for the near future when we will most likely implement various filters and drawing tools.
I hope this small introduction to the marvelous world of the 2D context of the canvas tag has been useful and fun for you. Your feedback on the content or features we can implement in RadImageEditor are more than welcome.
Nikodim Lazarov is a Senior Software Developer in the Telerik's ASP.NET AJAX devision. He has years of experience building web applications of various scales. Niko is a strong advocate of Web standards, TDD, Agile and basically anything that makes every developer a true craftsman. Outside of office he usually rides his bike, goes kayaking or is simply out with friends.
Subscribe to be the first to get our expert-written articles and tutorials for developers!