Introduction
One of the reasons for the popularity of the web is the graphical user
interface offered to the end users. Images, animations, fonts and other
interactive effects make a website appealing from an end user’s perspective. However,
one limitation that website developers often encounter is drawing graphics in
the browser. As a solution, developers often resort to Flash or Silverlight based plug-ins or generate
graphics on the fly at server side and then send it to the client. HTML5
does a great job in client side graphic rendering by offering what is known as canvas.
The actual drawing can be carried out using JavaScript code and certain new
graphic objects. Understanding HTML5 canvas and associated JavaScript objects
is important for any ASP.NET developer and
this article teaches you just that.
What is HTML5 Canvas?
HTML5 canvas is very similar to a real life drawing canvas in that it allows
you to draw shapes, text, backgrounds and many other drawing operations. Of
course, HTML5 canvas
is browser based and is measured in pixels. At HTML markup level, canvas is
represented by the <canvas> tag. A basic usage of <canvas> tag is
shown below:
<canvas id="myCanvas" width="500" height="500"></canvas>
The canvas tag, by itself, will not draw anything on the screen. You will
need to use some JavaScript code to draw on the canvas. Note that although the
above example sets the width and height properties in the markup itself, you
can also set them via canvas DOM element or CSS.
Canvas can be of great use while rendering graphics on the client side
dynamically. For example, consider that you are allowing the end user to design
simple logos or charts dynamically. Users can play with the data (such as logo
text, height and width or values to be plotted on the chart) and the result is
immediately visible on the screen. You can then save the user inputs on the
server side once the drawing process is complete.
Rendering Context Object
At the heart of drawing on the canvas is a rendering context object.
Rendering context object is responsible for displaying shapes and text on the
canvas. There can be more than one rendering context (say 2D context and 3D
context). Your JavaScript code can get hold of the rendering context using the
getContext() DOM method. The following piece of code shows how:
var myCanvas = document.getElementById('myCanvas'); var myContext = myCanvas.getContext("2d");
As you can see the getContext() method takes a type of context to use (2D in
this case) as its parameter. Once a rendering context is available, your code
can call various drawing methods on the context. The following table lists some
of the common methods of rendering context object:
Method |
Description |
fillRect() |
Draws a filled rectangle |
strokeRect() |
Draws a rectangular outline |
clearRect() |
Clears a rectangular region of the canvas |
lineTo() |
Draws a straight line |
arc() |
Draws an arc or circle |
moveTo() |
Moves the current drawing point to a specified location |
beginPath() |
Initiates drawing a path |
closePath() |
Marks the end of the path drawing operation |
stroke() |
Perform actual drawing of a path in outline fashion |
fill() |
Perform actual drawing of a path in filled fashion |
fillText() |
Draws a string of characters on the canvas |
Drawing on Canvas
Now that you have some idea about HTML5 canvas and various drawing
operations, let’s develop a simple web page that makes use of many of the above
drawing methods.
Create a new web page in any text editor or HTML designer (such as Microsoft
Expression Web) and add the <canvas> tag as shown previously. Then add
the following <script> block in the head section of the page.
window.onload = function () { var myCanvas = document.getElementById('myCanvas'); var context = myCanvas.getContext('2d'); ... }
To begin with, you will draw a rectangle with left and top coordinates equal
to (10,10) and width and height of 200 and 100 pixels respectively. Remember
that these coordinates are with respect to the canvas you defined earlier.
context.fillRect(10,10, 200, 100);
The fillRect() method takes x coordinate, y coordinate, width and height of
the rectangle and draws a filled rectangle as shown below:
Figure 1: The fillRect() method draws a filled rectangle
To draw a circle with radius 50 and center at coordinates 100 and 200 you
will write the following piece of code:
context.arc(100, 200, 50, 0, 2 * Math.PI, false); context.fill();
The arc() method draws an arc as per the given specifications. The first two
parameters indicate the coordinates of the center. The third parameter is the
radius of the circle. The next two parameters (0 and 2* Math.PI) represent the
start angle and end angle for the start and end points of the arc in radians as
measured from the X axis. The last boolean parameter decides whether the arc
will be drawn in anticlockwise direction (true) or clockwise direction (false).
Note that you must call fill() method to draw the arc (or stroke() method if
you wish just the outline rather than filled arc). The following figure shows
the circle drawn as a result of the preceding code:
Figure 2: The circle drawn as a result of the preceding code
To draw a line at coordinates 125,125 you will write:
context.moveTo(125,125); context.lineTo(125,45); context.stroke();
Note that the coordinates of the start point of the line are governed by the
"current" position on the canvas. In the above code the moveTo()
method marks the current drawing position to 125,125. The lineTo() method
accepts the coordinates of the end point of the line. Thus the start point of
the line is at 125,125 and end point at 125, 45. The stroke() method performs
the actual drawing operation.
Figure 3: The stroke() method performs the actual drawing operation.
Now let’s draw a triangle using a path operation.
context.beginPath(); context.moveTo(125,350); context.lineTo(100,600); context.lineTo(45,450); context.closePath(); context.stroke();
The beginPath() method initializes drawing of the path. The first call to
moveTo() method shifts the current drawing position to 125,350. The two calls
to lineTo() method then draw two sides of the triangle. The closePath() method
completes the triangle by completing the path.
Figure 4: The closePath() method completes the triangle by completing the path
Finally, let’s draw some text on the canvas.
context.font = '20pt Arial'; context.fillText('Drawing text on the Canvas', 0, 100);
The fillText() method does the job of outputting specified string at a
specific location (0,100). Notice that the font and font size of the text can
be controlled by setting the font property.
Figure 5: Draw some text on the canvas
In the above example, you used the default rendering properties for the
shapes. You can customize the look and feel of the shapes with the help of
various properties. Have a look at the following fragment of code:
context.fillStyle = 'blue'; context.strokeStyle = 'blue'; context.lineWidth = 10; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowBlur = 10; context.shadowColor = 'black'; context.font = '20pt Arial'; ...
The above code sets the drawing color to blue using fillStyle and
strokeStyle properties. The lineWidth property governs the width of the line
used to draw shapes. The shadowOffsetX, shaddowOffsetY, shadowBlur and shadowColor
properties decide the respective behavior of shadow. The following figure shows
some of the above shapes after applying the styling properties.
Figure 6: Applying the styling properties
Drawing Charts Using Canvas
Now let’s develop a more realistic example by plotting a pie chart on the
canvas. The pie chart will be drawn with some default values initially when the
page loads but you can get the values from the server via a web service or WCF
service. Begin by creating a new website in Visual Studio 2010. Add
a new web form and enter the following HTML markup into it (the following
markup has been trimmed to save some space. You can get the complete markup
from the code download.).
<!DOCTYPE html> <html lang="en"> <head> ... <script src="Scripts/jquery-1.4.4.js" type="text/javascript"></script> ... <div> <input type="button" value="Get Chart Data" id="Button1" /> ... <canvas id="myCanvas" width="400" height="500"></canvas> ... <script type="text/javascript"> var chartColors = ['red', 'green', 'blue', 'yellow', 'orange']; var chartData = [10, 20, 30, 40, 50]; var chartLabels = ['Part 1', 'Part 2', 'Part 3', 'Part 4', 'Part 5']; function GetTotal() { var total = 0; for (var j = 0; j < chartData.length; j++) { total += chartData[j]; } return total; } function DrawChart() { var canvas; var context; var angle = 0; var total = GetTotal(); canvas = document.getElementById("myCanvas"); context = canvas.getContext("2d"); context.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < chartData.length; i++) { context.fillStyle = chartColors[i]; context.beginPath(); context.moveTo(200, 150); context.arc(200, 150, 150, angle, angle + (Math.PI * 2 * (chartData[i] / total)), false); context.lineTo(200, 150); context.fill(); angle += Math.PI * 2 * (chartData[i] / total); } var offset = 350; for (var i = 0; i < chartColors.length; i++) { context.fillStyle = chartColors[i]; context.font = '10pt Arial'; context.fillRect(10, offset, 20, 20); context.fillText(chartLabels[i] + ' - ' + chartData[i], 40, offset + 15); offset += 30; } } DrawChart(); </script> ...
The above markup defines a canvas of size 400 X 500. It also has a button at
the top that you will put to use later. The JavaScript code defines three
global arrays viz. chartColors, chartData and chartLabels. As the names suggest
they store colors of individual sectors of the chart, data with which the pie
chart is to be plotted and labels explaining sector colors. In the above
example you are using 5 values but you can easily increase or decrease them by
adding or removing values from these three arrays.
The GetTotal() function simply sums up the data values from the chartData
array. The total is later used in the DrawChart() function.
The DrawChart() function iterates through the chartData array and draws
individual arcs with the help of arc() function. Notice the use of beginPath(),
moveTo(), lineTo() and fill() methods we discussed earlier. Another for loop
iterates through chartColors array and draws legends for various sectors of the
chart. The following figure shows a sample run of the web form.
Figure 7: The DrawChart() function
So far, you are using fixed set of values to plot the chart. Let’s change
our code so that it fetches the values by invoking a web method instead. The
web method that returns the chart data as an array of integers looks like this:
<script runat="server"> [WebMethod] public static int[] GetChartData() { Random r = new Random(); int[] data = new int[5]; for (int i = 0; i < 5; i++) { data[i] = r.Next(10, 100); } return data; } </script>
The GetChartData() web method fills an integer array with random integers
between 10 and 100. Of course, in a more real world scenario you will pick the
values from a database.
You will invoke the web method using jQuery so ensure that you have added
jQuery library to your website.
<script src="Scripts/jquery-1.4.4.js" type="text/javascript"></script>
Then wire the click event handler for the "Get Chart Data" button
as shown below:
$(document).ready(function () { $("#Button1").click(OnGetData); })
The OnGetData() function calls the GetChartData() web method as shown below:
function OnGetData(event) { var url = "default.aspx/GetChartData"; successHandler = function (results) { chartData = results.d; DrawChart(); } $.ajax({ type: "POST", url: url, contentType: "application/json; charset=utf-8", dataType: "json", success: successHandler, error: function (err) { alert(err.status + " - " + err.statusText); } }) }
The OnGetData() function makes use of $.ajax() function to call the web
method. Notice how URL to the web method is specified as <web
form>/<web method name>. Once the web method returns, the code as
specified by successHandler will be invoked. The successHandler code
simply assigns the array returned by the web method to chartData global
variable. The chart is then redrawn by calling the DrawChart() method. (NOTE:
Detailed explanation of calling web methods using jQuery is beyond the scope of
this article.)
Run the web form and try clicking on the button a few times. Every time the
chart is re-drawn with new random values returned by the web method.
Summary
Canvas and drawing features of HTML5 make it easy for developers to draw
shapes and text via client side JavaScript code. The <canvas> tag defines
an HTML5 canvas. Drawing operations can then be performed on the canvas using
various rendering context methods. This article gave you a peek inside these
drawing features. You also learned to draw a pie chart that fetches its values
from a web method.